/******************************************************************************* * 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.diagram.symbollibrary.ui; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.part.IPageSite; import org.eclipse.ui.part.Page; import org.simantics.diagram.symbolcontribution.SymbolProviderFactory; import org.simantics.diagram.symbollibrary.ISymbolGroup; import org.simantics.diagram.symbollibrary.ISymbolItem; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.gallery.GalleryViewer; import org.simantics.scenegraph.g2d.events.Event; import org.simantics.scenegraph.g2d.events.EventTypes; import org.simantics.scenegraph.g2d.events.IEventHandler; import org.simantics.scenegraph.g2d.events.MouseEvent; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonEvent; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent; import org.simantics.utils.threads.AWTThread; import org.simantics.utils.ui.SWTUtils; import org.simantics.utils.ui.jface.BaseSelectionProvider; /** * A page container for {@link SymbolLibraryComposite}. * *

* Supports context menu whose ID can be set with the * {@link #SymbolLibraryPage(SymbolProviderFactory, String)} constructor. By * default the page registers a context menu with name * {@value #DEFAULT_CONTEXT_MENU_ID}. The context menu selection provider * contain one of the following: *

*

* * @author Tuukka Lehtonen */ public class SymbolLibraryPage extends Page { public static final String DEFAULT_CONTEXT_MENU_ID = "#SymbolLibrary"; SymbolProviderFactory symbolProviderFactory; SymbolLibraryComposite library; Display display; // Context menu stuff String contextMenuId = DEFAULT_CONTEXT_MENU_ID; MenuManager menuManager; Menu menu; BaseSelectionProvider selectionProvider = new BaseSelectionProvider(); /** * An internal adapter from {@link IEventHandler} to * {@link SymbolLibraryEventHandler} interface. * *

* Attempts to retrieve the {@link ISymbolGroup} and the selection within * the corresponding GalleryViewer to give them to the possibly existing * external {@link SymbolLibraryEventHandler}. */ IEventHandler internalEventAdapter = new IEventHandler() { @Override public int getEventMask() { return EventTypes.MouseButtonMask; } @Override public boolean handleEvent(Event e) { SymbolLibraryEventHandler h = externalEventHandler; if (h == null) return false; // MouseButtonEvent be = (MouseButtonEvent) e; // System.out.println("event:"); // System.out.println("\tcontext: " + e.getContext()); // System.out.println("\tscreen pos: " + be.screenPosition); if (e.context instanceof ICanvasContext) { // GalleryViewer clicked ICanvasContext ctx = (ICanvasContext) e.context; GalleryViewer viewer = ctx.getHintStack().getHint(GalleryViewer.KEY_VIEWER); ISymbolGroup group = null; if (viewer != null) { Object input = viewer.getInput(); if (input instanceof ISymbolGroup) group = (ISymbolGroup) input; } h.handleEvent(e, group, viewer); } else if (e.context instanceof Control) { Control control = (Control) e.context; ISymbolGroup group = (ISymbolGroup) control.getData(SymbolLibraryKeys.KEY_GROUP); //GalleryViewer viewer = (GalleryViewer) control.getData(SymbolLibraryKeys.KEY_GALLERY); h.handleEvent(e, group, null); } else { // empty space event h.handleEvent(e, null, null); } return false; } }; /** * Default event handler handler that shows the popup context menu of this * SymbolLibraryPage. It will set {@link #selectionProvider} selection to * provide Eclipse menu extensions the possibility to examine the clicked * selection. */ volatile SymbolLibraryEventHandler externalEventHandler = new SymbolLibraryEventHandler() { @Override public boolean handleEvent(Event event, final ISymbolGroup group, final GalleryViewer viewer) { if (event instanceof MouseButtonReleasedEvent) { final MouseButtonEvent be = (MouseButtonEvent) event; if (be.button != MouseEvent.RIGHT_BUTTON) return false; // asyncExec to AWT to get proper selection from viewer AWTThread.getThreadAccess().asyncExec(new Runnable() { @Override public void run() { ISelection _selection = StructuredSelection.EMPTY; if (viewer != null) _selection = viewer.getSelection(); if (_selection.isEmpty() && group != null) _selection = new StructuredSelection(group); final ISelection selection = _selection; // asyncExec to SWT to show popup SWTUtils.asyncExec(display, new Runnable() { @Override public void run() { if (library.isDisposed()) return; selectionProvider.setAndFireNonEqualSelection(selection); menu.setLocation((int) be.screenPosition.getX(), (int) be.screenPosition.getY()); menu.setVisible(true); } }); } }); } return false; } }; public SymbolLibraryPage(SymbolProviderFactory symbolProviderFactory) { this.symbolProviderFactory = symbolProviderFactory; } // public SymbolLibraryPage(SymbolProviderFactory symbolProviderFactory, String contextMenuId) { // this.symbolProviderFactory = symbolProviderFactory; // this.contextMenuId = contextMenuId; // } /** * Set an event handler for the controls of this symbol library page (i.e. * SymbolLibraryComposite) that will receive all mouse events concerning the * symbol library controls. The events will be delivered in both SWT and AWT * threads since controls of both toolkits are involved in the UI of the * page. Actions performed in the event handler should be such that they are * scheduled to run in the according thread asynchronously and not handled * synchronously in the handler. * *

* This mechanism allows setting only a single event handler. Handler * chaining is possible. * * @param handler the handler to set for the page * @return * @see #getEventHandler() */ public SymbolLibraryEventHandler setEventHandler(SymbolLibraryEventHandler handler) { SymbolLibraryEventHandler old = this.externalEventHandler; this.externalEventHandler = handler; return old; } public SymbolLibraryEventHandler getEventHandler() { return externalEventHandler; } @Override public void createControl(Composite parent) { display = parent.getDisplay(); library = new SymbolLibraryComposite(parent, SWT.NONE, symbolProviderFactory); library.setEventHandler(internalEventAdapter); library.addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { library = null; } }); IPageSite site = getSite(); if (site != null && contextMenuId != null) { menuManager = new MenuManager("Symbol Library", contextMenuId); menuManager.setRemoveAllWhenShown(true); menuManager.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { menuManager.add(new GroupMarker(IWorkbenchActionConstants.WB_START)); // // FIXME: this is debug, remove // menuManager.add(new Action("Test") { // @Override // public void run() { // System.out.println("Selection: " + selectionProvider.getSelection()); // MessageDialog.openInformation(null, "Symbol Library Action", selectionProvider.getSelection().toString()); // } // }); } }); menu = menuManager.createContextMenu(library); library.setMenu(menu); site.registerContextMenu(menuManager.getId(), menuManager, selectionProvider); } } @Override public Control getControl() { return library; } public void setAllExpandedStates(boolean value) { library.setAllExpandedStates(value); } @Override public void setFocus() { if (library != null && !library.isDisposed()) library.setFocus(); } }