1/*
2 * Copyright (C) 2010 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.contacts.editor;
18
19import android.app.Dialog;
20import android.content.Context;
21import android.content.res.Resources;
22import android.os.Bundle;
23import android.text.TextUtils;
24import android.util.AttributeSet;
25import android.view.View;
26import android.widget.Button;
27
28import com.android.contacts.R;
29import com.android.contacts.datepicker.DatePicker;
30import com.android.contacts.datepicker.DatePickerDialog;
31import com.android.contacts.datepicker.DatePickerDialog.OnDateSetListener;
32import com.android.contacts.common.model.RawContactDelta;
33import com.android.contacts.common.model.ValuesDelta;
34import com.android.contacts.common.model.account.AccountType.EditField;
35import com.android.contacts.common.model.account.AccountType.EventEditType;
36import com.android.contacts.common.model.dataitem.DataKind;
37import com.android.contacts.common.util.CommonDateUtils;
38import com.android.contacts.common.util.DateUtils;
39
40import java.text.ParsePosition;
41import java.util.Calendar;
42import java.util.Date;
43import java.util.Locale;
44
45/**
46 * Editor that allows editing Events using a {@link DatePickerDialog}
47 */
48public class EventFieldEditorView extends LabeledEditorView {
49
50    /**
51     * Default string to show when there is no date selected yet.
52     */
53    private String mNoDateString;
54    private int mPrimaryTextColor;
55    private int mSecondaryTextColor;
56
57    private Button mDateView;
58
59    public EventFieldEditorView(Context context) {
60        super(context);
61    }
62
63    public EventFieldEditorView(Context context, AttributeSet attrs) {
64        super(context, attrs);
65    }
66
67    public EventFieldEditorView(Context context, AttributeSet attrs, int defStyle) {
68        super(context, attrs, defStyle);
69    }
70
71    /** {@inheritDoc} */
72    @Override
73    protected void onFinishInflate() {
74        super.onFinishInflate();
75
76        Resources resources = mContext.getResources();
77        mPrimaryTextColor = resources.getColor(R.color.primary_text_color);
78        mSecondaryTextColor = resources.getColor(R.color.secondary_text_color);
79        mNoDateString = mContext.getString(R.string.event_edit_field_hint_text);
80
81        mDateView = (Button) findViewById(R.id.date_view);
82        mDateView.setOnClickListener(new OnClickListener() {
83            @Override
84            public void onClick(View v) {
85                showDialog(R.id.dialog_event_date_picker);
86            }
87        });
88    }
89
90    @Override
91    public void editNewlyAddedField() {
92        showDialog(R.id.dialog_event_date_picker);
93    }
94
95    @Override
96    protected void requestFocusForFirstEditField() {
97        mDateView.requestFocus();
98    }
99
100    @Override
101    public void setEnabled(boolean enabled) {
102        super.setEnabled(enabled);
103
104        mDateView.setEnabled(!isReadOnly() && enabled);
105    }
106
107    @Override
108    public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly,
109            ViewIdGenerator vig) {
110        if (kind.fieldList.size() != 1) throw new IllegalStateException("kind must have 1 field");
111        super.setValues(kind, entry, state, readOnly, vig);
112
113        mDateView.setEnabled(isEnabled() && !readOnly);
114
115        rebuildDateView();
116    }
117
118    private void rebuildDateView() {
119        final EditField editField = getKind().fieldList.get(0);
120        final String column = editField.column;
121        String data = DateUtils.formatDate(getContext(), getEntry().getAsString(column),
122                false /*Use the short DateFormat to ensure that it fits inside the EditText*/);
123        if (TextUtils.isEmpty(data)) {
124            mDateView.setText(mNoDateString);
125            mDateView.setTextColor(mSecondaryTextColor);
126            setDeleteButtonVisible(false);
127        } else {
128            mDateView.setText(data);
129            mDateView.setTextColor(mPrimaryTextColor);
130            setDeleteButtonVisible(true);
131        }
132    }
133
134    @Override
135    public boolean isEmpty() {
136        final EditField editField = getKind().fieldList.get(0);
137        final String column = editField.column;
138        return TextUtils.isEmpty(getEntry().getAsString(column));
139    }
140
141    @Override
142    public Dialog createDialog(Bundle bundle) {
143        if (bundle == null) throw new IllegalArgumentException("bundle must not be null");
144        int dialogId = bundle.getInt(DIALOG_ID_KEY);
145        switch (dialogId) {
146            case R.id.dialog_event_date_picker:
147                return createDatePickerDialog();
148            default:
149                return super.createDialog(bundle);
150        }
151    }
152
153    @Override
154    protected EventEditType getType() {
155        return (EventEditType) super.getType();
156    }
157
158    @Override
159    protected void onLabelRebuilt() {
160        // if we changed to a type that requires a year, ensure that it is actually set
161        final String column = getKind().fieldList.get(0).column;
162        final String oldValue = getEntry().getAsString(column);
163        final DataKind kind = getKind();
164
165        final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US);
166        final int defaultYear = calendar.get(Calendar.YEAR);
167
168        // Check whether the year is optional
169        final boolean isYearOptional = getType().isYearOptional();
170
171        if (!isYearOptional && !TextUtils.isEmpty(oldValue)) {
172            final ParsePosition position = new ParsePosition(0);
173            final Date date2 = kind.dateFormatWithoutYear.parse(oldValue, position);
174
175            // Don't understand the date, lets not change it
176            if (date2 == null) return;
177
178            // This value is missing the year. Add it now
179            calendar.setTime(date2);
180            calendar.set(defaultYear, calendar.get(Calendar.MONTH),
181                    calendar.get(Calendar.DAY_OF_MONTH), CommonDateUtils.DEFAULT_HOUR, 0, 0);
182
183            onFieldChanged(column, kind.dateFormatWithYear.format(calendar.getTime()));
184            rebuildDateView();
185        }
186    }
187
188    /**
189     * Prepare dialog for entering a date
190     */
191    private Dialog createDatePickerDialog() {
192        final String column = getKind().fieldList.get(0).column;
193        final String oldValue = getEntry().getAsString(column);
194        final DataKind kind = getKind();
195
196        final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US);
197        final int defaultYear = calendar.get(Calendar.YEAR);
198
199        // Check whether the year is optional
200        final boolean isYearOptional = getType().isYearOptional();
201
202        final int oldYear, oldMonth, oldDay;
203
204        if (TextUtils.isEmpty(oldValue)) {
205            // Default to the current date
206            oldYear = defaultYear;
207            oldMonth = calendar.get(Calendar.MONTH);
208            oldDay = calendar.get(Calendar.DAY_OF_MONTH);
209        } else {
210            // Try parsing with year
211            Calendar cal = DateUtils.parseDate(oldValue, false);
212            if (cal != null) {
213                if (DateUtils.isYearSet(cal)) {
214                    oldYear = cal.get(Calendar.YEAR);
215                } else {
216                    //cal.set(Calendar.YEAR, 0);
217                    oldYear = isYearOptional ? DatePickerDialog.NO_YEAR : defaultYear;
218                }
219                oldMonth = cal.get(Calendar.MONTH);
220                oldDay = cal.get(Calendar.DAY_OF_MONTH);
221            } else {
222                return null;
223            }
224        }
225        final OnDateSetListener callBack = new OnDateSetListener() {
226            @Override
227            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
228                if (year == 0 && !isYearOptional) throw new IllegalStateException();
229                final Calendar outCalendar =
230                        Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US);
231
232                // If no year specified, set it to 2000 (we could pick any leap year here).
233                // The format string will ignore that year.
234                // For formats other than Exchange, the time of the day is ignored
235                outCalendar.clear();
236                outCalendar.set(year == DatePickerDialog.NO_YEAR ? 2000 : year, monthOfYear,
237                        dayOfMonth, CommonDateUtils.DEFAULT_HOUR, 0, 0);
238
239                final String resultString;
240                if (year == 0) {
241                    resultString = kind.dateFormatWithoutYear.format(outCalendar.getTime());
242                } else {
243                    resultString = kind.dateFormatWithYear.format(outCalendar.getTime());
244                }
245                onFieldChanged(column, resultString);
246                rebuildDateView();
247            }
248        };
249        final DatePickerDialog resultDialog = new DatePickerDialog(getContext(), callBack,
250                oldYear, oldMonth, oldDay, isYearOptional);
251        return resultDialog;
252    }
253
254    @Override
255    public void clearAllFields() {
256        // Update UI
257        mDateView.setText(mNoDateString);
258        mDateView.setTextColor(mSecondaryTextColor);
259
260        // Update state
261        final String column = getKind().fieldList.get(0).column;
262        onFieldChanged(column, "");
263    }
264}
265