package junit.extensions.eclipse.quick.internal;
import java.util.List;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.jface.bindings.Trigger;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.SWTKeySupport;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
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.ui.PlatformUI;
import org.eclipse.ui.keys.IBindingService;
public class PopupTableSelector {
private Shell shell;
private List items;
private Object selection;
private TriggerSequence[] forwardTriggerSequences = null;
private TriggerSequence[] backwardTriggerSequences = null;
private String commandForward;
private String commandBackward;
private ILabelProvider labelProvider;
private String title = ""; //$NON-NLS-1$
private boolean forward = true;
public PopupTableSelector(Shell shell, List items) {
this.shell = shell;
this.items = items;
}
public void setCommandBackward(String string) {
commandBackward = string;
}
public void setCommandForward(String string) {
commandForward = string;
}
public void setTitle(String string) {
title = string;
}
public void setLabelProvider(ILabelProvider provider) {
labelProvider = provider;
}
public Object select() {
final int MAX_ITEMS = 22;
selection = null;
final Shell dialog = new Shell(shell, SWT.MODELESS);
Display display = dialog.getDisplay();
dialog.setLayout(new FillLayout());
final Table table = new Table(dialog, SWT.SINGLE | SWT.FULL_SELECTION);
table.setHeaderVisible(true);
table.setLinesVisible(true);
TableColumn tc = new TableColumn(table, SWT.NONE);
tc.setResizable(false);
tc.setText(title);
addItems(table, items);
int tableItemCount = table.getItemCount();
switch (tableItemCount) {
case 0:
// do nothing;
break;
case 1:
table.setSelection(0);
break;
default:
table.setSelection(forward ? 0 : table.getItemCount() - 1);
}
tc.pack();
table.pack();
Rectangle tableBounds = table.getBounds();
tableBounds.height = Math.min(tableBounds.height, table.getItemHeight() * MAX_ITEMS);
table.setBounds(tableBounds);
dialog.pack();
tc.setWidth(table.getClientArea().width);
table.setFocus();
table.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
cancel(dialog);
}
});
Rectangle dialogBounds = dialog.getBounds();
Rectangle displayBounds = display.getClientArea();
Rectangle parentBounds = dialog.getParent().getBounds();
//Place it in the center of its parent;
dialogBounds.x = parentBounds.x + ((parentBounds.width - dialogBounds.width) / 2);
dialogBounds.y = parentBounds.y + ((parentBounds.height - dialogBounds.height) / 2);
if (!displayBounds.contains(dialogBounds.x, dialogBounds.y)
|| !displayBounds.contains(
dialogBounds.x + dialogBounds.width,
dialogBounds.y + dialogBounds.height)) {
//Place it in the center of the display if it is not visible
//when placed in the center of its parent;
dialogBounds.x = (displayBounds.width - dialogBounds.width) / 2;
dialogBounds.y = (displayBounds.height - dialogBounds.height) / 2;
}
dialog.setLocation(dialogBounds.x, dialogBounds.y);
/*
table.removeHelpListener(getHelpListener());
table.addHelpListener(new HelpListener() {
public void helpRequested(HelpEvent event) {
// Do nothing
}
});
*/
/* Fetch the key bindings for the forward and backward commands. They will not
* change while the dialog is open, but the context will. Bug 55581.
*/
final IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench()
.getAdapter(IBindingService.class);
if (commandForward != null) {
forwardTriggerSequences = bindingService.getActiveBindingsFor(commandForward);
}
if (commandBackward != null) {
backwardTriggerSequences = bindingService.getActiveBindingsFor(commandBackward);
}
// final IWorkbenchContextSupport contextSupport = page.getWorkbenchWindow().getWorkbench().getContextSupport();
try {
dialog.open();
addMouseListener(table, dialog);
// contextSupport.registerShell(dialog, IWorkbenchContextSupport.TYPE_NONE);
addKeyListener(table, dialog);
addTraverseListener(table);
while (!dialog.isDisposed())
if (!display.readAndDispatch())
display.sleep();
} finally {
if (!dialog.isDisposed())
cancel(dialog);
// contextSupport.unregisterShell(dialog);
}
return selection;
}
private void addItems(Table table, List items) {
TableItem tableItem = null;
for (int i = 0; i < items.size(); ++i) {
Object item = items.get(i);
tableItem = new TableItem(table, SWT.NONE);
tableItem.setText(labelProvider.getText(item));
tableItem.setData(item);
}
}
private void addMouseListener(final Table table, final Shell dialog) {
table.addMouseListener(new MouseListener() {
public void mouseDoubleClick(MouseEvent e) {
ok(dialog, table);
}
public void mouseDown(MouseEvent e) {
ok(dialog, table);
}
public void mouseUp(MouseEvent e) {
ok(dialog, table);
}
});
}
/**
* Adds a listener to the given table that blocks all traversal operations.
*
* @param table
* The table to which the traversal suppression should be added;
* must not be <code>null</code>.
*/
private final void addTraverseListener(final Table table) {
table.addTraverseListener(new TraverseListener() {
/**
* Blocks all key traversal events.
*
* @param event
* The trigger event; must not be <code>null</code>.
*/
public final void keyTraversed(final TraverseEvent event) {
event.doit = false;
}
});
}
private void addKeyListener(final Table table, final Shell dialog) {
table.addKeyListener(new KeyListener() {
private boolean firstKey = true;
private boolean quickReleaseMode = false;
public void keyPressed(KeyEvent e) {
int keyCode = e.keyCode;
char character = e.character;
int accelerator = SWTKeySupport.convertEventToUnmodifiedAccelerator(e);
KeyStroke keyStroke = SWTKeySupport.convertAcceleratorToKeyStroke(accelerator);
//System.out.println("\nPRESSED");
//printKeyEvent(e);
//System.out.println("accelerat:\t" + accelerator + "\t (" +
// KeySupport.formatStroke(Stroke.create(accelerator), true) +
// ")");
boolean acceleratorForward = false;
boolean acceleratorBackward = false;
if (commandForward != null) {
if (forwardTriggerSequences != null) {
final int forwardCount = forwardTriggerSequences.length;
for (int i = 0; i < forwardCount; i++) {
final TriggerSequence triggerSequence = forwardTriggerSequences[i];
// Compare the last key stroke of the binding.
final Trigger[] triggers = triggerSequence.getTriggers();
final int triggersLength = triggers.length;
if ((triggersLength > 0)
&& (triggers[triggersLength - 1].equals(keyStroke))) {
acceleratorForward = true;
break;
}
}
}
}
if (commandBackward != null) {
if (backwardTriggerSequences != null) {
final int backwardCount = backwardTriggerSequences.length;
for (int i = 0; i < backwardCount; i++) {
final TriggerSequence triggerSequence = backwardTriggerSequences[i];
// Compare the last key stroke of the binding.
final Trigger[] triggers = triggerSequence.getTriggers();
final int triggersLength = triggers.length;
if ((triggersLength > 0)
&& (triggers[triggersLength - 1].equals(keyStroke))) {
acceleratorBackward = true;
break;
}
}
}
}
if (character == SWT.CR || character == SWT.LF)
ok(dialog, table);
else if (acceleratorForward) {
if (firstKey && e.stateMask != 0)
quickReleaseMode = true;
int index = table.getSelectionIndex();
table.setSelection((index + 1) % table.getItemCount());
} else if (acceleratorBackward) {
if (firstKey && e.stateMask != 0)
quickReleaseMode = true;
int index = table.getSelectionIndex();
table.setSelection(index >= 1 ? index - 1 : table.getItemCount() - 1);
} else if (
keyCode != SWT.ALT
&& keyCode != SWT.COMMAND
&& keyCode != SWT.CTRL
&& keyCode != SWT.SHIFT
&& keyCode != SWT.ARROW_DOWN
&& keyCode != SWT.ARROW_UP
&& keyCode != SWT.ARROW_LEFT
&& keyCode != SWT.ARROW_RIGHT)
cancel(dialog);
firstKey = false;
}
public void keyReleased(KeyEvent e) {
int keyCode = e.keyCode;
int stateMask = e.stateMask;
//char character = e.character;
//int accelerator = stateMask | (keyCode != 0 ? keyCode :
// convertCharacter(character));
//System.out.println("\nRELEASED");
//printKeyEvent(e);
//System.out.println("accelerat:\t" + accelerator + "\t (" +
// KeySupport.formatStroke(Stroke.create(accelerator), true) +
// ")");
final IPreferencesService service = Platform.getPreferencesService();
final boolean stickyCycle = service.getBoolean(
"org.eclipse.ui.workbench", "STICKY_CYCLE", false, null); //$NON-NLS-1$ //$NON-NLS-2$
if ((!stickyCycle && (firstKey || quickReleaseMode)) && keyCode == stateMask)
ok(dialog, table);
}
});
}
private void cancel(Shell dialog) {
selection = null;
dialog.close();
}
private void ok(Shell dialog, final Table table) {
TableItem[] items = table.getSelection();
if (items != null && items.length == 1)
selection = items[0].getData();
dialog.close();
}
}