All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.mylyn.util.NbTaskDataModel Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.netbeans.modules.mylyn.util;

import java.util.EventListener;
import java.util.EventObject;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.mylyn.internal.tasks.core.data.TaskAttributeDiff;
import org.eclipse.mylyn.internal.tasks.core.data.TaskDataState;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.ITaskDataWorkingCopy;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskDataModel;
import org.eclipse.mylyn.tasks.core.data.TaskDataModelEvent;
import org.eclipse.mylyn.tasks.core.data.TaskDataModelListener;

/**
 *
 * @author Ondrej Vrabec
 */
public final class NbTaskDataModel {

    private final ITaskDataWorkingCopy workingCopy;
    private final TaskDataModel delegateModel;
    private final List listeners = new CopyOnWriteArrayList();
    private final NbTask task;
    private final Set unsavedChangedAttributes = new HashSet();
    
    NbTaskDataModel (TaskRepository taskRepository, NbTask task, ITaskDataWorkingCopy workingCopy) {
        this.task = task;
        this.delegateModel = new TaskDataModel(taskRepository, task.getDelegate(), workingCopy);
        this.workingCopy = workingCopy;
        delegateModel.addModelListener(new TaskDataModelListener() {
            @Override
            public void attributeChanged (TaskDataModelEvent modelEvent) {
                NbTaskDataModelEvent event = new NbTaskDataModelEvent(NbTaskDataModel.this, modelEvent);
                for (NbTaskDataModelListener list : listeners.toArray(new NbTaskDataModelListener[0])) {
                    list.attributeChanged(event);
                }
            }
        });
    }

    public boolean hasIncomingChanges (TaskAttribute taskAttribute, boolean includeConflicts) {
        TaskData repositoryData = workingCopy.getRepositoryData();
        if (repositoryData == null) {
            return false;
        }
        taskAttribute = repositoryData.getRoot().getMappedAttribute(taskAttribute.getPath());
        if (taskAttribute == null) {
            return false;
        }
        boolean incoming = delegateModel.hasIncomingChanges(taskAttribute);
        if (includeConflicts && !incoming && delegateModel.hasOutgoingChanges(taskAttribute)) {
            TaskData lastReadData = workingCopy.getLastReadData();
            if (lastReadData == null) {
                return true;
            }
            TaskAttribute oldAttribute = lastReadData.getRoot().getMappedAttribute(taskAttribute.getPath());
            if (oldAttribute == null) {
                return true;
            }
            return !repositoryData.getAttributeMapper().equals(taskAttribute, oldAttribute);
        }
        return incoming;
    }

    public boolean hasOutgoingChanges (TaskAttribute ta) {
        return delegateModel.hasOutgoingChanges(ta);
    }

    public TaskData getLocalTaskData () {
        return delegateModel.getTaskData();
    }

    public TaskData getLastReadTaskData () {
        return workingCopy.getLastReadData();
    }

    public TaskData getRepositoryTaskData () {
        return workingCopy.getRepositoryData();
    }
    
    public void addNbTaskDataModelListener (NbTaskDataModelListener listener) {
        listeners.add(listener);
    }
    
    public void removeNbTaskDataModelListener (NbTaskDataModelListener listener) {
        listeners.remove(listener);
    }

    public boolean isDirty () {
        return delegateModel.isDirty();
    }

    public void attributeChanged (TaskAttribute a) {
        synchronized (unsavedChangedAttributes) {
            // replace the task attribute in unsaved changes
            unsavedChangedAttributes.remove(a);
            unsavedChangedAttributes.add(a);
            delegateModel.attributeChanged(a);
        }
    }

    public Set getChangedAttributes () {
        return delegateModel.getChangedAttributes();
    }

    public Set getChangedOldAttributes () {
        return delegateModel.getChangedOldAttributes();
    }

    /**
     * Updates the model and all taskdata to keep track with external taskdata
     * changes (such as a task refresh)
     * @throws CoreException 
     */
    public void refresh () throws CoreException {
        // refresh reverts all taskdata to the state on disk
        delegateModel.refresh(null);
        // also clear unsaved changes in the mylyn model
        // this is needed because after refresh() the unsaved changes no longer
        // belong to the local taskdata (they're reinstantiated)
        delegateModel.revert();
        if (workingCopy instanceof TaskDataState && workingCopy.getLastReadData() == null) {
            ((TaskDataState) workingCopy).setLastReadData(workingCopy.getRepositoryData());
        }
        Set changedAttributes;
        synchronized (unsavedChangedAttributes) {
            changedAttributes = new HashSet(unsavedChangedAttributes);
        }
        for (TaskAttribute ta : changedAttributes) {
            // there are still local unsaved changes, keep them in local taskdata
            TaskData td = getLocalTaskData();
            td.getRoot().deepAddCopy(ta);
            TaskAttribute attribute = td.getRoot().getAttribute(ta.getId());
            // now refill the unsaved changes so they belong to the correct local TD
            attributeChanged(attribute);
        }
    }

    public void save () throws CoreException {
        save(null);
    }

    public void save (IProgressMonitor monitor) throws CoreException {
        // clear delegate model changes
        delegateModel.save(monitor);
        // now bit of hacking
        // task attributes with same values as local changes must be reverted
        TaskData editsData = workingCopy.getEditsData();
        TaskData repositoryData = workingCopy.getRepositoryData();
        synchronized (unsavedChangedAttributes) {
            if (editsData != null && repositoryData != null) {
                for (Iterator it = unsavedChangedAttributes.iterator(); it.hasNext(); ) {
                    TaskAttribute ta = it.next();
                    if (!editsDiffer(ta, repositoryData)) {
                        editsData.getRoot().removeAttribute(ta.getId());
                        it.remove();
                    }
                }
            }
            // are there any edits 
            boolean noChanges = unsavedChangedAttributes.isEmpty() && !hasOutgoingChanged();
            if (noChanges) {
                task.discardLocalEdits();
            }
            delegateModel.revert();
            unsavedChangedAttributes.clear();
        }
    }

    public boolean hasBeenRead () {
        return delegateModel.hasBeenRead();
    }

    public TaskRepository getTaskRepository () {
        return delegateModel.getTaskRepository();
    }
    
    public NbTask getTask () {
        return task;
    }

    ITask getDelegateTask () {
        return delegateModel.getTask();
    }

    public boolean hasOutgoingChanged () {
        return isDirty() || !getChangedAttributes().isEmpty();
    }

    public void clearUnsavedChanges () {
        if (isDirty()) {
            delegateModel.revert();
            unsavedChangedAttributes.clear();            
        }
    }

    private boolean editsDiffer (TaskAttribute ta, TaskData repositoryData) {
        TaskAttribute repositoryTA = repositoryData.getRoot().getMappedAttribute(ta.getPath());
        boolean changes = new TaskAttributeDiff(ta, repositoryTA).hasChanges();
        if (!changes) {
            // is a child attribue changed??
            for (TaskAttribute childTA : ta.getAttributes().values()) {
                if (editsDiffer(childTA, repositoryData)) {
                    changes = true;
                    break;
                }
            }
        }
        return changes;
    }
    
    public static interface NbTaskDataModelListener extends EventListener {

        public void attributeChanged (NbTaskDataModelEvent event);
        
    }
    
    public static final class NbTaskDataModelEvent extends EventObject {
        private final TaskDataModelEvent modelEvent;
        private final NbTaskDataModel model;

        private NbTaskDataModelEvent (NbTaskDataModel source, TaskDataModelEvent modelEvent) {
            super(source);
            this.model = source;
            this.modelEvent = modelEvent;
        }

        public NbTaskDataModel getModel () {
            return model;
        }
        
        public TaskAttribute getTaskAttribute () {
            return modelEvent.getTaskAttribute();
        }
        
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy