Revert "Usability fixes for GraphExplorerImpl -related WB selection propagation"
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Thu, 13 Dec 2018 11:43:37 +0000 (13:43 +0200)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Thu, 13 Dec 2018 11:43:37 +0000 (13:43 +0200)
This reverts commit 270834ce3962a4bca3945d06e642a99d21688c16.

bundles/org.simantics.browsing.ui.platform/src/org/simantics/browsing/ui/platform/PropertyPageView.java
bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/GraphExplorerImpl.java
bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/UpdateRunner.java
bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/jface/BasePostSelectionProvider.java
bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/jface/BaseSelectionProvider.java
bundles/org.simantics.views.swt.client/src/org/simantics/views/swt/client/impl/SWTExplorer.java
bundles/org.simantics.views.swt/META-INF/MANIFEST.MF
bundles/org.simantics.views.swt/src/org/simantics/views/swt/ModelledView.java

index 05109c8132bef66da570f2448270949503be2f10..0d4fc055b6ed2e7a8846052faba1e55ff3d3c310 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2018 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
  * in Industry THTH ry.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  *******************************************************************************/
 package org.simantics.browsing.ui.platform;
 
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.function.Consumer;
 
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.RegistryFactory;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.resource.LocalResourceManager;
@@ -31,6 +38,7 @@ import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.IWorkbenchPart3;
 import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.contexts.IContextService;
 import org.eclipse.ui.part.IContributedContentsView;
 import org.eclipse.ui.part.IPage;
@@ -41,6 +49,8 @@ import org.simantics.db.management.ISessionContextProvider;
 import org.simantics.selectionview.PropertyPage;
 import org.simantics.ui.workbench.IPropertyPage;
 import org.simantics.ui.workbench.ResourceInput;
+import org.simantics.utils.threads.SWTThread;
+import org.simantics.utils.threads.Throttler;
 import org.simantics.utils.ui.BundleUtils;
 import org.simantics.utils.ui.SWTUtils;
 
@@ -81,12 +91,19 @@ import org.simantics.utils.ui.SWTUtils;
  * @see IPropertyPage
  * @see PropertyPage
  */
-public class PropertyPageView extends PageBookView implements IContributedContentsView {
+public class PropertyPageView extends PageBookView implements ISelectionListener, IContributedContentsView {
+
+    /**
+     * Extension point used to modify behavior of the view
+     */
+    private static final String                   EXT_POINT                  = "org.eclipse.ui.propertiesView";              //$NON-NLS-1$
 
     private static final String                   PROPERTY_VIEW_CONTEXT      = "org.simantics.modeling.ui.properties";
 
     private static final String                   PROP_PINNED                = "pinned";
 
+    protected static final long                   SELECTION_CHANGE_THRESHOLD = 500;
+
     private ISessionContextProvider               contextProvider;
 
     /**
@@ -107,7 +124,7 @@ public class PropertyPageView extends PageBookView implements IContributedConten
 
     private IWorkbenchPart                        lastPart;
     private ISelection                            lastSelection;
-    private final Map<IWorkbenchPart, ISelection> lastSelections             = new WeakHashMap<>();
+    private final Map<IWorkbenchPart, ISelection> lastSelections             = new WeakHashMap<IWorkbenchPart, ISelection>();
 
     private ResourceManager                       resourceManager;
 
@@ -115,10 +132,9 @@ public class PropertyPageView extends PageBookView implements IContributedConten
     private ImageDescriptor                       pinned;
 
     /**
-     * The workbench post-selection listener for this view that changes the
-     * input of the pagebook page for the part which changed its selection. 
+     * Set of workbench parts, which should not be used as a source for PropertySheet
      */
-    private ISelectionListener                    selectionListener = this::doSelectionChanged;
+    private Set<String>                           ignoredViews;
 
     @Override
     public void createPartControl(Composite parent) {
@@ -195,12 +211,13 @@ public class PropertyPageView extends PageBookView implements IContributedConten
         // This prevents the Properties view from providing a selection to other
         // workbench parts, thus making them lose their selections which is not
         // desirable.
-        site.setSelectionProvider(null);
+//        site.setSelectionProvider(null);
 
         contextProvider = Simantics.getSessionContextProvider();
 
         if (!bootstrapOnly) {
-            site.getPage().addPostSelectionListener(selectionListener);
+            site.getPage().addSelectionListener(immediateSelectionListener);
+            site.getPage().addPostSelectionListener(this);
         }
     }
 
@@ -229,7 +246,8 @@ public class PropertyPageView extends PageBookView implements IContributedConten
 
         // Remove ourselves as a workbench selection listener.
         if (!bootstrapOnly) {
-            getSite().getPage().removePostSelectionListener(selectionListener);
+            getSite().getPage().removePostSelectionListener(this);
+            getSite().getPage().removeSelectionListener(immediateSelectionListener);
         }
 
         if (resourceManager != null) {
@@ -246,7 +264,7 @@ public class PropertyPageView extends PageBookView implements IContributedConten
         page.createControl(book);
         page.setMessage(Messages.PropertyPageView_noPropertiesAvailable);
         return page;
-        */
+         */
 
         PropertyPage page = new PropertyPage(getSite());
         initPage(page);
@@ -258,6 +276,7 @@ public class PropertyPageView extends PageBookView implements IContributedConten
 
     @Override
     protected PageRec doCreatePage(IWorkbenchPart part) {
+
         // NOTE: If the default page should be shown, this method must return null.
         if (part == null)
             return null;
@@ -315,10 +334,37 @@ public class PropertyPageView extends PageBookView implements IContributedConten
         return this == part || ignore;
     }
 
+    private Set<String> getIgnoredViews() {
+        if (ignoredViews == null) {
+            ignoredViews = new HashSet<String>();
+            IExtensionRegistry registry = RegistryFactory.getRegistry();
+            IExtensionPoint ep = registry.getExtensionPoint(EXT_POINT);
+            if (ep != null) {
+                IExtension[] extensions = ep.getExtensions();
+                for (int i = 0; i < extensions.length; i++) {
+                    IConfigurationElement[] elements = extensions[i].getConfigurationElements();
+                    for (int j = 0; j < elements.length; j++) {
+                        if ("excludeSources".equalsIgnoreCase(elements[j].getName())) { //$NON-NLS-1$
+                            String id = elements[j].getAttribute("id"); //$NON-NLS-1$
+                            if (id != null)
+                                ignoredViews.add(id);
+                        }
+                    }
+                }
+            }
+        }
+        return ignoredViews;
+    }
+
+    private boolean isViewIgnored(String partID) {
+        return getIgnoredViews().contains(partID);
+    }
+
     @Override
     protected boolean isImportant(IWorkbenchPart part) {
-        //System.out.println("isImportant(" + part.getSite().getId() + ")");
-        return !isWorkbenchSelectionPinned() && !isPropertyView(part);
+        String partID = part.getSite().getId();
+        //System.out.println("isImportant(" + partID + ")");
+        return !isWorkbenchSelectionPinned() && !isPropertyView(part) && !isViewIgnored(partID);
     }
 
     /**
@@ -371,10 +417,39 @@ public class PropertyPageView extends PageBookView implements IContributedConten
 //            super.partHidden(part);
     }
 
+    ISelectionListener immediateSelectionListener = new ISelectionListener() {
+       
+       private Throttler throttler = new Throttler(SWTThread.getThreadAccess(PlatformUI.getWorkbench().getDisplay()), 500, 3);
+       
+        @Override
+        public void selectionChanged(final IWorkbenchPart part, final ISelection selection) {
+               
+               // Do not process selections from self
+               if(PropertyPageView.this == part) return;
+               
+            throttler.schedule(new Runnable() {
+
+                               @Override
+                               public void run() {
+                                       PropertyPageView.this.doSelectionChanged(part, selection);                              
+                               }
+               
+            });
+            
+        }
+    };
+
     public ISelection getLastSelection() {
         return lastSelection;
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart,
+     *      org.eclipse.jface.viewers.ISelection)
+     */
+    @Override
     public void selectionChanged(IWorkbenchPart part, ISelection sel) {
         doSelectionChanged(part, sel);
     }
@@ -386,6 +461,7 @@ public class PropertyPageView extends PageBookView implements IContributedConten
      *         <code>false</code> otherwise
      */
     boolean doSelectionChanged(IWorkbenchPart part, ISelection sel) {
+       
         // we ignore our own selection or null selection
         if (isPropertyView(part) || sel == null) {
             return false;
@@ -423,8 +499,8 @@ public class PropertyPageView extends PageBookView implements IContributedConten
                 lastPart.addPropertyListener(partPropertyListener);
             }
 
+            updatePartName(ppage, sel);
             if (!sameSelection) {
-                updatePartName(ppage, sel);
                 ppage.selectionChanged(part, sel);
                 return true;
             }
@@ -440,11 +516,14 @@ public class PropertyPageView extends PageBookView implements IContributedConten
         // This check is not safe - there might be a burst of changes incoming
         //if (getPartName().equals(parameter)) return;
         //System.out.println("partNameUpdateCallback : " + parameter);
-        SWTUtils.asyncExec(getPageBook(), () -> {
-            if (!getPageBook().isDisposed()) {
-                if (getPartName().equals(parameter)) return;
-                //System.out.println("doSetParameterName : " + parameter);
-                doSetPartName(parameter);
+        SWTUtils.asyncExec(getPageBook(), new Runnable() {
+            @Override
+            public void run() {
+                if (!getPageBook().isDisposed()) {
+                    if (getPartName().equals(parameter)) return;
+                    //System.out.println("doSetParameterName : " + parameter);
+                    doSetPartName(parameter);
+                }
             }
         });
     };
index 0168ad864ae5e98258498d76fef7f04f42ee4282..df736c1e6dc2603315bea23f47b46a2170a52f55 100644 (file)
@@ -50,7 +50,6 @@ import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.resource.LocalResourceManager;
 import org.eclipse.jface.resource.ResourceManager;
-import org.eclipse.jface.util.OpenStrategy;
 import org.eclipse.jface.viewers.IPostSelectionProvider;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
@@ -69,6 +68,7 @@ import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.events.KeyListener;
 import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Font;
@@ -289,6 +289,24 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
 
     public static final int                        DEFAULT_MAX_CHILDREN                    = 1000;
 
+    private static final long                      POST_SELECTION_DELAY                    = 300;
+
+    /**
+     * The time in milliseconds that must elapse between consecutive
+     * {@link Tree} {@link SelectionListener#widgetSelected(SelectionEvent)}
+     * invocations in order for this class to construct a new selection.
+     * 
+     * <p>
+     * This is done because selection construction can be very expensive as the
+     * selected set grows larger when the user is pressing shift+arrow keys.
+     * GraphExplorerImpl will naturally listen to all changes in the tree
+     * selection, but as an optimization will not construct new
+     * StructuredSelection instances for every selection change event. A new
+     * selection will be constructed and set only if the selection hasn't
+     * changed for the amount of milliseconds specified by this constant.
+     */
+    private static final long                      SELECTION_CHANGE_QUIET_TIME             = 150;
+
     private final IThreadWorkQueue                 thread;
 
     /**
@@ -310,11 +328,11 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
     Tree                                           tree;
 
     @SuppressWarnings({ "rawtypes" })
-    final HashMap<CacheKey<?>, NodeQueryProcessor> processors            = new HashMap<>();
+    final HashMap<CacheKey<?>, NodeQueryProcessor> processors            = new HashMap<CacheKey<?>, NodeQueryProcessor>();
     @SuppressWarnings({ "rawtypes" })
-    final HashMap<Object, PrimitiveQueryProcessor> primitiveProcessors   = new HashMap<>();
+    final HashMap<Object, PrimitiveQueryProcessor> primitiveProcessors   = new HashMap<Object, PrimitiveQueryProcessor>();
     @SuppressWarnings({ "rawtypes" })
-    final HashMap<Class, DataSource>               dataSources           = new HashMap<>();
+    final HashMap<Class, DataSource>               dataSources           = new HashMap<Class, DataSource>();
     
     class GraphExplorerContext extends AbstractDisposable implements IGraphExplorerContext {
         // This is for query debugging only.
@@ -333,7 +351,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
          * <code>null</code> there's nothing scheduled yet in which case
          * scheduling can commence. Otherwise the update should be skipped.
          */
-        AtomicReference<Runnable> currentQueryUpdater = new AtomicReference<>();
+        AtomicReference<Runnable> currentQueryUpdater = new AtomicReference<Runnable>();
 
         /**
          * Keeps track of nodes that have already been auto-expanded. After
@@ -341,7 +359,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
          * expanded state after that. This makes it possible for the user to
          * close auto-expanded nodes.
          */
-        Map<NodeContext, Boolean>     autoExpanded  = new WeakHashMap<>();
+        Map<NodeContext, Boolean>     autoExpanded  = new WeakHashMap<NodeContext, Boolean>();
 
         
         @Override
@@ -464,7 +482,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
 
     GraphExplorerContext                         explorerContext     = new GraphExplorerContext();
 
-    HashSet<TreeItem>                            pendingItems        = new HashSet<>();
+    HashSet<TreeItem>                            pendingItems        = new HashSet<TreeItem>();
     boolean                                      updating            = false;
     boolean                                      pendingRoot         = false;
 
@@ -485,14 +503,14 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
      * Access this map only in the SWT thread to keep it thread-safe.
      * </p>
      */
-    BijectionMap<NodeContext, TreeItem>         contextToItem     = new BijectionMap<>();
+    BijectionMap<NodeContext, TreeItem>         contextToItem     = new BijectionMap<NodeContext, TreeItem>();
 
     /**
      * Columns of the UI viewer. Use {@link #setColumns(Column[])} to
      * initialize.
      */
     Column[]                                     columns           = new Column[0];
-    Map<String, Integer>                         columnKeyToIndex  = new HashMap<>();
+    Map<String, Integer>                         columnKeyToIndex  = new HashMap<String, Integer>();
     boolean                                      refreshingColumnSizes = false;
     boolean                                      columnsAreVisible = true;
 
@@ -519,12 +537,12 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
 
     /** Set to true when the Tree widget is disposed. */
     private boolean                              disposed                 = false;
-    private final CopyOnWriteArrayList<FocusListener>  focusListeners     = new CopyOnWriteArrayList<>();
-    private final CopyOnWriteArrayList<MouseListener>  mouseListeners     = new CopyOnWriteArrayList<>();
-    private final CopyOnWriteArrayList<KeyListener>    keyListeners       = new CopyOnWriteArrayList<>();
+    private final CopyOnWriteArrayList<FocusListener>  focusListeners           = new CopyOnWriteArrayList<FocusListener>();
+    private final CopyOnWriteArrayList<MouseListener>  mouseListeners           = new CopyOnWriteArrayList<MouseListener>();
+    private final CopyOnWriteArrayList<KeyListener>    keyListeners             = new CopyOnWriteArrayList<KeyListener>();
 
     /** Selection provider */
-    private   GraphExplorerPostSelectionProvider postSelectionProvider    = new GraphExplorerPostSelectionProvider(this);
+    private   GraphExplorerPostSelectionProvider postSelectionProvider = new GraphExplorerPostSelectionProvider(this);
     protected BasePostSelectionProvider          selectionProvider        = new BasePostSelectionProvider();
     protected SelectionDataResolver              selectionDataResolver;
     protected SelectionFilter                    selectionFilter;
@@ -552,12 +570,12 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
      * item was a part of the current selection in which case the selection must
      * be updated.
      */
-    private final Map<TreeItem, NodeContext>     selectedItems            = new HashMap<>();
+    private final Map<TreeItem, NodeContext>     selectedItems            = new HashMap<TreeItem, NodeContext>();
 
     /**
      * TODO: specify what this is for
      */
-    private final Set<NodeContext>               selectionRefreshContexts = new HashSet<>();
+    private final Set<NodeContext>               selectionRefreshContexts = new HashSet<NodeContext>();
 
     /**
      * If this field is non-null, it means that if {@link #setData(Event)}
@@ -631,7 +649,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
      * 
      * @see #setPendingImages(IProgressMonitor)
      */
-    Map<TreeItem, ImageTask> imageTasks     = new THashMap<>();
+    Map<TreeItem, ImageTask> imageTasks     = new THashMap<TreeItem, ImageTask>();
 
     /**
      * A state flag indicating whether the vertical scroll bar was visible for
@@ -695,7 +713,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
                        updateCounter = 0;
                        uiUpdateScheduler.schedule(this, 50, TimeUnit.MILLISECONDS);
                     } else {
-                       tree.getDisplay().asyncExec(new UpdateRunner(GraphExplorerImpl.this));
+                       tree.getDisplay().asyncExec(new UpdateRunner(GraphExplorerImpl.this, GraphExplorerImpl.this.explorerContext));
                     }
                     
                 }
@@ -770,7 +788,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
      * modified. These are used internally to prevent duplicate edits from being
      * initiated which should always be a sensible thing to do.
      */
-    private Set<NodeContext> currentlyModifiedNodes   = new THashSet<>();
+    private Set<NodeContext> currentlyModifiedNodes   = new THashSet<NodeContext>();
 
     private final TreeEditor editor;
     private Color            invalidModificationColor = null;
@@ -1363,14 +1381,17 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
         // Keep track of the previous single selection to help
         // decide whether to start editing a tree node on mouse
         // downs or not.
-        tree.addListener(SWT.Selection, event -> {
-            TreeItem[] selection = tree.getSelection();
-            if (selection.length == 1) {
-                //for (TreeItem item : selection)
-                //    System.out.println("selection: " + item);
-                previousSingleSelection = selection[0];
-            } else {
-                previousSingleSelection = null;
+        tree.addListener(SWT.Selection, new Listener() {
+            @Override
+            public void handleEvent(Event event) {
+                TreeItem[] selection = tree.getSelection();
+                if (selection.length == 1) {
+                    //for (TreeItem item : selection)
+                    //    System.out.println("selection: " + item);
+                    previousSingleSelection = selection[0];
+                } else {
+                    previousSingleSelection = null;
+                }
             }
         });
 
@@ -1472,33 +1493,39 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
         };
         tree.addListener(SWT.MouseDown, mouseEditListener);
         tree.addListener(SWT.DragDetect, mouseEditListener);
-        tree.addListener(SWT.DragDetect, event -> {
-            Point test = new Point(event.x, event.y);
-            TreeItem item = tree.getItem(test);
-            if(item != null) {
-                for(int i=0;i<tree.getColumnCount();i++) {
-                    Rectangle rect = item.getBounds(i);
-                    if(rect.contains(test)) {
-                        tree.setData(KEY_DRAG_COLUMN, i);
-                        return;
+        tree.addListener(SWT.DragDetect, new Listener() {
+            @Override
+            public void handleEvent(Event event) {
+                Point test = new Point(event.x, event.y);
+                TreeItem item = tree.getItem(test);
+                if(item != null) {
+                    for(int i=0;i<tree.getColumnCount();i++) {
+                        Rectangle rect = item.getBounds(i);
+                        if(rect.contains(test)) {
+                            tree.setData(KEY_DRAG_COLUMN, i);
+                            return;
+                        }
                     }
                 }
+                tree.setData(KEY_DRAG_COLUMN, -1);
             }
-            tree.setData(KEY_DRAG_COLUMN, -1);
         });
-        tree.addListener(SWT.MouseMove, event -> {
-            Point test = new Point(event.x, event.y);
-            TreeItem item = tree.getItem(test);
-            if(item != null) {
-                for(int i=0;i<tree.getColumnCount();i++) {
-                    Rectangle rect = item.getBounds(i);
-                    if(rect.contains(test)) {
-                        transientState.setActiveColumn(i);
-                        return;
+        tree.addListener(SWT.MouseMove, new Listener() {
+            @Override
+            public void handleEvent(Event event) {
+                Point test = new Point(event.x, event.y);
+                TreeItem item = tree.getItem(test);
+                if(item != null) {
+                    for(int i=0;i<tree.getColumnCount();i++) {
+                        Rectangle rect = item.getBounds(i);
+                        if(rect.contains(test)) {
+                               transientState.setActiveColumn(i);
+                            return;
+                        }
                     }
                 }
+               transientState.setActiveColumn(null);
             }
-            transientState.setActiveColumn(null);
         });
 
         // Add focus/mouse/key listeners for supporting the respective
@@ -1551,12 +1578,18 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
             }
         });
 
-        OpenStrategy os = new OpenStrategy(tree);
-        os.addPostSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
-            //System.out.println("OPENSTRATEGY: post selection changed: " + e);
-            resetSelection();
-            selectionProvider.firePostSelection(selectionProvider.getSelection());
-        }));
+               // Add a tree selection listener for keeping the selection of
+               // GraphExplorer's ISelectionProvider up-to-date.
+        tree.addSelectionListener(new SelectionListener() {
+            @Override
+            public void widgetDefaultSelected(SelectionEvent e) {
+                widgetSelected(e);
+            }
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+               widgetSelectionChanged(false);
+            }
+        });
 
         // This listener takes care of updating the set of currently selected
         // TreeItem instances. This set is needed because we need to know in
@@ -1578,14 +1611,108 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
         });
     }
 
+    /**
+     * Mod count for delaying post selection changed events.
+     */
+    int postSelectionModCount = 0;
+
+    /**
+     * Last tree selection modification time for implementing a quiet
+     * time for selection changes.
+     */
+    long lastSelectionModTime = System.currentTimeMillis() - 10000;
+
+    /**
+     * Current target time for the selection to be set. Calculated
+     * according to the set quiet time and last selection modification
+     * time.
+     */
+    long selectionSetTargetTime = 0;
+
+    /**
+     * <code>true</code> if delayed selection runnable is current scheduled or
+     * running.
+     */
+    boolean delayedSelectionScheduled = false;
+
+    Runnable SELECTION_DELAY = new Runnable() {
+        @Override
+        public void run() {
+            if (tree.isDisposed())
+                return;
+            long now = System.currentTimeMillis();
+            long waitTimeLeft = selectionSetTargetTime - now;
+            if (waitTimeLeft > 0) {
+                // Not enough quiet time, reschedule.
+                delayedSelectionScheduled = true;
+                tree.getDisplay().timerExec((int) waitTimeLeft, this);
+            } else {
+                // Time to perform selection, stop rescheduling.
+                delayedSelectionScheduled = false;
+                resetSelection();
+            }
+        }
+    };
+
+    private void widgetSelectionChanged(boolean forceSelectionChange) {
+        long modTime = System.currentTimeMillis();
+        long delta = modTime - lastSelectionModTime;
+        lastSelectionModTime = modTime;
+        if (!forceSelectionChange && delta < SELECTION_CHANGE_QUIET_TIME) {
+            long msToWait = SELECTION_CHANGE_QUIET_TIME - delta;
+            selectionSetTargetTime = modTime + msToWait;
+            if (!delayedSelectionScheduled) {
+                delayedSelectionScheduled = true;
+                tree.getDisplay().timerExec((int) msToWait, SELECTION_DELAY);
+            }
+            // Make sure that post selection change events do not fire.
+            ++postSelectionModCount;
+            return;
+        }
+
+        // Immediate selection reconstruction.
+        resetSelection();
+    }
+
     private void resetSelection() {
         final ISelection selection = getWidgetSelection();
-//        System.out.println("resetSelection()");
-//        System.out.println("    provider selection: " + selectionProvider.getSelection());
-//        System.out.println("    widget selection:   " + selection);
+
+        //System.out.println("resetSelection(" + postSelectionModCount + ")");
+        //System.out.println("    provider selection: " + selectionProvider.getSelection());
+        //System.out.println("    widget selection:   " + selection);
+
         selectionProvider.setAndFireNonEqualSelection(selection);
-    }
 
+        // Implement deferred firing of post selection events
+        final int count = ++postSelectionModCount;
+        //System.out.println("[" + System.currentTimeMillis() + "] scheduling postSelectionChanged " + count + ": " + selection);
+        ThreadUtils.getNonBlockingWorkExecutor().schedule(new Runnable() {
+            @Override
+            public void run() {
+                int newCount = postSelectionModCount;
+                // Don't publish selection yet, there's another change incoming.
+                //System.out.println("[" + System.currentTimeMillis() + "] checking post selection publish: " + count + " vs. " + newCount + ": " + selection);
+                if (newCount != count)
+                    return;
+                //System.out.println("[" + System.currentTimeMillis() + "] " + count + " count equals, firing post selection listeners: " + selection);
+
+                if (tree.isDisposed())
+                    return;
+
+                //System.out.println("scheduling fire post selection changed: " + selection);
+                tree.getDisplay().asyncExec(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (tree.isDisposed() || selectionProvider == null)
+                            return;
+                        //System.out.println("firing post selection changed: " + selection);
+                        selectionProvider.firePostSelection(selection);
+                    }
+                });
+            }
+        }, POST_SELECTION_DELAY, TimeUnit.MILLISECONDS);
+    }
+    
     protected void setDefaultProcessors() {
         // Add a simple IMAGER query processor that always returns null.
         // With this processor no images will ever be shown.
@@ -2300,7 +2427,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
 //                    System.out.println("MODCOUNT: " + modCount + " vs. " + count);
                     if (modCount != count)
                         return;
-                    resetSelection();
+                    widgetSelectionChanged(true);
                 }
             });
         }
index 80ef2bf3919ee245be32db9bf4249d288c2d8370..72c17ed747fe5f8d41f1e670cc5358993324a12d 100644 (file)
@@ -21,9 +21,8 @@ import org.simantics.browsing.ui.CheckedState;
 import org.simantics.browsing.ui.NodeContext;
 import org.simantics.browsing.ui.NodeQueryManager;
 import org.simantics.browsing.ui.common.internal.GENodeQueryManager;
+import org.simantics.browsing.ui.common.internal.IGraphExplorerContext;
 import org.simantics.browsing.ui.content.PrunedChildrenResult;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * This class is responsible for updating the {@link TreeItem}s contained by the
@@ -37,20 +36,21 @@ import org.slf4j.LoggerFactory;
  */
 class UpdateRunner implements Runnable {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(UpdateRunner.class);
-
     final GraphExplorerImpl ge;
+    //final IGraphExplorerContext geContext;
 
-    UpdateRunner(GraphExplorerImpl ge) {
+    UpdateRunner(GraphExplorerImpl ge, IGraphExplorerContext geContext) {
         this.ge = ge;
+      //  this.geContext = geContext;
     }
 
     public void run() {
        try {
                doRun();
        } catch (Throwable t) {
-               LOGGER.error("", t);
+               t.printStackTrace();
        }
+       
     }
 
     public void doRun() {
index b06143bf6ee23cc82574666390a0d49c3c99de4a..c5ca0e754cada161035bbcee68289b4dc135062a 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2018 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
  * in Industry THTH ry.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -21,6 +21,8 @@ import org.eclipse.jface.viewers.IPostSelectionProvider;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.simantics.utils.ObjectUtils;
 
 /**
  * BaseSelectionProvider is a base implementation ISelectionProvider -interface.
@@ -34,21 +36,40 @@ import org.eclipse.jface.viewers.SelectionChangedEvent;
  * </p>
  * 
  * @author Toni Kalajainen
- * @author Tuukka Lehtonen
  */
-public class BasePostSelectionProvider extends BaseSelectionProvider implements IPostSelectionProvider {
+public class BasePostSelectionProvider implements IPostSelectionProvider {
 
-    protected ListenerList<ISelectionChangedListener> postSelectionListeners = new ListenerList<>();
+    protected ListenerList selectionListeners = new ListenerList();
+
+    protected ListenerList postSelectionListeners = new ListenerList();
+
+    protected ISelection selection = StructuredSelection.EMPTY;
+
+    public void addSelectionChangedListener(ISelectionChangedListener listener) {
+        selectionListeners.add(listener);
+    }
+
+    public ISelection getSelection() {
+        return selection;
+    }
 
     public void clearListeners() {
-        super.clearListeners();
-        clearPostSelectionChangedListeners();
+        selectionListeners.clear();
+        postSelectionListeners.clear();
+    }
+
+    public void clearSelectionChangedListeners() {
+        postSelectionListeners.clear();
     }
 
     public void clearPostSelectionChangedListeners() {
         postSelectionListeners.clear();
     }
 
+    public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+        selectionListeners.remove(listener);
+    }
+
     @Override
     public void addPostSelectionChangedListener(ISelectionChangedListener listener) {
         postSelectionListeners.add(listener);
@@ -59,10 +80,30 @@ public class BasePostSelectionProvider extends BaseSelectionProvider implements
         postSelectionListeners.remove(listener);
     }
 
+    public void setSelection(ISelection selection) {
+        setSelectionWithoutFiring(selection);
+    }
+
+    protected Object[] getListeners() {
+        return selectionListeners.getListeners();
+    }
+
     protected Object[] getPostListeners() {
         return postSelectionListeners.getListeners();
     }
 
+    /**
+     * Notify other UIs that selection has changed
+     * @param selection new selection
+     */
+    public void fireSelection(ISelection selection) {
+        if (selection == null)
+            return;
+        SelectionChangedEvent e = new SelectionChangedEvent(this, selection);
+        for (Object l : getListeners())
+            ((ISelectionChangedListener) l).selectionChanged(e);
+    }
+
     /**
      * Notify other UIs that selection has changed
      * @param selection new selection
@@ -82,4 +123,46 @@ public class BasePostSelectionProvider extends BaseSelectionProvider implements
         }
     }
 
+    public void setSelectionWithoutFiring(ISelection selection) {
+        this.selection = selection;
+    }
+
+
+    /**
+     * Sets a new selection and always fires a SelectionChangedEvent about it.
+     * 
+     * @param selection the new selection
+     */
+    public void setAndFireSelection(ISelection selection) {
+        setSelection(selection);
+        fireSelection(selection);
+    }
+
+    /**
+     * Sets the new selection for this provider and fires all selection change
+     * listeners if the specified selection differs from the current selection.
+     * If the selection is either the same object or considered equal to the
+     * current selection, the listeners are not fired.
+     * 
+     * @param selection the new selection
+     */
+    public void setAndFireNonEqualSelection(ISelection selection) {
+        ISelection old = getSelection();
+        if (ObjectUtils.objectEquals(old, selection))
+            return;
+
+        this.selection = selection;
+        if (selection != null && !selection.equals(old))
+            fireSelection(selection);
+    }
+
+    public boolean selectionEquals(ISelection s) {
+        if (s == selection)
+            return true;
+        if (s == null)
+            // Old selection had to be non-null
+            return true;
+        return s.equals(selection);
+    }
+
 }
index 55ec0241b151540a9005b0f9ae842f7d685a3392..b2e6d921548618c790aa910bb3ee43713c2bda37 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2018 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
  * in Industry THTH ry.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -20,7 +20,6 @@ import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.ISelectionProvider;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.StructuredSelection;
-import org.simantics.utils.ObjectUtils;
 
 /**
  * BaseSelectionProvider is a base implementation ISelectionProvider -interface.
@@ -40,7 +39,7 @@ import org.simantics.utils.ObjectUtils;
  */
 public class BaseSelectionProvider implements ISelectionProvider {
 
-    protected ListenerList<ISelectionChangedListener> selectionListeners = new ListenerList<>();
+    protected ListenerList selectionListeners = new ListenerList();
 
     protected ISelection selection = StructuredSelection.EMPTY;
 
@@ -60,14 +59,6 @@ public class BaseSelectionProvider implements ISelectionProvider {
         return selection;
     }
 
-    public void clearListeners() {
-        clearSelectionChangedListeners();
-    }
-
-    public void clearSelectionChangedListeners() {
-        selectionListeners.clear();
-    }
-
     public void removeSelectionChangedListener(ISelectionChangedListener listener) {
         selectionListeners.remove(listener);
     }
@@ -115,15 +106,14 @@ public class BaseSelectionProvider implements ISelectionProvider {
      * 
      * @param selection the new selection
      */
-    public boolean setAndFireNonEqualSelection(ISelection selection) {
+    public void setAndFireNonEqualSelection(ISelection selection) {
         ISelection old = getSelection();
-        if (ObjectUtils.objectEquals(old, selection))
-            return false;
+        if (selection == old)
+            return;
 
         this.selection = selection;
-        if (selection != null)
+        if (selection != null && !selection.equals(old))
             fireSelection(selection);
-        return true;
     }
 
     public boolean selectionEquals(ISelection s) {
index e196e673267ddaf8d7a17ad6fc78b10c7eda78c2..1666413e9c56d45ee16e8afeda3baf3e07e17446 100644 (file)
@@ -10,8 +10,11 @@ import org.eclipse.jface.viewers.IPostSelectionProvider;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
 import org.eclipse.ui.IWorkbenchSite;
 import org.simantics.browsing.ui.Column;
 import org.simantics.browsing.ui.StatePersistor;
@@ -42,19 +45,9 @@ public class SWTExplorer extends SingleSWTViewNode<ModelBrowser> {
        public Boolean useNodeBrowseContexts;
        public Boolean useNodeActionContexts;
        public StatePersistor persistor;
-
+       
        public ISelection lastSelection;
-
-       private ISelectionChangedListener internalToExternalSelectionPropagator = event -> {
-               IWorkbenchSite site = getSite();
-               if (site != null) {
-                       ISelectionProvider sp = site.getSelectionProvider();
-                       if (sp != null) {
-                               sp.setSelection(event.getSelection());
-                       }
-               }
-       };
-
+       
        @Override
        public void createControls(Composite parent) {
 
@@ -77,30 +70,80 @@ public class SWTExplorer extends SingleSWTViewNode<ModelBrowser> {
                if (uiContext != null) {
                        control.setUiContexts(Collections.singleton(uiContext));
                }
-
+               
                control.setStatePersistor(persistor);
-
+               
                control.finish();
 
                setProperties();
-
+               
                control.setInputSource(PassThruInputSource.INSTANCE);
 
-               ISelectionProvider isp = (ISelectionProvider)control.getExplorer().getAdapter(ISelectionProvider.class);
-               if (isp instanceof IPostSelectionProvider) {
-                       ((IPostSelectionProvider) isp).addPostSelectionChangedListener(internalToExternalSelectionPropagator);
-               } else {
-                       isp.addSelectionChangedListener(internalToExternalSelectionPropagator);
-               }
-
-               control.addListenerToControl(SWT.Selection, event -> {
-                       if(selectionListener != null)
-                               selectionListener.apply(event);
-                       ISelection selection = (ISelection)control.getExplorer().getWidgetSelection();
-                       propertyCallback.apply("selection", selection);
-                       lastSelection = selection;
+               ISelectionProvider sp = (ISelectionProvider)control.getExplorer().getAdapter(ISelectionProvider.class);
+               sp.addSelectionChangedListener(new ISelectionChangedListener() {
+                       
+                       @Override
+                       public void selectionChanged(SelectionChangedEvent event) {
+                               if (site != null) {
+                                       ISelectionProvider sp = site.getSelectionProvider();
+                                       if (sp != null) {
+                                               sp.setSelection(event.getSelection());
+                                       }
+                               }
+                       }
+                       
                });
-
+               
+               IPostSelectionProvider psp = (IPostSelectionProvider)control.getExplorer().getAdapter(IPostSelectionProvider.class);
+               psp.addPostSelectionChangedListener(new ISelectionChangedListener() {
+                       
+                       @Override
+                       public void selectionChanged(SelectionChangedEvent event) {
+                               
+//                             ISelection selection = (ISelection)control.getExplorer().getWidgetSelection();
+                               if (site != null) {
+                                       ISelectionProvider sp = site.getSelectionProvider();
+                                       if (sp != null) {
+                                               sp.setSelection(event.getSelection());
+                                       }
+                               }
+                               
+                       }
+                       
+               });
+               
+               control.addListenerToControl(SWT.Selection, new Listener() {
+
+                       @Override
+                       public void handleEvent(Event event) {
+                               
+                               if(selectionListener != null)
+                                       selectionListener.apply(event);
+                               
+                               ISelection selection = (ISelection)control.getExplorer().getWidgetSelection();
+                               // [Tuukka@2012-04-08] Disabled this because it was causing
+                               // horrible selection feedback effects in the Model Browser
+                               // view that is using it. It causes the browser to react to
+                               // external selections which were initially published as its own
+                               // with a delay.
+                               //System.out.println("selection: " + selection);
+//                             if(publishSelection != null && publishSelection) {
+//                                     if (site != null) {
+//                                             ISelectionProvider sp = site.getSelectionProvider();
+//                                             if (sp != null) {
+//                                                     sp.setSelection(selection);
+//                                             }
+//                                     }
+//                             }
+                               
+                               propertyCallback.apply("selection", selection);
+                               
+                               lastSelection = selection;
+                               
+                       }
+                       
+               });
+                       
        }
 
        public void synchronizeColumnsVisible(Boolean columnsVisible) {
@@ -148,16 +191,5 @@ public class SWTExplorer extends SingleSWTViewNode<ModelBrowser> {
 
        final public void synchronizeLayout(LayoutBean layout) {
        }
-
-       @Override
-       public void dispose() {
-               ISelectionProvider isp = (ISelectionProvider)control.getExplorer().getAdapter(ISelectionProvider.class);
-               if (isp instanceof IPostSelectionProvider) {
-                       ((IPostSelectionProvider) isp).removePostSelectionChangedListener(internalToExternalSelectionPropagator);
-               } else {
-                       isp.removeSelectionChangedListener(internalToExternalSelectionPropagator);
-               }
-               super.dispose();
-       }
-
+       
 }
index cd17a18726a1e9a0d10ab0cd06b74e14314e814b..18048f38c7654a2b322b317d8370b4f32d537460 100644 (file)
@@ -16,8 +16,7 @@ Require-Bundle: org.simantics.browsing.ui.swt;bundle-version="1.1.0";visibility:
  org.simantics.project;bundle-version="1.0.1",
  org.simantics.scenegraph.loader;bundle-version="1.0.0";visibility:=reexport,
  org.simantics.scenegraph.ontology;bundle-version="1.0.0",
- org.simantics.utils.thread.swt;bundle-version="1.1.0",
- org.slf4j.api
+ org.simantics.utils.thread.swt;bundle-version="1.1.0"
 Export-Package: org.simantics.views.swt
 Bundle-Activator: org.simantics.views.swt.Activator
 Bundle-Vendor: Semantum Oy
index 92396f421de9d37e0b9673d8989d3ca894db64eb..f50954857e7d3611d7956968ece2559d6f9bf8ea 100644 (file)
@@ -27,6 +27,7 @@ import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.IWorkbenchPartReference;
 import org.eclipse.ui.IWorkbenchSite;
 import org.simantics.Simantics;
+import org.simantics.browsing.ui.common.ErrorLogger;
 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;
 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl;
 import org.simantics.db.ReadGraph;
@@ -35,6 +36,7 @@ import org.simantics.db.VirtualGraph;
 import org.simantics.db.WriteGraph;
 import org.simantics.db.common.request.WriteRequest;
 import org.simantics.db.common.request.WriteResultRequest;
+import org.simantics.db.common.utils.Logger;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.exception.ServiceNotFoundException;
 import org.simantics.db.layer0.util.RemoverUtil;
@@ -45,11 +47,8 @@ import org.simantics.layer0.Layer0;
 import org.simantics.scenegraph.ontology.ScenegraphResources;
 import org.simantics.scl.runtime.function.Function1;
 import org.simantics.ui.workbench.IPropertyPage;
-import org.simantics.utils.ui.ErrorLogger;
-import org.simantics.utils.ui.jface.BasePostSelectionProvider;
+import org.simantics.utils.ui.jface.ActiveSelectionProvider;
 import org.simantics.views.swt.client.base.SWTRoot;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * To use this class, first model your view contents in .pgraph files according
@@ -68,8 +67,6 @@ import org.slf4j.LoggerFactory;
  */
 public class ModelledView extends SimanticsView implements IPartListener2 {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(ModelledView.class);
-
     public static final int TIME_BEFORE_DISPOSE_WHEN_HIDDEN = 30000; // ms
     
     private static final boolean           DEBUG             = false;
@@ -91,11 +88,10 @@ public class ModelledView extends SimanticsView implements IPartListener2 {
 
     protected ModelledSupport              support;
 
-    private BasePostSelectionProvider      selectionProvider = new BasePostSelectionProvider() {
+    ActiveSelectionProvider                selectionProvider = new ActiveSelectionProvider() {
         @Override
         public void setSelection(ISelection selection) {
-            super.setAndFireNonEqualSelection(selection);
-            super.firePostSelection(selection);
+            super.setSelection(selection);
         }
     };
 
@@ -105,6 +101,7 @@ public class ModelledView extends SimanticsView implements IPartListener2 {
 
     @Override
     protected WidgetSupportImpl createSupport() {
+
         try {
             runtime = Simantics.getSession().sync(
                     new WriteResultRequest<Resource>(Simantics.getSession().getService(VirtualGraph.class)) {
@@ -117,13 +114,16 @@ public class ModelledView extends SimanticsView implements IPartListener2 {
                             return runtime;
                         }
                     });
-        } catch (ServiceNotFoundException | DatabaseException e) {
-            LOGGER.error("Failed to initialize modelled view database runtime support structures", e);
+        } catch (ServiceNotFoundException e) {
+            Logger.defaultLogError(e);
+        } catch (DatabaseException e) {
+            Logger.defaultLogError(e);
         }
 
         support = new ModelledSupport(this);
 
         return support;
+
     }
 
     public void fireInput() {
@@ -166,7 +166,9 @@ public class ModelledView extends SimanticsView implements IPartListener2 {
         }
 
         if (load) {
+
             try {
+
                 loader = new SWTViewLoaderProcess(this, getSite(), getClass().getSimpleName());
 
                 viewVariable = loader.getVariable(Simantics.getSession(), configurationURI(), runtime);
@@ -198,10 +200,17 @@ public class ModelledView extends SimanticsView implements IPartListener2 {
 
                 body.layout(true);
 
+                getSite().setSelectionProvider(selectionProvider);
+
             } catch (DatabaseException e) {
-                LOGGER.error("Failed to create modelled SWT view controls", e);
+
+                e.printStackTrace();
+                Logger.defaultLogError(e);
+
             }
+
         }
+
     }
 
     @Override
@@ -211,12 +220,14 @@ public class ModelledView extends SimanticsView implements IPartListener2 {
         // Only create controls if the part is TRULY visible.
         // Fast view parts seem to cause calls to createPartControl even
         // when the part is hidden in reality
+        boolean visible = site.getPage().isPartVisible(this);
         if (DEBUG)
             System.out.println(this + ": createControls( visible=" + site.getPage().isPartVisible(this) + " )");
         doCreateControls(true);
 
         getSite().setSelectionProvider(selectionProvider);
         getSite().getPage().addPartListener(this);
+
     }
 
     protected void inputChanged(IWorkbenchPart provider, Object input) {
@@ -280,8 +291,10 @@ public class ModelledView extends SimanticsView implements IPartListener2 {
                     RemoverUtil.remove(graph, rt);
                 }
             });
-        } catch (ServiceNotFoundException | DatabaseException e) {
-            LOGGER.error("Failed to dispose of modelled view database runtime support structures", e);
+        } catch (ServiceNotFoundException e) {
+            Logger.defaultLogError(e);
+        } catch (DatabaseException e) {
+            Logger.defaultLogError(e);
         }
     }
 
@@ -381,10 +394,10 @@ public class ModelledView extends SimanticsView implements IPartListener2 {
             }
         }
     }
-
+    
     // Can be used to cancel already scheduled dispose
     volatile boolean reallyClearExisting = false;
-
+    
     Runnable clearExisting = new Runnable() {
 
         @Override
@@ -432,5 +445,5 @@ public class ModelledView extends SimanticsView implements IPartListener2 {
     protected IPropertyPage getPropertyPage() {
        return null;
     }
-
+    
 }