blob: a85044ff107c8f7f4d4d6cd0be038f22674a5c19 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 - 2006 University Of British Columbia and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* University Of British Columbia - initial API and implementation
*******************************************************************************/
/*
* Created on Dec 26, 2004
*/
package org.eclipse.mylar.tasks.ui;
import java.io.File;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.mylar.context.core.ContextCorePlugin;
import org.eclipse.mylar.context.core.IMylarContext;
import org.eclipse.mylar.context.core.IMylarContextListener;
import org.eclipse.mylar.context.core.IMylarElement;
import org.eclipse.mylar.core.MylarStatusHandler;
import org.eclipse.mylar.internal.context.core.MylarContextManager;
import org.eclipse.mylar.internal.tasks.core.RepositoryTaskHandleUtil;
import org.eclipse.mylar.internal.tasks.core.WebTask;
import org.eclipse.mylar.internal.tasks.ui.TaskListPreferenceConstants;
import org.eclipse.mylar.internal.tasks.ui.WorkspaceAwareContextStore;
import org.eclipse.mylar.internal.tasks.ui.util.TaskListSaveManager;
import org.eclipse.mylar.internal.tasks.ui.util.TaskListWriter;
import org.eclipse.mylar.internal.tasks.ui.views.TaskActivationHistory;
import org.eclipse.mylar.monitor.core.InteractionEvent;
import org.eclipse.mylar.tasks.core.AbstractQueryHit;
import org.eclipse.mylar.tasks.core.AbstractRepositoryTask;
import org.eclipse.mylar.tasks.core.AbstractTaskContainer;
import org.eclipse.mylar.tasks.core.DateRangeActivityDelegate;
import org.eclipse.mylar.tasks.core.DateRangeContainer;
import org.eclipse.mylar.tasks.core.ITask;
import org.eclipse.mylar.tasks.core.ITaskActivityListener;
import org.eclipse.mylar.tasks.core.ITaskListChangeListener;
import org.eclipse.mylar.tasks.core.ITaskListElement;
import org.eclipse.mylar.tasks.core.TaskList;
import org.eclipse.mylar.tasks.core.TaskRepository;
import org.eclipse.mylar.tasks.core.TaskRepositoryManager;
/**
* TODO: pull task activity management out into new TaskActivityManager
*
* @author Mik Kersten
* @author Rob Elves (task activity)
*/
public class TaskListManager implements IPropertyChangeListener {
// Did have preference for this so should re-enable
private static final int START_HOUR = 8;
private static final long SECOND = 1000;
private static final long MINUTE = 60 * SECOND;
private static final long ROLLOVER_DELAY = 30 * MINUTE;
private static final int NUM_WEEKS_PREVIOUS = -1;
private static final int NUM_WEEKS_NEXT = 1;
private static final int NUM_WEEKS_FUTURE_START = 2;
private static final int NUM_WEEKS_FUTURE_END = 8;
private static final int NUM_WEEKS_PAST_START = -8;
private static final int NUM_WEEKS_PAST_END = -2;
public static final String ARCHIVE_CATEGORY_DESCRIPTION = "Archive";
private static final String DESCRIPTION_THIS_WEEK = "This Week";
private static final String DESCRIPTION_PREVIOUS_WEEK = "Previous Week";
private static final String DESCRIPTION_NEXT_WEEK = "Next Week";
private static final String DESCRIPTION_FUTURE = "Future";
private static final String DESCRIPTION_PAST = "Past";
public static final String[] ESTIMATE_TIMES = new String[] { "0 Hours", "1 Hours", "2 Hours", "3 Hours", "4 Hours",
"5 Hours", "6 Hours", "7 Hours", "8 Hours", "9 Hours", "10 Hours" };
private DateRangeContainer activityPreviousWeek;
private DateRangeContainer activityThisWeek;
private List<DateRangeContainer> activityWeekDays = new ArrayList<DateRangeContainer>();
private DateRangeContainer activityNextWeek;
private DateRangeContainer activityFuture;
private DateRangeContainer activityPast;
private ArrayList<DateRangeContainer> dateRangeContainers = new ArrayList<DateRangeContainer>();
private Set<ITask> tasksWithReminders = new HashSet<ITask>();
private Set<ITask> tasksWithDueDates = new HashSet<ITask>();
private ITask currentTask = null;
private String currentHandle = "";
private Calendar currentTaskStart = null;
private Calendar currentTaskEnd = null;
private Map<ITask, Long> taskElapsedTimeMap = new ConcurrentHashMap<ITask, Long>();
private List<ITaskActivityListener> activityListeners = new ArrayList<ITaskActivityListener>();
private TaskListWriter taskListWriter;
private File taskListFile;
private TaskListSaveManager taskListSaveManager;
// TODO: guard against overwriting the single instance?
private TaskList taskList = new TaskList();
private TaskActivationHistory taskActivityHistory = new TaskActivationHistory();
private boolean taskListInitialized = false;
private boolean taskActivityHistoryInitialized = false;
private int startDay;
private int endDay;
private int scheduledEndHour;
private Timer timer;
/** public for testing */
public Date startTime = new Date();
private final IMylarContextListener CONTEXT_LISTENER = new IMylarContextListener() {
public void contextActivated(IMylarContext context) {
// ignore
}
public void contextDeactivated(IMylarContext context) {
// ignore
}
public void presentationSettingsChanging(UpdateKind kind) {
// ignore
}
public void presentationSettingsChanged(UpdateKind kind) {
// ignore
}
public void interestChanged(List<IMylarElement> elements) {
List<InteractionEvent> events = ContextCorePlugin.getContextManager().getActivityHistoryMetaContext()
.getInteractionHistory();
InteractionEvent event = events.get(events.size() - 1);
parseInteractionEvent(event);
}
public void elementDeleted(IMylarElement element) {
// ignore
}
public void landmarkAdded(IMylarElement element) {
// ignore
}
public void landmarkRemoved(IMylarElement element) {
// ignore
}
public void relationsChanged(IMylarElement element) {
// ignore
}
};
private final ITaskListChangeListener CHANGE_LISTENER = new ITaskListChangeListener() {
public void containerAdded(AbstractTaskContainer container) {
}
public void containerDeleted(AbstractTaskContainer container) {
}
public void containerInfoChanged(AbstractTaskContainer container) {
}
public void localInfoChanged(ITask task) {
}
public void repositoryInfoChanged(ITask task) {
}
public void taskAdded(ITask task) {
}
public void taskDeleted(ITask task) {
TaskListManager.this.resetAndRollOver();
}
public void taskMoved(ITask task, AbstractTaskContainer fromContainer, AbstractTaskContainer toContainer) {
}
};
private int timeTicks = 0;
public TaskListManager(TaskListWriter taskListWriter, File file) {
this.taskListFile = file;
this.taskListWriter = taskListWriter;
timer = new Timer();
timer.schedule(new RolloverCheck(), ROLLOVER_DELAY, ROLLOVER_DELAY);
taskList.addChangeListener(CHANGE_LISTENER);
}
public void init() {
ContextCorePlugin.getContextManager().addActivityMetaContextListener(CONTEXT_LISTENER);
}
public void dispose() {
ContextCorePlugin.getContextManager().removeActivityMetaContextListener(CONTEXT_LISTENER);
}
public TaskList resetTaskList() {
resetActivity();
taskList.reset();
taskListInitialized = true;
return taskList;
}
private void resetActivity() {
taskElapsedTimeMap.clear();
dateRangeContainers.clear();
setupCalendarRanges();
}
/**
* Warning: if called twice task times will be wrong
*/
private void parseTaskActivityInteractionHistory() {
if (!TasksUiPlugin.getTaskListManager().isTaskListInitialized()) {
return;
}
List<InteractionEvent> events = ContextCorePlugin.getContextManager().getActivityHistoryMetaContext()
.getInteractionHistory();
for (InteractionEvent event : events) {
try {
parseInteractionEvent(event);
} catch (Exception e) {
MylarStatusHandler.fail(e, "Error parsing interaction event", false);
}
}
taskActivityHistoryInitialized = true;
parseFutureReminders();
}
public void parseFutureReminders() {
activityFuture.clear();
activityNextWeek.clear();
for (DateRangeContainer day : activityWeekDays) {
day.clear();
}
HashSet<ITask> toRemove = new HashSet<ITask>();
toRemove.addAll(activityThisWeek.getDateRangeDelegates());
for (ITask activity : toRemove) {
DateRangeActivityDelegate delegate = (DateRangeActivityDelegate) activity;
Calendar calendar = GregorianCalendar.getInstance();
Date schedDate = delegate.getScheduledForDate();
if (schedDate == null) {
schedDate = delegate.getDueDate();
}
if (schedDate != null) {
calendar.setTime(schedDate);
if (!activityThisWeek.includes(calendar) && activityThisWeek.getElapsed(delegate) == 0) {
activityThisWeek.remove(delegate);
}
} else {
if (activityThisWeek.getElapsed(delegate) == 0) {
activityThisWeek.remove(delegate);
}
}
}
GregorianCalendar tempCalendar = new GregorianCalendar();
tempCalendar.setFirstDayOfWeek(startDay);
Set<ITask> allScheduledTasks = new HashSet<ITask>();
allScheduledTasks.addAll(tasksWithReminders);
allScheduledTasks.addAll(tasksWithDueDates);
for (ITask task : allScheduledTasks) {
if (task instanceof DateRangeActivityDelegate) {
task = ((DateRangeActivityDelegate) task).getCorrespondingTask();
}
Date schedDate = task.getScheduledForDate();
if (schedDate == null || isOverdue(task)) {
schedDate = task.getDueDate();
}
if (schedDate != null) {
tempCalendar.setTime(schedDate);
if (activityNextWeek.includes(tempCalendar)) {
activityNextWeek.addTask(new DateRangeActivityDelegate(activityNextWeek, task, tempCalendar,
tempCalendar));
} else if (activityFuture.includes(tempCalendar)) {
activityFuture.addTask(new DateRangeActivityDelegate(activityFuture, task, tempCalendar,
tempCalendar));
} else if (activityThisWeek.includes(tempCalendar) && !activityThisWeek.getChildren().contains(task)) {
activityThisWeek.addTask(new DateRangeActivityDelegate(activityThisWeek, task, tempCalendar,
tempCalendar));
} else if (activityPreviousWeek.includes(tempCalendar)
&& !activityPreviousWeek.getChildren().contains(task)) {
activityPreviousWeek.addTask(new DateRangeActivityDelegate(activityPreviousWeek, task,
tempCalendar, tempCalendar));
} else if (activityPast.includes(tempCalendar) && !activityPast.getChildren().contains(task)) {
activityPast.addTask(new DateRangeActivityDelegate(activityPast, task, tempCalendar, tempCalendar));
}
for (DateRangeContainer day : activityWeekDays) {
if (day.includes(tempCalendar) && !day.getChildren().contains(task)) {
day.addTask(new DateRangeActivityDelegate(day, task, tempCalendar, tempCalendar, this
.getElapsedTime(task)));
}
}
}
}
}
/** public for testing * */
public void parseInteractionEvent(InteractionEvent event) {
if (event.getDelta().equals(MylarContextManager.ACTIVITY_DELTA_ACTIVATED)) {
if (!event.getStructureHandle().equals(MylarContextManager.ACTIVITY_HANDLE_ATTENTION)) {
ITask activatedTask = TasksUiPlugin.getTaskListManager().getTaskList().getTask(
event.getStructureHandle());
if (currentTask != null && activatedTask != null) {
if (!currentTask.equals(activatedTask)) {
GregorianCalendar calendarEnd = new GregorianCalendar();
calendarEnd.setFirstDayOfWeek(startDay);
calendarEnd.setTime(event.getDate());
calendarEnd.getTime();
// Activation of different task before deactivation of
// previous, log was inconsistent,
// finish what we started
taskDeactivated(calendarEnd);
} else {
// skip re-activations of same task
return;
}
}
currentTask = activatedTask;
if (currentTask != null) {
GregorianCalendar calendar = new GregorianCalendar();
calendar.setFirstDayOfWeek(startDay);
calendar.setTime(event.getDate());
currentTaskStart = calendar;
currentHandle = event.getStructureHandle();
}
} else if (event.getStructureHandle().equals(MylarContextManager.ACTIVITY_HANDLE_ATTENTION)) {
if (currentTask != null && !currentHandle.equals("")) {
long active = event.getEndDate().getTime() - event.getDate().getTime();
// add to running total
if (taskElapsedTimeMap.containsKey(currentTask)) {
long pastTime = taskElapsedTimeMap.get(currentTask);
taskElapsedTimeMap.put(currentTask, pastTime + active);
timeTicks++;
if (taskActivityHistoryInitialized && timeTicks > 3) {
// Save incase of system failure.
// TODO: request asynchronous save
ContextCorePlugin.getContextManager().saveActivityHistoryContext();
timeTicks = 0;
}
} else {
taskElapsedTimeMap.put(currentTask, active);
}
}
}
} else if (event.getDelta().equals(MylarContextManager.ACTIVITY_DELTA_DEACTIVATED)) {
if (!event.getStructureHandle().equals(MylarContextManager.ACTIVITY_HANDLE_ATTENTION)
&& currentHandle.equals(event.getStructureHandle())) {
GregorianCalendar calendarEnd = new GregorianCalendar();
calendarEnd.setFirstDayOfWeek(startDay);
calendarEnd.setTime(event.getDate());
calendarEnd.getTime();
taskDeactivated(calendarEnd);
} else if (event.getStructureHandle().equals(MylarContextManager.ACTIVITY_HANDLE_ATTENTION)) {
// Deactivated attention events not currently used (ignored)
}
}
}
private void taskDeactivated(GregorianCalendar calendarEnd) {
currentTaskEnd = calendarEnd;
Set<DateRangeContainer> rangeSet = new HashSet<DateRangeContainer>();
rangeSet.addAll(dateRangeContainers);
rangeSet.add(activityThisWeek);
for (DateRangeContainer week : rangeSet) {
if (week.includes(currentTaskStart) && (!isWeekDay(week) && !week.isFuture())) {
if (currentTask != null) {
// add to date range 'bin'
Long activeTime = taskElapsedTimeMap.get(currentTask);
if (activeTime == null) {
activeTime = new Long(0);
}
DateRangeActivityDelegate delegate = new DateRangeActivityDelegate(week, currentTask,
currentTaskStart, currentTaskEnd, activeTime);
week.addTask(delegate);
if (taskActivityHistoryInitialized) {
for (ITaskActivityListener listener : activityListeners) {
listener.activityChanged(week);
}
}
}
}
}
currentTask = null;
currentHandle = "";
}
/** public for testing * */
public DateRangeContainer getActivityThisWeek() {
return activityThisWeek;
}
/** public for testing * */
public DateRangeContainer getActivityPast() {
return activityPast;
}
/** public for testing * */
public DateRangeContainer getActivityFuture() {
return activityFuture;
}
/** public for testing * */
public DateRangeContainer getActivityNextWeek() {
return activityNextWeek;
}
/** public for testing * */
public DateRangeContainer getActivityPrevious() {
return activityPreviousWeek;
}
/** total elapsed time based on activation history */
public long getElapsedTime(ITask task) {
if (taskElapsedTimeMap.containsKey(task)) {
return taskElapsedTimeMap.get(task);
} else {
return 0;
}
}
private void setupCalendarRanges() {
// MylarTaskListPlugin.getMylarCorePrefs().getInt(TaskListPreferenceConstants.PLANNING_STARTDAY);
startDay = Calendar.MONDAY;
// MylarTaskListPlugin.getMylarCorePrefs().getInt(TaskListPreferenceConstants.PLANNING_ENDDAY);
endDay = Calendar.SUNDAY;
// scheduledStartHour =
// TasksUiPlugin.getDefault().getPreferenceStore().getInt(
// TaskListPreferenceConstants.PLANNING_STARTHOUR);
scheduledEndHour = TasksUiPlugin.getDefault().getPreferenceStore().getInt(
TaskListPreferenceConstants.PLANNING_ENDHOUR);
activityWeekDays.clear();
for (int x = startDay; x < (startDay + 7); x++) {
GregorianCalendar dayStart = new GregorianCalendar();
GregorianCalendar dayEnd = new GregorianCalendar();
dayStart.setFirstDayOfWeek(startDay);
dayEnd.setFirstDayOfWeek(startDay);
if (x > 7) {
dayStart.set(Calendar.DAY_OF_WEEK, x % 7);
dayEnd.set(Calendar.DAY_OF_WEEK, x % 7);
} else {
dayStart.set(Calendar.DAY_OF_WEEK, x);
dayEnd.set(Calendar.DAY_OF_WEEK, x);
}
dayStart.set(Calendar.HOUR_OF_DAY, 0);
dayStart.set(Calendar.MINUTE, 0);
dayStart.set(Calendar.SECOND, 0);
dayStart.set(Calendar.MILLISECOND, 0);
dayStart.getTime();
dayEnd.set(Calendar.HOUR_OF_DAY, dayEnd.getMaximum(Calendar.HOUR_OF_DAY));
dayEnd.set(Calendar.MINUTE, dayEnd.getMaximum(Calendar.MINUTE));
dayEnd.set(Calendar.SECOND, dayEnd.getMaximum(Calendar.SECOND));
dayEnd.set(Calendar.MILLISECOND, dayEnd.getMaximum(Calendar.MILLISECOND));
dayEnd.getTime();
String summary = "<unknown>";
switch (dayStart.get(Calendar.DAY_OF_WEEK)) {
case Calendar.MONDAY:
summary = "Monday";
break;
case Calendar.TUESDAY:
summary = "Tuesday";
break;
case Calendar.WEDNESDAY:
summary = "Wednesday";
break;
case Calendar.THURSDAY:
summary = "Thursday";
break;
case Calendar.FRIDAY:
summary = "Friday";
break;
case Calendar.SATURDAY:
summary = "Saturday";
break;
case Calendar.SUNDAY:
summary = "Sunday";
break;
}
DateRangeContainer day = new DateRangeContainer(dayStart, dayEnd, summary, taskList);
activityWeekDays.add(day);
dateRangeContainers.add(day);
}
GregorianCalendar currentBegin = new GregorianCalendar();
currentBegin.setFirstDayOfWeek(startDay);
currentBegin.setTime(startTime);
snapToStartOfWeek(currentBegin);
GregorianCalendar currentEnd = new GregorianCalendar();
currentEnd.setFirstDayOfWeek(startDay);
currentEnd.setTime(startTime);
snapToEndOfWeek(currentEnd);
activityThisWeek = new DateRangeContainer(currentBegin, currentEnd, DESCRIPTION_THIS_WEEK, taskList);
// dateRangeContainers.add(activityThisWeek);
GregorianCalendar previousStart = new GregorianCalendar();
previousStart.setFirstDayOfWeek(startDay);
previousStart.setTime(startTime);
previousStart.add(Calendar.WEEK_OF_YEAR, NUM_WEEKS_PREVIOUS);
snapToStartOfWeek(previousStart);
GregorianCalendar previousEnd = new GregorianCalendar();
previousEnd.setFirstDayOfWeek(startDay);
previousEnd.setTime(startTime);
previousEnd.add(Calendar.WEEK_OF_YEAR, NUM_WEEKS_PREVIOUS);
snapToEndOfWeek(previousEnd);
activityPreviousWeek = new DateRangeContainer(previousStart.getTime(), previousEnd.getTime(),
DESCRIPTION_PREVIOUS_WEEK, taskList);
dateRangeContainers.add(activityPreviousWeek);
GregorianCalendar nextStart = new GregorianCalendar();
nextStart.setFirstDayOfWeek(startDay);
nextStart.setTime(startTime);
nextStart.add(Calendar.WEEK_OF_YEAR, NUM_WEEKS_NEXT);
snapToStartOfWeek(nextStart);
GregorianCalendar nextEnd = new GregorianCalendar();
nextEnd.setFirstDayOfWeek(startDay);
nextEnd.setTime(startTime);
nextEnd.add(Calendar.WEEK_OF_YEAR, NUM_WEEKS_NEXT);
snapToEndOfWeek(nextEnd);
activityNextWeek = new DateRangeContainer(nextStart.getTime(), nextEnd.getTime(), DESCRIPTION_NEXT_WEEK,
taskList);
dateRangeContainers.add(activityNextWeek);
GregorianCalendar futureStart = new GregorianCalendar();
futureStart.setFirstDayOfWeek(startDay);
futureStart.setTime(startTime);
futureStart.add(Calendar.WEEK_OF_YEAR, NUM_WEEKS_FUTURE_START);
snapToStartOfWeek(futureStart);
GregorianCalendar futureEnd = new GregorianCalendar();
futureEnd.setFirstDayOfWeek(startDay);
futureEnd.setTime(startTime);
futureEnd.add(Calendar.WEEK_OF_YEAR, NUM_WEEKS_FUTURE_END);
snapToEndOfWeek(futureEnd);
activityFuture = new DateRangeContainer(futureStart.getTime(), futureEnd.getTime(), DESCRIPTION_FUTURE,
taskList);
dateRangeContainers.add(activityFuture);
GregorianCalendar pastStart = new GregorianCalendar();
pastStart.setFirstDayOfWeek(startDay);
pastStart.setTime(startTime);
pastStart.add(Calendar.WEEK_OF_YEAR, NUM_WEEKS_PAST_START);
snapToStartOfWeek(pastStart);
GregorianCalendar pastEnd = new GregorianCalendar();
pastEnd.setFirstDayOfWeek(startDay);
pastEnd.setTime(startTime);
pastEnd.add(Calendar.WEEK_OF_YEAR, NUM_WEEKS_PAST_END);
snapToEndOfWeek(pastEnd);
activityPast = new DateRangeContainer(pastStart.getTime(), pastEnd.getTime(), DESCRIPTION_PAST, taskList);
dateRangeContainers.add(activityPast);
}
public void snapToNextDay(Calendar cal) {
cal.add(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.getTime();
}
private void snapToStartOfWeek(Calendar cal) {
cal.getTime();
cal.set(Calendar.DAY_OF_WEEK, startDay);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.getTime();
}
private void snapToEndOfWeek(Calendar cal) {
cal.getTime();
cal.set(Calendar.DAY_OF_WEEK, endDay);
cal.set(Calendar.HOUR_OF_DAY, cal.getMaximum(Calendar.HOUR_OF_DAY));
cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
cal.set(Calendar.MILLISECOND, cal.getMaximum(Calendar.MILLISECOND));
cal.getTime();
}
public Calendar setSecheduledIn(Calendar calendar, int days) {
calendar.add(Calendar.DAY_OF_MONTH, days);
calendar.set(Calendar.HOUR_OF_DAY, scheduledEndHour);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar;
}
/**
* Will schedule for today if past work-day's end.
*/
public Calendar setScheduledEndOfDay(Calendar calendar) {
// Calendar now = Calendar.getInstance();
// if (now.get(Calendar.HOUR_OF_DAY) >= scheduledEndHour) {
// setSecheduledIn(calendar, 1);
// }
calendar.set(Calendar.HOUR_OF_DAY, scheduledEndHour);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar;
}
public void setScheduledNextWeek(Calendar calendar) {
calendar.setTimeInMillis(TasksUiPlugin.getTaskListManager().getActivityNextWeek().getStart().getTimeInMillis());
setScheduledEndOfDay(calendar);
}
public List<DateRangeContainer> getDateRanges() {
// parseFutureReminders();
// return dateRangeContainers.toArray(new
// ITaskListElement[dateRangeContainers.size()]);
return dateRangeContainers;
}
/**
* Every call to this method generates a unique handle, subsequent calls
* will have incremented task numbers
*/
public String genUniqueTaskHandle() {
return TaskRepositoryManager.PREFIX_LOCAL + taskList.getNextTaskNum();
}
public void refactorRepositoryUrl(String oldUrl, String newUrl) {
if (oldUrl == null || newUrl == null || oldUrl.equals(newUrl)) {
return;
}
List<ITask> activeTasks = taskList.getActiveTasks();
for (ITask task : new ArrayList<ITask>(activeTasks)) {
deactivateTask(task);
}
taskList.refactorRepositoryUrl(oldUrl, newUrl);
File dataDir = new File(TasksUiPlugin.getDefault().getDataDirectory(),
WorkspaceAwareContextStore.CONTEXTS_DIRECTORY);
if (dataDir.exists() && dataDir.isDirectory()) {
for (File file : dataDir.listFiles()) {
int dotIndex = file.getName().lastIndexOf(".xml");
if (dotIndex != -1) {
String storedHandle;
try {
storedHandle = URLDecoder.decode(file.getName().substring(0, dotIndex),
MylarContextManager.CONTEXT_FILENAME_ENCODING);
int delimIndex = storedHandle.lastIndexOf(RepositoryTaskHandleUtil.HANDLE_DELIM);
if (delimIndex != -1) {
String storedUrl = storedHandle.substring(0, delimIndex);
if (oldUrl.equals(storedUrl)) {
String id = RepositoryTaskHandleUtil.getTaskId(storedHandle);
String newHandle = RepositoryTaskHandleUtil.getHandle(newUrl, id);
File newFile = ContextCorePlugin.getContextManager().getFileForContext(newHandle);
file.renameTo(newFile);
}
}
} catch (Exception e) {
MylarStatusHandler.fail(e, "Could not move context file: " + file.getName(), false);
}
}
}
}
saveTaskList();
}
public boolean readExistingOrCreateNewList() {
try {
if (taskListFile.exists()) {
taskListWriter.readTaskList(taskList, taskListFile, TasksUiPlugin.getDefault().getTaskDataManager());
} else {
resetTaskList();
}
for (ITask task : taskList.getAllTasks()) {
if (task.getScheduledForDate() != null) {
tasksWithReminders.add(task);
}
if (task.getDueDate() != null) {
tasksWithDueDates.add(task);
}
}
resetActivity();
// parseFutureReminders();
taskListInitialized = true;
for (ITaskActivityListener listener : new ArrayList<ITaskActivityListener>(activityListeners)) {
listener.taskListRead();
}
} catch (Exception e) {
MylarStatusHandler.log(e, "Could not read task list");
return false;
}
return true;
}
/**
* Only to be called upon initial startup by plugin.
*/
public void initActivityHistory() {
resetAndRollOver();
taskActivityHistory.loadPersistentHistory();
}
/**
* Will not save an empty task list to avoid losing data on bad startup.
*/
public synchronized void saveTaskList() {
try {
if (taskListInitialized) {
taskListSaveManager.saveTaskList(true, false);
// TasksUiPlugin.getDefault().getPreferenceStore().setValue(TaskListPreferenceConstants.TASK_ID,
// nextLocalTaskId);
} else {
MylarStatusHandler.log("task list save attempted before initialization", this);
}
} catch (Exception e) {
MylarStatusHandler.fail(e, "Could not save task list", true);
}
}
public TaskList getTaskList() {
return taskList;
}
public void addActivityListener(ITaskActivityListener listener) {
activityListeners.add(listener);
}
public void removeActivityListener(ITaskActivityListener listener) {
activityListeners.remove(listener);
}
public void activateTask(ITask task) {
if (!TasksUiPlugin.getDefault().isMultipleActiveTasksMode()) {
deactivateAllTasks();
}
try {
taskList.setActive(task, true);
for (ITaskActivityListener listener : new ArrayList<ITaskActivityListener>(activityListeners)) {
try {
listener.taskActivated(task);
} catch (Throwable t) {
MylarStatusHandler.fail(t, "task activity listener failed: " + listener, false);
}
}
} catch (Throwable t) {
MylarStatusHandler.fail(t, "could not activate task", false);
}
}
public void deactivateAllTasks() {
// Make a copy to avoid modification on list being traversed; can result
// in a ConcurrentModificationException
List<ITask> activeTasks = taskList.getActiveTasks();
for (ITask task : activeTasks) {
deactivateTask(task);
}
}
public void deactivateTask(ITask task) {
if (task == null) {
return;
}
if (task.isActive()) {
taskList.setActive(task, false);
for (ITaskActivityListener listener : new ArrayList<ITaskActivityListener>(activityListeners)) {
try {
listener.taskDeactivated(task);
} catch (Throwable t) {
MylarStatusHandler.fail(t, "notification failed for: " + listener, false);
}
}
}
}
public void setTaskListFile(File file) {
this.taskListFile = file;
}
public void copyDataDirContentsTo(String newDataDir) {
taskListSaveManager.copyDataDirContentsTo(newDataDir);
}
public boolean isTaskListInitialized() {
return taskListInitialized;
}
public TaskListWriter getTaskListWriter() {
return taskListWriter;
}
public File getTaskListFile() {
return taskListFile;
}
public boolean isActiveThisWeek(ITask task) {
for (ITask activityDelegateTask : activityThisWeek.getChildren()) {
if (activityDelegateTask.getHandleIdentifier().equals(task.getHandleIdentifier())) {
return true;
}
}
return false;
}
/**
* @return if a repository task, will only return true if the user is a
*/
public boolean isCompletedToday(ITask task) {
if (task != null) {
if (task instanceof AbstractRepositoryTask && !(task instanceof WebTask)) {
AbstractRepositoryTask repositoryTask = (AbstractRepositoryTask) task;
TaskRepository repository = TasksUiPlugin.getRepositoryManager().getRepository(
repositoryTask.getRepositoryKind(), repositoryTask.getRepositoryUrl());
if (repository != null && repositoryTask.getOwner() != null
&& !repositoryTask.getOwner().equals(repository.getUserName())) {
return false;
}
}
Date completionDate = task.getCompletionDate();
if (completionDate != null) {
Calendar tomorrow = Calendar.getInstance();
snapToNextDay(tomorrow);
Calendar yesterday = Calendar.getInstance();
yesterday.set(Calendar.HOUR_OF_DAY, 0);
yesterday.set(Calendar.MINUTE, 0);
yesterday.set(Calendar.SECOND, 0);
yesterday.set(Calendar.MILLISECOND, 0);
return completionDate.compareTo(yesterday.getTime()) == 1
&& completionDate.compareTo(tomorrow.getTime()) == -1;
}
}
return false;
}
public boolean isScheduledAfterThisWeek(ITask task) {
if (task != null) {
Date reminder = task.getScheduledForDate();
if (reminder != null) {
return reminder.compareTo(activityNextWeek.getStart().getTime()) > -1;
}
}
return false;
}
public boolean isScheduledForLater(ITask task) {
if (task != null) {
Date reminder = task.getScheduledForDate();
if (reminder != null) {
return reminder.compareTo(activityFuture.getStart().getTime()) > -1;
}
}
return false;
}
public boolean isScheduledForThisWeek(ITask task) {
if (task != null) {
Date reminder = task.getScheduledForDate();
if (reminder != null) {
Calendar weekStart = Calendar.getInstance();
snapToStartOfWeek(weekStart);
return (reminder.compareTo(weekStart.getTime()) >= 0 && reminder.compareTo(activityThisWeek.getEnd()
.getTime()) <= 0);
}
}
return false;
}
public boolean isScheduledForToday(ITask task) {
if (task != null) {
Date reminder = task.getScheduledForDate();
if (reminder != null) {
Calendar dayStart = Calendar.getInstance();
dayStart.set(Calendar.HOUR_OF_DAY, 0);
dayStart.set(Calendar.MINUTE, 0);
dayStart.set(Calendar.SECOND, 0);
dayStart.set(Calendar.MILLISECOND, 0);
Calendar midnight = GregorianCalendar.getInstance();
snapToNextDay(midnight);
return (reminder.compareTo(dayStart.getTime()) >= 0 && reminder.compareTo(midnight.getTime()) == -1);
}
}
return false;
}
/**
* TODO: Need to migrate to use of this method for setting of reminders
*/
public void setScheduledFor(ITask task, Date reminderDate) {
if (task == null)
return;
task.setScheduledForDate(reminderDate);
task.setReminded(false);
if (reminderDate == null) {
tasksWithReminders.remove(task);
} else {
tasksWithReminders.remove(task);
tasksWithReminders.add(task);
}
parseFutureReminders();
taskList.notifyLocalInfoChanged(task);
}
public void setDueDate(ITask task, Date dueDate) {
task.setDueDate(dueDate);
if (dueDate == null) {
tasksWithDueDates.remove(task);
} else {
tasksWithDueDates.remove(task);
tasksWithDueDates.add(task);
}
parseFutureReminders();
taskList.notifyLocalInfoChanged(task);
}
/**
* @return true if task due date != null and has past
*/
public boolean isOverdue(ITask task) {
return (!task.isCompleted() && task.getDueDate() != null && new Date().after(task.getDueDate()));
}
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty().equals(TaskListPreferenceConstants.PLANNING_STARTHOUR)
|| event.getProperty().equals(TaskListPreferenceConstants.PLANNING_ENDHOUR)) {
// event.getProperty().equals(TaskListPreferenceConstants.PLANNING_STARTDAY)
// scheduledStartHour =
// TasksUiPlugin.getDefault().getPreferenceStore().getInt(
// TaskListPreferenceConstants.PLANNING_STARTHOUR);
scheduledEndHour = TasksUiPlugin.getDefault().getPreferenceStore().getInt(
TaskListPreferenceConstants.PLANNING_ENDHOUR);
}
}
/** public for testing */
public void resetAndRollOver() {
taskActivityHistoryInitialized = false;
tasksWithReminders.clear();
tasksWithDueDates.clear();
for (ITask task : taskList.getAllTasks()) {
if (task.getScheduledForDate() != null) {
tasksWithReminders.add(task);
}
if (task.getDueDate() != null) {
tasksWithDueDates.add(task);
}
}
resetActivity();
parseTaskActivityInteractionHistory();
for (ITaskActivityListener listener : activityListeners) {
listener.calendarChanged();
}
}
private class RolloverCheck extends TimerTask {
@Override
public void run() {
if (!Platform.isRunning() || ContextCorePlugin.getDefault() == null) {
return;
} else {
Calendar now = GregorianCalendar.getInstance();
DateRangeContainer thisWeek = getActivityThisWeek();
if (!thisWeek.includes(now)) {
startTime = new Date();
resetAndRollOver();
}
}
}
}
public TaskActivationHistory getTaskActivationHistory() {
return taskActivityHistory;
}
public Set<ITask> getScheduledForThisWeek() {
Set<ITask> tasksScheduled = new HashSet<ITask>();
for (ITask task : getActivityThisWeek().getChildren()) {
if (isScheduledForThisWeek(task)) {
tasksScheduled.add(task);
}
}
return tasksScheduled;
}
/**
* @param element
* tasklist element to retrieve a task for currently will work
* for (ITask, AbstractQueryHit)
* @param force -
* if a query hit is passed you can either force construction of
* the task or not (if not and no task, null is returned) TODO:
* Move into TaskList?
*/
public ITask getTaskForElement(ITaskListElement element, boolean force) {
ITask task = null;
if (element instanceof AbstractQueryHit) {
if (force) {
task = ((AbstractQueryHit) element).getOrCreateCorrespondingTask();
} else {
task = ((AbstractQueryHit) element).getCorrespondingTask();
}
} else if (element instanceof ITask) {
task = (ITask) element;
}
return task;
}
protected void setTaskListSaveManager(TaskListSaveManager taskListSaveManager) {
this.taskListSaveManager = taskListSaveManager;
this.taskList.addChangeListener(taskListSaveManager);
}
public List<DateRangeContainer> getActivityWeekDays() {
return activityWeekDays;
}
public boolean isWeekDay(DateRangeContainer dateRangeTaskContainer) {
return activityWeekDays.contains(dateRangeTaskContainer);
}
public int getStartHour() {
return START_HOUR;
}
}