summaryrefslogtreecommitdiffstats
path: root/src/com/android/calendar/AgendaByDayAdapter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/calendar/AgendaByDayAdapter.java')
-rw-r--r--src/com/android/calendar/AgendaByDayAdapter.java364
1 files changed, 364 insertions, 0 deletions
diff --git a/src/com/android/calendar/AgendaByDayAdapter.java b/src/com/android/calendar/AgendaByDayAdapter.java
new file mode 100644
index 00000000..a695693b
--- /dev/null
+++ b/src/com/android/calendar/AgendaByDayAdapter.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.calendar;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.pim.DateUtils;
+import android.pim.Time;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+public class AgendaByDayAdapter extends BaseAdapter {
+ private static final int TYPE_DAY = 0;
+ private static final int TYPE_MEETING = 1;
+ private static final int TYPE_LAST = 2;
+
+ private final Context mContext;
+ private final AgendaAdapter mAgendaAdapter;
+ private final LayoutInflater mInflater;
+ private ArrayList<RowInfo> mRowInfo;
+ private int mTodayJulianDay;
+ private Time mTime = new Time();
+
+ public AgendaByDayAdapter(Context context, AgendaAdapter agendaAdapter) {
+ mContext = context;
+ mAgendaAdapter = agendaAdapter;
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ public int getCount() {
+ if (mRowInfo != null) {
+ return mRowInfo.size();
+ }
+ return mAgendaAdapter.getCount();
+ }
+
+ public Object getItem(int position) {
+ if (mRowInfo != null) {
+ RowInfo row = mRowInfo.get(position);
+ if (row.mType == TYPE_DAY) {
+ return row;
+ } else {
+ return mAgendaAdapter.getItem(row.mData);
+ }
+ }
+ return mAgendaAdapter.getItem(position);
+ }
+
+ public long getItemId(int position) {
+ if (mRowInfo != null) {
+ RowInfo row = mRowInfo.get(position);
+ if (row.mType == TYPE_DAY) {
+ return position;
+ } else {
+ return mAgendaAdapter.getItemId(row.mData);
+ }
+ }
+ return mAgendaAdapter.getItemId(position);
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return TYPE_LAST;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mRowInfo != null && mRowInfo.size() > position ?
+ mRowInfo.get(position).mType : TYPE_DAY;
+ }
+
+ private static class ViewHolder {
+ TextView dateView;
+ TextView dayOfWeekView;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if ((mRowInfo == null) || (position > mRowInfo.size())) {
+ // If we have no row info, mAgendaAdapter returns the view.
+ return mAgendaAdapter.getView(position, convertView, parent);
+ }
+
+ RowInfo row = mRowInfo.get(position);
+ if (row.mType == TYPE_DAY) {
+ ViewHolder holder;
+ View agendaDayView;
+ if ((convertView == null) || (convertView.getTag() == null)) {
+ // Create a new AgendaView with a ViewHolder for fast access to
+ // views w/o calling findViewById()
+ holder = new ViewHolder();
+ agendaDayView = mInflater.inflate(R.layout.agenda_day, parent, false);
+ holder.dateView = (TextView) agendaDayView.findViewById(R.id.date);
+ holder.dayOfWeekView = (TextView) agendaDayView.findViewById(R.id.day_of_week);
+ agendaDayView.setTag(holder);
+ } else {
+ agendaDayView = convertView;
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ // Re-use the member variable "mTime" which is set to the local timezone.
+ Time date = mTime;
+ long millis = date.setJulianDay(row.mData);
+ int flags = DateUtils.FORMAT_NUMERIC_DATE;
+ holder.dateView.setText(DateUtils.formatDateRange(millis, millis, flags));
+
+ if (row.mData == mTodayJulianDay) {
+ holder.dayOfWeekView.setText(R.string.agenda_today);
+ } else {
+ int weekDay = date.weekDay + Calendar.SUNDAY;
+ holder.dayOfWeekView.setText(DateUtils.getDayOfWeekString(weekDay,
+ DateUtils.LENGTH_LONG));
+ }
+ return agendaDayView;
+ } else if (row.mType == TYPE_MEETING) {
+ return mAgendaAdapter.getView(row.mData, convertView, parent);
+ } else {
+ // Error
+ throw new IllegalStateException("Unknown event type:" + row.mType);
+ }
+ }
+
+ public void clearDayHeaderInfo() {
+ mRowInfo = null;
+ }
+
+ public void calculateDays(Cursor cursor) {
+ ArrayList<RowInfo> rowInfo = new ArrayList<RowInfo>();
+ int prevStartDay = -1;
+ Time time = new Time();
+ long now = System.currentTimeMillis();
+ time.set(now);
+ mTodayJulianDay = Time.getJulianDay(now, time.gmtoff);
+ LinkedList<MultipleDayInfo> multipleDayList = new LinkedList<MultipleDayInfo>();
+ for (int position = 0; cursor.moveToNext(); position++) {
+ boolean allDay = cursor.getInt(AgendaActivity.INDEX_ALL_DAY) != 0;
+ int startDay = cursor.getInt(AgendaActivity.INDEX_START_DAY);
+
+ if (startDay != prevStartDay) {
+ // Check if we skipped over any empty days
+ if (prevStartDay == -1) {
+ rowInfo.add(new RowInfo(TYPE_DAY, startDay));
+ } else {
+ // If there are any multiple-day events that span the empty
+ // range of days, then create day headers and events for
+ // those multiple-day events.
+ boolean dayHeaderAdded = false;
+ for (int currentDay = prevStartDay + 1; currentDay <= startDay; currentDay++) {
+ dayHeaderAdded = false;
+ Iterator<MultipleDayInfo> iter = multipleDayList.iterator();
+ while (iter.hasNext()) {
+ MultipleDayInfo info = iter.next();
+ // If this event has ended then remove it from the
+ // list.
+ if (info.mEndDay < currentDay) {
+ iter.remove();
+ continue;
+ }
+
+ // If this is the first event for the day, then
+ // insert a day header.
+ if (!dayHeaderAdded) {
+ rowInfo.add(new RowInfo(TYPE_DAY, currentDay));
+ dayHeaderAdded = true;
+ }
+ rowInfo.add(new RowInfo(TYPE_MEETING, info.mPosition));
+ }
+ }
+
+ // If the day header was not added for the start day, then
+ // add it now.
+ if (!dayHeaderAdded) {
+ rowInfo.add(new RowInfo(TYPE_DAY, startDay));
+ }
+ }
+ prevStartDay = startDay;
+ }
+
+ // Add in the event for this cursor position
+ rowInfo.add(new RowInfo(TYPE_MEETING, position));
+
+ // If this event spans multiple days, then add it to the multipleDay
+ // list.
+ int endDay = cursor.getInt(AgendaActivity.INDEX_END_DAY);
+ if (endDay > startDay) {
+ multipleDayList.add(new MultipleDayInfo(position, endDay));
+ }
+ }
+
+ // There are no more cursor events but we might still have multiple-day
+ // events left. So create day headers and events for those.
+ if (prevStartDay > 0) {
+ // Get the Julian day for the last day of this month. To do that,
+ // we set the date to one less than the first day of the next month,
+ // and then normalize.
+ time.setJulianDay(prevStartDay);
+ time.month += 1;
+ time.monthDay = 0; // monthDay starts with 1, so this is the previous day
+ long millis = time.normalize(true /* ignore isDst */);
+ int lastDayOfMonth = Time.getJulianDay(millis, time.gmtoff);
+
+ for (int currentDay = prevStartDay + 1; currentDay <= lastDayOfMonth; currentDay++) {
+ boolean dayHeaderAdded = false;
+ Iterator<MultipleDayInfo> iter = multipleDayList.iterator();
+ while (iter.hasNext()) {
+ MultipleDayInfo info = iter.next();
+ // If this event has ended then remove it from the
+ // list.
+ if (info.mEndDay < currentDay) {
+ iter.remove();
+ continue;
+ }
+
+ // If this is the first event for the day, then
+ // insert a day header.
+ if (!dayHeaderAdded) {
+ rowInfo.add(new RowInfo(TYPE_DAY, currentDay));
+ dayHeaderAdded = true;
+ }
+ rowInfo.add(new RowInfo(TYPE_MEETING, info.mPosition));
+ }
+ }
+ }
+ mRowInfo = rowInfo;
+ }
+
+ private static class RowInfo {
+ // mType is either a day header (TYPE_DAY) or an event (TYPE_MEETING)
+ final int mType;
+
+ // If mType is TYPE_DAY, then mData is the Julian day. Otherwise
+ // mType is TYPE_MEETING and mData is the cursor position.
+ final int mData;
+
+ RowInfo(int type, int data) {
+ mType = type;
+ mData = data;
+ }
+ }
+
+ private static class MultipleDayInfo {
+ final int mPosition;
+ final int mEndDay;
+
+ MultipleDayInfo(int position, int endDay) {
+ mPosition = position;
+ mEndDay = endDay;
+ }
+ }
+
+ /**
+ * Searches for the day that matches the given Time object and returns the
+ * list position of that day. If there are no events for that day, then it
+ * finds the nearest day (before or after) that has events and returns the
+ * list position for that day.
+ *
+ * @param time the date to search for
+ * @return the cursor position of the first event for that date, or zero
+ * if no match was found
+ */
+ public int findDayPositionNearestTime(Time time) {
+ if (mRowInfo == null) {
+ return 0;
+ }
+ long millis = time.toMillis(false /* use isDst */);
+ int julianDay = Time.getJulianDay(millis, time.gmtoff);
+ int minDistance = 1000; // some big number
+ int minIndex = 0;
+ int len = mRowInfo.size();
+ for (int index = 0; index < len; index++) {
+ RowInfo row = mRowInfo.get(index);
+ if (row.mType == TYPE_DAY) {
+ int distance = Math.abs(julianDay - row.mData);
+ if (distance == 0) {
+ return index;
+ }
+ if (distance < minDistance) {
+ minDistance = distance;
+ minIndex = index;
+ }
+ }
+ }
+
+ // We didn't find an exact match so take the nearest day that had
+ // events.
+ return minIndex;
+ }
+
+ /**
+ * Finds the Julian day containing the event at the given position.
+ *
+ * @param position the list position of an event
+ * @return the Julian day containing that event
+ */
+ public int findJulianDayFromPosition(int position) {
+ if (mRowInfo == null || position < 0) {
+ return 0;
+ }
+
+ int len = mRowInfo.size();
+ if (position >= len) return 0; // no row info at this position
+
+ for (int index = position; index >= 0; index--) {
+ RowInfo row = mRowInfo.get(index);
+ if (row.mType == TYPE_DAY) {
+ return row.mData;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Converts a list position to a cursor position. The list contains
+ * day headers as well as events. The cursor contains only events.
+ *
+ * @param listPos the list position of an event
+ * @return the corresponding cursor position of that event
+ */
+ public int getCursorPosition(int listPos) {
+ if (mRowInfo != null && listPos >= 0) {
+ RowInfo row = mRowInfo.get(listPos);
+ if (row.mType == TYPE_MEETING) {
+ return row.mData;
+ }
+ }
+ return listPos;
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ if (mRowInfo != null && position < mRowInfo.size()) {
+ RowInfo row = mRowInfo.get(position);
+ return row.mType == TYPE_MEETING;
+ }
+ return true;
+ }
+}
+