Merge branch 'hotfix/4.8.1' into develop
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / view / derivate / DerivateView.java
index 5e6f23c0a5f1698f5c1a68f0a61bcdbe443f3394..a536b023d6cba0c8a6fa5e088170dca824163696 100644 (file)
@@ -3,6 +3,7 @@ package eu.etaxonomy.taxeditor.editor.view.derivate;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -10,11 +11,25 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Named;
+
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jface.action.MenuManager;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.e4.ui.di.Persist;
+import org.eclipse.e4.ui.model.application.ui.MDirtyable;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.EMenuService;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
 import org.eclipse.jface.util.LocalSelectionTransfer;
 import org.eclipse.jface.viewers.AbstractTreeViewer;
 import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TreeNode;
@@ -26,18 +41,8 @@ import org.eclipse.swt.dnd.Transfer;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.Tree;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IEditorSite;
 import org.eclipse.ui.IMemento;
-import org.eclipse.ui.ISelectionListener;
-import org.eclipse.ui.ISelectionService;
-import org.eclipse.ui.IWorkbenchPart;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.part.EditorPart;
 
 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
@@ -51,56 +56,64 @@ import eu.etaxonomy.cdm.model.taxon.Taxon;
 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
 import eu.etaxonomy.taxeditor.editor.EditorUtil;
-import eu.etaxonomy.taxeditor.editor.Messages;
 import eu.etaxonomy.taxeditor.editor.MultiPageTaxonEditor;
+import eu.etaxonomy.taxeditor.editor.l10n.Messages;
 import eu.etaxonomy.taxeditor.editor.view.derivate.searchFilter.DerivateSearchCompositeController;
+import eu.etaxonomy.taxeditor.model.AbstractUtility;
 import eu.etaxonomy.taxeditor.model.IContextListener;
 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
 import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
 import eu.etaxonomy.taxeditor.model.IPartContentHasMedia;
 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
+import eu.etaxonomy.taxeditor.model.MessagingUtils;
 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
 import eu.etaxonomy.taxeditor.session.ICdmEntitySession;
 import eu.etaxonomy.taxeditor.session.ICdmEntitySessionEnabled;
 import eu.etaxonomy.taxeditor.store.CdmStore;
 import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateContentProvider;
 import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateLabelProvider;
+import eu.etaxonomy.taxeditor.workbench.part.IE4SavablePart;
 
 /**
  * Displays the derivate hierarchy of the specimen specified in the editor input.
  *
  */
-public class DerivateView extends EditorPart implements IPartContentHasFactualData, IConversationEnabled,
+public class DerivateView implements IPartContentHasFactualData, IConversationEnabled,
         ICdmEntitySessionEnabled, IDirtyMarkable, IPostOperationEnabled, IPartContentHasDetails, IPartContentHasSupplementalData, IPartContentHasMedia,
-        IContextListener, ISelectionListener {
+        IContextListener, IE4SavablePart {
+
+    private static final String SPECIMEN_EDITOR = Messages.DerivateView_SPECIMEN_EDITOR;
+
     public static final String ID = "eu.etaxonomy.taxeditor.editor.view.derivate.DerivateView"; //$NON-NLS-1$
+    public static final String INPUT_ID = ID+".editorInput"; //$NON-NLS-1$
 
     public static final String YOU_NEED_TO_SAVE_BEFORE_PERFORMING_THIS_ACTION = Messages.DerivateView_YOU_NEED_TO_SAVE;
     public static final String VIEW_HAS_UNSAVED_CHANGES = Messages.DerivateView_UNSAVED_CHANGES;
 
     private static final List<String> SPECIMEN_INIT_STRATEGY = Arrays.asList(new String[] {
-            "descriptions",
-            "annotations",
-            "markers",
-            "credits",
-            "extensions",
-            "rights",
-            "sources",
-            "derivationEvents.derivatives.annotations",
-            "derivationEvents.derivatives.markers",
-            "derivationEvents.derivatives.credits",
-            "derivationEvents.derivatives.extensions",
-            "derivationEvents.derivatives.rights",
-            "derivationEvents.derivatives.sources"
+            "descriptions", //$NON-NLS-1$
+            "annotations", //$NON-NLS-1$
+            "markers", //$NON-NLS-1$
+            "credits", //$NON-NLS-1$
+            "extensions", //$NON-NLS-1$
+            "rights", //$NON-NLS-1$
+            "sources", //$NON-NLS-1$
+            "derivationEvents.derivatives.annotations", //$NON-NLS-1$
+            "derivationEvents.derivatives.markers", //$NON-NLS-1$
+            "derivationEvents.derivatives.credits", //$NON-NLS-1$
+            "derivationEvents.derivatives.extensions", //$NON-NLS-1$
+            "derivationEvents.derivatives.rights", //$NON-NLS-1$
+            "derivationEvents.derivatives.sources" //$NON-NLS-1$
     });
 
+       private static final int WARN_THRESHOLD = 200;
+
+
        private ConversationHolder conversation;
 
        private TreeViewer viewer;
 
-    private boolean isDirty;
-
     private final int dndOperations = DND.DROP_MOVE;
 
     private DerivateLabelProvider labelProvider;
@@ -129,37 +142,57 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
 
     private Taxon selectedTaxon;
 
-    private ISelectionService selectionService;
+    @Inject
+    private ESelectionService selService;
+
+    @Inject
+    private MDirtyable dirty;
+
+    @Inject
+    private EPartService partService;
+
+    private ISelectionChangedListener selectionChangedListener;
 
     /**
      * Default constructor
      */
+    @Inject
     public DerivateView() {
     }
 
-
     /**
      * {@inheritDoc}
      */
-    @Override
-    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
-        this.setSite(site);
-        this.setInput(input);
-        this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
-        this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
-
-        if (CdmStore.isActive() && conversation == null) {
-            conversation = CdmStore.createConversation();
+    public void init(DerivateViewEditorInput editorInput){
+        this.derivateToRootEntityMap = new HashMap<>();
+        this.rootElements = new HashSet<>();
+
+        //init tree
+        Collection<UUID> derivativeUuids = editorInput.getDerivativeUuids();
+        checkWarnThreshold(derivativeUuids);
+        updateRootEntities(derivativeUuids);
+        //set taxon filter
+        derivateSearchCompositeController.setTaxonFilter(editorInput.getTaxonUuid());
+        //reset status bar
+        //TODO e4
+//        getEditorSite().getActionBars().getStatusLineManager().setMessage(""); //$NON-NLS-1$
+    }
+
+    @PostConstruct
+    public void createPartControl(Composite parent, EMenuService menuService) {
+        if (CdmStore.isActive()){
+            if(conversation == null){
+                conversation = CdmStore.createConversation();
+            }
+            if(cdmEntitySession!=null){
+                cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
+            }
         }
-        if (CdmStore.isActive()) {
-            cdmEntitySession = CdmStore.getCurrentSessionManager().newSession(this, true);
+        else{
+            return;
         }
         //listen to context changes
         CdmStore.getContextManager().addContextListener(this);
-    }
-
-    @Override
-    public void createPartControl(Composite parent) {
 
         parent.setLayout(new GridLayout());
 
@@ -186,25 +219,13 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         viewer.setLabelProvider(labelProvider);
         viewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
         viewer.getTree().setEnabled(CdmStore.isActive());
-        // Propagate selection from viewer
-        getSite().setSelectionProvider(viewer);
 
-        //listen to selection changes
-        selectionService = getSite().getWorkbenchWindow().getSelectionService();
-        selectionService.addSelectionListener(this);
+        //propagate selection
+        selectionChangedListener = (event -> selService.setSelection(AbstractUtility.getElementsFromSelectionChangedEvent(event)));
+        viewer.addSelectionChangedListener(selectionChangedListener);
 
         //create context menu
-        MenuManager menuManager = new MenuManager();
-        menuManager.setRemoveAllWhenShown(true);
-        getSite().registerContextMenu(menuManager, viewer);
-        Control control = viewer.getControl();
-        Menu menu = menuManager.createContextMenu(control);
-        control.setMenu(menu);
-
-        //init tree
-        updateRootEntities(((DerivateViewEditorInput)getEditorInput()).getDerivativeUuids());
-        //reset status bar
-        getEditorSite().getActionBars().getStatusLineManager().setMessage("");
+        menuService.registerContextMenu(viewer.getControl(), "eu.etaxonomy.taxeditor.editor.popupmenu.specimeneditor");
 
         //add drag'n'drop support
         Transfer[] transfers = new Transfer[] {LocalSelectionTransfer.getTransfer(),};
@@ -237,8 +258,8 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
 
             List<SpecimenOrObservationBase> derivates = null;
             if(derivativeUuids!=null){
-                this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
-                this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
+                this.derivateToRootEntityMap = new HashMap<>();
+                this.rootElements = new HashSet<>();
                 derivates = CdmStore.getService(IOccurrenceService.class).load(new ArrayList(derivativeUuids), SPECIMEN_INIT_STRATEGY);
             }
             updateRootEntities(derivates);
@@ -248,55 +269,61 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
 
 
     public void updateRootEntities(List<SpecimenOrObservationBase> derivates) {
+        if(derivates!=null){
+            this.derivateToRootEntityMap = new HashMap<>();
+            this.rootElements = new HashSet<>();
+            for (SpecimenOrObservationBase derivate : derivates) {
 
-            if(derivates!=null){
-                this.derivateToRootEntityMap = new HashMap<SpecimenOrObservationBase<?>, SpecimenOrObservationBase<?>>();
-                this.rootElements = new HashSet<SpecimenOrObservationBase<?>>();
-                for (SpecimenOrObservationBase derivate : derivates) {
-
-                    if(derivate instanceof FieldUnit){
-                        derivateToRootEntityMap.put(derivate, derivate);
+                if(derivate instanceof FieldUnit){
+                    derivateToRootEntityMap.put(derivate, derivate);
+                }
+                else {
+                    SpecimenOrObservationBase<?> topMostDerivate = EditorUtil.getTopMostDerivate(derivate);
+                    if(topMostDerivate!=null){
+                        derivateToRootEntityMap.put(derivate, topMostDerivate);
                     }
-                    else {
-                        SpecimenOrObservationBase<?> topMostDerivate = EditorUtil.getTopMostDerivate(derivate);
-                        if(topMostDerivate!=null){
-                            derivateToRootEntityMap.put(derivate, topMostDerivate);
-                        }
-                        else{
-                            derivateToRootEntityMap.put(derivate, derivate);
-                        }
+                    else{
+                        derivateToRootEntityMap.put(derivate, derivate);
                     }
                 }
-                for (SpecimenOrObservationBase<?> specimen : derivateToRootEntityMap.values()) {
-                    rootElements.add(specimen);
-                }
             }
-            labelProvider.updateLabelCache(rootElements);
-            viewer.setInput(rootElements);
+            for (SpecimenOrObservationBase<?> specimen : derivateToRootEntityMap.values()) {
+                rootElements.add(specimen);
+            }
+        }
+        labelProvider.updateLabelCache(rootElements);
+        viewer.setInput(rootElements);
 
-            getEditorSite().getActionBars().getStatusLineManager().setMessage(rootElements.size() +" derivative hierarchies found");
+        //TODO e4
+        //            getEditorSite().getActionBars().getStatusLineManager().setMessage(String.format(Messages.DerivateView_CNT_DERIVATIVES_FOUND, rootElements.size()));
 
-            //set selection to derivatives if the filter criteria
-            //taxon assignment or or derivative type are set
-            if(derivates!=null && !derivateSearchCompositeController.isDefaultSearch()){
-                List<TreeNode> nodesToSelect = new ArrayList<TreeNode>();
-                for (SpecimenOrObservationBase specimenOrObservationBase : derivates) {
-                    nodesToSelect.add(new TreeNode(specimenOrObservationBase));
-                }
-                viewer.setSelection(new StructuredSelection(nodesToSelect));
-            }
-            else{
-                viewer.setSelection(null);
+        //set selection to derivatives if the filter criteria
+        //taxon assignment or derivative type are set
+        if(derivates!=null && !derivateSearchCompositeController.isDefaultSearch()){
+            List<TreeNode> nodesToSelect = new ArrayList<>();
+            for (SpecimenOrObservationBase specimenOrObservationBase : derivates) {
+                nodesToSelect.add(new TreeNode(specimenOrObservationBase));
             }
+            setSelection(new StructuredSelection(nodesToSelect));
+        }
+        else{
+            setSelection(null);
+        }
+    }
 
+    private void setSelection(StructuredSelection selection){
+        viewer.removeSelectionChangedListener(selectionChangedListener);
+        viewer.setSelection(selection);
+        viewer.addSelectionChangedListener(selectionChangedListener);
     }
 
     public void updateLabelCache(){
         labelProvider.updateLabelCache(rootElements);
     }
 
+    @Persist
     @Override
-    public void doSave(IProgressMonitor monitor) {
+    public void save(IProgressMonitor monitor) {
         String taskName = Messages.DerivateView_SAVING_HIERARCHY;
         monitor.beginTask(taskName, 3);
         if (!conversation.isBound()) {
@@ -307,47 +334,26 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         // commit the conversation and start a new transaction immediately
         conversation.commit(true);
 
-        if(CdmStore.getCurrentSessionManager().isRemoting()) {
-            CdmStore.getService(IOccurrenceService.class).merge(new ArrayList<SpecimenOrObservationBase>(rootElements), true);
-        }
+        CdmStore.getService(IOccurrenceService.class).merge(new ArrayList<>(rootElements), true);
+
         monitor.worked(1);
 
         this.setDirty(false);
         monitor.worked(1);
         monitor.done();
-        firePropertyChange(PROP_DIRTY);
+        dirty.setDirty(false);
         refreshTree();
     }
 
-    @Override
-    public void doSaveAs() {
-    }
-
-    @Override
-    public String getTitleToolTip() {
-        return Messages.DerivateView_DERIVATIVE_EDITOR;
-    }
-
-    @Override
-    public boolean isDirty() {
-        return isDirty;
-    }
-
     /**
      * @param isDirty the isDirty to set
      */
     public void setDirty(boolean isDirty) {
-        this.isDirty = isDirty;
-    }
-
-    @Override
-    public boolean isSaveAsAllowed() {
-        return false;
+        dirty.setDirty(isDirty);
     }
 
-    @Override
+    @Focus
     public void setFocus() {
-        viewer.getControl().setFocus();
         //make sure to bind again if maybe in another view the conversation was unbound
         if(conversation!=null && !conversation.isBound()){
             conversation.bind();
@@ -355,6 +361,9 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         if(cdmEntitySession != null) {
             cdmEntitySession.bind();
         }
+        if(derivateSearchCompositeController!=null) {
+            derivateSearchCompositeController.setFocusOnSearchField();
+        }
     }
 
     @Override
@@ -369,7 +378,7 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
     @Override
     public void changed(Object element) {
         setDirty(true);
-        firePropertyChange(IEditorPart.PROP_DIRTY);
+        //firePropertyChange(IEditorPart.PROP_DIRTY);
         viewer.update(new TreeNode(element), null);
     }
 
@@ -381,17 +390,17 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
     @Override
     public Map<Object, List<String>> getPropertyPathsMap() {
         List<String> specimenPropertyPaths = Arrays.asList(new String[] {
-                "descriptions",
-                "derivationEvents.derivates",
-                "annotations",
-                "markers",
-                "credits",
-                "extensions",
-                "rights",
-                "sources"
+                "descriptions", //$NON-NLS-1$
+                "derivationEvents.derivates", //$NON-NLS-1$
+                "annotations", //$NON-NLS-1$
+                "markers", //$NON-NLS-1$
+                "credits", //$NON-NLS-1$
+                "extensions", //$NON-NLS-1$
+                "rights", //$NON-NLS-1$
+                "sources" //$NON-NLS-1$
         });
         Map<Object, List<String>> specimenPropertyPathMap =
-                new HashMap<Object, List<String>>();
+                new HashMap<>();
         specimenPropertyPathMap.put(SpecimenOrObservationBase.class,specimenPropertyPaths);
         return specimenPropertyPathMap;
     }
@@ -413,13 +422,19 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
      * Refreshes the derivate hierarchy tree
      */
     public void refreshTree(){
-        viewer.refresh();
+       if(!viewer.getTree().isDisposed()){
+               viewer.refresh();
+       }
     }
 
     //FIXME:Remoting hack to make this work for remoting
     //This should actually be resolved using remoting post operations
     public void remove(Object obj) {
+        if (obj instanceof TreeNode){
+            obj = ((TreeNode)obj).getValue();
+        }
         rootElements.remove(obj);
+        Object o = this.derivateToRootEntityMap.remove(obj);
         viewer.setInput(rootElements);
     }
 
@@ -468,9 +483,8 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         return cdmEntitySession;
     }
 
-    @Override
+    @PreDestroy
     public void dispose() {
-        super.dispose();
         if(conversation!=null){
             conversation.close();
         }
@@ -479,14 +493,22 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
         }
     }
 
-    @Override
-    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+
+    @Inject
+    @Optional
+    public void selectionChanged(@Optional @Named(IServiceConstants.ACTIVE_SELECTION) ISelection selection,
+            @Named(IServiceConstants.ACTIVE_PART) MPart activePart, MPart thisPart)
+    {
+       if(activePart == thisPart || viewer==null){
+            return;
+        }
         if(viewer.getTree().isDisposed()){
             return;
         }
         if(listenToSelectionChange){
-            if(part instanceof MultiPageTaxonEditor){
-                selectedTaxon = ((MultiPageTaxonEditor) part).getTaxon();
+            selectedTaxon = null;
+            if(activePart instanceof MultiPageTaxonEditor){
+                selectedTaxon = ((MultiPageTaxonEditor) activePart).getTaxon();
             }
             else if(selection instanceof IStructuredSelection){
                 Object selectedElement = ((IStructuredSelection) selection).getFirstElement();
@@ -501,16 +523,28 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
             }
             if(selectedTaxon!=null){
                 Collection<SpecimenOrObservationBase> fieldUnits = CdmStore.getService(IOccurrenceService.class).listFieldUnitsByAssociatedTaxon(selectedTaxon, null, null);
-                Collection<UUID> uuids = new HashSet<UUID>();
+                Collection<UUID> uuids = new HashSet<>();
                 for (SpecimenOrObservationBase specimenOrObservationBase : fieldUnits) {
                     uuids.add(specimenOrObservationBase.getUuid());
                 }
+                checkWarnThreshold(uuids);
                 updateRootEntities(uuids);
-                setPartName("Derivative Editor: " + selectedTaxon.getName());
+
+                thisPart.setLabel(SPECIMEN_EDITOR+": " + selectedTaxon.getName()); //$NON-NLS-1$
+            }
+            else{
+                updateRootEntities((Collection<UUID>)Collections.EMPTY_LIST);
             }
         }
     }
 
+       private void checkWarnThreshold(Collection<UUID> uuids) {
+               if(uuids!=null && uuids.size()>WARN_THRESHOLD){
+                       MessagingUtils.warningDialog(Messages.DerivateView_PERF_WARNING, this.getClass(), String.format(Messages.DerivateView_PERF_WARNING_MESSAGE, uuids.size()));
+                       uuids.clear();
+               }
+       }
+
     public TreeViewer getViewer() {
         return viewer;
     }
@@ -520,18 +554,18 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
      */
     @Override
     public List<SpecimenOrObservationBase<?>> getRootEntities() {
-        return new ArrayList<SpecimenOrObservationBase<?>>(rootElements);
+        return new ArrayList<>(rootElements);
     }
 
-    public void toggleListenToSelectionChange() {
+    public void toggleListenToSelectionChange(MPart part) {
         listenToSelectionChange = !listenToSelectionChange;
         derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
         if(!listenToSelectionChange){
             selectedTaxon = null;
-            setPartName("Derivative Editor");
+            part.setLabel(SPECIMEN_EDITOR);
         }
         else if(selectedTaxon==null){
-            setPartName("Derivative Editor [no taxon selected]");
+            part.setLabel(SPECIMEN_EDITOR+Messages.DerivateView_NO_TAXON_SELECTED);
         }
     }
 
@@ -564,7 +598,9 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
     @Override
     public void contextStart(IMemento memento, IProgressMonitor monitor) {
         derivateSearchCompositeController.setEnabled(!listenToSelectionChange);
-        viewer.getTree().setEnabled(true);
+        if(!viewer.getTree().isDisposed()){
+            viewer.getTree().setEnabled(true);
+        }
         refreshTree();
     }
 
@@ -582,4 +618,9 @@ public class DerivateView extends EditorPart implements IPartContentHasFactualDa
     public void workbenchShutdown(IMemento memento, IProgressMonitor monitor) {
     }
 
+
+    public boolean isDirty() {
+        return dirty.isDirty();
+    }
+
 }