/*******************************************************************************
* 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: * *
* 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.IStandardPropertyPage
which will make this view do the above
* automatically without implementing getAdapter
.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 SetPropertySheet
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