[hg] main-silver: moving common code in bugtracking systems rela...

  • From: Ondrej Vrabec < >
  • To:
  • Subject: [hg] main-silver: moving common code in bugtracking systems rela...
  • Date: Sat, 17 Aug 2013 04:12:43 -0700

changeset e43065890f05 in main-silver ((none))
details: http://hg.netbeans.org/main-silver/rev/e43065890f05
description:
        moving common code in bugtracking systems related to mylyn tasks into 
mylyn.utils

diffstat:

 bugzilla/manifest.mf                                                         
 |    2 +-
 bugzilla/nbproject/project.xml                                               
 |    2 +-
 bugzilla/src/org/netbeans/modules/bugzilla/issue/BugzillaIssue.java          
 |  452 +--------
 bugzilla/src/org/netbeans/modules/bugzilla/issue/IssuePanel.java             
 |    8 +-
 
bugzilla/src/org/netbeans/modules/bugzilla/repository/BugzillaRepository.java 
|   12 +-
 mylyn.util/manifest.mf                                                       
 |    2 +-
 mylyn.util/src/org/netbeans/modules/mylyn/util/AbstractNbTaskWrapper.java    
 |  456 ++++++++++
 mylyn.util/src/org/netbeans/modules/mylyn/util/MylynSupport.java             
 |    1 +
 mylyn.util/src/org/netbeans/modules/mylyn/util/NbTask.java                   
 |   20 +-
 mylyn.util/src/org/netbeans/modules/mylyn/util/NbTaskDataModel.java          
 |    4 +
 10 files changed, 550 insertions(+), 409 deletions(-)

diffs (1474 lines):

diff --git a/bugzilla/manifest.mf b/bugzilla/manifest.mf
--- a/bugzilla/manifest.mf
+++ b/bugzilla/manifest.mf
@@ -3,5 +3,5 @@
 OpenIDE-Module: org.netbeans.modules.bugzilla
 OpenIDE-Module-Localizing-Bundle: 
org/netbeans/modules/bugzilla/Bundle.properties
 OpenIDE-Module-Layer: org/netbeans/modules/bugzilla/layer.xml
-OpenIDE-Module-Specification-Version: 1.40
+OpenIDE-Module-Specification-Version: 1.41
 
diff --git a/bugzilla/nbproject/project.xml b/bugzilla/nbproject/project.xml
--- a/bugzilla/nbproject/project.xml
+++ b/bugzilla/nbproject/project.xml
@@ -83,7 +83,7 @@
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>1.12</specification-version>
+                        <specification-version>1.13</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
diff --git 
a/bugzilla/src/org/netbeans/modules/bugzilla/issue/BugzillaIssue.java 
b/bugzilla/src/org/netbeans/modules/bugzilla/issue/BugzillaIssue.java
--- a/bugzilla/src/org/netbeans/modules/bugzilla/issue/BugzillaIssue.java
+++ b/bugzilla/src/org/netbeans/modules/bugzilla/issue/BugzillaIssue.java
@@ -48,8 +48,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.lang.ref.Reference;
-import java.lang.ref.SoftReference;
 import java.net.URL;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -94,37 +92,30 @@
 import org.netbeans.modules.bugzilla.repository.IssueField;
 import org.openide.filesystems.FileUtil;
 import org.netbeans.modules.bugzilla.util.BugzillaUtil;
+import org.netbeans.modules.mylyn.util.AbstractNbTaskWrapper;
 import org.netbeans.modules.mylyn.util.MylynSupport;
 import org.netbeans.modules.mylyn.util.NbTask;
 import org.netbeans.modules.mylyn.util.NbTask.SynchronizationState;
-import org.netbeans.modules.mylyn.util.NbTaskListener;
-import org.netbeans.modules.mylyn.util.NbTaskListener.TaskEvent;
 import org.netbeans.modules.mylyn.util.NbTaskDataModel;
 import org.netbeans.modules.mylyn.util.NbTaskDataModel.NbTaskDataModelEvent;
-import 
org.netbeans.modules.mylyn.util.NbTaskDataModel.NbTaskDataModelListener;
 import org.netbeans.modules.mylyn.util.NbTaskDataState;
 import org.netbeans.modules.mylyn.util.commands.SubmitTaskCommand;
 import org.netbeans.modules.mylyn.util.commands.SynchronizeTasksCommand;
-import org.netbeans.modules.mylyn.util.TaskDataListener;
 import org.openide.awt.StatusDisplayer;
 import org.openide.util.NbBundle;
-import org.openide.util.RequestProcessor.Task;
-import org.openide.util.WeakListeners;
 
 /**
  *
  * @author Tomas Stupka
  * @author Jan Stola
  */
-public class BugzillaIssue {
+public class BugzillaIssue extends AbstractNbTaskWrapper {
 
     public static final String RESOLVE_FIXED = "FIXED";                      
                                   // NOI18N
     public static final String RESOLVE_DUPLICATE = "DUPLICATE";              
                                   // NOI18N
     public static final String VCSHOOK_BUGZILLA_FIELD = 
"netbeans.vcshook.bugzilla.";                           // NOI18N
-    public static final String ATTR_NEW_UNREAD = 
"NetBeans.bugzilla.markedNewUnread"; //NOI18N
     private static final SimpleDateFormat CC_DATE_FORMAT = new 
SimpleDateFormat("yyyy-MM-dd HH:mm");            // NOI18N
 
-    private Reference<TaskData> repositoryDataRef;
     private final BugzillaRepository repository;
 
     private IssueController controller;
@@ -179,39 +170,19 @@
     private Map<String, TaskOperation> availableOperations;
 
     private final PropertyChangeSupport support;
-    private NbTask task;
     private String recentChanges = "";
     private String tooltip = "";
-    private NbTaskDataModel model;
-    private static final Object MODEL_LOCK = new Object();
-    private NbTaskDataModelListener list;
-    private final Task repositoryTaskDataLoaderTask;
-    private boolean readPending;
-    private final TaskDataListenerImpl taskDataListener;
-    private final TaskListenerImpl taskListener;
 
     private static final URL ICON_REMOTE_PATH = 
IssuePanel.class.getClassLoader().getResource("org/netbeans/modules/bugzilla/resources/remote.png");
 //NOI18N
     private static final URL ICON_CONFLICT_PATH = 
IssuePanel.class.getClassLoader().getResource("org/netbeans/modules/bugzilla/resources/conflict.png");
 //NOI18N
     private static final URL ICON_UNSUBMITTED_PATH = 
IssuePanel.class.getClassLoader().getResource("org/netbeans/modules/bugzilla/resources/unsubmitted.png");
 //NOI18N
 
     public BugzillaIssue (NbTask task, BugzillaRepository repo) {
-        this.task = task;
+        super(task);
         this.repository = repo;
-        this.repositoryDataRef = new SoftReference<TaskData>(null);
         support = new PropertyChangeSupport(this);
-        repositoryTaskDataLoaderTask = 
Bugzilla.getInstance().getRequestProcessor().create(new Runnable() {
-            @Override
-            public void run () {
-                loadRepositoryTaskData();
-            }
-        });
         updateRecentChanges();
         updateTooltip();
-        MylynSupport mylynSupp = MylynSupport.getInstance();
-        taskDataListener = new TaskDataListenerImpl();
-        
mylynSupp.addTaskDataListener(WeakListeners.create(TaskDataListener.class, 
taskDataListener, mylynSupp));
-        taskListener = new TaskListenerImpl();
-        task.addNbTaskListener(WeakListeners.create(NbTaskListener.class, 
taskListener, mylynSupp));
     }
 
     public void addPropertyChangeListener(PropertyChangeListener listener) {
@@ -229,66 +200,31 @@
         support.firePropertyChange(IssueProvider.EVENT_ISSUE_REFRESHED, 
null, null);
     }
 
-    void deleteTask () {
-        synchronized (MODEL_LOCK) {
-            if (list != null) {
-                model.removeNbTaskDataModelListener(list);
-                list = null;
-            }
-            model = null;
-        }
-        MylynSupport mylynSupp = MylynSupport.getInstance();
-        mylynSupp.removeTaskDataListener(taskDataListener);
-        task.removeNbTaskListener(taskListener);
-        getRepository().deleteTask(task);
+    @Override
+    protected void taskDeleted (NbTask task) {
+        getRepository().taskDeleted(getID(task));
     }
 
-    void markNewRead () {
-        task.setAttribute(ATTR_NEW_UNREAD, null);
+    void markUserChange () {
+        if (isMarkedNewUnread()) {
+            markNewRead();
+        }
     }
 
-    boolean isMarkedNewUnread () {
-        return isNew() && 
Boolean.TRUE.toString().equals(task.getAttribute(ATTR_NEW_UNREAD));
+    void delete () {
+        deleteTask();
     }
     
     private void fireSeenChanged(boolean wasSeen, boolean seen) {
         support.firePropertyChange(IssueStatusProvider.EVENT_SEEN_CHANGED, 
wasSeen, seen);
     }
 
-    public boolean isNew() {
-        return task.getSynchronizationState() == 
SynchronizationState.OUTGOING_NEW;
-    }
-
     public void opened() {
         if(Bugzilla.LOG.isLoggable(Level.FINE)) Bugzilla.LOG.log(Level.FINE, 
"issue {0} open start", new Object[] {getID()});
-        list = new NbTaskDataModelListener() {
-            @Override
-            public void attributeChanged (NbTaskDataModelEvent event) {
-                NbTaskDataModel m = model;
-                if (event.getModel() == m) {
-                    if (controller != null) {
-                        // view might not exist yet and we won't 
unnecessarily create it
-                        controller.modelStateChanged(m.isDirty(), 
m.isDirty() || !m.getChangedAttributes().isEmpty());
-                    }
-                }
-            }
-        };
         Bugzilla.getInstance().getRequestProcessor().post(new Runnable() {
             @Override
             public void run () {
-                if (task.getSynchronizationState() == 
SynchronizationState.INCOMING_NEW) {
-                    // mark as seen so no fields are highlighted
-                    setUpToDate(true, false);
-                }
-                // clear upon close
-                synchronized (MODEL_LOCK) {
-                    if (readPending) {
-                        // make sure remote changes are not lost and still 
highlighted in the editor
-                        setUpToDate(false, false);
-                    }
-                    model = task.getTaskDataModel();
-                    model.addNbTaskDataModelListener(list);
-                }
+                editorOpened();
                 ensureConfigurationUptodate();
                 refreshViewData(true);
             }
@@ -298,50 +234,25 @@
             return;
         }
         if (!isNew()) {
-            repository.scheduleForRefresh(task);
+            repository.scheduleForRefresh(getNbTask());
         }
         if(Bugzilla.LOG.isLoggable(Level.FINE)) Bugzilla.LOG.log(Level.FINE, 
"issue {0} open finish", new Object[] {getID()});
     }
 
     public void closed () {
-        final NbTaskDataModel m = model;
-        final boolean markedAsNewUnread = isMarkedNewUnread();
-        if (m != null) {
-            if (list != null) {
-                m.removeNbTaskDataModelListener(list);
-                list = null;
-            }
-            readPending = false;
             Bugzilla.getInstance().getRequestProcessor().post(new Runnable() 
{
                 @Override
                 public void run () {
-                    if (markedAsNewUnread) {
-                        // was not modified by user and not yet saved
-                        deleteTask();
-                    } else {
-                        synchronized (MODEL_LOCK) {
-                            if (model == m) {
-                                model = null;
-                            }
-                        }
-                        if (m.isDirty()) {
-                            try {
-                                save(m);
-                            } catch (CoreException ex) {
-                                Bugzilla.LOG.log(Level.WARNING, null, ex);
-                            }
-                        }
-                    }
+                editorClosed();
                 }
             });
-        }
         if(Bugzilla.LOG.isLoggable(Level.FINE)) Bugzilla.LOG.log(Level.FINE, 
"issue {0} close start", new Object[] {getID()});
-        repository.stopRefreshing(task);
+        repository.stopRefreshing(getNbTask());
         if(Bugzilla.LOG.isLoggable(Level.FINE)) Bugzilla.LOG.log(Level.FINE, 
"issue {0} close finish", new Object[] {getID()});
     }
 
     public String getDisplayName() {
-        return getDisplayName(task);
+        return getDisplayName(getNbTask());
     }
 
     public static String getDisplayName (NbTask task) {
@@ -492,77 +403,19 @@
         return info;
     }
 
-    public Date getLastModifyDate() {
-        return task.getModificationDate();
-    }
-
-    public long getLastModify() {
-        Date lastModifyDate = getLastModifyDate();
-        if(lastModifyDate != null) {
-            return lastModifyDate.getTime();
-        } else {
-            return -1;
-        }
-    }
-
-    public Date getCreatedDate() {
-        return task.getCreationDate();
-    }
-
-    public long getCreated() {
-        Date createdDate = getCreatedDate();
-        if (createdDate != null) {
-            return createdDate.getTime();
-        } else {
-            return -1;
-        }
-    }
-
     public String getRecentChanges() {
         return recentChanges;
     }
 
-    /**
-     * Returns the id from the given taskData or null if taskData.isNew()
-     * @param taskData
-     * @return id or null
-     */
-    public static String getID(TaskData taskData) {
-        if(taskData.isNew()) {
-            return null;
-        }
-        return taskData.getTaskId();
-    }
-
-    /**
-     * Returns the id of the given task or null if task is new
-     * @param task
-     * @return id or null
-     */
-    public static String getID (NbTask task) {
-        if (task.getSynchronizationState() == 
SynchronizationState.OUTGOING_NEW) {
-            return "-" + task.getTaskId();
-        }
-        return task.getTaskId();
-    }
-
     public BugzillaRepository getRepository() {
         return repository;
     }
 
-    public String getID() {
-        return getID(task);
-    }
-
-    public String getSummary() {
-        return task.getSummary();
-    }
-
     private void ensureConfigurationUptodate () {
         BugzillaConfiguration conf = getRepository().getConfiguration();
         NbTaskDataState taskDataState = null;
         try {
-            taskDataState = task.getTaskDataState();
+            taskDataState = getNbTask().getTaskDataState();
         } catch (CoreException ex) {
             Bugzilla.LOG.log(Level.INFO, null, ex);
         }
@@ -606,31 +459,8 @@
         }
     }
 
-    private TaskData getRepositoryTaskData () {
-        TaskData taskData = repositoryDataRef.get();
-        if (taskData == null) {
-            if (EventQueue.isDispatchThread()) {
-                repositoryTaskDataLoaderTask.schedule(100);
-            } else {
-                return loadRepositoryTaskData();
-            }
-        }
-        return taskData;
-    }
-
-    private TaskData loadRepositoryTaskData () {
-        // this method is time consuming
-        assert !EventQueue.isDispatchThread();
-        TaskData td = repositoryDataRef.get();
-        if (td != null) {
-            return td;
-        }
-        try {
-            MylynSupport mylynSupp = MylynSupport.getInstance();
-            NbTaskDataState taskDataState = task.getTaskDataState();
-            if (taskDataState != null) {
-                td = taskDataState.getRepositoryData();
-                repositoryDataRef = new SoftReference<TaskData>(td);
+    @Override
+    protected void repositoryTaskDataLoaded (TaskData repositoryTaskData) {
                 EventQueue.invokeLater(new Runnable() {
                     @Override
                     public void run () {
@@ -643,14 +473,9 @@
                     }
                 });
             }
-        } catch (CoreException ex) {
-            Bugzilla.LOG.log(Level.WARNING, null, ex);
-        }
-        return td;
-    }
 
     public String getRepositoryFieldValue (IssueField f) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         TaskData td;
         if (m == null) {
             td = getRepositoryTaskData();
@@ -664,12 +489,12 @@
     }
     
     public String getFieldValue(IssueField f) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         return getFieldValue(m == null ? null : m.getLocalTaskData(), f);
     }
 
     String getLastSeenFieldValue (IssueField f) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         return getFieldValue(m == null ? null : m.getLastReadTaskData(), f);
     }
 
@@ -718,7 +543,7 @@
             assert false : "can't set value into IssueField " + f.getKey();  
     // NOI18N
             return;
         }
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         // should not happen, setFieldValue either runs with model lock
         // or it is called from issue editor in AWT - the editor could not 
be closed by user in the meantime
         assert m != null;
@@ -742,7 +567,7 @@
     }
 
     void setFieldValues(IssueField f, List<String> ccs) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         // should not happen, setFieldValue either runs with model lock
         // or it is called from issue editor in AWT - the editor could not 
be closed by user in the meantime
         assert m != null;
@@ -756,17 +581,17 @@
     }
 
     public List<String> getRepositoryFieldValues (IssueField f) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         return getFieldValues(m == null ? getRepositoryTaskData() : 
m.getRepositoryTaskData(), f);
     }
 
     public List<String> getFieldValues(IssueField f) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         return getFieldValues(m == null ? null : m.getLocalTaskData(), f);
     }
 
     List<String> getLastSeenFieldValues (IssueField f) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         return getFieldValues(m == null ? null : m.getLastReadTaskData(), f);
     }
     
@@ -801,7 +626,7 @@
      * @return a status value
      */
     public int getFieldStatus(IssueField f) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         if (m == null) {
             return FIELD_STATUS_UPTODATE;
         }
@@ -839,11 +664,11 @@
                 String value = getFieldValue(IssueField.STATUS);
                 if(!(value.equals("RESOLVED") && 
resolution.equals(getFieldValue(IssueField.RESOLUTION)))) { // NOI18N
                     setOperation(BugzillaOperation.resolve);
-                    TaskAttribute rta = model.getLocalTaskData().getRoot();
+                    TaskAttribute rta = 
getModel().getLocalTaskData().getRoot();
                     TaskAttribute ta = 
rta.getMappedAttribute(BugzillaOperation.resolve.getInputId());
                     if(ta != null) { // ta can be null when changing status 
from CLOSED to RESOLVED
                         ta.setValue(resolution);
-                        model.attributeChanged(ta);
+                        getModel().attributeChanged(ta);
                     }
                 }
             }
@@ -855,7 +680,7 @@
     }
 
     void duplicate(String id) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         setOperation(BugzillaOperation.duplicate);
         TaskAttribute rta = m.getLocalTaskData().getRoot();
         TaskAttribute ta = 
rta.getMappedAttribute(BugzillaOperation.duplicate.getInputId());
@@ -864,7 +689,7 @@
     }
 
     boolean canReassign() {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         if (m == null) {
             return false;
         }
@@ -881,7 +706,7 @@
     }
     
     boolean canAssignToDefault() {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         if (m == null) {
             return false;
         }
@@ -900,13 +725,13 @@
     }
     
     boolean hasTimeTracking() {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         return m != null && m.getLocalTaskData().getRoot()
                 .getMappedAttribute(BugzillaAttribute.ACTUAL_TIME.getKey()) 
!= null; // XXX dummy
     }
 
     void reassign(String user) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         setOperation(BugzillaOperation.reassign);
         TaskAttribute rta = m.getLocalTaskData().getRoot();
         TaskAttribute ta = 
rta.getMappedAttribute(BugzillaOperation.reassign.getInputId());
@@ -934,7 +759,7 @@
     }
 
     private void setOperation (BugzillaOperation operation) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         TaskAttributeMapper mapper = 
m.getLocalTaskData().getAttributeMapper();
         for (TaskOperation op : 
mapper.getTaskOperations(m.getLocalTaskData().getRoot())) {
             if (op.getOperationId().equals(operation.toString())) {
@@ -945,7 +770,7 @@
     }
     
     private void setOperation (TaskOperation operation) {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         TaskAttribute rta = m.getLocalTaskData().getRoot();
         TaskAttribute ta = rta.getMappedAttribute(TaskAttribute.OPERATION);
         m.getLocalTaskData().getAttributeMapper().setTaskOperation(ta, 
operation);
@@ -953,7 +778,7 @@
     }
 
     List<Attachment> getAttachments() {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         List<TaskAttribute> attrs = m == null ? null : m.getLocalTaskData()
                 
.getAttributeMapper().getAttributesByType(m.getLocalTaskData(), 
TaskAttribute.TYPE_ATTACHMENT);
         if (attrs == null) {
@@ -997,7 +822,7 @@
     }
 
     Comment[] getComments() {
-        NbTaskDataModel m = model;
+        NbTaskDataModel m = getModel();
         List<TaskAttribute> attrs = m == null ? null : m.getLocalTaskData()
                 
.getAttributeMapper().getAttributesByType(m.getLocalTaskData(), 
TaskAttribute.TYPE_COMMENT);
         if (attrs == null) {
@@ -1069,7 +894,7 @@
                 @Override
                 public void run () {
                     Bugzilla.LOG.log(Level.FINER, "adding comment [{0}] to 
issue #{1}", new Object[]{comment, getID()});
-                    TaskAttribute ta = 
model.getLocalTaskData().getRoot().getMappedAttribute(IssueField.COMMENT.getKey());
+                    TaskAttribute ta = 
getModel().getLocalTaskData().getRoot().getMappedAttribute(IssueField.COMMENT.getKey());
                     String value = ta.getValue();
                     if (value == null || value.trim().isEmpty()) {
                         value = comment;
@@ -1077,7 +902,7 @@
                         value += "\n\n" + comment; //NOI18N
                     }
                     ta.setValue(value);
-                    model.attributeChanged(ta);
+                    getModel().attributeChanged(ta);
                 }
             });
         }
@@ -1093,12 +918,12 @@
     private void prepareSubmit() {
         if (initialProduct != null) {
             // product change
-            TaskAttribute ta = 
model.getLocalTaskData().getRoot().getMappedAttribute(BugzillaAttribute.CONFIRM_PRODUCT_CHANGE.getKey());
+            TaskAttribute ta = 
getModel().getLocalTaskData().getRoot().getMappedAttribute(BugzillaAttribute.CONFIRM_PRODUCT_CHANGE.getKey());
             if (ta == null) {
-                ta = 
BugzillaTaskDataHandler.createAttribute(model.getLocalTaskData().getRoot(), 
BugzillaAttribute.CONFIRM_PRODUCT_CHANGE);
+                ta = 
BugzillaTaskDataHandler.createAttribute(getModel().getLocalTaskData().getRoot(),
 BugzillaAttribute.CONFIRM_PRODUCT_CHANGE);
             }
             ta.setValue("1");                                                
   // NOI18N
-            model.attributeChanged(ta);
+            getModel().attributeChanged(ta);
         }
     }
 
@@ -1119,7 +944,7 @@
                 SubmitTaskCommand submitCmd;
                 try {
                     if (saveChanges()) {
-                        submitCmd = 
MylynSupport.getInstance().getCommandFactory().createSubmitTaskCommand(model);
+                        submitCmd = 
MylynSupport.getInstance().getCommandFactory().createSubmitTaskCommand(getModel());
                     } else {
                         result[0] = false;
                         return;
@@ -1130,19 +955,19 @@
                     return;
                 }
                 repository.getExecutor().execute(submitCmd);
+                if (!submitCmd.hasFailed()) {
+                    taskSubmitted(submitCmd.getSubmittedTask());
+                }
 
                 if (!wasNew) {
                     refresh();
                 } else {
                     RepositoryResponse rr = 
submitCmd.getRepositoryResponse();
                     if(!submitCmd.hasFailed()) {
-                        NbTask newTask = submitCmd.getSubmittedTask();
-                        assert newTask != null;
-                        assert newTask != task;
-                        task = newTask;
-                        task.addNbTaskListener(taskListener);
-                        resetModel();
-                        String id = task.getTaskId();
+                        updateRecentChanges();
+                        updateTooltip();
+                        fireDataChanged();
+                        String id = getID();
                         try {
                             repository.getIssueCache().setIssueData(id, 
BugzillaIssue.this);
                         } catch (IOException ex) {
@@ -1176,42 +1001,8 @@
         return result[0];
     }
 
-    boolean cancelChanges () {
-        try {
-            if (saveChanges()) {
-                task.discardLocalEdits();
-                model.refresh();
-                return true;
-            }
-        } catch (CoreException ex) {
-            Bugzilla.LOG.log(Level.WARNING, null, ex);
-        }
-        return false;
-    }
-
-    boolean saveChanges () {
-        try {
-            save(model);
-            return true;
-        } catch (CoreException ex) {
-            Bugzilla.LOG.log(Level.WARNING, null, ex);
-        }
-        return false;
-    }
-    
-    boolean hasLocalEdits () {
-        NbTaskDataModel m = model;
-        return !(m == null || m.getChangedAttributes().isEmpty());
-    }
-
     boolean updateModelAndRefresh () {
-        try {
-            model.refresh();
-            return refresh();
-        } catch (CoreException ex) {
-            Bugzilla.LOG.log(Level.INFO, null, ex);
-        }
-        return false;
+        return updateModel() && refresh();
     }
     
     public boolean refresh() {
@@ -1220,6 +1011,7 @@
     }
 
     private boolean refresh (boolean afterSubmitRefresh) { // XXX 
cacheThisIssue - we probalby don't need this, just always set the issue into 
the cache
+        NbTask task = getNbTask();
         assert task != null;
         assert !EventQueue.isDispatchThread() : "Accessing remote host. Do 
not call in awt"; // NOI18N
         try {
@@ -1248,6 +1040,7 @@
     Map<String, TaskOperation> getAvailableOperations () {
         if (availableOperations == null) {
             HashMap<String, TaskOperation> operations = new HashMap<String, 
TaskOperation>(5);
+            NbTaskDataModel model = getModel();
             List<TaskAttribute> allOperations = 
model.getLocalTaskData().getAttributeMapper().getAttributesByType(model.getLocalTaskData(),
 TaskAttribute.TYPE_OPERATION);
             for (TaskAttribute operation : allOperations) {
                 // the test must be here, 'operation' (applying writable 
action) is also among allOperations
@@ -1274,32 +1067,10 @@
         return null;
     }
 
-    public boolean isFinished() {
-        return task.isCompleted();
-    }
-
-    public IssueStatusProvider.Status getStatus() {
-        return task.getNbStatus();
-    }
-
     public void setUpToDate (boolean seen) {
         setUpToDate(seen, true);
     }
 
-    private void setUpToDate (boolean seen, boolean markReadPending) {
-        synchronized (MODEL_LOCK) {
-            if (markReadPending) {
-                // this is a workaround to keep incoming changes visible in 
editor
-                SynchronizationState syncState = 
task.getSynchronizationState();
-                readPending |= syncState == SynchronizationState.INCOMING
-                    || syncState == SynchronizationState.CONFLICT;
-            } else {
-                readPending = false;
-            }
-            task.markSeen(seen);
-        }
-    }
-
     private boolean updateTooltip () {
         String displayName = getDisplayName();
         if (displayName.startsWith("#")) { //NOI18N
@@ -1307,7 +1078,7 @@
         }
         String oldTooltip = tooltip;
 
-        SynchronizationState state = task.getSynchronizationState();
+        SynchronizationState state = getSynchronizationState();
         URL iconPath = getStateIcon(state);
         String iconCode = "";
         if (iconPath != null) {
@@ -1391,13 +1162,13 @@
     private boolean updateRecentChanges () {
         String oldChanges = recentChanges;
         recentChanges = "";
-        SynchronizationState syncState = task.getSynchronizationState();
+        SynchronizationState syncState = getSynchronizationState();
         if (syncState == SynchronizationState.INCOMING_NEW) {
             recentChanges = NbBundle.getMessage(BugzillaIssue.class, 
"LBL_NEW_STATUS"); //NOI18N
         } else if (syncState == SynchronizationState.INCOMING
                 || syncState == SynchronizationState.CONFLICT) {
             try {
-                NbTaskDataState taskDataState = task.getTaskDataState();
+                NbTaskDataState taskDataState = 
getNbTask().getTaskDataState();
                 TaskData repositoryData = taskDataState.getRepositoryData();
                 TaskData lastReadData = taskDataState.getLastReadData();
                 List<IssueField> changedFields = new ArrayList<IssueField>();
@@ -1490,70 +1261,28 @@
         return !oldChanges.equals(recentChanges);
     }
 
-    private boolean wasSeen () {
-        SynchronizationState syncState = task.getSynchronizationState();
-        return syncState == SynchronizationState.OUTGOING
-            || syncState == SynchronizationState.OUTGOING_NEW
-            || syncState == SynchronizationState.SYNCHRONIZED;
+    @Override
+    protected void modelSaved (NbTaskDataModel model) {
+        if (controller != null) {
+            controller.modelStateChanged(model.isDirty(), 
model.hasOutgoingChanged());
+        }
     }
 
-    private void save (NbTaskDataModel model) throws CoreException {
-        markNewRead();
-        if (model.isDirty()) {
-            if (isNew()) {
-                String summary = task.getSummary();
-                String newSummary = getFieldValue(model.getLocalTaskData(), 
IssueField.SUMMARY);
-                if (!(newSummary.isEmpty() || newSummary.equals(summary))) {
-                    task.setSummary(newSummary);
-                    fireDataChanged();
+    @Override
+    protected String getSummary (TaskData taskData) {
+        return getFieldValue(taskData, IssueField.SUMMARY);
                 }
-            }
-            model.save();
+
+    @Override
+    protected void attributeChanged (NbTaskDataModelEvent event, 
NbTaskDataModel model) {
             if (controller != null) {
+            // view might not exist yet and we won't unnecessarily create it
                 controller.modelStateChanged(model.isDirty(), 
model.isDirty() || !model.getChangedAttributes().isEmpty());
             }
         }
-    }
 
-    private void runWithModelLoaded (Runnable runnable) {
-        synchronized (MODEL_LOCK) {
-            boolean closeModel = false;
-            try {
-                if (model == null) {
-                    closeModel = true;
-                    model = task.getTaskDataModel();
-                }
-                runnable.run();
-            } finally {
-                if (closeModel) {
-                    if (model != null && model.isDirty()) {
-                        try {
-                            // let's not loose edits
-                            model.save();
-                        } catch (CoreException ex) {
-                            Bugzilla.LOG.log(Level.INFO, null, ex);
-                        }
-                    }
-                    model = null;
-                }
-            }
-        }
-    }
-
-    private void resetModel () {
-        synchronized (MODEL_LOCK) {
-            if (list != null) {
-                model.removeNbTaskDataModelListener(list);
-            }
-            model = task.getTaskDataModel();
-            repositoryDataRef.clear();
-            if (list != null) {
-                model.addNbTaskDataModelListener(list);
-            }
-        }
-        updateRecentChanges();
-        updateTooltip();
-        fireDataChanged();
+    boolean save () {
+        return saveChanges();
     }
 
     class Comment {
@@ -1743,25 +1472,10 @@
         
     }
     
-    private class TaskDataListenerImpl implements TaskDataListener {
-        
         @Override
-        public void taskDataUpdated (TaskDataEvent event) {
-            if (event.getTask() == task) {
-                if (event.getTaskData() != null && 
!event.getTaskData().isPartial()) {
-                    repositoryDataRef = new 
SoftReference<TaskData>(event.getTaskData());
-                }
-                if (event.getTaskDataUpdated()) {
+    protected void taskDataUpdated () {
                     availableOperations = null;
                     ensureConfigurationUptodate();
-                    NbTaskDataModel m = model;
-                    if (m != null) {
-                        try {
-                            m.refresh();
-                        } catch (CoreException ex) {
-                            Bugzilla.LOG.log(Level.INFO, null, ex);
-                        }
-                    }
                     Bugzilla.getInstance().getRequestProcessor().post(new 
Runnable() {
                         @Override
                         public void run() {
@@ -1776,17 +1490,10 @@
                         }
                     });
                 }
-            }
-        }
-    }
-    
-    private class TaskListenerImpl implements NbTaskListener {
 
         @Override
-        public void taskModified (TaskEvent event) {
-            if (event.getTask() == task && event.getKind() == 
TaskEvent.Kind.MODIFIED) {
-                boolean syncStateChanged = event.taskStateChanged();
-                boolean seen = wasSeen();
+    protected void taskModified (boolean syncStateChanged) {
+        boolean seen = isSeen();
                 if (updateRecentChanges() | updateTooltip()) {
                     fireDataChanged();
                 }
@@ -1794,12 +1501,5 @@
                     fireSeenChanged(!seen, seen);
                 }
             }
-        }
         
     }
-
-    void makeClean() throws CoreException {
-        save(model);
-    }
-    
-}
diff --git a/bugzilla/src/org/netbeans/modules/bugzilla/issue/IssuePanel.java 
b/bugzilla/src/org/netbeans/modules/bugzilla/issue/IssuePanel.java
--- a/bugzilla/src/org/netbeans/modules/bugzilla/issue/IssuePanel.java
+++ b/bugzilla/src/org/netbeans/modules/bugzilla/issue/IssuePanel.java
@@ -310,8 +310,8 @@
         Mutex.EVENT.readAccess(new Runnable() {
             @Override
             public void run () {
-                if (!reloading && isDirty && issue.isMarkedNewUnread()) {
-                    issue.markNewRead();
+                if (!reloading && isDirty) {
+                    issue.markUserChange();
                 }
                 btnSaveChanges.setEnabled(isDirty);
                 if (!isDirty) {
@@ -3072,7 +3072,7 @@
             public void run() {
                 boolean saved = false;
                 try {
-                    saved = issue.saveChanges();
+                    saved = issue.save();
                 } finally {
                     final boolean fSaved = saved;
                     EventQueue.invokeLater(new Runnable() {
@@ -3107,7 +3107,7 @@
         RP.post(new Runnable() {
             @Override
             public void run() {
-                issue.deleteTask();
+                issue.delete();
             }
         });
     }//GEN-LAST:event_btnDeleteTaskActionPerformed
diff --git 
a/bugzilla/src/org/netbeans/modules/bugzilla/repository/BugzillaRepository.java
 
b/bugzilla/src/org/netbeans/modules/bugzilla/repository/BugzillaRepository.java
--- 
a/bugzilla/src/org/netbeans/modules/bugzilla/repository/BugzillaRepository.java
+++ 
b/bugzilla/src/org/netbeans/modules/bugzilla/repository/BugzillaRepository.java
@@ -85,7 +85,6 @@
 import org.netbeans.modules.mylyn.util.MylynSupport;
 import org.netbeans.modules.mylyn.util.MylynUtils;
 import org.netbeans.modules.mylyn.util.NbTask;
-import org.netbeans.modules.mylyn.util.NbTask.SynchronizationState;
 import org.netbeans.modules.mylyn.util.commands.SimpleQueryCommand;
 import org.netbeans.modules.mylyn.util.commands.SynchronizeTasksCommand;
 import org.netbeans.modules.mylyn.util.UnsubmittedTasksContainer;
@@ -205,7 +204,6 @@
         NbTask task;
         try {
             task = MylynSupport.getInstance().createTask(taskRepository, new 
TaskMapping(product, component));
-            task.setAttribute(BugzillaIssue.ATTR_NEW_UNREAD, 
Boolean.TRUE.toString());
             return getIssueForTask(task);
         } catch (CoreException ex) {
             Bugzilla.LOG.log(Level.WARNING, null, ex);
@@ -247,14 +245,8 @@
         return issue;
     }
 
-    public void deleteTask (NbTask task) {
-        assert task.getSynchronizationState() == 
SynchronizationState.OUTGOING_NEW
-                : "Only new local tasks can be deleted: " + 
task.getSynchronizationState();
-        if (task.getSynchronizationState() == 
SynchronizationState.OUTGOING_NEW) {
-            String id = BugzillaIssue.getID(task);
-            task.delete();
-            getCache().removeIssue(id);
-        }
+    public void taskDeleted (String taskId) {
+        getCache().removeIssue(taskId);
     }
 
     public Collection<BugzillaIssue> getUnsubmittedIssues () {
diff --git a/mylyn.util/manifest.mf b/mylyn.util/manifest.mf
--- a/mylyn.util/manifest.mf
+++ b/mylyn.util/manifest.mf
@@ -2,6 +2,6 @@
 AutoUpdate-Show-In-Client: false
 OpenIDE-Module: org.netbeans.modules.mylyn.util
 OpenIDE-Module-Localizing-Bundle: 
org/netbeans/modules/mylyn/util/Bundle.properties
-OpenIDE-Module-Specification-Version: 1.12
+OpenIDE-Module-Specification-Version: 1.13
 OpenIDE-Module-Install: 
org/netbeans/modules/mylyn/util/internal/ModuleLifecycleManager.class
 
diff --git 
a/mylyn.util/src/org/netbeans/modules/mylyn/util/AbstractNbTaskWrapper.java 
b/mylyn.util/src/org/netbeans/modules/mylyn/util/AbstractNbTaskWrapper.java
new file mode 100644
--- /dev/null
+++ 
b/mylyn.util/src/org/netbeans/modules/mylyn/util/AbstractNbTaskWrapper.java
@@ -0,0 +1,456 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.mylyn.util;
+
+import java.awt.EventQueue;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.util.Date;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.mylyn.tasks.core.data.TaskData;
+import org.netbeans.modules.bugtracking.spi.IssueStatusProvider;
+import org.openide.util.RequestProcessor;
+import org.openide.util.WeakListeners;
+
+/**
+ *
+ * @author Ondrej Vrabec
+ */
+public abstract class AbstractNbTaskWrapper {
+    
+    static final String ATTR_NEW_UNREAD = "NetBeans.task.markedNewUnread"; 
//NOI18N
+    private static final Object MODEL_LOCK = new Object();
+    private static final Logger LOG = 
Logger.getLogger(AbstractNbTaskWrapper.class.getName());
+    private static final RequestProcessor RP = new 
RequestProcessor("NBTasks"); //NOI18N
+
+    private NbTask task;
+    private NbTaskDataModel model;
+    private NbTaskDataModel.NbTaskDataModelListener list;
+    private boolean readPending;
+    private final TaskDataListenerImpl taskDataListener;
+    private final TaskListenerImpl taskListener;
+    private Reference<TaskData> repositoryDataRef;
+    private final RequestProcessor.Task repositoryTaskDataLoaderTask;
+
+    public AbstractNbTaskWrapper (NbTask task) {
+        this.task = task;
+        this.repositoryDataRef = new SoftReference<TaskData>(null);
+        repositoryTaskDataLoaderTask = RP.create(new Runnable() {
+            @Override
+            public void run () {
+                loadRepositoryTaskData();
+            }
+        });
+        MylynSupport mylynSupp = MylynSupport.getInstance();
+        taskDataListener = new TaskDataListenerImpl();
+        
mylynSupp.addTaskDataListener(WeakListeners.create(TaskDataListener.class, 
taskDataListener, mylynSupp));
+        taskListener = new TaskListenerImpl();
+        task.addNbTaskListener(WeakListeners.create(NbTaskListener.class, 
taskListener, mylynSupp));
+    }
+
+    /**
+     * Returns the id of the given task or null if task is new
+     * @param task
+     * @return id or null
+     */
+    public static String getID (NbTask task) {
+        if (task.getSynchronizationState() == 
NbTask.SynchronizationState.OUTGOING_NEW) {
+            return "-" + task.getTaskId();
+        }
+        return task.getTaskId();
+    }
+
+    protected final TaskData getRepositoryTaskData () {
+        TaskData taskData = repositoryDataRef.get();
+        if (taskData == null) {
+            if (EventQueue.isDispatchThread()) {
+                repositoryTaskDataLoaderTask.schedule(100);
+            } else {
+                return loadRepositoryTaskData();
+            }
+        }
+        return taskData;
+    }
+
+    private TaskData loadRepositoryTaskData () {
+        // this method is time consuming
+        assert !EventQueue.isDispatchThread();
+        TaskData td = repositoryDataRef.get();
+        if (td != null) {
+            return td;
+        }
+        try {
+            NbTaskDataState taskDataState = task.getTaskDataState();
+            if (taskDataState != null) {
+                td = taskDataState.getRepositoryData();
+                repositoryDataRef = new SoftReference<TaskData>(td);
+                repositoryTaskDataLoaded(td);
+            }
+        } catch (CoreException ex) {
+            LOG.log(Level.WARNING, null, ex);
+        }
+        return td;
+    }
+
+    protected final void deleteTask () {
+        assert task.getSynchronizationState() == 
NbTask.SynchronizationState.OUTGOING_NEW : "Only new local tasks can be 
deleted: " + task.getSynchronizationState();
+        synchronized (MODEL_LOCK) {
+            if (list != null) {
+                model.removeNbTaskDataModelListener(list);
+                list = null;
+            }
+            model = null;
+        }
+        MylynSupport mylynSupp = MylynSupport.getInstance();
+        mylynSupp.removeTaskDataListener(taskDataListener);
+        task.removeNbTaskListener(taskListener);
+        if (task.getSynchronizationState() == 
NbTask.SynchronizationState.OUTGOING_NEW) {
+            task.delete();
+            taskDeleted(task);
+        }
+    }
+
+    protected abstract void taskDeleted (NbTask task);
+
+    public final boolean isMarkedNewUnread () {
+        return isNew() && 
Boolean.TRUE.toString().equals(task.getAttribute(ATTR_NEW_UNREAD));
+    }
+
+    public final boolean isNew () {
+        return task.isNew();
+    }
+
+    protected final void markNewRead () {
+        task.setAttribute(ATTR_NEW_UNREAD, null);
+    }
+
+    public final void setUpToDate (boolean seen, boolean markReadPending) {
+        synchronized (MODEL_LOCK) {
+            if (markReadPending) {
+                // this is a workaround to keep incoming changes visible in 
editor
+                NbTask.SynchronizationState syncState = 
task.getSynchronizationState();
+                readPending |= syncState == 
NbTask.SynchronizationState.INCOMING
+                        || syncState == NbTask.SynchronizationState.CONFLICT;
+            } else {
+                readPending = false;
+            }
+            task.markSeen(seen);
+        }
+    }
+
+    protected final void editorOpened () {
+        list = new NbTaskDataModel.NbTaskDataModelListener() {
+            @Override
+            public void attributeChanged 
(NbTaskDataModel.NbTaskDataModelEvent event) {
+                NbTaskDataModel m = model;
+                if (event.getModel() == m) {
+                    AbstractNbTaskWrapper.this.attributeChanged(event, m);
+                }
+            }
+        };
+        if (task.getSynchronizationState() == 
NbTask.SynchronizationState.INCOMING_NEW) {
+            // mark as seen so no fields are highlighted
+            setUpToDate(true, false);
+        }
+        // clear upon close
+        synchronized (MODEL_LOCK) {
+            if (readPending) {
+                // make sure remote changes are not lost and still 
highlighted in the editor
+                setUpToDate(false, false);
+            }
+            model = task.getTaskDataModel();
+            model.addNbTaskDataModelListener(list);
+        }
+    }
+
+    protected final void editorClosed () {
+        final NbTaskDataModel m = model;
+        final boolean markedAsNewUnread = isMarkedNewUnread();
+        if (m != null) {
+            if (list != null) {
+                m.removeNbTaskDataModelListener(list);
+                list = null;
+            }
+            readPending = false;
+            if (markedAsNewUnread) {
+                // was not modified by user and not yet saved
+                deleteTask();
+            } else {
+                synchronized (MODEL_LOCK) {
+                    if (model == m) {
+                        model = null;
+                    }
+                }
+                if (m.isDirty()) {
+                    try {
+                        save();
+                    } catch (CoreException ex) {
+                        LOG.log(Level.WARNING, null, ex);
+                    }
+                }
+            }
+        }
+    }
+
+    protected final void runWithModelLoaded (Runnable runnable) {
+        synchronized (MODEL_LOCK) {
+            boolean closeModel = false;
+            try {
+                if (model == null) {
+                    closeModel = true;
+                    model = task.getTaskDataModel();
+                }
+                runnable.run();
+            } finally {
+                if (closeModel) {
+                    if (model != null && model.isDirty()) {
+                        try {
+                            // let's not loose edits
+                            model.save();
+                        } catch (CoreException ex) {
+                            LOG.log(Level.INFO, null, ex);
+                        }
+                    }
+                    model = null;
+                }
+            }
+        }
+    }
+
+    protected abstract void attributeChanged 
(NbTaskDataModel.NbTaskDataModelEvent event, NbTaskDataModel model);
+
+    private void save () throws CoreException {
+        NbTaskDataModel m = this.model;
+        markNewRead();
+        if (m.isDirty()) {
+            if (isNew()) {
+                String summary = task.getSummary();
+                String newSummary = getSummary(m.getLocalTaskData());
+                if (newSummary != null && !(newSummary.isEmpty() || 
newSummary.equals(summary))) {
+                    task.setSummary(newSummary);
+                    taskModified(false);
+                }
+            }
+            m.save();
+            modelSaved(m);
+        }
+    }
+    
+    protected final void taskSubmitted (NbTask task) {
+        if (task != null && task != this.task) {
+            this.task.removeNbTaskListener(taskListener);
+            this.task = task;
+            task.addNbTaskListener(taskListener);
+            synchronized (MODEL_LOCK) {
+                if (list != null) {
+                    model.removeNbTaskDataModelListener(list);
+                }
+                model = task.getTaskDataModel();
+                repositoryDataRef.clear();
+                if (list != null) {
+                    model.addNbTaskDataModelListener(list);
+                }
+            }
+        }
+    }
+
+    protected final boolean saveChanges () {
+        try {
+            save();
+            return true;
+        } catch (CoreException ex) {
+            LOG.log(Level.WARNING, null, ex);
+        }
+        return false;
+    }
+
+    public final boolean cancelChanges () {
+        try {
+            if (saveChanges()) {
+                task.discardLocalEdits();
+                model.refresh();
+                return true;
+            }
+        } catch (CoreException ex) {
+            LOG.log(Level.WARNING, null, ex);
+        }
+        return false;
+    }
+
+    public final boolean hasLocalEdits () {
+        NbTaskDataModel m = model;
+        return !(m == null || m.getChangedAttributes().isEmpty());
+    }
+
+    protected final boolean updateModel () {
+        try {
+            model.refresh();
+            return true;
+        } catch (CoreException ex) {
+            LOG.log(Level.INFO, null, ex);
+        }
+        return false;
+    }
+
+    protected abstract void modelSaved (NbTaskDataModel model);
+
+    protected abstract String getSummary (TaskData taskData);
+
+    protected abstract void taskDataUpdated ();
+
+    protected final boolean isSeen () {
+        NbTask.SynchronizationState syncState = 
task.getSynchronizationState();
+        return syncState == NbTask.SynchronizationState.OUTGOING
+                || syncState == NbTask.SynchronizationState.OUTGOING_NEW
+                || syncState == NbTask.SynchronizationState.SYNCHRONIZED;
+    }
+
+    protected abstract void taskModified (boolean syncStateChanged);
+
+    protected final NbTaskDataModel getModel () {
+        return model;
+    }
+
+    protected abstract void repositoryTaskDataLoaded (TaskData 
repositoryTaskData);
+
+    protected final NbTask getNbTask () {
+        return task;
+    }
+
+    public final long getCreated () {
+        Date createdDate = getCreatedDate();
+        if (createdDate != null) {
+            return createdDate.getTime();
+        } else {
+            return -1;
+        }
+    }
+
+    public final Date getCreatedDate () {
+        return task.getCreationDate();
+    }
+
+    public final long getLastModify () {
+        Date lastModifyDate = getLastModifyDate();
+        if (lastModifyDate != null) {
+            return lastModifyDate.getTime();
+        } else {
+            return -1;
+        }
+    }
+
+    public final Date getLastModifyDate () {
+        return task.getModificationDate();
+    }
+
+    public final String getSummary () {
+        return task.getSummary();
+    }
+
+    public final String getID () {
+        return getID(task);
+    }
+
+    public final boolean isFinished () {
+        return task.isCompleted();
+    }
+
+    public final IssueStatusProvider.Status getStatus () {
+        return getNbStatus();
+    }
+
+    protected final NbTask.SynchronizationState getSynchronizationState () {
+        return task.getSynchronizationState();
+    }
+
+    public final IssueStatusProvider.Status getNbStatus () {
+        switch (getSynchronizationState()) {
+            case CONFLICT:
+            case INCOMING:
+                return IssueStatusProvider.Status.MODIFIED;
+            case INCOMING_NEW:
+                return IssueStatusProvider.Status.NEW;
+            case OUTGOING:
+            case OUTGOING_NEW:
+            case SYNCHRONIZED:
+                return IssueStatusProvider.Status.SEEN;
+        }
+        return null;
+    }
+
+    private class TaskDataListenerImpl implements TaskDataListener {
+
+        @Override
+        public void taskDataUpdated (TaskDataListener.TaskDataEvent event) {
+            if (event.getTask() == task) {
+                if (event.getTaskData() != null && 
!event.getTaskData().isPartial()) {
+                    repositoryDataRef = new 
SoftReference<TaskData>(event.getTaskData());
+                }
+                if (event.getTaskDataUpdated()) {
+                    NbTaskDataModel m = model;
+                    if (m != null) {
+                        try {
+                            m.refresh();
+                        } catch (CoreException ex) {
+                            LOG.log(Level.INFO, null, ex);
+                        }
+                    }
+                    AbstractNbTaskWrapper.this.taskDataUpdated();
+                }
+            }
+        }
+    }
+
+    private class TaskListenerImpl implements NbTaskListener {
+
+        @Override
+        public void taskModified (NbTaskListener.TaskEvent event) {
+            if (event.getTask() == task && event.getKind() == 
NbTaskListener.TaskEvent.Kind.MODIFIED) {
+                boolean syncStateChanged = event.taskStateChanged();
+                AbstractNbTaskWrapper.this.taskModified(syncStateChanged);
+            }
+        }
+
+    }
+}
diff --git a/mylyn.util/src/org/netbeans/modules/mylyn/util/MylynSupport.java 
b/mylyn.util/src/org/netbeans/modules/mylyn/util/MylynSupport.java
--- a/mylyn.util/src/org/netbeans/modules/mylyn/util/MylynSupport.java
+++ b/mylyn.util/src/org/netbeans/modules/mylyn/util/MylynSupport.java
@@ -356,6 +356,7 @@
             task.setSummary(summary);
         }
         taskList.addTask(task, 
taskList.getUnsubmittedContainer(task.getAttribute(ITasksCoreConstants.ATTRIBUTE_OUTGOING_NEW_REPOSITORY_URL)));
+        task.setAttribute(AbstractNbTaskWrapper.ATTR_NEW_UNREAD, 
Boolean.TRUE.toString());
         return MylynSupport.getInstance().toNbTask(task);
     }
 
diff --git a/mylyn.util/src/org/netbeans/modules/mylyn/util/NbTask.java 
b/mylyn.util/src/org/netbeans/modules/mylyn/util/NbTask.java
--- a/mylyn.util/src/org/netbeans/modules/mylyn/util/NbTask.java
+++ b/mylyn.util/src/org/netbeans/modules/mylyn/util/NbTask.java
@@ -47,7 +47,6 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.mylyn.internal.tasks.core.TaskContainerDelta;
 import org.eclipse.mylyn.tasks.core.ITask;
-import org.netbeans.modules.bugtracking.spi.IssueStatusProvider;
 import org.netbeans.modules.mylyn.util.internal.TaskListener;
 import org.openide.util.WeakListeners;
 
@@ -145,21 +144,6 @@
         return delegate.isCompleted();
     }
 
-    public IssueStatusProvider.Status getNbStatus () {
-        switch (delegate.getSynchronizationState()) {
-            case CONFLICT:
-            case INCOMING:
-                return IssueStatusProvider.Status.MODIFIED;
-            case INCOMING_NEW:
-                return IssueStatusProvider.Status.NEW;
-            case OUTGOING:
-            case OUTGOING_NEW:
-            case SYNCHRONIZED:
-                return IssueStatusProvider.Status.SEEN;
-        }
-        return null;
-    }
-
     public void setSummary (String summary) {
         delegate.setSummary(summary);
     }
@@ -220,6 +204,10 @@
         return MylynSupport.getInstance().getTaskDataState(this);
     }
 
+    boolean isNew () {
+        return syncState == SynchronizationState.OUTGOING_NEW;
+    }
+
     public static enum SynchronizationState {
         INCOMING_NEW,
         INCOMING,
diff --git 
a/mylyn.util/src/org/netbeans/modules/mylyn/util/NbTaskDataModel.java 
b/mylyn.util/src/org/netbeans/modules/mylyn/util/NbTaskDataModel.java
--- a/mylyn.util/src/org/netbeans/modules/mylyn/util/NbTaskDataModel.java
+++ b/mylyn.util/src/org/netbeans/modules/mylyn/util/NbTaskDataModel.java
@@ -186,6 +186,10 @@
         return delegateModel.getTask();
     }
     
+    public boolean hasOutgoingChanged () {
+        return isDirty() || !getChangedAttributes().isEmpty();
+    }
+    
     public static interface NbTaskDataModelListener extends EventListener {
 
         public void attributeChanged (NbTaskDataModelEvent event);

[hg] main-silver: moving common code in bugtracking systems rela...

Ondrej Vrabec 08/17/2013

Project Features

About this Project

ConnectedDeveloper was started in November 2009, is owned by tpavek, and has 66 members.
By use of this website, you agree to the NetBeans Policies and Terms of Use (revision 20140418.2d69abc). © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo
 
 
Close
loading
Please Confirm
Close