//----------------------------------------------------------------------------
// 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);
}
}
}