AgendaListView.java revision a9507932dbc49ecb9f5c71fda6af3a47b0b2a39a
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.calendar.agenda;
18
19import com.android.calendar.CalendarController;
20import com.android.calendar.CalendarController.EventType;
21import com.android.calendar.DeleteEventHelper;
22import com.android.calendar.R;
23import com.android.calendar.Utils;
24import com.android.calendar.agenda.AgendaAdapter.ViewHolder;
25import com.android.calendar.agenda.AgendaWindowAdapter.EventInfo;
26
27import android.content.Context;
28import android.graphics.Color;
29import android.graphics.Rect;
30import android.text.format.Time;
31import android.util.Log;
32import android.view.View;
33import android.widget.AdapterView;
34import android.widget.AdapterView.OnItemClickListener;
35import android.widget.ListView;
36import android.widget.TextView;
37
38public class AgendaListView extends ListView implements OnItemClickListener {
39
40    private static final String TAG = "AgendaListView";
41    private static final boolean DEBUG = false;
42
43    private AgendaWindowAdapter mWindowAdapter;
44    private DeleteEventHelper mDeleteEventHelper;
45    private Context mContext;
46    private String mTimeZone;
47
48    private Runnable mTZUpdater = new Runnable() {
49        @Override
50        public void run() {
51            mTimeZone = Utils.getTimeZone(mContext, this);
52        }
53    };
54
55    public AgendaListView(Context context) {
56        super(context, null);
57        mContext = context;
58        mTimeZone = Utils.getTimeZone(context, mTZUpdater);
59        setOnItemClickListener(this);
60        setChoiceMode(ListView.CHOICE_MODE_SINGLE);
61        setVerticalScrollBarEnabled(false);
62        mWindowAdapter = new AgendaWindowAdapter(context, this);
63        setAdapter(mWindowAdapter);
64        setCacheColorHint(context.getResources().getColor(R.color.agenda_item_not_selected));
65        mDeleteEventHelper =
66            new DeleteEventHelper(context, null, false /* don't exit when done */);
67    }
68
69    @Override
70    protected void onDetachedFromWindow() {
71        super.onDetachedFromWindow();
72        mWindowAdapter.close();
73    }
74
75    // Implementation of the interface OnItemClickListener
76    @Override
77    public void onItemClick(AdapterView<?> a, View v, int position, long id) {
78        if (id != -1) {
79            // Switch to the EventInfo view
80            EventInfo event = mWindowAdapter.getEventByPosition(position);
81            mWindowAdapter.setSelectedPosition(position);
82            if (event != null) {
83                CalendarController.getInstance(mContext).sendEventRelatedEvent(this,
84                        EventType.VIEW_EVENT, event.id, event.begin, event.end, 0, 0);
85            }
86        }
87    }
88
89    public void goTo(Time time, String searchQuery, boolean forced) {
90        if (time == null) {
91            time = new Time(mTimeZone);
92            long goToTime = getFirstVisibleTime();
93            if (goToTime <= 0) {
94                goToTime = System.currentTimeMillis();
95            }
96            time.set(goToTime);
97        }
98        mWindowAdapter.refresh(time, searchQuery, forced);
99    }
100
101    public void refresh(boolean forced) {
102        Time time = new Time(Utils.getTimeZone(mContext, null));
103        long goToTime = getFirstVisibleTime();
104        if (goToTime <= 0) {
105            goToTime = System.currentTimeMillis();
106        }
107        time.set(goToTime);
108        mWindowAdapter.refresh(time, null, forced);
109    }
110
111    public void deleteSelectedEvent() {
112        int position = getSelectedItemPosition();
113        EventInfo event = mWindowAdapter.getEventByPosition(position);
114        if (event != null) {
115            mDeleteEventHelper.delete(event.begin, event.end, event.id, -1);
116        }
117    }
118
119    @Override
120    public int getFirstVisiblePosition() {
121        // TODO File bug!
122        // getFirstVisiblePosition doesn't always return the first visible
123        // item. Sometimes, it is above the visible one.
124        // instead. I loop through the viewgroup children and find the first
125        // visible one. BTW, getFirstVisiblePosition() == getChildAt(0). I
126        // am not looping through the entire list.
127       View v = getFirstVisibleView();
128       if (v != null) {
129           if (DEBUG) {
130               Log.v(TAG, "getFirstVisiblePosition: " + AgendaWindowAdapter.getViewTitle(v));
131           }
132           return getPositionForView(v);
133       }
134       return -1;
135    }
136
137    public View getFirstVisibleView() {
138        Rect r = new Rect();
139        int childCount = getChildCount();
140        for (int i = 0; i < childCount; ++i) {
141            View listItem = getChildAt(i);
142            listItem.getLocalVisibleRect(r);
143            if (r.top >= 0) { // if visible
144                return listItem;
145            }
146        }
147        return null;
148    }
149
150    public long getSelectedTime() {
151        int position = getSelectedItemPosition();
152        if (position >= 0) {
153            EventInfo event = mWindowAdapter.getEventByPosition(position);
154            if (event != null) {
155                return event.begin;
156            }
157        }
158        return getFirstVisibleTime();
159    }
160
161    public long getFirstVisibleTime() {
162        int position = getFirstVisiblePosition();
163        if (DEBUG) {
164            Log.v(TAG, "getFirstVisiblePosition = " + position);
165        }
166
167        EventInfo event = mWindowAdapter.getEventByPosition(position);
168        if (event != null) {
169            return event.begin;
170        }
171        return 0;
172    }
173
174    // Move the currently selected or visible focus down by offset amount.
175    // offset could be negative.
176    public void shiftSelection(int offset) {
177        shiftPosition(offset);
178        int position = getSelectedItemPosition();
179        if (position != INVALID_POSITION) {
180            setSelectionFromTop(position + offset, 0);
181        }
182    }
183
184    private void shiftPosition(int offset) {
185        if (DEBUG) {
186            Log.v(TAG, "Shifting position "+ offset);
187        }
188
189        View firstVisibleItem = getFirstVisibleView();
190
191        if (firstVisibleItem != null) {
192            Rect r = new Rect();
193            firstVisibleItem.getLocalVisibleRect(r);
194            // if r.top is < 0, getChildAt(0) and getFirstVisiblePosition() is
195            // returning an item above the first visible item.
196            int position = getPositionForView(firstVisibleItem);
197            setSelectionFromTop(position + offset, r.top > 0 ? -r.top : r.top);
198            if (DEBUG) {
199                if (firstVisibleItem.getTag() instanceof AgendaAdapter.ViewHolder) {
200                    ViewHolder viewHolder = (AgendaAdapter.ViewHolder)firstVisibleItem.getTag();
201                    Log.v(TAG, "Shifting from " + position + " by " + offset + ". Title "
202                            + viewHolder.title.getText());
203                } else if (firstVisibleItem.getTag() instanceof AgendaByDayAdapter.ViewHolder) {
204                    AgendaByDayAdapter.ViewHolder viewHolder =
205                        (AgendaByDayAdapter.ViewHolder)firstVisibleItem.getTag();
206                    Log.v(TAG, "Shifting from " + position + " by " + offset + ". Date  "
207                            + viewHolder.dateView.getText());
208                } else if (firstVisibleItem instanceof TextView) {
209                    Log.v(TAG, "Shifting: Looking at header here. " + getSelectedItemPosition());
210                }
211            }
212        } else if (getSelectedItemPosition() >= 0) {
213            if (DEBUG) {
214                Log.v(TAG, "Shifting selection from " + getSelectedItemPosition() + " by " + offset);
215            }
216            setSelection(getSelectedItemPosition() + offset);
217        }
218    }
219
220    public void setHideDeclinedEvents(boolean hideDeclined) {
221        mWindowAdapter.setHideDeclinedEvents(hideDeclined);
222    }
223
224    public void onResume() {
225        mTZUpdater.run();
226        mWindowAdapter.onResume();
227    }
228    public void onPause() {
229        mWindowAdapter.notifyDataSetInvalidated();
230    }
231}
232