/*******************************************************************************
- * 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;
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;
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;
* @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;
/**
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;
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) {
// 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);
}
}
// Remove ourselves as a workbench selection listener.
if (!bootstrapOnly) {
- getSite().getPage().removePostSelectionListener(selectionListener);
+ getSite().getPage().removePostSelectionListener(this);
+ getSite().getPage().removeSelectionListener(immediateSelectionListener);
}
if (resourceManager != null) {
page.createControl(book);
page.setMessage(Messages.PropertyPageView_noPropertiesAvailable);
return page;
- */
+ */
PropertyPage page = new PropertyPage(getSite());
initPage(page);
@Override
protected PageRec doCreatePage(IWorkbenchPart part) {
+
// NOTE: If the default page should be shown, this method must return null.
if (part == null)
return null;
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);
}
/**
// 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);
}
* <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;
lastPart.addPropertyListener(partPropertyListener);
}
+ updatePartName(ppage, sel);
if (!sameSelection) {
- updatePartName(ppage, sel);
ppage.selectionChanged(part, sel);
return true;
}
// 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);
+ }
}
});
};
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;
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;
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;
/**
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.
* <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
* 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
GraphExplorerContext explorerContext = new GraphExplorerContext();
- HashSet<TreeItem> pendingItems = new HashSet<>();
+ HashSet<TreeItem> pendingItems = new HashSet<TreeItem>();
boolean updating = false;
boolean pendingRoot = false;
* 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;
/** 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;
* 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)}
*
* @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
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));
}
}
* 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;
// 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;
+ }
}
});
};
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
}
});
- 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
});
}
+ /**
+ * 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.
// System.out.println("MODCOUNT: " + modCount + " vs. " + count);
if (modCount != count)
return;
- resetSelection();
+ widgetSelectionChanged(true);
}
});
}
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
*/
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() {
/*******************************************************************************
- * 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
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.
* </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);
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
}
}
+ 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);
+ }
+
}
/*******************************************************************************
- * 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
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.
*/
public class BaseSelectionProvider implements ISelectionProvider {
- protected ListenerList<ISelectionChangedListener> selectionListeners = new ListenerList<>();
+ protected ListenerList selectionListeners = new ListenerList();
protected ISelection selection = StructuredSelection.EMPTY;
return selection;
}
- public void clearListeners() {
- clearSelectionChangedListeners();
- }
-
- public void clearSelectionChangedListeners() {
- selectionListeners.clear();
- }
-
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
selectionListeners.remove(listener);
}
*
* @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) {
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;
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) {
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) {
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();
- }
-
+
}
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
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;
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;
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
*/
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;
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);
}
};
@Override
protected WidgetSupportImpl createSupport() {
+
try {
runtime = Simantics.getSession().sync(
new WriteResultRequest<Resource>(Simantics.getSession().getService(VirtualGraph.class)) {
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() {
}
if (load) {
+
try {
+
loader = new SWTViewLoaderProcess(this, getSite(), getClass().getSimpleName());
viewVariable = loader.getVariable(Simantics.getSession(), configurationURI(), runtime);
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
// 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) {
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);
}
}
}
}
}
-
+
// Can be used to cancel already scheduled dispose
volatile boolean reallyClearExisting = false;
-
+
Runnable clearExisting = new Runnable() {
@Override
protected IPropertyPage getPropertyPage() {
return null;
}
-
+
}