/*******************************************************************************
* 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 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.swt.widgets.Display;
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.PartInitException;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.part.IContributedContentsView;
import org.eclipse.ui.part.IPage;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.part.PageBookView;
import org.simantics.Simantics;
import org.simantics.browsing.ui.swt.IVariablesPage;
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.ui.BundleUtils;
/**
* 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 == ISessionContextProvider.class) * // Get ISessionContextProvider from somewhere, i.e. SimanticsUI * if (c == IPropertyPage.class) * return new PropertyPage(getSite(), this); * } ** * 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;
*/
VariablesPage page = new VariablesPage(getSite(), this);
page.setAdapter(this);
initPage(page);
page.createControl(book);
//System.out.println("PPV create default page: " + page);
return page;
}
@Override
protected PageRec doCreatePage(IWorkbenchPart part) {
return null;
// // 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));
//
// VariablesPage page = new VariablesPage(getSite(), this);
//
// // Make sure that the adaptation is provided by this class
// // in order not to leave the ISessionContextProvider adaptability
// // up to clients to implement.
// page.setAdapter(this);
// //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);
}
@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;
}
@Override
protected boolean isImportant(IWorkbenchPart part) {
// If selection is pinned, part activations are not important.
if (pinSelection)
return false;
// Ignore self, try all others.
return part != this;
}
/**
* 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);
}
bootstrapSelection = null;
}
}
@Override
protected void partHidden(IWorkbenchPart part) {
// Make sure that pinned view is not hidden when the editor is hidden
if(!pinSelection)
super.partHidden(part);
}
long lastSelectionChangeTime = -1000;
ISelectionListener immediateSelectionListener = new ISelectionListener() {
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
// Check that enough time has passed since the last selection change.
long time = System.currentTimeMillis();
long delta = time - lastSelectionChangeTime;
lastSelectionChangeTime = time;
//System.out.println("time delta: " + delta + " : " + selection);
if (delta > SELECTION_CHANGE_THRESHOLD) {
VariablesPageView.this.selectionChanged(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) {
// we ignore our own selection or null selection
if (part == this || sel == null) {
return;
}
// ignore workbench selections when pinned also
if (pinSelection)
return;
// pass the selection change to the page
//System.out.println("PPV selection changed: " + sel + " " + this);
IPage page = getCurrentPage();
if (page instanceof IVariablesPage) {
IVariablesPage ppage = (IVariablesPage) page;
ppage.selectionChanged(part, sel);
// Make sure that the part name is not updated unnecessarily because
// of immediate and post selection listeners.
boolean sameSelection = false;
if (part == lastPart) {
if (sel != null && sel.equals(lastSelection))
sameSelection = true;
}
if (lastPart != null) {
lastPart.removePropertyListener(partPropertyListener);
}
lastPart = part;
lastSelection = sel;
if (lastPart != null) {
lastPart.addPropertyListener(partPropertyListener);
}
if (!sameSelection) {
final Display d = getSite().getShell().getDisplay();
ppage.updatePartName(sel, parameter -> {
if (!d.isDisposed())
d.asyncExec(() -> 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);
}
}
};
}