/******************************************************************************* * Copyright (c) 2004, 2015 Tasktop Technologies 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: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.tasks.core.data; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.core.runtime.Status; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants; import org.eclipse.mylyn.tasks.core.ITask; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.data.TaskDataModelEvent.EventKind; /** * @author Steffen Pingel * @since 3.0 * @noextend This class is not intended to be subclassed by clients. */ public class TaskDataModel { private List<TaskDataModelListener> listeners; private final ITask task; private final TaskRepository taskRepository; private final Set<TaskAttribute> unsavedChangedAttributes; private final ITaskDataWorkingCopy workingCopy; public TaskDataModel(TaskRepository taskRepository, ITask task, ITaskDataWorkingCopy taskDataState) { Assert.isNotNull(taskRepository); Assert.isNotNull(task); Assert.isNotNull(taskDataState); this.task = task; this.taskRepository = taskRepository; this.workingCopy = taskDataState; this.unsavedChangedAttributes = new HashSet<TaskAttribute>(); } public void addModelListener(TaskDataModelListener listener) { if (listeners == null) { listeners = new ArrayList<TaskDataModelListener>(); } listeners.add(listener); } /** * Invoke upon change to attribute value. * * @param attribute * changed attribute */ public void attributeChanged(TaskAttribute attribute) { unsavedChangedAttributes.add(attribute); if (this.listeners != null) { final TaskDataModelEvent event = new TaskDataModelEvent(this, EventKind.CHANGED, attribute); TaskDataModelListener[] listeners = this.listeners.toArray(new TaskDataModelListener[0]); for (final TaskDataModelListener listener : listeners) { SafeRunner.run(new ISafeRunnable() { public void handleException(Throwable e) { StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Listener failed", e)); //$NON-NLS-1$ } public void run() throws Exception { listener.attributeChanged(event); } }); } } } /** * Returns the instance of <code>taskAttribute</code> that the user last read. * * @param taskAttribute * the attribute * @return the last read state; null, if <code>taskAttribute</code> has never been read * @since 3.5 */ public TaskAttribute getLastReadAttribute(TaskAttribute taskAttribute) { TaskData lastReadData = workingCopy.getLastReadData(); if (lastReadData == null) { return null; } return lastReadData.getRoot().getMappedAttribute(taskAttribute.getPath()); } public Set<TaskAttribute> getChangedAttributes() { Set<TaskAttribute> changedAttributes = new LinkedHashSet<TaskAttribute>(); changedAttributes.addAll(workingCopy.getEditsData().getRoot().getAttributes().values()); changedAttributes.addAll(unsavedChangedAttributes); return changedAttributes; } public Set<TaskAttribute> getChangedOldAttributes() { Set<TaskAttribute> newChangedAttributes = getChangedAttributes(); Set<TaskAttribute> oldAttributes = new LinkedHashSet<TaskAttribute>(); TaskData repositoryReadData = workingCopy.getRepositoryData(); if (repositoryReadData != null) { for (TaskAttribute taskAttribute : newChangedAttributes) { TaskAttribute attOld = repositoryReadData.getRoot().getAttribute(taskAttribute.getId()); if (attOld != null) { oldAttributes.add(attOld); } } } return oldAttributes; } public ITask getTask() { return task; } public TaskData getTaskData() { return workingCopy.getLocalData(); } public TaskRepository getTaskRepository() { return taskRepository; } public boolean hasBeenRead() { return workingCopy.getLastReadData() != null; } public boolean hasIncomingChanges(TaskAttribute taskAttribute) { TaskData lastReadData = workingCopy.getLastReadData(); if (lastReadData == null) { return true; } if (hasOutgoingChanges(taskAttribute)) { return false; } TaskAttribute oldAttribute = lastReadData.getRoot().getMappedAttribute(taskAttribute.getPath()); if (oldAttribute == null) { return true; } return !getTaskData().getAttributeMapper().equals(taskAttribute, oldAttribute); } public boolean hasOutgoingChanges(TaskAttribute taskAttribute) { return workingCopy.getEditsData().getRoot().getMappedAttribute(taskAttribute.getPath()) != null; } public boolean isDirty() { return unsavedChangedAttributes.size() > 0 || !workingCopy.isSaved(); } public void refresh(IProgressMonitor monitor) throws CoreException { workingCopy.refresh(monitor); if (this.listeners != null) { for (final TaskDataModelListener listener : listeners) { SafeRunner.run(new ISafeRunnable() { public void handleException(Throwable e) { StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Listener failed", e)); //$NON-NLS-1$ } public void run() throws Exception { listener.modelRefreshed(); } }); } } } public void removeModelListener(TaskDataModelListener listener) { listeners.remove(listener); } public void revert() { workingCopy.revert(); unsavedChangedAttributes.clear(); } public void save(IProgressMonitor monitor) throws CoreException { workingCopy.save(unsavedChangedAttributes, monitor); unsavedChangedAttributes.clear(); } }