/******************************************************************************* * 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.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.Consumer; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IPartListener; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.part.IPageBookViewPage; import org.eclipse.ui.part.Page; import org.simantics.browsing.ui.GraphExplorer; import org.simantics.browsing.ui.swt.IVariablesPage; import org.simantics.browsing.ui.swt.widgets.GraphExplorerComposite; import org.simantics.browsing.ui.swt.widgets.GraphExplorerComposite.InputSource; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.ResourceArray; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.AdaptionException; import org.simantics.db.exception.DatabaseException; import org.simantics.db.management.ISessionContext; import org.simantics.db.management.ISessionContextChangedListener; import org.simantics.db.management.ISessionContextProvider; import org.simantics.db.management.SessionContextChangedEvent; import org.simantics.db.procedure.Listener; import org.simantics.db.request.Read; import org.simantics.ui.utils.ResourceAdaptionUtils; import org.simantics.utils.ui.AdaptionUtils; import org.simantics.utils.ui.ErrorLogger; /** *

* Subclasses may extend or reimplement the following methods as required: *

*

* * @author Tuukka Lehtonen */ public class VariablesPage extends Page implements IPageBookViewPage, IVariablesPage { protected static final int MAX_SELECTION_LENGTH_TO_SHOW = 5; protected ISessionContext sessionContext; protected GraphExplorerComposite explorer; /** * @param site the workbench part site that contains this page or * null if there is no site, i.e. the page is within a * dialog or a plain shell. */ public VariablesPage(IWorkbenchPartSite site) { this.site = site; } /** * @param site the workbench part site that contains this page or * null if there is no site, i.e. the page is within a * dialog or a plain shell. * @param adapter must provide an adapter for * ISessionContextProvider.class */ public VariablesPage(IWorkbenchPartSite site, IAdaptable adapter) { this(site); setAdapter(adapter); } @Override public void dispose() { // Stop listening for title changes. if (currentPartNameListener != null) currentPartNameListener.dispose(); if (adapter != null) { ISessionContextProvider contextProvider = getSessionContextProvider(); contextProvider.removeContextChangedListener(contextChangeListener); } if (sourcePart != null) { sourcePart.getSite().getPage().removePartListener(partListener); sourcePart = null; } site = null; adapter = null; explorer = null; sessionContext = null; } protected ISessionContextProvider getSessionContextProvider() { return (ISessionContextProvider) getAdapter().getAdapter(ISessionContextProvider.class); } protected ISessionContext getSessionContext() { return sessionContext; } @Override public final void createControl(Composite parent) { createPageControls(parent); // Attach to current session context provider to keep the UI intact even // when the current UI session changes. ISessionContextProvider contextProvider = getSessionContextProvider(); contextProvider.addContextChangedListener(contextChangeListener); setSessionContext(contextProvider.getSessionContext()); } /** * Override to customize the UI component created on this page. * * @param parent */ protected void createPageControls(Composite parent) { Map args = new HashMap(); Set browseContexts = new HashSet(); browseContexts.add("org.simantics.browsing.ui.graph.variablesView"); args.put("browseContexts", browseContexts); explorer = new GraphExplorerComposite(args, site, parent, SWT.NONE); explorer.setInputSource(new InputSource() { @Override public Object get(ISessionContext ctx, Object selection) { final Resource input = AdaptionUtils.adaptToSingle(selection, Resource.class); if(input == null) { return GraphExplorer.EMPTY_INPUT; } final VariablePrefix prefix = AdaptionUtils.adaptToSingle(selection, VariablePrefix.class); if(prefix == null) { return new VariablesInput(null, input); } else { return new VariablesInput(prefix.getPrefix(), input); } } }); } /** * @param newContext */ protected final void setSessionContext(ISessionContext newContext) { ISessionContext oldContext = this.sessionContext; this.sessionContext = newContext; // System.out.println("AbstractPropertyPage.setSessionContext: " + oldContext + " -> " + newContext); sessionContextChanged(oldContext, newContext); } /** * @param oldContext * @param newContext */ protected void sessionContextChanged(ISessionContext oldContext, ISessionContext newContext) { explorer.applySessionContext(newContext); // explorer.setSessionContext(newContext); } protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() { @Override public void sessionContextChanged(SessionContextChangedEvent event) { setSessionContext(event.getNewValue()); } }; @Override public Control getControl() { return (explorer != null) ? explorer : null; } @Override public ISelection getSelection() { // if (!explorer.isDisposed()) { // return explorer.getSelection(); // } return null; } /** * Sets focus to a part in the page. * @see org.eclipse.ui.part.Page#setFocus() */ @Override public void setFocus() { // if (explorer != null && !explorer.isDisposed()) { // explorer.requestFocus(); // } } protected void sourcePartClosed(IWorkbenchPart part) { // if (!explorer.isDisposed()) { // explorer.setInput(StructuredSelection.EMPTY, false); // } } protected void sourceSelectionChanged(ISelection selection) { if (!explorer.isDisposed()) { explorer.setInput(selection, false); } } static class PartNameListener implements Listener { private boolean disposed = false; private final Consumer updateCallback; public PartNameListener(Consumer updateCallback) { assert updateCallback != null; this.updateCallback = updateCallback; } public void dispose() { disposed = true; } @Override public boolean isDisposed() { return disposed; } @Override public void execute(String result) { //System.out.println("part name changed: " + result); updateCallback.accept(result); } @Override public void exception(Throwable t) { ErrorLogger.defaultLogError(t); } } PartNameListener currentPartNameListener = null; @Override public void updatePartName(final ISelection forSelection, Consumer updateCallback) { PartNameListener oldListener = currentPartNameListener; PartNameListener newListener = new PartNameListener(updateCallback); if (oldListener != null) oldListener.dispose(); if (sessionContext != null) { sessionContext.getSession().asyncRequest(new Read() { @Override public String perform(ReadGraph graph) throws DatabaseException { return computeTitle(graph, forSelection); } }, newListener); } } protected static String safeGetName(ReadGraph g, Resource r) throws DatabaseException { try { return g.adapt(r, String.class); } catch (AdaptionException e) { return NameUtils.getSafeName(g, r); } } protected String computeTitle(ReadGraph graph, ISelection selection) throws DatabaseException { boolean sameTypes = true; try { final ResourceArray[] ras = ResourceAdaptionUtils.toResourceArrays(selection); if (ras.length == 0) return null; // Check if all the input resource are of the same type. Collection types = null; for (ResourceArray ra : ras) { if (ra.isEmpty()) { return null; } if (types == null) { types = graph.getPrincipalTypes(ra.resources[0]); } else { Collection ts = graph.getPrincipalTypes(ra.resources[0]); ts.removeAll(types); if (!ts.isEmpty()) { sameTypes = false; break; } } } if (sameTypes) { // If the resource no longer exists, provide default name only. if (!graph.hasStatement(ras[0].resources[0])) { return null; } String name = safeGetName(graph, ras[0].resources[0]); if (ras.length > 1) name += " [" + ras.length +"]"; return name; } else { Collection names = new ArrayList(ras.length); boolean truncate = ras.length > MAX_SELECTION_LENGTH_TO_SHOW; int end = Math.min(ras.length, MAX_SELECTION_LENGTH_TO_SHOW); int missing = ras.length - end; for (int i = 0; i < end; ++i) { // If the resource no longer exists, provide default name only. if (!graph.hasStatement(ras[i].resources[0])) continue; names.add(safeGetName(graph, ras[i].resources[0])); } if (names.isEmpty()) { return null; } if (truncate) names.add("+ " + missing + " more..."); String name = names.toString(); return name; } } catch (Throwable t) { t.printStackTrace(); return null; } } /** * Part listener which cleans up this page when the source part is closed. * This is hooked only when there is a source part. */ private class PartListener implements IPartListener { public void partActivated(IWorkbenchPart part) { } public void partBroughtToTop(IWorkbenchPart part) { } public void partClosed(IWorkbenchPart part) { if (sourcePart == part) { sourcePart = null; sourcePartClosed(part); } } public void partDeactivated(IWorkbenchPart part) { } public void partOpened(IWorkbenchPart part) { } } private PartListener partListener = new PartListener(); protected IWorkbenchPartSite site; private IWorkbenchPart sourcePart; protected IAdaptable adapter; @Override public void setAdapter(IAdaptable adapter) { assert adapter != null; this.adapter = adapter; } public IAdaptable getAdapter() { assert adapter != null; return adapter; } @Override public void selectionChanged(IWorkbenchPart part, ISelection selection) { if (getControl() == null) { return; } if (sourcePart != null) { sourcePart.getSite().getPage().removePartListener(partListener); sourcePart = null; } // change the viewer input since the workbench selection has changed. sourceSelectionChanged(selection); sourcePart = part; if (sourcePart != null) { sourcePart.getSite().getPage().addPartListener(partListener); } } }