/*******************************************************************************
* Copyright (c) 2004, 2008 John Krasnay and others.
* 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:
* John Krasnay - initial API and implementation
*******************************************************************************/
package net.sf.vex.editor;
import net.sf.vex.swt.VexWidget;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
/**
* Class that owns the content assistant window, the popup where the user
* can select elements or other content to insert. This class is a singleton
* owned by VexPlugin. It should not be instantiated directly.
*/
public abstract class ContentAssistant {
/**
* Class constructor.
*/
public ContentAssistant() {
}
/**
* Returns the list of actions to be displayed in this assistant.
* @param vexWidget VexWidget to which the actions apply.
*/
public abstract IAction[] getActions(VexWidget widget);
/**
* Returns the title to be displayed in the assistant's title bar.
* @param vexWidget VexWidget for which we are displaying the assistant.
*/
public abstract String getTitle(VexWidget widget);
/**
* Show the content assitant window for the given editor.
* @param vexWidget VexWidget for which we are displaying the assistant.
*/
public void show(VexWidget vexWidget) {
this.actions = this.getActions(vexWidget);
Shell parent = vexWidget.getShell();
this.assistantShell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MODELESS);
this.assistantShell.setText(this.getTitle(vexWidget));
this.assistantShell.addControlListener(this.controlListener);
this.assistantShell.addDisposeListener(this.disposeListener);
this.assistantShell.addShellListener(this.shellListener);
GridLayout layout = new GridLayout();
layout.numColumns = 1;
this.assistantShell.setLayout(layout);
GridData gd;
this.textWidget = new Text(this.assistantShell, SWT.SINGLE);
this.textWidget.addModifyListener(this.modifyListener);
gd = new GridData();
gd.grabExcessHorizontalSpace = true;
gd.horizontalAlignment = GridData.FILL;
this.textWidget.setLayoutData(gd);
this.textWidget.addKeyListener(this.keyListener);
this.textWidget.addModifyListener(this.modifyListener);
this.treeWidget = new Tree(assistantShell, SWT.SINGLE);
this.treeWidget.addKeyListener(this.keyListener);
this.treeWidget.addMouseListener(this.mouseListener);
this.treeWidget.addSelectionListener(this.selectionListener);
gd = new GridData();
gd.grabExcessHorizontalSpace = true;
gd.horizontalAlignment = GridData.FILL;
gd.grabExcessVerticalSpace = true;
gd.verticalAlignment = GridData.FILL;
this.treeWidget.setLayoutData(gd);
this.assistantShell.setBounds(this.getSize());
this.repopulateList();
this.mouseDown = false;
this.assistantShell.open();
}
//======================================================== PRIVATE
private static final String SETTINGS_SECTION = "contentAssistant"; //$NON-NLS-1$
private static final String SETTINGS_X = "x"; //$NON-NLS-1$
private static final String SETTINGS_Y = "y"; //$NON-NLS-1$
private static final String SETTINGS_WIDTH = "width"; //$NON-NLS-1$
private static final String SETTINGS_HEIGHT = "height"; //$NON-NLS-1$
private Shell assistantShell;
private Text textWidget;
private Tree treeWidget;
private IAction[] actions;
private boolean mouseDown;
/**
* Perform the action that is currently selected in the tree view, if any,
* and dispose the assistant shell.
*/
private void doAction() {
TreeItem[] items = treeWidget.getSelection();
if (items.length > 0) {
IAction action = (IAction) items[0].getData();
action.run();
}
assistantShell.dispose();
}
private IDialogSettings getSettings() {
IDialogSettings rootSettings = VexPlugin.getInstance().getDialogSettings();
IDialogSettings settings = rootSettings.getSection(SETTINGS_SECTION);
if (settings == null) {
settings = rootSettings.addNewSection(SETTINGS_SECTION);
}
return settings;
}
private Rectangle getSize() {
IDialogSettings settings = this.getSettings();
int x = 100;
int y = 100;
int width = 200;
int height = 300;
if (settings.get(SETTINGS_X) != null) {
x = settings.getInt(SETTINGS_X);
y = settings.getInt(SETTINGS_Y);
width = settings.getInt(SETTINGS_WIDTH);
height = settings.getInt(SETTINGS_HEIGHT);
}
return new Rectangle(x, y, width, height);
}
private void repopulateList() {
String prefix = this.textWidget.getText();
this.treeWidget.removeAll();
TreeItem first = null;
for (int i = 0; i < this.actions.length; i++) {
IAction action = this.actions[i];
if (action.getText().startsWith(prefix)) {
TreeItem item = new TreeItem(this.treeWidget, SWT.NONE);
if (first == null) {
first = item;
}
item.setData(action);
item.setText(action.getText());
}
}
if (first != null) {
this.treeWidget.setSelection(new TreeItem[] { first });
}
}
private void saveSize() {
IDialogSettings settings = this.getSettings();
Rectangle bounds = this.assistantShell.getBounds();
settings.put(SETTINGS_X, bounds.x);
settings.put(SETTINGS_Y, bounds.y);
settings.put(SETTINGS_WIDTH, bounds.width);
settings.put(SETTINGS_HEIGHT, bounds.height);
}
private ControlListener controlListener = new ControlListener() {
public void controlMoved(ControlEvent e) {
saveSize();
}
public void controlResized(ControlEvent e) {
saveSize();
}
};
private DisposeListener disposeListener = new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
assistantShell = null;
}
};
private KeyListener keyListener = new KeyListener() {
public void keyPressed(KeyEvent e) {
if (e.keyCode == 13) {
doAction();
} else if (e.widget == textWidget && e.keyCode == SWT.ARROW_DOWN) {
treeWidget.setFocus();
}
}
public void keyReleased(KeyEvent e) {
}
};
private ModifyListener modifyListener = new ModifyListener() {
public void modifyText(ModifyEvent e) {
repopulateList();
}
};
private MouseListener mouseListener = new MouseListener() {
public void mouseDoubleClick(MouseEvent e) {
}
public void mouseDown(MouseEvent e) {
mouseDown = true;
}
public void mouseUp(MouseEvent e) {
mouseDown = false;
}
};
private SelectionListener selectionListener = new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
// If selected with the mouse, we do the selected action.
if (mouseDown) {
doAction();
}
}
public void widgetDefaultSelected(SelectionEvent e) {
}
};
private ShellListener shellListener = new ShellListener() {
public void shellActivated(ShellEvent e) {
}
public void shellClosed(ShellEvent e) {
}
public void shellDeactivated(ShellEvent e) {
assistantShell.dispose();
}
public void shellDeiconified(ShellEvent e) {
}
public void shellIconified(ShellEvent e) {
}
};
}