1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.diagram.symbollibrary.ui;
\r
14 import org.eclipse.jface.action.GroupMarker;
\r
15 import org.eclipse.jface.action.IMenuListener;
\r
16 import org.eclipse.jface.action.IMenuManager;
\r
17 import org.eclipse.jface.action.MenuManager;
\r
18 import org.eclipse.jface.viewers.ISelection;
\r
19 import org.eclipse.jface.viewers.StructuredSelection;
\r
20 import org.eclipse.swt.SWT;
\r
21 import org.eclipse.swt.events.DisposeEvent;
\r
22 import org.eclipse.swt.events.DisposeListener;
\r
23 import org.eclipse.swt.widgets.Composite;
\r
24 import org.eclipse.swt.widgets.Control;
\r
25 import org.eclipse.swt.widgets.Display;
\r
26 import org.eclipse.swt.widgets.Menu;
\r
27 import org.eclipse.ui.IWorkbenchActionConstants;
\r
28 import org.eclipse.ui.part.IPageSite;
\r
29 import org.eclipse.ui.part.Page;
\r
30 import org.simantics.diagram.symbolcontribution.SymbolProviderFactory;
\r
31 import org.simantics.diagram.symbollibrary.ISymbolGroup;
\r
32 import org.simantics.diagram.symbollibrary.ISymbolItem;
\r
33 import org.simantics.g2d.canvas.ICanvasContext;
\r
34 import org.simantics.g2d.gallery.GalleryViewer;
\r
35 import org.simantics.scenegraph.g2d.events.Event;
\r
36 import org.simantics.scenegraph.g2d.events.EventTypes;
\r
37 import org.simantics.scenegraph.g2d.events.IEventHandler;
\r
38 import org.simantics.scenegraph.g2d.events.MouseEvent;
\r
39 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonEvent;
\r
40 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;
\r
41 import org.simantics.utils.threads.AWTThread;
\r
42 import org.simantics.utils.ui.SWTUtils;
\r
43 import org.simantics.utils.ui.jface.BaseSelectionProvider;
\r
46 * A page container for {@link SymbolLibraryComposite}.
\r
49 * Supports context menu whose ID can be set with the
\r
50 * {@link #SymbolLibraryPage(SymbolProviderFactory, String)} constructor. By
\r
51 * default the page registers a context menu with name
\r
52 * {@value #DEFAULT_CONTEXT_MENU_ID}. The context menu selection provider
\r
53 * contain one of the following:
\r
55 * <li>StructuredSelection of {@link ISymbolItem}s if the user clicks inside a
\r
57 * <li>StructuredSelection of a single {@link ISymbolGroup} if the user clicks a
\r
58 * single symbol group title</li>
\r
59 * <li>Empty selection if the user clicks on empty space</li>
\r
63 * @author Tuukka Lehtonen
\r
65 public class SymbolLibraryPage extends Page {
\r
67 public static final String DEFAULT_CONTEXT_MENU_ID = "#SymbolLibrary";
\r
69 SymbolProviderFactory symbolProviderFactory;
\r
71 SymbolLibraryComposite library;
\r
75 // Context menu stuff
\r
76 String contextMenuId = DEFAULT_CONTEXT_MENU_ID;
\r
77 MenuManager menuManager;
\r
79 BaseSelectionProvider selectionProvider = new BaseSelectionProvider();
\r
82 * An internal adapter from {@link IEventHandler} to
\r
83 * {@link SymbolLibraryEventHandler} interface.
\r
86 * Attempts to retrieve the {@link ISymbolGroup} and the selection within
\r
87 * the corresponding GalleryViewer to give them to the possibly existing
\r
88 * external {@link SymbolLibraryEventHandler}.
\r
90 IEventHandler internalEventAdapter = new IEventHandler() {
\r
92 public int getEventMask() {
\r
93 return EventTypes.MouseButtonMask;
\r
96 public boolean handleEvent(Event e) {
\r
97 SymbolLibraryEventHandler h = externalEventHandler;
\r
101 // MouseButtonEvent be = (MouseButtonEvent) e;
\r
102 // System.out.println("event:");
\r
103 // System.out.println("\tcontext: " + e.getContext());
\r
104 // System.out.println("\tscreen pos: " + be.screenPosition);
\r
106 if (e.context instanceof ICanvasContext) {
\r
107 // GalleryViewer clicked
\r
108 ICanvasContext ctx = (ICanvasContext) e.context;
\r
109 GalleryViewer viewer = ctx.getHintStack().getHint(GalleryViewer.KEY_VIEWER);
\r
110 ISymbolGroup group = null;
\r
111 if (viewer != null) {
\r
112 Object input = viewer.getInput();
\r
113 if (input instanceof ISymbolGroup)
\r
114 group = (ISymbolGroup) input;
\r
116 h.handleEvent(e, group, viewer);
\r
117 } else if (e.context instanceof Control) {
\r
118 Control control = (Control) e.context;
\r
119 ISymbolGroup group = (ISymbolGroup) control.getData(SymbolLibraryKeys.KEY_GROUP);
\r
120 //GalleryViewer viewer = (GalleryViewer) control.getData(SymbolLibraryKeys.KEY_GALLERY);
\r
121 h.handleEvent(e, group, null);
\r
123 // empty space event
\r
124 h.handleEvent(e, null, null);
\r
131 * Default event handler handler that shows the popup context menu of this
\r
132 * SymbolLibraryPage. It will set {@link #selectionProvider} selection to
\r
133 * provide Eclipse menu extensions the possibility to examine the clicked
\r
136 volatile SymbolLibraryEventHandler externalEventHandler = new SymbolLibraryEventHandler() {
\r
138 public boolean handleEvent(Event event, final ISymbolGroup group, final GalleryViewer viewer) {
\r
139 if (event instanceof MouseButtonReleasedEvent) {
\r
140 final MouseButtonEvent be = (MouseButtonEvent) event;
\r
141 if (be.button != MouseEvent.RIGHT_BUTTON)
\r
144 // asyncExec to AWT to get proper selection from viewer
\r
145 AWTThread.getThreadAccess().asyncExec(new Runnable() {
\r
147 public void run() {
\r
148 ISelection _selection = StructuredSelection.EMPTY;
\r
149 if (viewer != null)
\r
150 _selection = viewer.getSelection();
\r
151 if (_selection.isEmpty() && group != null)
\r
152 _selection = new StructuredSelection(group);
\r
154 final ISelection selection = _selection;
\r
156 // asyncExec to SWT to show popup
\r
157 SWTUtils.asyncExec(display, new Runnable() {
\r
159 public void run() {
\r
160 if (library.isDisposed())
\r
162 selectionProvider.setAndFireNonEqualSelection(selection);
\r
163 menu.setLocation((int) be.screenPosition.getX(), (int) be.screenPosition.getY());
\r
164 menu.setVisible(true);
\r
174 public SymbolLibraryPage(SymbolProviderFactory symbolProviderFactory) {
\r
175 this.symbolProviderFactory = symbolProviderFactory;
\r
178 // public SymbolLibraryPage(SymbolProviderFactory symbolProviderFactory, String contextMenuId) {
\r
179 // this.symbolProviderFactory = symbolProviderFactory;
\r
180 // this.contextMenuId = contextMenuId;
\r
184 * Set an event handler for the controls of this symbol library page (i.e.
\r
185 * SymbolLibraryComposite) that will receive all mouse events concerning the
\r
186 * symbol library controls. The events will be delivered in both SWT and AWT
\r
187 * threads since controls of both toolkits are involved in the UI of the
\r
188 * page. Actions performed in the event handler should be such that they are
\r
189 * scheduled to run in the according thread asynchronously and not handled
\r
190 * synchronously in the handler.
\r
193 * This mechanism allows setting only a single event handler. Handler
\r
194 * chaining is possible.
\r
196 * @param handler the handler to set for the page
\r
198 * @see #getEventHandler()
\r
200 public SymbolLibraryEventHandler setEventHandler(SymbolLibraryEventHandler handler) {
\r
201 SymbolLibraryEventHandler old = this.externalEventHandler;
\r
202 this.externalEventHandler = handler;
\r
206 public SymbolLibraryEventHandler getEventHandler() {
\r
207 return externalEventHandler;
\r
211 public void createControl(Composite parent) {
\r
212 display = parent.getDisplay();
\r
213 library = new SymbolLibraryComposite(parent, SWT.NONE, symbolProviderFactory);
\r
214 library.setEventHandler(internalEventAdapter);
\r
215 library.addDisposeListener(new DisposeListener() {
\r
217 public void widgetDisposed(DisposeEvent e) {
\r
222 IPageSite site = getSite();
\r
223 if (site != null && contextMenuId != null) {
\r
224 menuManager = new MenuManager("Symbol Library", contextMenuId);
\r
225 menuManager.setRemoveAllWhenShown(true);
\r
226 menuManager.addMenuListener(new IMenuListener() {
\r
228 public void menuAboutToShow(IMenuManager manager) {
\r
229 menuManager.add(new GroupMarker(IWorkbenchActionConstants.WB_START));
\r
231 // // FIXME: this is debug, remove
\r
232 // menuManager.add(new Action("Test") {
\r
234 // public void run() {
\r
235 // System.out.println("Selection: " + selectionProvider.getSelection());
\r
236 // MessageDialog.openInformation(null, "Symbol Library Action", selectionProvider.getSelection().toString());
\r
242 menu = menuManager.createContextMenu(library);
\r
243 library.setMenu(menu);
\r
244 site.registerContextMenu(menuManager.getId(), menuManager, selectionProvider);
\r
249 public Control getControl() {
\r
253 public void setAllExpandedStates(boolean value) {
\r
254 library.setAllExpandedStates(value);
\r
258 public void setFocus() {
\r
259 if (library != null && !library.isDisposed())
\r
260 library.setFocus();
\r