X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=bundles%2Forg.simantics.browsing.ui.platform%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fplatform%2FPropertyPageView.java;h=0d4fc055b6ed2e7a8846052faba1e55ff3d3c310;hb=e88be95edf1f80781646cfdf717ec1b663264179;hp=4b98bd3e9d2c7741570de09c6af230890e6901e8;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.browsing.ui.platform/src/org/simantics/browsing/ui/platform/PropertyPageView.java b/bundles/org.simantics.browsing.ui.platform/src/org/simantics/browsing/ui/platform/PropertyPageView.java index 4b98bd3e9..0d4fc055b 100644 --- a/bundles/org.simantics.browsing.ui.platform/src/org/simantics/browsing/ui/platform/PropertyPageView.java +++ b/bundles/org.simantics.browsing.ui.platform/src/org/simantics/browsing/ui/platform/PropertyPageView.java @@ -1,614 +1,614 @@ -/******************************************************************************* - * 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 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -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.jface.resource.ResourceManager; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IMemento; -import org.eclipse.ui.IPropertyListener; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IViewPart; -import org.eclipse.ui.IViewSite; -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; -import org.eclipse.ui.part.IPageBookViewPage; -import org.eclipse.ui.part.PageBook; -import org.simantics.db.management.ISessionContextProvider; -import org.simantics.selectionview.PropertyPage; -import org.simantics.ui.SimanticsUI; -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; - -/** - * This is a version of the standard eclipse PropertySheet view a - * graph database access twist. It presents a property view based the active - * workbench part and the active part's current selection. - * - *

- * To get a property page for your own view or editor part you can do one of the - * following: - * - *

    - *
  1. Implement getAdapter for your view or editor part as follows: - * - *
    - * Object getAdapter(Class c) {
    - *     if (c == IPropertyPage.class) {
    - *         // Get the browse contexts to use from somewhere
    - *         Set<String> browseContexts = Collections.singleton("...");
    - *         return new StandardPropertyPage(getSite(), browseContexts);
    - *     }
    - *     return super.getAdapter(c);
    - * }
    - * 
    - * - * This method also allows customization of the actual property page control - * that gets created. PropertyPage serves as a good starting point - * for your own version.
  2. - *
  3. Make the workbench part implement the marker interface - * IStandardPropertyPage which will make this view do the above - * automatically without implementing getAdapter.
  4. - *
- * - * @author Tuukka Lehtonen - * - * @see IStandardPropertyPage - * @see IPropertyPage - * @see PropertyPage - */ -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; - - /** - * The initial selection when the property sheet opens - */ - private ISelection bootstrapSelection; - - /** - * A flag for indicating whether or not this view will only use the - * bootstrap selection and and IPropertyPage source instead of listening to - * the input constantly. - */ - private final boolean bootstrapOnly = false; - - private IMemento memento; - - private boolean pinSelection = false; - - private IWorkbenchPart lastPart; - private ISelection lastSelection; - private final Map lastSelections = new WeakHashMap(); - - private ResourceManager resourceManager; - - private ImageDescriptor notPinned; - private ImageDescriptor pinned; - - /** - * Set of workbench parts, which should not be used as a source for PropertySheet - */ - private Set ignoredViews; - - @Override - public void createPartControl(Composite parent) { - super.createPartControl(parent); - - this.resourceManager = new LocalResourceManager(JFaceResources.getResources()); - notPinned = BundleUtils.getImageDescriptorFromPlugin("org.simantics.browsing.ui.common", "icons/table_multiple.png"); - pinned = BundleUtils.getImageDescriptorFromPlugin("org.simantics.browsing.ui.common", "icons/table_multiple_pinned.png"); - - IContextService cs = (IContextService) getSite().getService(IContextService.class); - cs.activateContext(PROPERTY_VIEW_CONTEXT); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.part.PageBookView#getAdapter(java.lang.Class) - */ - @SuppressWarnings("rawtypes") - @Override - public Object getAdapter(Class adapter) { - if (adapter == IContributedContentsView.class) { - // This makes it possible to duplicate a PropertyPageView with another - // secondary ID and make it show the same property page that was showing - // in the original property page view. - return new IContributedContentsView() { - @Override - public IWorkbenchPart getContributingPart() { - return getContributingEditor(); - } - }; - } - return super.getAdapter(adapter); - } - - /** - * Returns the editor which contributed the current - * page to this view. - * - * @return the editor which contributed the current page - * or null if no editor contributed the current page - */ - private IWorkbenchPart getContributingEditor() { - return getCurrentContributingPart(); - } - - /* (non-Javadoc) - * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento) - */ - @Override - public void init(IViewSite site, IMemento memento) throws PartInitException { - this.memento = memento; - init(site); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.part.PageBookView#init(org.eclipse.ui.IViewSite) - */ - @Override - public void init(IViewSite site) throws PartInitException { - String secondaryId = site.getSecondaryId(); - if (secondaryId != null) { - ResourceInput input = ResourceInput.unmarshall(secondaryId); - if (input != null) { - //bootstrapOnly = true; - } - } - - //System.out.println("PPV init: " + this); - super.init(site); - - // 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); - - contextProvider = SimanticsUI.getSessionContextProvider(); - - if (!bootstrapOnly) { - site.getPage().addSelectionListener(immediateSelectionListener); - site.getPage().addPostSelectionListener(this); - } - } - - @Override - public void saveState(IMemento memento) { - if (this.memento != null) { - memento.putMemento(this.memento); - } - } - - /* (non-Javadoc) - * Method declared on IWorkbenchPart. - */ - @Override - public void dispose() { - //System.out.println("PPV dispose: " + this); - // Dispose of this before nullifying contextProvider because this - // dispose may just need the context provider - at least PropertyPage - // disposal will. - super.dispose(); - - if (lastPart != null) - lastPart.removePropertyListener(partPropertyListener); - - contextProvider = null; - - // Remove ourselves as a workbench selection listener. - if (!bootstrapOnly) { - getSite().getPage().removePostSelectionListener(this); - getSite().getPage().removeSelectionListener(immediateSelectionListener); - } - - if (resourceManager != null) { - resourceManager.dispose(); - resourceManager = null; - } - } - - @Override - protected IPage createDefaultPage(PageBook book) { - /* - MessagePage page = new MessagePage(); - initPage(page); - page.createControl(book); - page.setMessage(Messages.PropertyPageView_noPropertiesAvailable); - return page; - */ - - PropertyPage page = new PropertyPage(getSite()); - initPage(page); - page.createControl(book); - //System.out.println("PPV create default page: " + page); - return 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; - - //System.out.println("PPV try to create page for part: " + (part != null ? part.getTitle() : null)); - - // Try to get a property page. - IPropertyPage page = (IPropertyPage) part.getAdapter(IPropertyPage.class); - if (page != null) { - //System.out.println("PPV created page: " + page); - if (page instanceof IPageBookViewPage) { - initPage((IPageBookViewPage) page); - } - page.createControl(getPageBook()); - //System.out.println("PPV created page control: " + page.getControl()); - return new PageRec(part, page); - } - return null; - } - - @Override - protected void doDestroyPage(IWorkbenchPart part, PageRec pageRecord) { - //System.out.println("PPV destroy page for part: " + part.getTitle()); - - IPropertyPage page = (IPropertyPage) pageRecord.page; - page.dispose(); - pageRecord.dispose(); - } - - @Override - protected IWorkbenchPart getBootstrapPart() { - IWorkbenchPage page = getSite().getPage(); - if (page != null) { - bootstrapSelection = page.getSelection(); - return page.getActivePart(); - } - return null; - } - - private boolean isPropertyView(IWorkbenchPart part) { - boolean ignore = false; - - if (part instanceof IWorkbenchPart3) { - IWorkbenchPart3 part3 = (IWorkbenchPart3) part; - ignore = Boolean.parseBoolean(part3.getPartProperty(PROP_PINNED)); - } - - // See org.simantics.modeling.ui.actions.DuplicatePinnedViewHandler -// ignore |= part.getSite().getId().endsWith("Pinned"); - String thisId = getSite().getId(); - String otherId = part.getSite().getId(); - //System.out.println(thisId + " - " + otherId); - ignore |= otherId.startsWith(thisId); - - return this == part || ignore; - } - - private Set getIgnoredViews() { - if (ignoredViews == null) { - ignoredViews = new HashSet(); - 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) { - String partID = part.getSite().getId(); - //System.out.println("isImportant(" + partID + ")"); - return !isWorkbenchSelectionPinned() && !isPropertyView(part) && !isViewIgnored(partID); - } - - /** - * The PropertySheet implementation of this - * IPartListener method first sees if the active part is an - * IContributedContentsView adapter and if so, asks it for - * its contributing part. - */ - @Override - public void partActivated(IWorkbenchPart part) { -// if (bootstrapSelection == null && bootstrapOnly) -// return; - - // Look for a declaratively-contributed adapter - including not yet - // loaded adapter factories. - // See bug 86362 [PropertiesView] Can not access AdapterFactory, when - // plugin is not loaded. - IWorkbenchPart source = getSourcePart(part); - //System.out.println("PPV part activated: " + part + ",src " + source + ",view " + this + " bss: " + bootstrapSelection + " pin " + pinSelection); - super.partActivated(source); - - // When the view is first opened, pass the selection to the page - if (bootstrapSelection != null) { - IPage page = getCurrentPage(); - if (page instanceof IPropertyPage) { - IPropertyPage ppage = (IPropertyPage) page; - // FIXME: should this pass source or part ?? - ppage.selectionChanged(part, bootstrapSelection); - updatePartName(ppage, bootstrapSelection); - } - bootstrapSelection = null; - } - } - - - @Override - public void partClosed(IWorkbenchPart part) { - // Make sure that pinned view is not reset even if its originating - // editor is closed. - if (!pinSelection) - super.partClosed(part); - } - - @Override - protected void partHidden(IWorkbenchPart part) { - // Fast views are quite unusable if this code is enabled. - - // Make sure that pinned view is not hidden when the editor is hidden -// if(!pinSelection) -// 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); - } - - /** - * @param part - * @param sel - * @return true if the changed selection affected the view, - * false otherwise - */ - boolean doSelectionChanged(IWorkbenchPart part, ISelection sel) { - - // we ignore our own selection or null selection - if (isPropertyView(part) || sel == null) { - return false; - } - // ignore workbench selections when pinned also - if (pinSelection) - return false; - - // pass the selection change to the page - part = getSourcePart(part); - IPage page = getCurrentPage(); - //System.out.println("PPV selection changed to (" + part + ", " + sel + "): " + page); - if (page instanceof IPropertyPage) { - IPropertyPage ppage = (IPropertyPage) page; - - // Prevent parts that do not contribute a property page from messing - // up the contents/title of the currently active property page. - PageRec pageRec = getPageRec(part); - if (pageRec == null || pageRec.page != page) - return false; - - // Make sure that the part name is not updated unnecessarily because - // of immediate and post selection listeners. - ISelection lastPartSelection = lastSelections.get(part); - //System.out.println(" LAST PART SELECTION(" + part + "): " + lastPartSelection); - boolean sameSelection = lastPartSelection != null && sel.equals(lastPartSelection); - - if (lastPart != null) { - lastPart.removePropertyListener(partPropertyListener); - } - lastPart = part; - lastSelection = sel; - lastSelections.put(part, sel); - if (lastPart != null) { - lastPart.addPropertyListener(partPropertyListener); - } - - updatePartName(ppage, sel); - if (!sameSelection) { - ppage.selectionChanged(part, sel); - return true; - } - } - return false; - } - - void updatePartName(IPropertyPage ppage, ISelection sel) { - ppage.updatePartName(sel, partNameUpdateCallback); - } - - Consumer partNameUpdateCallback = parameter -> { - // 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(), new Runnable() { - @Override - public void run() { - if (!getPageBook().isDisposed()) { - if (getPartName().equals(parameter)) return; - //System.out.println("doSetParameterName : " + parameter); - doSetPartName(parameter); - } - } - }); - }; - - void doSetPartName(String partName) { - // Is the page view disposed ?? - if (contextProvider == null) - return; - if (partName == null) { - // Return to default - partName = "Selection"; - } - setPartName(partName); - } - - public boolean isWorkbenchSelectionPinned() { - return pinSelection; - } - - public void pinWorkbenchSelection(boolean pin) { - if (pin == pinSelection) - return; - - pinSelection = pin; - setPartProperty(PROP_PINNED, Boolean.toString(pin)); - - if (pin) { - setTitleImage(resourceManager.createImage(pinned)); - } else { - setTitleImage(resourceManager.createImage(notPinned)); - } - updateContentDescription(pin, lastPart); - // Since lastPart is another PropertyView, we do not want to listen it's changes (At least current implementation is done so) - if (lastPart != null) { - lastPart.removePropertyListener(partPropertyListener); - } - lastPart = null; - - } - - IWorkbenchPart getSourcePart(IWorkbenchPart part) { - IContributedContentsView view = (IContributedContentsView) part.getAdapter(IContributedContentsView.class); - if (view != null) { - IWorkbenchPart source = view.getContributingPart(); - if (source != null) - return source; - } - return part; - } - - private void updateContentDescription(boolean selectionPinned, IWorkbenchPart sourcePart) { - if (selectionPinned) { - if (sourcePart == null) { - setContentDescription("No selection"); - } else { - sourcePart = getSourcePart(sourcePart); - - StringBuilder desc = new StringBuilder("Selection from "); - if (sourcePart instanceof IEditorPart) - desc.append("editor "); - if (sourcePart instanceof IViewPart) - desc.append("view "); - desc.append('\''); - desc.append(sourcePart.getTitle()); - desc.append('\''); - - setContentDescription(desc.toString()); - } - } else { - setContentDescription(""); - } - } - - IPropertyListener partPropertyListener = new IPropertyListener() { - @Override - public void propertyChanged(Object source, int propId) { - if (propId == IWorkbenchPart.PROP_TITLE) { - updateContentDescription(pinSelection, lastPart); - } - } - }; - - @Override - public IWorkbenchPart getContributingPart() { - return lastPart; - } - -} +/******************************************************************************* + * 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 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +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.jface.resource.ResourceManager; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.IPropertyListener; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IViewSite; +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; +import org.eclipse.ui.part.IPageBookViewPage; +import org.eclipse.ui.part.PageBook; +import org.simantics.Simantics; +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; + +/** + * This is a version of the standard eclipse PropertySheet view a + * graph database access twist. It presents a property view based the active + * workbench part and the active part's current selection. + * + *

+ * To get a property page for your own view or editor part you can do one of the + * following: + * + *

    + *
  1. Implement getAdapter for your view or editor part as follows: + * + *
    + * Object getAdapter(Class c) {
    + *     if (c == IPropertyPage.class) {
    + *         // Get the browse contexts to use from somewhere
    + *         Set<String> browseContexts = Collections.singleton("...");
    + *         return new StandardPropertyPage(getSite(), browseContexts);
    + *     }
    + *     return super.getAdapter(c);
    + * }
    + * 
    + * + * This method also allows customization of the actual property page control + * that gets created. PropertyPage serves as a good starting point + * for your own version.
  2. + *
  3. Make the workbench part implement the marker interface + * IStandardPropertyPage which will make this view do the above + * automatically without implementing getAdapter.
  4. + *
+ * + * @author Tuukka Lehtonen + * + * @see IStandardPropertyPage + * @see IPropertyPage + * @see PropertyPage + */ +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; + + /** + * The initial selection when the property sheet opens + */ + private ISelection bootstrapSelection; + + /** + * A flag for indicating whether or not this view will only use the + * bootstrap selection and and IPropertyPage source instead of listening to + * the input constantly. + */ + private final boolean bootstrapOnly = false; + + private IMemento memento; + + private boolean pinSelection = false; + + private IWorkbenchPart lastPart; + private ISelection lastSelection; + private final Map lastSelections = new WeakHashMap(); + + private ResourceManager resourceManager; + + private ImageDescriptor notPinned; + private ImageDescriptor pinned; + + /** + * Set of workbench parts, which should not be used as a source for PropertySheet + */ + private Set ignoredViews; + + @Override + public void createPartControl(Composite parent) { + super.createPartControl(parent); + + this.resourceManager = new LocalResourceManager(JFaceResources.getResources()); + notPinned = BundleUtils.getImageDescriptorFromPlugin("org.simantics.browsing.ui.common", "icons/table_multiple.png"); + pinned = BundleUtils.getImageDescriptorFromPlugin("org.simantics.browsing.ui.common", "icons/table_multiple_pinned.png"); + + IContextService cs = (IContextService) getSite().getService(IContextService.class); + cs.activateContext(PROPERTY_VIEW_CONTEXT); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.part.PageBookView#getAdapter(java.lang.Class) + */ + @SuppressWarnings("rawtypes") + @Override + public Object getAdapter(Class adapter) { + if (adapter == IContributedContentsView.class) { + // This makes it possible to duplicate a PropertyPageView with another + // secondary ID and make it show the same property page that was showing + // in the original property page view. + return new IContributedContentsView() { + @Override + public IWorkbenchPart getContributingPart() { + return getContributingEditor(); + } + }; + } + return super.getAdapter(adapter); + } + + /** + * Returns the editor which contributed the current + * page to this view. + * + * @return the editor which contributed the current page + * or null if no editor contributed the current page + */ + private IWorkbenchPart getContributingEditor() { + return getCurrentContributingPart(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento) + */ + @Override + public void init(IViewSite site, IMemento memento) throws PartInitException { + this.memento = memento; + init(site); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.part.PageBookView#init(org.eclipse.ui.IViewSite) + */ + @Override + public void init(IViewSite site) throws PartInitException { + String secondaryId = site.getSecondaryId(); + if (secondaryId != null) { + ResourceInput input = ResourceInput.unmarshall(secondaryId); + if (input != null) { + //bootstrapOnly = true; + } + } + + //System.out.println("PPV init: " + this); + super.init(site); + + // 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); + + contextProvider = Simantics.getSessionContextProvider(); + + if (!bootstrapOnly) { + site.getPage().addSelectionListener(immediateSelectionListener); + site.getPage().addPostSelectionListener(this); + } + } + + @Override + public void saveState(IMemento memento) { + if (this.memento != null) { + memento.putMemento(this.memento); + } + } + + /* (non-Javadoc) + * Method declared on IWorkbenchPart. + */ + @Override + public void dispose() { + //System.out.println("PPV dispose: " + this); + // Dispose of this before nullifying contextProvider because this + // dispose may just need the context provider - at least PropertyPage + // disposal will. + super.dispose(); + + if (lastPart != null) + lastPart.removePropertyListener(partPropertyListener); + + contextProvider = null; + + // Remove ourselves as a workbench selection listener. + if (!bootstrapOnly) { + getSite().getPage().removePostSelectionListener(this); + getSite().getPage().removeSelectionListener(immediateSelectionListener); + } + + if (resourceManager != null) { + resourceManager.dispose(); + resourceManager = null; + } + } + + @Override + protected IPage createDefaultPage(PageBook book) { + /* + MessagePage page = new MessagePage(); + initPage(page); + page.createControl(book); + page.setMessage(Messages.PropertyPageView_noPropertiesAvailable); + return page; + */ + + PropertyPage page = new PropertyPage(getSite()); + initPage(page); + page.createControl(book); + //System.out.println("PPV create default page: " + page); + return 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; + + //System.out.println("PPV try to create page for part: " + (part != null ? part.getTitle() : null)); + + // Try to get a property page. + IPropertyPage page = (IPropertyPage) part.getAdapter(IPropertyPage.class); + if (page != null) { + //System.out.println("PPV created page: " + page); + if (page instanceof IPageBookViewPage) { + initPage((IPageBookViewPage) page); + } + page.createControl(getPageBook()); + //System.out.println("PPV created page control: " + page.getControl()); + return new PageRec(part, page); + } + return null; + } + + @Override + protected void doDestroyPage(IWorkbenchPart part, PageRec pageRecord) { + //System.out.println("PPV destroy page for part: " + part.getTitle()); + + IPropertyPage page = (IPropertyPage) pageRecord.page; + page.dispose(); + pageRecord.dispose(); + } + + @Override + protected IWorkbenchPart getBootstrapPart() { + IWorkbenchPage page = getSite().getPage(); + if (page != null) { + bootstrapSelection = page.getSelection(); + return page.getActivePart(); + } + return null; + } + + private boolean isPropertyView(IWorkbenchPart part) { + boolean ignore = false; + + if (part instanceof IWorkbenchPart3) { + IWorkbenchPart3 part3 = (IWorkbenchPart3) part; + ignore = Boolean.parseBoolean(part3.getPartProperty(PROP_PINNED)); + } + + // See org.simantics.modeling.ui.actions.DuplicatePinnedViewHandler +// ignore |= part.getSite().getId().endsWith("Pinned"); + String thisId = getSite().getId(); + String otherId = part.getSite().getId(); + //System.out.println(thisId + " - " + otherId); + ignore |= otherId.startsWith(thisId); + + return this == part || ignore; + } + + private Set getIgnoredViews() { + if (ignoredViews == null) { + ignoredViews = new HashSet(); + 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) { + String partID = part.getSite().getId(); + //System.out.println("isImportant(" + partID + ")"); + return !isWorkbenchSelectionPinned() && !isPropertyView(part) && !isViewIgnored(partID); + } + + /** + * The PropertySheet implementation of this + * IPartListener method first sees if the active part is an + * IContributedContentsView adapter and if so, asks it for + * its contributing part. + */ + @Override + public void partActivated(IWorkbenchPart part) { +// if (bootstrapSelection == null && bootstrapOnly) +// return; + + // Look for a declaratively-contributed adapter - including not yet + // loaded adapter factories. + // See bug 86362 [PropertiesView] Can not access AdapterFactory, when + // plugin is not loaded. + IWorkbenchPart source = getSourcePart(part); + //System.out.println("PPV part activated: " + part + ",src " + source + ",view " + this + " bss: " + bootstrapSelection + " pin " + pinSelection); + super.partActivated(source); + + // When the view is first opened, pass the selection to the page + if (bootstrapSelection != null) { + IPage page = getCurrentPage(); + if (page instanceof IPropertyPage) { + IPropertyPage ppage = (IPropertyPage) page; + // FIXME: should this pass source or part ?? + ppage.selectionChanged(part, bootstrapSelection); + updatePartName(ppage, bootstrapSelection); + } + bootstrapSelection = null; + } + } + + + @Override + public void partClosed(IWorkbenchPart part) { + // Make sure that pinned view is not reset even if its originating + // editor is closed. + if (!pinSelection) + super.partClosed(part); + } + + @Override + protected void partHidden(IWorkbenchPart part) { + // Fast views are quite unusable if this code is enabled. + + // Make sure that pinned view is not hidden when the editor is hidden +// if(!pinSelection) +// 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); + } + + /** + * @param part + * @param sel + * @return true if the changed selection affected the view, + * false otherwise + */ + boolean doSelectionChanged(IWorkbenchPart part, ISelection sel) { + + // we ignore our own selection or null selection + if (isPropertyView(part) || sel == null) { + return false; + } + // ignore workbench selections when pinned also + if (pinSelection) + return false; + + // pass the selection change to the page + part = getSourcePart(part); + IPage page = getCurrentPage(); + //System.out.println("PPV selection changed to (" + part + ", " + sel + "): " + page); + if (page instanceof IPropertyPage) { + IPropertyPage ppage = (IPropertyPage) page; + + // Prevent parts that do not contribute a property page from messing + // up the contents/title of the currently active property page. + PageRec pageRec = getPageRec(part); + if (pageRec == null || pageRec.page != page) + return false; + + // Make sure that the part name is not updated unnecessarily because + // of immediate and post selection listeners. + ISelection lastPartSelection = lastSelections.get(part); + //System.out.println(" LAST PART SELECTION(" + part + "): " + lastPartSelection); + boolean sameSelection = lastPartSelection != null && sel.equals(lastPartSelection); + + if (lastPart != null) { + lastPart.removePropertyListener(partPropertyListener); + } + lastPart = part; + lastSelection = sel; + lastSelections.put(part, sel); + if (lastPart != null) { + lastPart.addPropertyListener(partPropertyListener); + } + + updatePartName(ppage, sel); + if (!sameSelection) { + ppage.selectionChanged(part, sel); + return true; + } + } + return false; + } + + void updatePartName(IPropertyPage ppage, ISelection sel) { + ppage.updatePartName(sel, partNameUpdateCallback); + } + + Consumer partNameUpdateCallback = parameter -> { + // 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(), new Runnable() { + @Override + public void run() { + if (!getPageBook().isDisposed()) { + if (getPartName().equals(parameter)) return; + //System.out.println("doSetParameterName : " + parameter); + doSetPartName(parameter); + } + } + }); + }; + + void doSetPartName(String partName) { + // Is the page view disposed ?? + if (contextProvider == null) + return; + if (partName == null) { + // Return to default + partName = "Selection"; + } + setPartName(partName); + } + + public boolean isWorkbenchSelectionPinned() { + return pinSelection; + } + + public void pinWorkbenchSelection(boolean pin) { + if (pin == pinSelection) + return; + + pinSelection = pin; + setPartProperty(PROP_PINNED, Boolean.toString(pin)); + + if (pin) { + setTitleImage(resourceManager.createImage(pinned)); + } else { + setTitleImage(resourceManager.createImage(notPinned)); + } + updateContentDescription(pin, lastPart); + // Since lastPart is another PropertyView, we do not want to listen it's changes (At least current implementation is done so) + if (lastPart != null) { + lastPart.removePropertyListener(partPropertyListener); + } + lastPart = null; + + } + + IWorkbenchPart getSourcePart(IWorkbenchPart part) { + IContributedContentsView view = (IContributedContentsView) part.getAdapter(IContributedContentsView.class); + if (view != null) { + IWorkbenchPart source = view.getContributingPart(); + if (source != null) + return source; + } + return part; + } + + private void updateContentDescription(boolean selectionPinned, IWorkbenchPart sourcePart) { + if (selectionPinned) { + if (sourcePart == null) { + setContentDescription("No selection"); + } else { + sourcePart = getSourcePart(sourcePart); + + StringBuilder desc = new StringBuilder("Selection from "); + if (sourcePart instanceof IEditorPart) + desc.append("editor "); + if (sourcePart instanceof IViewPart) + desc.append("view "); + desc.append('\''); + desc.append(sourcePart.getTitle()); + desc.append('\''); + + setContentDescription(desc.toString()); + } + } else { + setContentDescription(""); + } + } + + IPropertyListener partPropertyListener = new IPropertyListener() { + @Override + public void propertyChanged(Object source, int propId) { + if (propId == IWorkbenchPart.PROP_TITLE) { + updateContentDescription(pinSelection, lastPart); + } + } + }; + + @Override + public IWorkbenchPart getContributingPart() { + return lastPart; + } + +}