TaskTimes.java :  » Clock » android-timetracker » net » ser1 » timetracker » Android Open Source

Android Open Source » Clock » android timetracker 
android timetracker » net » ser1 » timetracker » TaskTimes.java
/**
 * TimeTracker 
 * 2008, 2009 Sean Russell
 * @author Sean Russell <ser@germane-software.com>
 */
package net.ser1.timetracker;

import static net.ser1.timetracker.DBHelper.END;
import static net.ser1.timetracker.DBHelper.RANGES_TABLE;
import static net.ser1.timetracker.DBHelper.RANGE_COLUMNS;
import static net.ser1.timetracker.DBHelper.START;
import static net.ser1.timetracker.DBHelper.TASK_ID;
import static net.ser1.timetracker.EditTime.END_DATE;
import static net.ser1.timetracker.EditTime.START_DATE;
import static net.ser1.timetracker.TimeRange.NULL;
import static net.ser1.timetracker.DBHelper.TASK_NAME;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.method.SingleLineTransformationMethod;
import android.view.ContextMenu;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.AdapterContextMenuInfo;

public class TaskTimes extends ListActivity implements DialogInterface.OnClickListener {

    private TimesAdapter adapter;
    private static int FONT_SIZE;
    private static final int ADD_TIME = 0,  DELETE_TIME = 2,  EDIT_TIME = 3,  MOVE_TIME = 4;
    private static final int SEP = -99;
    private boolean decimalFormat;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedPreferences preferences = getSharedPreferences("timetracker.pref", MODE_PRIVATE);
        FONT_SIZE = preferences.getInt(Tasks.FONTSIZE, 16);
        if (adapter == null) {
            adapter = new TimesAdapter(this);
            setListAdapter(adapter);
        }
        decimalFormat = preferences.getBoolean( Tasks.TIMEDISPLAY, false );
        registerForContextMenu(getListView());
        Bundle extras = getIntent().getExtras();
        if (extras.get(START) != null) {
            adapter.loadTimes(extras.getInt(TASK_ID),
                    extras.getLong(START),
                    extras.getLong(END));
        } else {
            adapter.loadTimes(extras.getInt(TASK_ID));
        }
    }

        @Override
    protected void onStop() {
        adapter.close();
        super.onStop();
    }

    @Override
    protected void onResume() {
        super.onResume();
        getListView().invalidate();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        menu.add(0, ADD_TIME, 0, R.string.add_time_title).setIcon(android.R.drawable.ic_menu_add);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem i) {
        int id = i.getItemId();
        if (id == ADD_TIME) {
            Intent intent = new Intent(this, EditTime.class);
            intent.putExtra(EditTime.CLEAR, true);
            startActivityForResult(intent, id);
        }
        return super.onOptionsItemSelected(i);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
            ContextMenuInfo menuInfo) {
        menu.setHeaderTitle("Time menu");
        menu.add(0, EDIT_TIME, 0, "Edit Time");
        menu.add(0, DELETE_TIME, 0, "Delete Time");
        menu.add(0, MOVE_TIME, 0, "Move Time");
    }
    private TimeRange selectedRange;

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        selectedRange = (TimeRange) adapter.getItem((int) info.id);
        int id = item.getItemId();
        action = id;
        switch (id) {
            case DELETE_TIME:
                showDialog(id);
                break;
            case EDIT_TIME:
                Intent intent = new Intent(this, EditTime.class);
                intent.putExtra(EditTime.START_DATE, selectedRange.getStart());
                intent.putExtra(EditTime.END_DATE, selectedRange.getEnd());
                startActivityForResult(intent, id);
                break;
            case MOVE_TIME:
                showDialog(id);
            default:
                break;
        }
        return super.onContextItemSelected(item);
    }

    private int action;
    public void onClick(DialogInterface dialog, int whichButton) {
        switch (action) {
        case DELETE_TIME:
            adapter.deleteTimeRange(selectedRange);
            break;
        case MOVE_TIME:
            adapter.assignTimeToTaskAt(selectedRange, whichButton);
            break;
        default:
            break;
        }
        if (TaskTimes.this != null)
            TaskTimes.this.getListView().invalidate();
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
            case DELETE_TIME:
                return new AlertDialog.Builder(this)
                        .setTitle(R.string.delete_task_title)
                        .setIcon(android.R.drawable.stat_sys_warning)
                        .setCancelable(true)
                        .setMessage(R.string.delete_time_message)
                        .setPositiveButton(R.string.delete_ok, this)
                        .setNegativeButton(android.R.string.cancel, null).create();
            case MOVE_TIME:
                return new AlertDialog.Builder(this)
                        .setCursor(adapter.getTaskNames(), this, TASK_NAME)
                        .create();
            default:
                break;
        }
        return null;
    }
    private static final DateFormat SEPFORMAT = new SimpleDateFormat("EEEE, MMM dd yyyy");

    private class TimesAdapter extends BaseAdapter {

        private Context savedContext;
        private DBHelper dbHelper;
        private ArrayList<TimeRange> times;

        public TimesAdapter(Context c) {
            savedContext = c;
            dbHelper = new DBHelper(c);
            dbHelper.getWritableDatabase();
            times = new ArrayList<TimeRange>();
        }

        @Override
        public boolean areAllItemsEnabled() {
            return false;
        }

        @Override
        public boolean isEnabled(int position) {
            return times.get(position).getEnd() != SEP;
        }

        public void close() {
            dbHelper.close();
        }

        public void deleteTimeRange(TimeRange range) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();

            String whereClause = START + " = ? AND " + TASK_ID + " = ?";
            String[] whereValues;
            if (range.getEnd() == NULL) {
                whereClause += " AND " + END + " ISNULL";
                whereValues = new String[]{
                            String.valueOf(range.getStart()),
                            String.valueOf(getIntent().getExtras().getInt(DBHelper.TASK_ID))
                        };
            } else {
                whereClause += " AND " + END + " = ?";
                whereValues = new String[]{
                            String.valueOf(range.getStart()),
                            String.valueOf(getIntent().getExtras().getInt(DBHelper.TASK_ID)),
                            String.valueOf(range.getEnd())
                        };
            }
            db.delete(RANGES_TABLE, whereClause, whereValues);
            int pos = times.indexOf(range);
            if (pos > -1) {
                times.remove(pos);
                // p-1 = sep && p = END ||
                // p-1 = sep && p+1 = END
                // But, by this time, p+1 is now p, because we've removed p
                if (pos != 0 && times.get(pos - 1).getEnd() == SEP &&
                        (pos == times.size() || times.get(pos).getEnd() == SEP)) {
                    times.remove(pos - 1);
                }
            }
            notifyDataSetChanged();
        }

        protected void loadTimes(int selectedTaskId) {
            loadTimes(TASK_ID + " = ?",
                    new String[]{String.valueOf(selectedTaskId)});
        }

        protected void loadTimes(int selectedTaskId, long start, long end) {
            loadTimes(TASK_ID + " = ? AND " + START + " < ? AND " + START + " > ?",
                    new String[]{String.valueOf(selectedTaskId),
                        String.valueOf(end),
                        String.valueOf(start)});
        }

        protected void loadTimes(String where, String[] args) {
            SQLiteDatabase db = dbHelper.getReadableDatabase();
            Cursor c = db.query(RANGES_TABLE, RANGE_COLUMNS, where, args,
                    null, null, START + "," + END);
            if (c.moveToFirst()) {
                do {
                    times.add(new TimeRange(c.getLong(0),
                            c.isNull(1) ? NULL : c.getLong(1)));
                } while (c.moveToNext());
            }
            c.close();
            addSeparators();
            notifyDataSetChanged();
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            Object item = getItem(position);
            if (item == null) {
                return convertView;
            }
            TimeRange range = (TimeRange) item;
            if (range.getEnd() == SEP) {
                TextView headerText;
                if (convertView == null || !(convertView instanceof TextView)) {
                    headerText = new TextView(savedContext);
                    headerText.setTextSize(FONT_SIZE);
                    headerText.setTextColor(Color.YELLOW);
                    headerText.setTypeface(Typeface.DEFAULT, Typeface.ITALIC);
                    headerText.setText(SEPFORMAT.format(new Date(range.getStart())));
                } else {
                    headerText = (TextView) convertView;
                }
                headerText.setText(SEPFORMAT.format(new Date(range.getStart())));
                return headerText;
            }
            TimeView timeView;
            if (convertView == null || !(convertView instanceof TimeView)) {
                timeView = new TimeView(savedContext, (TimeRange) item);
            } else {
                timeView = (TimeView) convertView;
            }
            timeView.setTimeRange((TimeRange) item);
            return timeView;
        }

        public int getCount() {
            return times.size();
        }

        public Object getItem(int position) {
            return times.get(position);
        }

        public long getItemId(int position) {
            return position;
        }

        private void assignTimeToTaskAt(TimeRange range, int which) {
            Cursor c = getTaskNames();
            if (c.moveToFirst()) {
                while (which > 0) {
                    c.moveToNext();
                    which--;
                }
            }
            int newTaskId = c.getInt(0);
            if (!c.isAfterLast()) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();

                String whereClause = START + " = ? AND " + TASK_ID + " = ?";
                String[] whereValues;
                if (range.getEnd() == NULL) {
                    whereClause += " AND " + END + " ISNULL";
                    whereValues = new String[]{
                                String.valueOf(range.getStart()),
                                String.valueOf(getIntent().getExtras().getInt(DBHelper.TASK_ID))
                            };
                } else {
                    whereClause += " AND " + END + " = ?";
                    whereValues = new String[]{
                                String.valueOf(range.getStart()),
                                String.valueOf(getIntent().getExtras().getInt(DBHelper.TASK_ID)),
                                String.valueOf(range.getEnd())
                            };
                }
                ContentValues values = new ContentValues();
                values.put(TASK_ID, newTaskId);
                db.update(RANGES_TABLE, values, whereClause, whereValues);
                int pos = times.indexOf(range);
                times.remove(pos);
                if (pos != 0 && times.get(pos - 1).getEnd() == SEP && 
                        (pos == times.size() || times.get(pos).getEnd() == SEP)) {
                    times.remove(pos - 1);
                }
                notifyDataSetChanged();
            }
            c.close();
        }

        private class TimeView extends LinearLayout {

            private TextView dateRange;
            private TextView total;

            public TimeView(Context context, TimeRange t) {
                super(context);
                setOrientation(LinearLayout.HORIZONTAL);
                setPadding(5, 10, 5, 10);

                dateRange = new TextView(context);
                dateRange.setTextSize(FONT_SIZE);
                addView(dateRange, new LinearLayout.LayoutParams(
                        LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT, 1f));

                total = new TextView(context);
                total.setTextSize(FONT_SIZE);
                total.setGravity(Gravity.RIGHT);
                total.setTransformationMethod(SingleLineTransformationMethod.getInstance());
                addView(total, new LinearLayout.LayoutParams(
                        LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT, 0.0f));

                setTimeRange(t);
            }

            public void setTimeRange(TimeRange t) {
                dateRange.setText(t.toString());
                total.setText(Tasks.formatTotal(decimalFormat, t.getTotal()));
            /* If the following is added, then the timer to update the
             * display must also be added
            if (t.getEnd() == NULL) {
            dateRange.getPaint().setShadowLayer(1, 1, 1,Color.YELLOW);
            total.getPaint().setShadowLayer(1, 1, 1, Color.YELLOW);
            } else {
            dateRange.getPaint().clearShadowLayer();
            total.getPaint().clearShadowLayer();
            }
             */
            }
        }

        public void clear() {
            times.clear();
        }

        public void addTimeRange(long sd, long ed) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            ContentValues values = new ContentValues();
            values.put(TASK_ID, getIntent().getExtras().getInt(TASK_ID));
            values.put(START, sd);
            values.put(END, ed);
            db.insert(RANGES_TABLE, END, values);
            insert(times, new TimeRange(sd, ed));
            notifyDataSetChanged();
        }

        // Inserts an item into the list in order.  Why Java doesn't provide
        // this is beyond me.
        private void insert(ArrayList<TimeRange> list, TimeRange item) {
            int insertPoint = 0;
            for (; insertPoint < list.size(); insertPoint++) {
                if (list.get(insertPoint).compareTo(item) != -1) {
                    break;
                }
            }
            list.add(insertPoint, item);
            if (insertPoint > 0) {
                Calendar c = Calendar.getInstance();
                c.setFirstDayOfWeek(Calendar.MONDAY);
                TimeRange prev = list.get(insertPoint - 1);
                c.setTimeInMillis(prev.getStart());
                int pyear = c.get(Calendar.YEAR),
                        pday = c.get(Calendar.DAY_OF_YEAR);
                c.setTimeInMillis(item.getStart());
                if (pday != c.get(Calendar.DAY_OF_YEAR) ||
                        pyear != c.get(Calendar.YEAR)) {
                    times.add(insertPoint, new TimeRange(startOfDay(item.getStart()), SEP));
                }
            } else {
                times.add(insertPoint, new TimeRange(startOfDay(item.getStart()), SEP));
            }
        }

        private long startOfDay(long start) {
            Calendar cal = Calendar.getInstance();
            cal.setFirstDayOfWeek(Calendar.MONDAY);
            cal.setTimeInMillis(start);
            cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
            cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
            cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
            cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND));
            return cal.getTimeInMillis();
        }

        private void addSeparators() {
            int dayOfYear = -1, year = -1;
            Calendar curDay = Calendar.getInstance();
            curDay.setFirstDayOfWeek(Calendar.MONDAY);
            for (int i = 0; i < times.size(); i++) {
                TimeRange tr = times.get(i);
                curDay.setTimeInMillis(tr.getStart());
                int doy = curDay.get(Calendar.DAY_OF_YEAR);
                int y = curDay.get(Calendar.YEAR);
                if (doy != dayOfYear || y != year) {
                    dayOfYear = doy;
                    year = y;
                    times.add(i, new TimeRange(startOfDay(tr.getStart()), SEP));
                    i++;
                }
            }
        }

        public void updateTimeRange(long sd, long ed, int newTaskId, TimeRange old) {
            SQLiteDatabase db = dbHelper.getWritableDatabase();
            ContentValues values = new ContentValues();
            values.put(START, sd);
            int currentTaskId = getIntent().getExtras().getInt(TASK_ID);
            String whereClause = START + "=? AND " + TASK_ID + "=?";
            String[] whereValues;
            if (ed != NULL) {
                values.put(END, ed);
                whereClause += " AND " + END + "=?";
                whereValues = new String[]{String.valueOf(old.getStart()),
                            String.valueOf(currentTaskId),
                            String.valueOf(old.getEnd())
                        };
            } else {
                whereClause += " AND " + END + " ISNULL";
                whereValues = new String[]{String.valueOf(old.getStart()),
                            String.valueOf(currentTaskId)
                        };
            }
            db.update(RANGES_TABLE, values,
                    whereClause,
                    whereValues);
            if (newTaskId != currentTaskId) {
                times.remove(old);
            } else {
                old.setStart(sd);
                old.setEnd(ed);
            }
            notifyDataSetChanged();
        }

        protected Cursor getTaskNames() {
            SQLiteDatabase db = dbHelper.getReadableDatabase();
            Cursor c = db.query(DBHelper.TASK_TABLE, DBHelper.TASK_COLUMNS, null, null,
                    null, null, TASK_NAME);
            return c;
        }
    }

    @Override
    public void onActivityResult(int reqCode, int resCode, Intent intent) {
        if (resCode == Activity.RESULT_OK) {
            long sd = intent.getExtras().getLong(START_DATE);
            long ed = intent.getExtras().getLong(END_DATE);
            switch (reqCode) {
                case ADD_TIME:
                    adapter.addTimeRange(sd, ed);
                    break;
                case EDIT_TIME:
                    adapter.updateTimeRange(sd, ed,
                            getIntent().getExtras().getInt(TASK_ID), selectedRange);
                    break;
            }
        }
        this.getListView().invalidate();
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        // Disable previous
        selectedRange = (TimeRange) getListView().getItemAtPosition(position);
        if (selectedRange != null) {
            Intent intent = new Intent(this, EditTime.class);
            intent.putExtra(EditTime.START_DATE, selectedRange.getStart());
            intent.putExtra(EditTime.END_DATE, selectedRange.getEnd());
            startActivityForResult(intent, EDIT_TIME);
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.