//---------------------------------------------------------------------------- // COMPONENT NAME: LPEX Editor // // © Copyright IBM Corporation 2007, 2008 // All Rights Reserved. // // DESCRIPTION: // KeyReferenceAction - sample user-defined action (ref) //---------------------------------------------------------------------------- package com.ibm.lpex.samples; import com.ibm.lpex.core.LpexAction; import com.ibm.lpex.core.LpexActionConstants; import com.ibm.lpex.core.LpexBaseAction; import com.ibm.lpex.core.LpexResources; import com.ibm.lpex.core.LpexStringTokenizer; import com.ibm.lpex.core.LpexView; import java.util.Iterator; import java.util.TreeSet; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.jface.dialogs.PopupDialog; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.help.IWorkbenchHelpSystem; import org.eclipse.ui.keys.IBindingService; /** * Sample action <b>ref</b> - display a key reference for the current view. * Use this action to display a dialog with the editor actions available in * the current document view, and their associated keys. * * <p>Here is the KeyReferenceAction * <a href="doc-files/KeyReferenceAction.java.html">source code</a>.</p> * * <p>To run this sample: * <ul> * <li>Define this user action via an editor preference page, where available, * or from the editor command line: * <pre>set actionClass.ref com.ibm.lpex.samples.KeyReferenceAction</pre></li> * <li>Run it from the editor command line: * <pre>action ref</pre> * or associate it with a key (here, <b>Ctrl+Shift+L</b> in all contexts): * <pre>set keyAction.c-s-l.t.c.p ref</pre></li> * </ul></p> * * @see com.ibm.lpex.samples All the samples */ public class KeyReferenceAction implements LpexAction { /** * Runs the action. * Displays the key reference dialog. */ public void doAction(LpexView lpexView) { KeyReferenceDialog keyReferenceDialog = new KeyReferenceDialog(lpexView); // without a parent shell, keyReferenceDialog's shell won't close on Esc... if (keyReferenceDialog.getShell() == null) { keyReferenceDialog.setParentShell(lpexView.window().getShell()); } keyReferenceDialog.open(); } /** * Returns the availability of this action. * This action can run in any view that has an associated window. */ public boolean available(LpexView lpexView) { return lpexView.window() != null; } } /** * Dialog that displays the LPEX actions and their associated keys * available in a view. Transient dialog, based on PopupDialog. */ class KeyReferenceDialog extends PopupDialog { // associated LPEX document view LpexView _lpexView; // are we running inside the Eclipse workbench? IWorkbench _workbench; // table with the actions and keys of the current view Table _table; // list of actions that we don't need to show in this dialog static final String[] hiddenActions = { "appendToActionArgument", "eclipseCopy", "eclipseCut", "eclipseDelete", "eclipsePaste", "eclipseRedo", "eclipseUndo", "nullAction", "saveToWriter" }; /** * Creates an instance of KeyReferenceDialog. * * @param lpexView the associated LPEX document view */ KeyReferenceDialog(LpexView lpexView) { super((Shell)null, PopupDialog.INFOPOPUP_SHELLSTYLE /*can get focus*/, true, false, false, false, null, null); _lpexView = lpexView; try { _workbench = PlatformUI.getWorkbench(); } catch(Exception x) {} // indicate the current editor profile and document parser String parser = _lpexView.query("parser"); if (parser != null) { // LPEX Key Reference - profile: "{0}", parser: "{1}" setInfoText(LpexResources.message("keyReferencePP", _lpexView.query("baseProfile"), parser)); } else { setInfoText(LpexResources.message("keyReferenceP", _lpexView.query("baseProfile"))); } } /** * Opens the KeyReferenceDialog. */ public int open() { Shell shell = getShell(); if (shell != null) { close(); // close any previously-opened dialog } // create dialog, set its bounds, open it create(); setLocationAndSize(); return super.open(); } // public boolean close() { // // TEST: click other window > minimize it > focus not quite there in orig LPEX window // // _lpexView.window().setFocus(); BUT leaves cheese when click on orig LPEX window... // return super.close(); // } /** * Allows the user of this dialog to set a parent shell. */ protected void setParentShell(Shell newParentShell) { super.setParentShell(newParentShell); } /** * Creates the fills a table with the actions and keys. */ protected Control createDialogArea(Composite parent) { // do we need a hosting Composite?! _table = new Table(parent, SWT.FULL_SELECTION | SWT.SINGLE); // _table.setLayoutData(new GridData(GridData.FILL_BOTH)); _table.setBackground(parent.getBackground()); _table.setLinesVisible(true); TableColumn actionNameColumn = new TableColumn(_table, SWT.LEFT, 0); TableColumn actionKeyColumn = new TableColumn(_table, SWT.LEFT, 1); // fill table with the editor actions and their keys populateTableWithActionKeys(); // pack the columns for their contents actionNameColumn.pack(); actionKeyColumn.pack(); // listen to user selecting a table item _table.addListener(SWT.DefaultSelection, new Listener() { public void handleEvent(Event event) { selectionEvent(); } }); // listen to mouse hovering over a table item _table.addListener(SWT.MouseHover, new Listener() { public void handleEvent(Event event) { hoverEvent(event); } }); // listen to F1 (Help) key if (_workbench != null) { _table.addListener(SWT.Help, new Listener() { public void handleEvent(Event event) { helpEvent(); } }); } return _table; } /** * Positions the dialog in the bottom right corner of the workbench or screen. */ private void setLocationAndSize() { int x, y; Shell shell = getShell(); int width = shell.getSize().x; int height = shell.getSize().y; if (_workbench != null) { Rectangle workbenchBounds = _workbench.getWorkbenchWindows()[0].getShell().getBounds(); int maxHeight = workbenchBounds.height / 2; if (height > maxHeight) { height = maxHeight; } x = workbenchBounds.x + workbenchBounds.width - width - 10; y = workbenchBounds.y + workbenchBounds.height - height - 10; } else { Rectangle displayBounds = shell.getDisplay().getClientArea(); int maxHeight = displayBounds.height / 2; if (height > maxHeight) { height = maxHeight; } x = displayBounds.width - width - 10; y = displayBounds.height - height - 10; } shell.setBounds(x, y, width, height); } /** * Fills table with all LPEX actions available in the associated view. */ private void populateTableWithActionKeys() { // use a sorted set (action) for the contents of the table TreeSet<String> treeSet = new TreeSet<String>(); // put the default and user-defined editor actions in the set LpexStringTokenizer st = new LpexStringTokenizer(_lpexView.query("defaultActions")+" "+ _lpexView.query("actions")); while (st.hasMoreTokens()) { String actionName = st.nextToken(); if (showAction(actionName)) { // SPECIAL CASE: when running LpexAbstractTextEditor (inside Eclipse's // IDE), bring up Eclipse's own Key Assist dialog on 2nd Ctrl+Shift+L if (_workbench != null && actionName.equals("cslAction")) { actionName = "Show Eclipse key assist"; } treeSet.add(actionName); } } // populate table from the set Color unavailableColor = _table.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY); Iterator<String> iterator = treeSet.iterator(); while (iterator.hasNext()) { String actionName = iterator.next(); int actionId = _lpexView.actionId(actionName); String keyText = _lpexView.actionKeyText(actionId); // create a new table item for the action TableItem item = new TableItem(_table, SWT.NULL); item.setText(0, actionName); // 1st column - action item.setText(1, (keyText != null)? keyText : ""); // 2nd column - key item.setData(actionName); // gray out item if it's an editor action not available in the current context // (hmm, this may cause a gray left margin for the entire table!?) if (actionId != LpexActionConstants.ACTION_INVALID && !_lpexView.actionAvailable(actionId)) { item.setForeground(unavailableColor); } } // TODO add key-bindings to dialog, so can run action by pressing its key!? // TODO add available editor commands!? } /** * Returns whether we should show the given action in the dialog. */ private boolean showAction(String actionName) { for (int i = 0; i < hiddenActions.length; i++) { if (hiddenActions[i].equals(actionName)) { return false; } } return true; } /** * Returns the table as the control to get focus when dialog displayed. */ protected Control getFocusControl() { return _table; } /** * Runs the action specified in the selected table item. */ private void selectionEvent() { // get the action of the item selected in the table int selectedIndex = _table.getSelectionIndex(); if (selectedIndex >= 0) { String actionName = (String)_table.getItem(selectedIndex).getData(); // SPECIAL CASE: when running LpexAbstractTextEditor (inside Eclipse's // IDE), bring up Eclipse's own Key Assist dialog on 2nd Ctrl+Shift+L if (_workbench != null && actionName.equals("Show Eclipse key assist")) { super.close(); ((IBindingService)_workbench.getService(IBindingService.class)) .openKeyAssistDialog(); return; } int actionId = _lpexView.actionId(actionName); // if the action is available, run it if (_lpexView.actionAvailable(actionId)) { // close dialog before running action, so LPEX window is restored focus super.close(); _lpexView.triggerAction(actionId); } } } /** * Displays tooltip information, if available, for the hovered table item. * @param event the event that triggered this table-listener notification */ private void hoverEvent(Event event) { String tooltip = null; TableItem item = _table.getItem(new Point(event.x, event.y)); if (item != null) { String actionName = (String)item.getData(); LpexAction action = _lpexView.action(actionName); // try to get an acceptable tooltip if (action != null && action instanceof LpexBaseAction) { tooltip = ((LpexBaseAction)action).getToolTipText(_lpexView); } if (tooltip == null) { tooltip = LpexResources.message("popup." + actionName + ".description"); } } _table.setToolTipText(tooltip); } /** * Displays help, if available, for the selected table item. */ private void helpEvent() { // get the action of the item selected in the table int selectedIndex = _table.getSelectionIndex(); if (selectedIndex >= 0) { String actionName = (String)_table.getItem(selectedIndex).getData(); LpexAction action = _lpexView.action(actionName); // try to get a context help id String contextHelpId = null; if (action != null && action instanceof LpexBaseAction) { contextHelpId = ((LpexBaseAction)action).getHelpId(_lpexView); } if (contextHelpId == null) { contextHelpId = "com.ibm.lpex.popup_" + actionName + "_context"; } super.close(); // no help will display if contextHelpId not defined in LPEX Editor plug-in _workbench.getHelpSystem().displayHelp(contextHelpId); } } }