mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-04 07:35:24 +02:00
LaunchBar: ui changes in selector
- added ability to filter by typing in selector pop-up - refactored list part of selection in its own components which is kind of list viewer - filter is visible by default if we have more than 7 elements in drop down - filter become visible if user start typing, even if it was not visible originally - moving storing of history size into the list viewer itself - hooked up proper focus support and keyboard traversal - modified CButton so we can re-use it for Edit button of selectors and list items - when filtering is activated history list is no longer available Change-Id: I2057ad658f5a5c9f8fbce203748d26d7e4b14dd6
This commit is contained in:
parent
bb7f665007
commit
edeec7aaaa
9 changed files with 1416 additions and 436 deletions
BIN
bundles/org.eclipse.launchbar.ui/icons/edit_cold.png
Normal file
BIN
bundles/org.eclipse.launchbar.ui/icons/edit_cold.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 574 B |
|
@ -99,7 +99,15 @@ public class Activator extends AbstractUIPlugin {
|
|||
}
|
||||
|
||||
public Image getImage(String id) {
|
||||
return getImageRegistry().get(id);
|
||||
Image im = getImageRegistry().get(id);
|
||||
if (im == null) {
|
||||
ImageDescriptor des = getImageDescriptor(id);
|
||||
if (des != null) {
|
||||
im = des.createImage();
|
||||
getImageRegistry().put(id, im);
|
||||
}
|
||||
}
|
||||
return im;
|
||||
}
|
||||
|
||||
public static ImageDescriptor getImageDescriptor(String path) {
|
||||
|
|
|
@ -10,25 +10,27 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.launchbar.ui.internal.controls;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.MouseAdapter;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.events.MouseTrackAdapter;
|
||||
import org.eclipse.swt.events.PaintEvent;
|
||||
import org.eclipse.swt.events.PaintListener;
|
||||
import org.eclipse.swt.events.SelectionListener;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Canvas;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.TypedListener;
|
||||
|
||||
public class CButton extends Canvas {
|
||||
|
||||
private boolean inButton;
|
||||
private Image hotImage;
|
||||
private Image coldImage;
|
||||
|
||||
|
||||
public CButton(Composite parent, int style) {
|
||||
super(parent, style);
|
||||
|
||||
addPaintListener(new PaintListener() {
|
||||
@Override
|
||||
public void paintControl(PaintEvent e) {
|
||||
|
@ -47,17 +49,28 @@ public class CButton extends Canvas {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
addMouseTrackListener(new MouseTrackAdapter() {
|
||||
@Override
|
||||
public void mouseEnter(MouseEvent e) {
|
||||
inButton = true;
|
||||
redraw();
|
||||
setSelected(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExit(MouseEvent e) {
|
||||
inButton = false;
|
||||
redraw();
|
||||
setSelected(false);
|
||||
}
|
||||
});
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseUp(MouseEvent e) {
|
||||
setSelected(true);
|
||||
handleSelection(inButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDoubleClick(MouseEvent e) {
|
||||
setSelected(true);
|
||||
handleDefaultSelection(inButton);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -65,14 +78,12 @@ public class CButton extends Canvas {
|
|||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
||||
if (hotImage != null)
|
||||
hotImage.dispose();
|
||||
|
||||
if (coldImage != null)
|
||||
coldImage.dispose();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Point computeSize(int wHint, int hHint, boolean changed) {
|
||||
int width = 0;
|
||||
|
@ -91,7 +102,7 @@ public class CButton extends Canvas {
|
|||
}
|
||||
return new Point(width, height);
|
||||
}
|
||||
|
||||
|
||||
public void setHotImage(Image image) {
|
||||
this.hotImage = image;
|
||||
}
|
||||
|
@ -100,4 +111,29 @@ public class CButton extends Canvas {
|
|||
this.coldImage = image;
|
||||
}
|
||||
|
||||
protected void handleSelection(boolean selection) {
|
||||
// Send event
|
||||
notifyListeners(SWT.Selection, null);
|
||||
}
|
||||
|
||||
protected void handleDefaultSelection(boolean selection) {
|
||||
// Send event
|
||||
notifyListeners(SWT.DefaultSelection, null);
|
||||
}
|
||||
|
||||
public void addSelectionListener(SelectionListener listener) {
|
||||
checkWidget();
|
||||
TypedListener typedListener = new TypedListener(listener);
|
||||
addListener(SWT.Selection, typedListener);
|
||||
addListener(SWT.DefaultSelection, typedListener);
|
||||
}
|
||||
|
||||
public void setSelected(boolean sel) {
|
||||
inButton = sel;
|
||||
redraw();
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return inButton;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,52 +10,53 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.launchbar.ui.internal.controls;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.eclipse.jface.layout.GridDataFactory;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
import org.eclipse.jface.layout.GridLayoutFactory;
|
||||
import org.eclipse.jface.viewers.ICellModifier;
|
||||
import org.eclipse.jface.viewers.ILabelProvider;
|
||||
import org.eclipse.jface.viewers.ISelectionChangedListener;
|
||||
import org.eclipse.jface.viewers.IStructuredContentProvider;
|
||||
import org.eclipse.jface.viewers.SelectionChangedEvent;
|
||||
import org.eclipse.jface.viewers.StructuredSelection;
|
||||
import org.eclipse.launchbar.ui.IHoverProvider;
|
||||
import org.eclipse.launchbar.ui.internal.Activator;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.ScrolledComposite;
|
||||
import org.eclipse.swt.events.DisposeEvent;
|
||||
import org.eclipse.swt.events.DisposeListener;
|
||||
import org.eclipse.swt.events.MouseAdapter;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.events.MouseListener;
|
||||
import org.eclipse.swt.events.MouseTrackAdapter;
|
||||
import org.eclipse.swt.events.MouseTrackListener;
|
||||
import org.eclipse.swt.events.PaintEvent;
|
||||
import org.eclipse.swt.events.PaintListener;
|
||||
import org.eclipse.swt.events.TraverseEvent;
|
||||
import org.eclipse.swt.events.TraverseListener;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.LineAttributes;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Canvas;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.swt.widgets.Sash;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
public abstract class CSelector extends Composite {
|
||||
private IStructuredContentProvider contentProvider;
|
||||
private ILabelProvider labelProvider;
|
||||
private IHoverProvider hoverProvider;
|
||||
private Comparator<Object> sorter;
|
||||
private Comparator<?> sorter;
|
||||
private Comparator<?> sorterTop;
|
||||
private Object input;
|
||||
private Composite buttonComposite;
|
||||
private String toolTipText;
|
||||
|
@ -68,19 +69,10 @@ public abstract class CSelector extends Composite {
|
|||
protected final Color highlightColor;
|
||||
protected final Color white;
|
||||
private boolean mouseOver;
|
||||
private Image editImage;
|
||||
private boolean inEditButton;
|
||||
private Image buttonImage;
|
||||
private Label currentIcon;
|
||||
private Label currentLabel;
|
||||
private Shell popup;
|
||||
private ListItem listItems[];
|
||||
private int selIndex;
|
||||
private ScrolledComposite listScrolled;
|
||||
private final int itemH = 30;
|
||||
private int scrollBucket;
|
||||
private final int maxScrollBucket = 7;
|
||||
private int separatorIndex = -1;
|
||||
private LaunchBarListViewer listViewer;
|
||||
private MouseTrackListener mouseTrackListener = new MouseTrackListener() {
|
||||
@Override
|
||||
public void mouseEnter(MouseEvent e) {
|
||||
|
@ -130,43 +122,91 @@ public abstract class CSelector extends Composite {
|
|||
@Override
|
||||
public void mouseUp(MouseEvent event) {
|
||||
if (popup == null || popup.isDisposed()) {
|
||||
setFocus();
|
||||
openPopup();
|
||||
} else {
|
||||
closePopup();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected boolean isFocusAncestor(Control control) {
|
||||
while (control != null && control != this && !(control instanceof Shell)) {
|
||||
control = control.getParent();
|
||||
}
|
||||
return control == this;
|
||||
}
|
||||
private Listener focusOutListener = new Listener() {
|
||||
private Job closingJob;
|
||||
|
||||
@Override
|
||||
public void handleEvent(Event event) {
|
||||
switch (event.type) {
|
||||
case SWT.FocusOut:
|
||||
Control focusControl = getDisplay().getFocusControl();
|
||||
if (focusControl != null && focusControl.getShell() == popup) {
|
||||
Point loc = getDisplay().getCursorLocation();
|
||||
if (!getBounds().contains(toControl(loc))) {
|
||||
// Don't do it if we're in the selector, we'll deal with that later
|
||||
closePopup();
|
||||
}
|
||||
case SWT.FocusIn:
|
||||
if (closingJob != null)
|
||||
closingJob.cancel();
|
||||
if (event.widget instanceof Control && isFocusAncestor((Control) event.widget)) {
|
||||
break; // not closing
|
||||
}
|
||||
if (!isPopUpInFocus()) {
|
||||
closePopup();
|
||||
}
|
||||
break;
|
||||
case SWT.MouseUp:
|
||||
case SWT.FocusOut:
|
||||
if (isPopUpInFocus()) {
|
||||
// we about to loose focus from popup children, but it may go
|
||||
// to another child, lets schedule a job to wait before we close
|
||||
if (closingJob != null)
|
||||
closingJob.cancel();
|
||||
closingJob = new Job("Closing popup") {
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
if (monitor.isCanceled())
|
||||
return Status.CANCEL_STATUS;
|
||||
|
||||
closePopup();
|
||||
closingJob = null;
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
};
|
||||
closingJob.schedule(300);
|
||||
}
|
||||
break;
|
||||
case SWT.MouseUp: {
|
||||
if (popup != null && !popup.isDisposed()) {
|
||||
Point loc = getDisplay().getCursorLocation();
|
||||
if (!popup.getBounds().contains(loc) && !getBounds().contains(toControl(loc))) {
|
||||
if (!popup.getBounds().contains(loc) && !getBounds().contains(getParent().toControl(loc))) {
|
||||
closePopup();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
private ICellModifier modifier = new ICellModifier() {
|
||||
@Override
|
||||
public void modify(Object element, String property, Object value) {
|
||||
handleEdit(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(Object element, String property) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canModify(Object element, String property) {
|
||||
return isEditable(element);
|
||||
}
|
||||
};
|
||||
|
||||
public CSelector(Composite parent, int style) {
|
||||
super(parent, style);
|
||||
backgroundColor = new Color(getDisplay(), new RGB(249, 249, 249));
|
||||
outlineColor = new Color(getDisplay(), new RGB(189, 195, 200));
|
||||
highlightColor = new Color(getDisplay(), new RGB(223, 239, 241));
|
||||
backgroundColor = getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
|
||||
outlineColor = getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
|
||||
highlightColor = getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION);
|
||||
white = getDisplay().getSystemColor(SWT.COLOR_WHITE);
|
||||
GridLayout mainButtonLayout = new GridLayout();
|
||||
setLayout(mainButtonLayout);
|
||||
|
@ -186,16 +226,17 @@ public abstract class CSelector extends Composite {
|
|||
addMouseTrackListener(mouseTrackListener);
|
||||
}
|
||||
|
||||
private boolean isPopUpInFocus() {
|
||||
Control focusControl = getDisplay().getFocusControl();
|
||||
if (focusControl != null && focusControl.getShell() == popup) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
backgroundColor.dispose();
|
||||
outlineColor.dispose();
|
||||
highlightColor.dispose();
|
||||
if (editImage != null)
|
||||
editImage.dispose();
|
||||
if (buttonImage != null)
|
||||
buttonImage.dispose();
|
||||
if (popup != null)
|
||||
popup.dispose();
|
||||
}
|
||||
|
@ -272,11 +313,12 @@ public abstract class CSelector extends Composite {
|
|||
arrow.addMouseListener(mouseListener);
|
||||
arrow.addMouseTrackListener(mouseTrackListener);
|
||||
if (editable) {
|
||||
Control editButton = createEditButton(buttonComposite, element);
|
||||
final EditButton editButton = new EditButton(buttonComposite, SWT.NONE);
|
||||
editButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, true));
|
||||
editButton.setBackground(backgroundColor);
|
||||
editButton.addMouseListener(new MouseAdapter() {
|
||||
editButton.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void mouseUp(MouseEvent e) {
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
// Need to run this after the current event storm
|
||||
// Or we get a disposed error.
|
||||
getDisplay().asyncExec(new Runnable() {
|
||||
|
@ -316,32 +358,25 @@ public abstract class CSelector extends Composite {
|
|||
}
|
||||
popup = new Shell(getShell(), SWT.TOOL | SWT.ON_TOP);
|
||||
popup.setLayout(GridLayoutFactory.fillDefaults().spacing(0, 0).create());
|
||||
listScrolled = new ScrolledComposite(popup, SWT.V_SCROLL | SWT.NO_BACKGROUND);
|
||||
listScrolled.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
listScrolled.setExpandHorizontal(true);
|
||||
final Composite listComp = new Composite(listScrolled, SWT.NONE);
|
||||
listScrolled.setContent(listComp);
|
||||
listComp.setLayout(GridLayoutFactory.fillDefaults().spacing(0, 0).create());
|
||||
if (sorter != null)
|
||||
Arrays.sort(elements, sorter);
|
||||
listItems = new ListItem[elements.length];
|
||||
if (elements.length > 0) {
|
||||
listItems[0] = new ListItem(listComp, SWT.NONE, elements[0], 0);
|
||||
listItems[0].lazyInit();
|
||||
final int hHint = Math.max(listItems[0].computeSize(SWT.DEFAULT, SWT.DEFAULT).y, 16);
|
||||
for (int i = 1; i < elements.length; ++i) {
|
||||
ListItem item = new ListItem(listComp, SWT.NONE, elements[i], i);
|
||||
if (i < maxScrollBucket) { // this is how many visible by default
|
||||
item.lazyInit();
|
||||
} else {
|
||||
((GridData) item.getLayoutData()).heightHint = hHint;
|
||||
|
||||
|
||||
listViewer = new LaunchBarListViewer(popup);
|
||||
initializeListViewer(listViewer);
|
||||
listViewer.setFilterVisible(elements.length > 7);
|
||||
listViewer.setInput(input);
|
||||
listViewer.addSelectionChangedListener(new ISelectionChangedListener() {
|
||||
@Override
|
||||
public void selectionChanged(SelectionChangedEvent event) {
|
||||
if (!listViewer.isFinalSelection())
|
||||
return;
|
||||
StructuredSelection ss = (StructuredSelection) event.getSelection();
|
||||
if (!ss.isEmpty()) {
|
||||
setSelection(ss.getFirstElement());
|
||||
fireSelectionChanged();
|
||||
}
|
||||
listItems[i] = item;
|
||||
closePopup();
|
||||
}
|
||||
createSash(listComp, hHint);
|
||||
}
|
||||
Point listCompSize = listComp.computeSize(SWT.DEFAULT, SWT.DEFAULT);
|
||||
listComp.setSize(listCompSize);
|
||||
});
|
||||
if (hasActionArea())
|
||||
createActionArea(popup);
|
||||
Rectangle buttonBounds = getBounds();
|
||||
|
@ -350,295 +385,53 @@ public abstract class CSelector extends Composite {
|
|||
popup.setLocation(popupLocation.x, popupLocation.y + 5);
|
||||
Point size = popup.computeSize(SWT.DEFAULT, SWT.DEFAULT);
|
||||
Point buttonSize = getSize();
|
||||
size.x = Math.min(size.x + 16, buttonSize.x * 4 / 3);
|
||||
size.y = Math.min(size.y, 250);
|
||||
size.x = Math.max(size.x, buttonSize.x);
|
||||
size.y = Math.min(size.y, 300);
|
||||
popup.setSize(size);
|
||||
popup.setVisible(true);
|
||||
popup.setFocus();
|
||||
getDisplay().addFilter(SWT.FocusIn, focusOutListener);
|
||||
getDisplay().addFilter(SWT.FocusOut, focusOutListener);
|
||||
getDisplay().addFilter(SWT.MouseUp, focusOutListener);
|
||||
popup.addDisposeListener(new DisposeListener() {
|
||||
@Override
|
||||
public void widgetDisposed(DisposeEvent e) {
|
||||
getDisplay().removeFilter(SWT.FocusIn, focusOutListener);
|
||||
getDisplay().removeFilter(SWT.FocusOut, focusOutListener);
|
||||
getDisplay().removeFilter(SWT.MouseUp, focusOutListener);
|
||||
}
|
||||
});
|
||||
selIndex = -1;
|
||||
scrollBucket = 0;
|
||||
if (hoverProvider != null) {
|
||||
hoverProvider.dismissHover(selection != null ? selection : null, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void createSash(final Composite listComp, final int hHint) {
|
||||
if (separatorIndex<0) return;
|
||||
|
||||
final Sash sash = new Sash(listComp, SWT.BORDER | SWT.HORIZONTAL);
|
||||
sash.setLayoutData(GridDataFactory.fillDefaults().create());
|
||||
|
||||
if (separatorIndex < listItems.length)
|
||||
sash.moveAbove(listItems[separatorIndex]);
|
||||
else
|
||||
sash.moveBelow(null);
|
||||
|
||||
sash.addListener(SWT.Selection, new Listener() {
|
||||
@Override
|
||||
public void handleEvent(Event e) {
|
||||
separatorIndex = (e.y + hHint/2) / hHint;
|
||||
}
|
||||
});
|
||||
|
||||
sash.addMouseListener(new MouseListener() {
|
||||
@Override
|
||||
public void mouseUp(MouseEvent e) {
|
||||
setSeparatorIndex(separatorIndex); // call setter if it was overriden
|
||||
if (separatorIndex >= 0) {
|
||||
if (separatorIndex < listItems.length)
|
||||
sash.moveAbove(listItems[separatorIndex]);
|
||||
else
|
||||
sash.moveBelow(null);
|
||||
listComp.layout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDown(MouseEvent e) {
|
||||
sash.moveAbove(null); // keep on top so user see it when moving
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDoubleClick(MouseEvent e) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
|
||||
sash.setToolTipText("Increase/Decrease size of recently used elements pane");
|
||||
protected void initializeListViewer(LaunchBarListViewer listViewer) {
|
||||
listViewer.setContentProvider(contentProvider);
|
||||
listViewer.setLabelProvider(labelProvider);
|
||||
listViewer.setCellModifier(modifier);
|
||||
listViewer.setComparator(sorter);
|
||||
listViewer.setHistoryComparator(sorterTop);
|
||||
}
|
||||
|
||||
private void closePopup() {
|
||||
arrowTransition.to(arrowMax);
|
||||
popup.setVisible(false);
|
||||
getDisplay().asyncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (popup == null || popup.isDisposed())
|
||||
return;
|
||||
arrowTransition.to(arrowMax);
|
||||
popup.setVisible(false);
|
||||
popup.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
TraverseListener listItemTraverseListener = new TraverseListener() {
|
||||
@Override
|
||||
public void keyTraversed(TraverseEvent e) {
|
||||
final ListItem currItem = selIndex >= 0 ? listItems[selIndex] : null;
|
||||
if (currItem == null && e.keyCode != SWT.ARROW_DOWN) {
|
||||
return;
|
||||
}
|
||||
if (e.detail == SWT.TRAVERSE_ARROW_NEXT || e.detail == SWT.TRAVERSE_TAB_NEXT) {
|
||||
if (inEditButton || e.keyCode == SWT.ARROW_DOWN) {
|
||||
int maxIdx = listItems.length - 1;
|
||||
if (selIndex < maxIdx) {
|
||||
inEditButton = false;
|
||||
if (currItem != null)
|
||||
currItem.setBackground(white);
|
||||
// move to next item
|
||||
selIndex++;
|
||||
if (scrollBucket < maxScrollBucket) {
|
||||
scrollBucket++;
|
||||
} else {
|
||||
// need to scroll the list up 1 item
|
||||
int sY = listScrolled.getOrigin().y;
|
||||
listScrolled.setOrigin(0, sY + itemH);
|
||||
}
|
||||
listItems[selIndex].setBackground(highlightColor);
|
||||
} else if (selIndex == maxIdx && maxIdx > maxScrollBucket) {
|
||||
// level the scroll for any offset at the bottom of the list
|
||||
listScrolled.setOrigin(0, itemH * (maxIdx - maxScrollBucket + 1));
|
||||
}
|
||||
} else if (currItem.editButton != null) {
|
||||
// move focus on edit button
|
||||
inEditButton = true;
|
||||
currItem.editButton.redraw();
|
||||
}
|
||||
} else if (e.detail == SWT.TRAVERSE_ARROW_PREVIOUS || e.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
|
||||
if (!inEditButton || e.keyCode == SWT.ARROW_UP) {
|
||||
if (selIndex > 0) {
|
||||
inEditButton = false;
|
||||
currItem.setBackground(white);
|
||||
// move to previous item
|
||||
selIndex--;
|
||||
if (scrollBucket > 0) {
|
||||
scrollBucket--;
|
||||
} else {
|
||||
// need to scroll the list down 1 item
|
||||
int sY = listScrolled.getOrigin().y;
|
||||
listScrolled.setOrigin(0, sY - itemH);
|
||||
}
|
||||
listItems[selIndex].setBackground(highlightColor);
|
||||
} else if (selIndex == 0) {
|
||||
// level any offset @ beginning
|
||||
listScrolled.setOrigin(0, 0);
|
||||
}
|
||||
} else if (currItem.editButton != null) {
|
||||
// remove focus from edit button
|
||||
inEditButton = false;
|
||||
currItem.editButton.redraw();
|
||||
}
|
||||
} else if (e.detail == SWT.TRAVERSE_RETURN) {
|
||||
if (inEditButton) {
|
||||
inEditButton = false;
|
||||
// edit button in list item was pressed
|
||||
getDisplay().asyncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (CSelector.this.selection != null)
|
||||
handleEdit(currItem.element);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// list item was pressed
|
||||
popup.dispose();
|
||||
setSelection(currItem.element);
|
||||
fireSelectionChanged();
|
||||
}
|
||||
} else if (e.detail == SWT.TRAVERSE_ESCAPE) {
|
||||
popup.dispose();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private class ListItem extends Composite {
|
||||
protected final Object element;
|
||||
private Label icon;
|
||||
private Label label;
|
||||
protected Control editButton;
|
||||
private int index;
|
||||
|
||||
public ListItem(Composite parent, int style, Object _element, int index) {
|
||||
super(parent, style);
|
||||
this.element = _element;
|
||||
this.index = index;
|
||||
setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||
addPaintListener(new PaintListener() {
|
||||
@Override
|
||||
public void paintControl(PaintEvent e) {
|
||||
Point size = getSize();
|
||||
GC gc = e.gc;
|
||||
gc.setForeground(outlineColor);
|
||||
gc.drawLine(0, size.y - 1, size.x, size.y - 1);
|
||||
if (label == null)
|
||||
lazyInit();
|
||||
}
|
||||
});
|
||||
// lazyInit();
|
||||
} // end ListItem(..)
|
||||
|
||||
protected void lazyInit() {
|
||||
Image image = labelProvider.getImage(element);
|
||||
boolean editable = isEditable(element);
|
||||
int columns = 1;
|
||||
if (image != null)
|
||||
columns++;
|
||||
if (editable)
|
||||
columns++;
|
||||
GridLayout layout = new GridLayout(columns, false);
|
||||
layout.marginWidth = layout.marginHeight = 7;
|
||||
setLayout(layout);
|
||||
MouseListener listItemMouseListener = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseUp(MouseEvent e) {
|
||||
popup.dispose();
|
||||
setSelection(element);
|
||||
fireSelectionChanged();
|
||||
}
|
||||
};
|
||||
MouseTrackListener listItemMouseTrackListener = new MouseTrackAdapter() {
|
||||
@Override
|
||||
public void mouseEnter(MouseEvent e) {
|
||||
setBackground(highlightColor);
|
||||
int idx = getIndex();
|
||||
if (idx != selIndex) {
|
||||
if (selIndex >= 0) {
|
||||
listItems[selIndex].setBackground(white);
|
||||
scrollBucket = Math.max(Math.min(scrollBucket + idx - selIndex, maxScrollBucket), 0);
|
||||
} else { // initially
|
||||
scrollBucket = Math.min(idx, maxScrollBucket);
|
||||
}
|
||||
}
|
||||
selIndex = idx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExit(MouseEvent e) {
|
||||
setBackground(white);
|
||||
}
|
||||
};
|
||||
addMouseListener(listItemMouseListener);
|
||||
// addMouseTrackListener(listItemMouseTrackListener);
|
||||
if (image != null) {
|
||||
icon = createImage(this, image);
|
||||
icon.addMouseListener(listItemMouseListener);
|
||||
icon.addMouseTrackListener(listItemMouseTrackListener);
|
||||
}
|
||||
label = createLabel(this, element);
|
||||
label.addMouseListener(listItemMouseListener);
|
||||
label.addMouseTrackListener(listItemMouseTrackListener);
|
||||
if (editable) {
|
||||
editButton = createEditButton(this, element);
|
||||
editButton.setBackground(white);
|
||||
editButton.addMouseTrackListener(listItemMouseTrackListener);
|
||||
editButton.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseUp(MouseEvent e) {
|
||||
// Need to run this after the current event storm
|
||||
// Or we get a disposed error.
|
||||
getDisplay().asyncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (CSelector.this.selection != null)
|
||||
handleEdit(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
editButton.addTraverseListener(listItemTraverseListener);
|
||||
} else {
|
||||
addTraverseListener(listItemTraverseListener);
|
||||
}
|
||||
setBackground(white);
|
||||
layout(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(Color color) {
|
||||
super.setBackground(color);
|
||||
if (icon != null && !icon.isDisposed())
|
||||
icon.setBackground(color);
|
||||
if (label != null && !label.isDisposed())
|
||||
label.setBackground(color);
|
||||
if (editButton != null && !editButton.isDisposed())
|
||||
editButton.setBackground(color);
|
||||
}
|
||||
|
||||
public void setImage(Image image) {
|
||||
if (icon != null && !icon.isDisposed())
|
||||
icon.setImage(image);
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
if (!label.isDisposed())
|
||||
label.setText(text);
|
||||
}
|
||||
|
||||
protected int getIndex() {
|
||||
return index;
|
||||
}
|
||||
} // end ListItem class
|
||||
|
||||
private Label createImage(Composite parent, Image image) {
|
||||
Rectangle bounds = image.getBounds();
|
||||
boolean disposeImage = false;
|
||||
if (bounds.height > 16 || bounds.width > 16) {
|
||||
buttonImage = new Image(getDisplay(), 16, 16);
|
||||
Image buttonImage = new Image(getDisplay(), 16, 16);
|
||||
GC gc = new GC(buttonImage);
|
||||
gc.setAntialias(SWT.ON);
|
||||
gc.setInterpolation(SWT.HIGH);
|
||||
|
@ -646,6 +439,7 @@ public abstract class CSelector extends Composite {
|
|||
image.getBounds().height, 0, 0, 16, 16);
|
||||
gc.dispose();
|
||||
image = buttonImage;
|
||||
disposeImage = true;
|
||||
}
|
||||
Label icon = new Label(parent, SWT.NONE);
|
||||
icon.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, true));
|
||||
|
@ -670,43 +464,6 @@ public abstract class CSelector extends Composite {
|
|||
return label;
|
||||
}
|
||||
|
||||
private Control createEditButton(Composite parent, Object element) {
|
||||
if (editImage == null) {
|
||||
editImage = Activator.getImageDescriptor("icons/config_config.png").createImage();
|
||||
}
|
||||
final Canvas editButton = new Canvas(parent, SWT.NONE) {
|
||||
@Override
|
||||
public Point computeSize(int wHint, int hHint, boolean changed) {
|
||||
Rectangle bounds = editImage.getBounds();
|
||||
return new Point(bounds.width, bounds.height);
|
||||
};
|
||||
};
|
||||
editButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, true));
|
||||
editButton.setToolTipText("Edit");
|
||||
editButton.addPaintListener(new PaintListener() {
|
||||
@Override
|
||||
public void paintControl(PaintEvent e) {
|
||||
GC gc = e.gc;
|
||||
gc.setAlpha(inEditButton ? 255 : 64);
|
||||
gc.drawImage(editImage, 0, 0);
|
||||
}
|
||||
});
|
||||
editButton.addMouseTrackListener(new MouseTrackAdapter() {
|
||||
@Override
|
||||
public void mouseEnter(MouseEvent e) {
|
||||
inEditButton = true;
|
||||
editButton.redraw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExit(MouseEvent e) {
|
||||
inEditButton = false;
|
||||
editButton.redraw();
|
||||
}
|
||||
});
|
||||
return editButton;
|
||||
}
|
||||
|
||||
public void setContentProvider(IStructuredContentProvider contentProvider) {
|
||||
this.contentProvider = contentProvider;
|
||||
}
|
||||
|
@ -731,10 +488,24 @@ public abstract class CSelector extends Composite {
|
|||
return hoverProvider;
|
||||
}
|
||||
|
||||
public void setSorter(Comparator<Object> sorter) {
|
||||
/**
|
||||
* Set sorter for the bottom part of the selector
|
||||
*
|
||||
* @param sorter
|
||||
*/
|
||||
public void setSorter(Comparator<?> sorter) {
|
||||
this.sorter = sorter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sorter for the "history" part of the selector
|
||||
*
|
||||
* @param sorter
|
||||
*/
|
||||
public void setHistorySortComparator(Comparator<?> sorter) {
|
||||
this.sorterTop = sorter;
|
||||
}
|
||||
|
||||
public void setInput(Object input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
@ -757,15 +528,7 @@ public abstract class CSelector extends Composite {
|
|||
}
|
||||
}
|
||||
if (popup != null && !popup.isDisposed()) {
|
||||
Object[] elements = contentProvider.getElements(input);
|
||||
int i;
|
||||
for (i = 0; i < elements.length; ++i)
|
||||
if (element == elements[i])
|
||||
break;
|
||||
if (i != elements.length) {
|
||||
listItems[i].setImage(labelProvider.getImage(element));
|
||||
listItems[i].setText(labelProvider.getText(element));
|
||||
}
|
||||
listViewer.update(element, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -785,11 +548,4 @@ public abstract class CSelector extends Composite {
|
|||
// nothing to do here
|
||||
}
|
||||
|
||||
public int getSeparatorIndex() {
|
||||
return separatorIndex;
|
||||
}
|
||||
|
||||
public void setSeparatorIndex(int separatorIndex) {
|
||||
this.separatorIndex = separatorIndex;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.launchbar.ui.internal.controls;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
@ -26,7 +25,6 @@ import org.eclipse.debug.internal.ui.DebugUIPlugin;
|
|||
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchGroupExtension;
|
||||
import org.eclipse.debug.ui.ILaunchGroup;
|
||||
import org.eclipse.jface.dialogs.MessageDialog;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.viewers.ILabelProvider;
|
||||
import org.eclipse.jface.viewers.IStructuredContentProvider;
|
||||
import org.eclipse.jface.viewers.LabelProvider;
|
||||
|
@ -79,27 +77,13 @@ public class ConfigSelector extends CSelector {
|
|||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getElements(Object inputElement) {
|
||||
ILaunchDescriptor[] descs = uiManager.getManager().getLaunchDescriptors();
|
||||
if (descs.length > 0) {
|
||||
int separatorIndex = getSeparatorIndex();
|
||||
if (descs.length > separatorIndex + 1) {
|
||||
ILaunchDescriptor[] descsCopy = new ILaunchDescriptor[separatorIndex + descs.length];
|
||||
System.arraycopy(descs, 0, descsCopy, 0, separatorIndex); // copy first 3 elements
|
||||
System.arraycopy(descs, 0, descsCopy, separatorIndex, descs.length); // copy all into rest
|
||||
// sort rest
|
||||
Arrays.sort(descsCopy, separatorIndex, descsCopy.length, new Comparator<ILaunchDescriptor>() {
|
||||
@Override
|
||||
public int compare(ILaunchDescriptor o1, ILaunchDescriptor o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
return descsCopy;
|
||||
} else
|
||||
return descs;
|
||||
}
|
||||
return noConfigs;
|
||||
if (descs.length == 0)
|
||||
return noConfigs;
|
||||
return descs;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -141,13 +125,23 @@ public class ConfigSelector extends CSelector {
|
|||
return defaultProvider.getText(element);
|
||||
}
|
||||
});
|
||||
// no sorter on view, data is sorted by provider
|
||||
setSorter(null);
|
||||
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
|
||||
int separator = store.getInt(Activator.PREF_LAUNCH_HISTORY_SIZE);
|
||||
if (separator <= 0)
|
||||
separator = 1;
|
||||
setSeparatorIndex(separator);
|
||||
// no sorter for top, data is sorted by provider in historical order
|
||||
setHistorySortComparator(null);
|
||||
// alphabetic sorter
|
||||
setSorter(new Comparator<ILaunchDescriptor>() {
|
||||
@Override
|
||||
public int compare(ILaunchDescriptor o1, ILaunchDescriptor o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeListViewer(LaunchBarListViewer listViewer) {
|
||||
listViewer.setHistorySupported(true);
|
||||
listViewer.setHistoryPreferenceName(Activator.PREF_LAUNCH_HISTORY_SIZE);
|
||||
super.initializeListViewer(listViewer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -162,17 +156,7 @@ public class ConfigSelector extends CSelector {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSeparatorIndex(int separatorIndex) {
|
||||
super.setSeparatorIndex(separatorIndex);
|
||||
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
|
||||
int separator = store.getInt(Activator.PREF_LAUNCH_HISTORY_SIZE);
|
||||
if (separator != getSeparatorIndex()) {
|
||||
store.setValue(Activator.PREF_LAUNCH_HISTORY_SIZE, getSeparatorIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isEditable(Object element) {
|
||||
return element instanceof ILaunchDescriptor;
|
||||
|
@ -233,7 +217,7 @@ public class ConfigSelector extends CSelector {
|
|||
GridLayout buttonLayout = new GridLayout();
|
||||
buttonLayout.marginWidth = buttonLayout.marginHeight = 7;
|
||||
createButton.setLayout(buttonLayout);
|
||||
createButton.setBackground(white);
|
||||
createButton.setBackground(backgroundColor);
|
||||
createButton.addPaintListener(new PaintListener() {
|
||||
@Override
|
||||
public void paintControl(PaintEvent e) {
|
||||
|
@ -247,7 +231,7 @@ public class ConfigSelector extends CSelector {
|
|||
final Label createLabel = new Label(createButton, SWT.None);
|
||||
createLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||
createLabel.setText("Create New Configuration...");
|
||||
createLabel.setBackground(white);
|
||||
createLabel.setBackground(backgroundColor);
|
||||
|
||||
MouseListener mouseListener = new MouseAdapter() {
|
||||
public void mouseUp(org.eclipse.swt.events.MouseEvent e) {
|
||||
|
@ -281,8 +265,8 @@ public class ConfigSelector extends CSelector {
|
|||
}
|
||||
@Override
|
||||
public void mouseExit(MouseEvent e) {
|
||||
createButton.setBackground(white);
|
||||
createLabel.setBackground(white);
|
||||
createButton.setBackground(backgroundColor);
|
||||
createLabel.setBackground(backgroundColor);
|
||||
}
|
||||
};
|
||||
createButton.addMouseTrackListener(mouseTrackListener);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package org.eclipse.launchbar.ui.internal.controls;
|
||||
|
||||
import org.eclipse.launchbar.ui.internal.Activator;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
|
||||
public class EditButton extends CButton {
|
||||
public EditButton(Composite parent, int style) {
|
||||
super(parent, style);
|
||||
setHotImage(Activator.getDefault().getImage("icons/config_config.png"));
|
||||
setColdImage(Activator.getDefault().getImage("icons/edit_cold.png"));
|
||||
setToolTipText("Edit");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,472 @@
|
|||
package org.eclipse.launchbar.ui.internal.controls;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
import org.eclipse.jface.layout.GridDataFactory;
|
||||
import org.eclipse.jface.layout.GridLayoutFactory;
|
||||
import org.eclipse.jface.viewers.ILabelProvider;
|
||||
import org.eclipse.jface.viewers.StructuredSelection;
|
||||
import org.eclipse.jface.viewers.Viewer;
|
||||
import org.eclipse.jface.viewers.ViewerFilter;
|
||||
import org.eclipse.osgi.util.NLS;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.accessibility.AccessibleAdapter;
|
||||
import org.eclipse.swt.accessibility.AccessibleEvent;
|
||||
import org.eclipse.swt.events.DisposeEvent;
|
||||
import org.eclipse.swt.events.DisposeListener;
|
||||
import org.eclipse.swt.events.FocusAdapter;
|
||||
import org.eclipse.swt.events.FocusEvent;
|
||||
import org.eclipse.swt.events.ModifyEvent;
|
||||
import org.eclipse.swt.events.ModifyListener;
|
||||
import org.eclipse.swt.events.MouseAdapter;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.events.TraverseEvent;
|
||||
import org.eclipse.swt.events.TraverseListener;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
import org.eclipse.ui.internal.WorkbenchMessages;
|
||||
import org.eclipse.ui.progress.WorkbenchJob;
|
||||
|
||||
/**
|
||||
* A simple control that provides a text widget and controls a list viewer
|
||||
*/
|
||||
public class FilterControl extends Composite {
|
||||
/**
|
||||
* The filter text widget to be used by this tree. This value may be <code>null</code> if there is no filter widget, or if the
|
||||
* controls have not yet been created.
|
||||
*/
|
||||
protected Text filterText;
|
||||
/**
|
||||
* The viewer for the filtered tree. This value should never be <code>null</code> after the widget creation methods are
|
||||
* complete.
|
||||
*/
|
||||
protected LaunchBarListViewer listViewer;
|
||||
|
||||
protected ViewerFilter patternFilter;
|
||||
/**
|
||||
* The text to initially show in the filter text control.
|
||||
*/
|
||||
protected String initialText = ""; //$NON-NLS-1$
|
||||
protected String patternText = null;
|
||||
/**
|
||||
* The job used to refresh the tree.
|
||||
*/
|
||||
private Job refreshJob;
|
||||
/**
|
||||
* The parent composite this control.
|
||||
*/
|
||||
protected Composite parent;
|
||||
|
||||
/**
|
||||
* Creates a filter control, to be fully function attachListViewer must be called shortly after
|
||||
*
|
||||
* @param parent
|
||||
*/
|
||||
public FilterControl(Composite parent) {
|
||||
super(parent, SWT.NONE);
|
||||
this.parent = parent;
|
||||
patternFilter = new ViewerFilter() {
|
||||
@Override
|
||||
public boolean select(Viewer viewer, Object parentElement, Object element) {
|
||||
String text = ((ILabelProvider) listViewer.getLabelProvider()).getText(element);
|
||||
if (patternText == null)
|
||||
return true;
|
||||
String trim = patternText.trim();
|
||||
if (trim.isEmpty())
|
||||
return true;
|
||||
if (text == null)
|
||||
return false;
|
||||
if (text.contains(trim))
|
||||
return true;
|
||||
if (text.toLowerCase().contains(trim.toLowerCase()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the filtered list.
|
||||
*/
|
||||
protected void init() {
|
||||
createControl(this, SWT.NONE);
|
||||
createRefreshJob();
|
||||
setInitialText(WorkbenchMessages.FilteredTree_FilterMessage);
|
||||
setFont(parent.getFont());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the filtered tree's controls. Subclasses should override.
|
||||
*
|
||||
* @param parent
|
||||
* @param treeStyle
|
||||
*/
|
||||
protected void createControl(Composite parent, int treeStyle) {
|
||||
setLayout(GridLayoutFactory.fillDefaults().spacing(0, 0).create());
|
||||
if (parent.getLayout() instanceof GridLayout) {
|
||||
setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
|
||||
}
|
||||
Composite fc = createFilterControls(parent);
|
||||
fc.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the filter controls. By default, a text and corresponding tool bar button that clears the contents of the text is
|
||||
* created. Subclasses may override.
|
||||
*
|
||||
* @param parent
|
||||
* parent <code>Composite</code> of the filter controls
|
||||
* @return the <code>Composite</code> that contains the filter controls
|
||||
*/
|
||||
protected Composite createFilterControls(Composite parent) {
|
||||
createFilterText(parent);
|
||||
return parent;
|
||||
}
|
||||
|
||||
public Control attachListViewer(LaunchBarListViewer listViewer) {
|
||||
this.listViewer = listViewer;
|
||||
// listViewer.getControl().setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
|
||||
listViewer.getControl().addDisposeListener(new DisposeListener() {
|
||||
@Override
|
||||
public void widgetDisposed(DisposeEvent e) {
|
||||
refreshJob.cancel();
|
||||
}
|
||||
});
|
||||
listViewer.addFilter(patternFilter);
|
||||
return listViewer.getControl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the refresh job for the receiver.
|
||||
*
|
||||
*/
|
||||
private void createRefreshJob() {
|
||||
refreshJob = doCreateRefreshJob();
|
||||
refreshJob.setSystem(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
boolean oldVisible = getVisible();
|
||||
if (oldVisible == true && visible == false && listViewer != null && filterText.isFocusControl()) {
|
||||
listViewer.setFocus();
|
||||
}
|
||||
if (getLayoutData() instanceof GridData) {
|
||||
((GridData) getLayoutData()).heightHint = visible ? SWT.DEFAULT : 0;
|
||||
}
|
||||
super.setVisible(visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a workbench job that will refresh the tree based on the current filter text. Subclasses may override.
|
||||
*
|
||||
* @return a workbench job that can be scheduled to refresh the tree
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
protected WorkbenchJob doCreateRefreshJob() {
|
||||
return new WorkbenchJob("Refresh Filter") {//$NON-NLS-1$
|
||||
@Override
|
||||
public IStatus runInUIThread(IProgressMonitor monitor) {
|
||||
if (listViewer == null)
|
||||
return Status.CANCEL_STATUS;
|
||||
if (listViewer.getControl().isDisposed()) {
|
||||
return Status.CANCEL_STATUS;
|
||||
}
|
||||
updatePatternText();
|
||||
if (patternText == null) {
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
Control redrawControl = listViewer.getControl();
|
||||
try {
|
||||
// don't want the user to see updates that will be made to
|
||||
// the tree
|
||||
// we are setting redraw(false) on the composite to avoid
|
||||
// dancing scrollbar
|
||||
redrawControl.setRedraw(false);
|
||||
listViewer.setHistorySupported(patternText == null || patternText.isEmpty());
|
||||
listViewer.refresh(true);
|
||||
updateListSelection(false);
|
||||
} finally {
|
||||
redrawControl.setRedraw(true);
|
||||
}
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the filter text and adds listeners. This method calls {@link #doCreateFilterText(Composite)} to create the text
|
||||
* control. Subclasses should override {@link #doCreateFilterText(Composite)} instead of overriding this method.
|
||||
*
|
||||
* @param parent
|
||||
* <code>Composite</code> of the filter text
|
||||
*/
|
||||
protected void createFilterText(Composite parent) {
|
||||
filterText = doCreateFilterText(parent);
|
||||
filterText.getAccessible().addAccessibleListener(
|
||||
new AccessibleAdapter() {
|
||||
@Override
|
||||
public void getName(AccessibleEvent e) {
|
||||
String filterTextString = filterText.getText();
|
||||
if (filterTextString.length() == 0
|
||||
|| filterTextString.equals(initialText)) {
|
||||
e.result = initialText;
|
||||
} else {
|
||||
e.result = NLS.bind(
|
||||
WorkbenchMessages.FilteredTree_AccessibleListenerFiltered,
|
||||
new String[] {
|
||||
filterTextString,
|
||||
String.valueOf(getFilteredItemsCount()) });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of filtered items
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private int getFilteredItemsCount() {
|
||||
return listViewer.getItemCount();
|
||||
}
|
||||
});
|
||||
filterText.addFocusListener(new FocusAdapter() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
if (filterText.getText().equals(initialText)) {
|
||||
setFilterText(""); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
});
|
||||
filterText.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseDown(MouseEvent e) {
|
||||
if (filterText.getText().equals(initialText)) {
|
||||
clearText();
|
||||
}
|
||||
}
|
||||
});
|
||||
// enter key set focus to tree
|
||||
filterText.addTraverseListener(new TraverseListener() {
|
||||
@Override
|
||||
public void keyTraversed(TraverseEvent e) {
|
||||
if (e.detail == SWT.TRAVERSE_RETURN) {
|
||||
e.doit = false;
|
||||
listViewer.setFocus();
|
||||
updateListSelection(true);
|
||||
} else if (e.detail == SWT.TRAVERSE_ARROW_NEXT) {
|
||||
listViewer.setFocus();
|
||||
updateListSelection(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
filterText.addModifyListener(new ModifyListener() {
|
||||
@Override
|
||||
public void modifyText(ModifyEvent e) {
|
||||
textChanged();
|
||||
}
|
||||
});
|
||||
// if we're using a field with built in cancel we need to listen for
|
||||
// default selection changes (which tell us the cancel button has been
|
||||
// pressed)
|
||||
if ((filterText.getStyle() & SWT.ICON_CANCEL) != 0) {
|
||||
filterText.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetDefaultSelected(SelectionEvent e) {
|
||||
if (e.detail == SWT.ICON_CANCEL)
|
||||
clearText();
|
||||
}
|
||||
});
|
||||
}
|
||||
filterText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
|
||||
}
|
||||
|
||||
protected void updateListSelection(boolean enter) {
|
||||
if (listViewer.getItemCount() == 0) {
|
||||
if (enter)
|
||||
Display.getCurrent().beep();
|
||||
} else {
|
||||
StructuredSelection sel;
|
||||
// if the initial filter text hasn't changed, do not try to match
|
||||
if (patternText != null && !patternText.trim().isEmpty()) {
|
||||
// select item with triggering event, it may close the popup if list used as combo
|
||||
sel = new StructuredSelection(listViewer.getTopFilteredElement());
|
||||
} else {
|
||||
sel = new StructuredSelection(listViewer.getTopElement());
|
||||
}
|
||||
if (enter)
|
||||
listViewer.setDefaultSelection(sel);
|
||||
else
|
||||
listViewer.setSelection(sel);
|
||||
}
|
||||
}
|
||||
|
||||
protected Text doCreateFilterText(Composite parent) {
|
||||
return new Text(parent, SWT.SINGLE | SWT.BORDER | SWT.SEARCH
|
||||
| SWT.ICON_CANCEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the receiver after the text has changed.
|
||||
*/
|
||||
protected void textChanged() {
|
||||
String old = patternText;
|
||||
updatePatternText();
|
||||
if (patternText != null && old == null && patternText.isEmpty())
|
||||
return;// we changing from initial selection to empty string
|
||||
if (patternText == old)
|
||||
return;
|
||||
// cancel currently running job first, to prevent unnecessary redraw
|
||||
refreshJob.cancel();
|
||||
refreshJob.schedule(getRefreshJobDelay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time delay that should be used when scheduling the filter refresh job. Subclasses may override.
|
||||
*
|
||||
* @return a time delay in milliseconds before the job should run
|
||||
*
|
||||
*/
|
||||
protected long getRefreshJobDelay() {
|
||||
return 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the background for the widgets that support the filter text area.
|
||||
*
|
||||
* @param background
|
||||
* background <code>Color</code> to set
|
||||
*/
|
||||
@Override
|
||||
public void setBackground(Color background) {
|
||||
super.setBackground(background);
|
||||
// listComposite.setBackground(background);
|
||||
// filterText.setBackground(background);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the text in the filter text widget.
|
||||
*/
|
||||
protected void clearText() {
|
||||
setFilterText(""); //$NON-NLS-1$
|
||||
// textChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text in the filter control.
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
protected void setFilterText(String string) {
|
||||
if (filterText != null) {
|
||||
filterText.setText(string);
|
||||
selectAll();
|
||||
}
|
||||
}
|
||||
|
||||
public Text getFilterText() {
|
||||
return filterText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tree viewer of the receiver.
|
||||
*
|
||||
* @return the tree viewer
|
||||
*/
|
||||
public LaunchBarListViewer getViewer() {
|
||||
return listViewer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter text for the receiver, if it was created. Otherwise return <code>null</code>.
|
||||
*
|
||||
* @return the filter Text, or null if it was not created
|
||||
*/
|
||||
public Text getFilterControl() {
|
||||
return filterText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to return the text of the filter control. If the text widget is not created, then null is returned.
|
||||
*
|
||||
* @return String in the text, or null if the text does not exist
|
||||
*/
|
||||
protected String getFilterString() {
|
||||
return filterText != null ? filterText.getText() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text that will be shown until the first focus. A default value is provided, so this method only need be called if
|
||||
* overriding the default initial text is desired.
|
||||
*
|
||||
* @param text
|
||||
* initial text to appear in text field
|
||||
*/
|
||||
public void setInitialText(String text) {
|
||||
initialText = text;
|
||||
if (filterText != null) {
|
||||
filterText.setMessage(text);
|
||||
if (filterText.isFocusControl()) {
|
||||
setFilterText(initialText);
|
||||
textChanged();
|
||||
} else {
|
||||
getDisplay().asyncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!filterText.isDisposed() && filterText.isFocusControl()) {
|
||||
setFilterText(initialText);
|
||||
textChanged();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setFilterText(initialText);
|
||||
textChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select all text in the filter text field.
|
||||
*
|
||||
*/
|
||||
protected void selectAll() {
|
||||
if (filterText != null) {
|
||||
filterText.selectAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the initial text for the receiver.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
protected String getInitialText() {
|
||||
return initialText;
|
||||
}
|
||||
|
||||
private void updatePatternText() {
|
||||
String text = getFilterString();
|
||||
boolean initial = initialText != null
|
||||
&& initialText.equals(text);
|
||||
if (initial) {
|
||||
patternText = null;
|
||||
} else if (text != null) {
|
||||
patternText = text;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,711 @@
|
|||
package org.eclipse.launchbar.ui.internal.controls;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jface.layout.GridDataFactory;
|
||||
import org.eclipse.jface.layout.GridLayoutFactory;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.viewers.ArrayContentProvider;
|
||||
import org.eclipse.jface.viewers.ICellModifier;
|
||||
import org.eclipse.jface.viewers.IFontProvider;
|
||||
import org.eclipse.jface.viewers.ILabelProvider;
|
||||
import org.eclipse.jface.viewers.IStructuredContentProvider;
|
||||
import org.eclipse.jface.viewers.LabelProvider;
|
||||
import org.eclipse.jface.viewers.StructuredSelection;
|
||||
import org.eclipse.jface.viewers.StructuredViewer;
|
||||
import org.eclipse.jface.viewers.Viewer;
|
||||
import org.eclipse.jface.viewers.ViewerComparator;
|
||||
import org.eclipse.jface.viewers.ViewerFilter;
|
||||
import org.eclipse.launchbar.core.ILaunchDescriptor;
|
||||
import org.eclipse.launchbar.ui.internal.Activator;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.ScrolledComposite;
|
||||
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.MouseAdapter;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.events.MouseListener;
|
||||
import org.eclipse.swt.events.MouseTrackAdapter;
|
||||
import org.eclipse.swt.events.MouseTrackListener;
|
||||
import org.eclipse.swt.events.PaintEvent;
|
||||
import org.eclipse.swt.events.PaintListener;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.events.TraverseEvent;
|
||||
import org.eclipse.swt.events.TraverseListener;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.layout.RowLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.swt.widgets.Sash;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Widget;
|
||||
|
||||
public class LaunchBarListViewer extends StructuredViewer {
|
||||
private ScrolledComposite listScrolled;
|
||||
private Composite listComposite;
|
||||
private ListItem[] listItems;
|
||||
private int selIndex;
|
||||
private int itemH = 30;
|
||||
private int scrollBucket;
|
||||
private final int maxScrollBucket = 6;
|
||||
private int separatorIndex = -1;
|
||||
private boolean historySupported = true;
|
||||
private ICellModifier modifier;
|
||||
private ViewerComparator historyComparator;
|
||||
private boolean finalSelection = false;
|
||||
private FilterControl filterControl;
|
||||
private Sash sash;
|
||||
private String historyPref;
|
||||
|
||||
private static class LaunchBarListViewerComparator extends ViewerComparator {
|
||||
public LaunchBarListViewerComparator(Comparator<?> comp) {
|
||||
super(comp);
|
||||
}
|
||||
|
||||
// have to override it because standard ViewerComparator compares by labels only
|
||||
@Override
|
||||
public int compare(Viewer viewer, Object e1, Object e2) {
|
||||
return getComparator().compare(e1, e2);
|
||||
}
|
||||
}
|
||||
private TraverseListener listItemTraverseListener = new TraverseListener() {
|
||||
@Override
|
||||
public void keyTraversed(TraverseEvent e) {
|
||||
final ListItem currItem = selIndex >= 0 ? listItems[selIndex] : null;
|
||||
if (currItem == null && e.keyCode != SWT.ARROW_DOWN) {
|
||||
return;
|
||||
}
|
||||
if (e.detail == SWT.TRAVERSE_ARROW_NEXT || e.detail == SWT.TRAVERSE_TAB_NEXT) {
|
||||
if (e.keyCode == SWT.ARROW_DOWN) {
|
||||
int maxIdx = listItems.length - 1;
|
||||
if (selIndex < maxIdx) {
|
||||
// move to next item
|
||||
listItems[selIndex + 1].setSelected(true);
|
||||
if (scrollBucket < maxScrollBucket) {
|
||||
scrollBucket++;
|
||||
} else {
|
||||
// need to scroll the list up 1 item
|
||||
int sY = listScrolled.getOrigin().y;
|
||||
listScrolled.setOrigin(0, sY + itemH);
|
||||
}
|
||||
} else if (selIndex == maxIdx && maxIdx > maxScrollBucket) {
|
||||
// level the scroll for any offset at the bottom of the list
|
||||
listScrolled.setOrigin(0, itemH * (maxIdx - maxScrollBucket + 1));
|
||||
}
|
||||
}
|
||||
} else if (e.detail == SWT.TRAVERSE_ARROW_PREVIOUS || e.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
|
||||
if (e.keyCode == SWT.ARROW_UP) {
|
||||
if (selIndex > 0) {
|
||||
// move to previous item
|
||||
if (scrollBucket > 0) {
|
||||
scrollBucket--;
|
||||
} else {
|
||||
// need to scroll the list down 1 item
|
||||
int sY = listScrolled.getOrigin().y;
|
||||
listScrolled.setOrigin(0, sY - itemH);
|
||||
}
|
||||
listItems[selIndex - 1].setSelected(true);
|
||||
} else if (selIndex == 0) {
|
||||
// level any offset @ beginning
|
||||
listScrolled.setOrigin(0, 0);
|
||||
}
|
||||
} else if (currItem.editButton != null) {
|
||||
// remove focus from edit button
|
||||
currItem.editButton.setSelected(false);
|
||||
currItem.editButton.redraw();
|
||||
}
|
||||
} else if (e.detail == SWT.TRAVERSE_RETURN) {
|
||||
setDefaultSelection(new StructuredSelection(currItem.element));
|
||||
} else if (e.detail == SWT.TRAVERSE_ESCAPE) {
|
||||
setDefaultSelection(new StructuredSelection());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
private class ListItem extends Composite {
|
||||
protected final Object element;
|
||||
private Label icon;
|
||||
private Label label;
|
||||
protected EditButton editButton;
|
||||
private int index;
|
||||
private Color backgroundColor = getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
|
||||
private Color outlineColor = getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
|
||||
private Color highlightColor = getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION);
|
||||
private ILabelProvider labelProvider;
|
||||
private ICellModifier modifer;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + index + "] " + labelProvider.getText(element);
|
||||
}
|
||||
public ListItem(Composite parent, int style, Object element, int index, ILabelProvider labelProvider,
|
||||
ICellModifier modifier) {
|
||||
super(parent, style);
|
||||
this.element = element;
|
||||
this.index = index;
|
||||
this.labelProvider = labelProvider;
|
||||
this.modifer = modifier;
|
||||
setData(element);
|
||||
addPaintListener(new PaintListener() {
|
||||
@Override
|
||||
public void paintControl(PaintEvent e) {
|
||||
Point size = getSize();
|
||||
GC gc = e.gc;
|
||||
gc.setForeground(outlineColor);
|
||||
gc.drawLine(0, size.y - 1, size.x, size.y - 1);
|
||||
if (label == null)
|
||||
lazyInit();
|
||||
}
|
||||
});
|
||||
// lazyInit();
|
||||
} // end ListItem(..)
|
||||
|
||||
protected void lazyInit() {
|
||||
Image image = labelProvider.getImage(element);
|
||||
boolean editable = isEditable(element);
|
||||
int columns = 1;
|
||||
if (image != null)
|
||||
columns++;
|
||||
if (editable)
|
||||
columns++;
|
||||
GridLayout layout = new GridLayout(columns, false);
|
||||
layout.marginWidth = layout.marginHeight = 7;
|
||||
setLayout(layout);
|
||||
MouseListener listItemMouseListener = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseUp(MouseEvent e) {
|
||||
setDefaultSelection(new StructuredSelection(element));
|
||||
}
|
||||
};
|
||||
MouseTrackListener listItemMouseTrackListener = new MouseTrackAdapter() {
|
||||
@Override
|
||||
public void mouseEnter(MouseEvent e) {
|
||||
setSelected(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExit(MouseEvent e) {
|
||||
setSelected(false);
|
||||
}
|
||||
};
|
||||
addMouseListener(listItemMouseListener);
|
||||
addMouseTrackListener(listItemMouseTrackListener);
|
||||
if (image != null) {
|
||||
icon = createImage(this, image);
|
||||
icon.addMouseListener(listItemMouseListener);
|
||||
icon.addMouseTrackListener(listItemMouseTrackListener);
|
||||
}
|
||||
label = createLabel(this, element);
|
||||
label.addMouseListener(listItemMouseListener);
|
||||
label.addMouseTrackListener(listItemMouseTrackListener);
|
||||
if (editable) {
|
||||
editButton = new EditButton(this, SWT.NONE);
|
||||
editButton.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
// Need to run this after the current event storm
|
||||
// Or we get a disposed error.
|
||||
getDisplay().asyncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (editButton.isSelected())
|
||||
handleEdit(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
editButton.setBackground(backgroundColor);
|
||||
editButton.addMouseTrackListener(listItemMouseTrackListener);
|
||||
editButton.addTraverseListener(listItemTraverseListener);
|
||||
} else {
|
||||
// add traverse listnener to control which will have keyboard focus
|
||||
addTraverseListener(listItemTraverseListener);
|
||||
}
|
||||
addKeyListener(new KeyListener() {
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.character != 0 && !filterControl.isVisible()) {
|
||||
// enable filter control and send the character there
|
||||
filterControl.setVisible(true);
|
||||
filterControl.setFocus();
|
||||
filterControl.getParent().layout(true);
|
||||
filterControl.getFilterText().setText(e.character + "");
|
||||
filterControl.getFilterText().setSelection(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
setBackground(backgroundColor);
|
||||
layout(true);
|
||||
}
|
||||
|
||||
public void setSelected(boolean selected) {
|
||||
if (selected) {
|
||||
setBackground(highlightColor);
|
||||
int idx = getIndex();
|
||||
if (idx != selIndex) {
|
||||
if (selIndex >= 0) {
|
||||
listItems[selIndex].setBackground(backgroundColor);
|
||||
scrollBucket = Math.max(Math.min(scrollBucket + idx - selIndex, maxScrollBucket), 0);
|
||||
} else { // initially
|
||||
scrollBucket = Math.min(idx, maxScrollBucket);
|
||||
}
|
||||
}
|
||||
selIndex = idx;
|
||||
} else {
|
||||
setBackground(backgroundColor);
|
||||
}
|
||||
if (editButton != null) {
|
||||
editButton.setSelected(selected);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isEditable(Object element) {
|
||||
if (modifer != null) {
|
||||
return modifer.canModify(element, null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void handleEdit(Object element) {
|
||||
if (modifer != null) {
|
||||
modifer.modify(element, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(Color color) {
|
||||
super.setBackground(color);
|
||||
if (icon != null && !icon.isDisposed())
|
||||
icon.setBackground(color);
|
||||
if (label != null && !label.isDisposed())
|
||||
label.setBackground(color);
|
||||
if (editButton != null && !editButton.isDisposed())
|
||||
editButton.setBackground(color);
|
||||
}
|
||||
|
||||
public void setImage(Image image) {
|
||||
if (icon != null && !icon.isDisposed())
|
||||
icon.setImage(image);
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
if (!label.isDisposed())
|
||||
label.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setFocus() {
|
||||
super.setFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
private Label createImage(Composite parent, Image image) {
|
||||
Rectangle bounds = image.getBounds();
|
||||
boolean disposeImage = false;
|
||||
if (bounds.height > 16 || bounds.width > 16) {
|
||||
Image buttonImage = new Image(getDisplay(), 16, 16);
|
||||
GC gc = new GC(buttonImage);
|
||||
gc.setAntialias(SWT.ON);
|
||||
gc.setInterpolation(SWT.HIGH);
|
||||
// resize to 16 pixels
|
||||
gc.drawImage(image, 0, 0, image.getBounds().width,
|
||||
image.getBounds().height, 0, 0, 16, 16);
|
||||
gc.dispose();
|
||||
image = buttonImage;
|
||||
disposeImage = true;
|
||||
}
|
||||
Label icon = new Label(parent, SWT.NONE);
|
||||
icon.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, true));
|
||||
icon.setImage(image);
|
||||
if (disposeImage) {
|
||||
final Image disposableImage = image;
|
||||
icon.addDisposeListener(new DisposeListener() {
|
||||
@Override
|
||||
public void widgetDisposed(DisposeEvent e) {
|
||||
disposableImage.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
private Label createLabel(Composite parent, Object element) {
|
||||
Label label = new Label(parent, SWT.NONE);
|
||||
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
|
||||
ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();
|
||||
label.setText(labelProvider.getText(element));
|
||||
if (labelProvider instanceof IFontProvider) {
|
||||
label.setFont(((IFontProvider) labelProvider).getFont(element));
|
||||
}
|
||||
return label;
|
||||
}
|
||||
} // end ListItem class
|
||||
|
||||
public LaunchBarListViewer(Composite parent) {
|
||||
filterControl = new FilterControl(parent);
|
||||
listScrolled = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.NO_BACKGROUND);
|
||||
listScrolled.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
listScrolled.setExpandHorizontal(true);
|
||||
listComposite = new Composite(listScrolled, SWT.NONE);
|
||||
listScrolled.setContent(listComposite);
|
||||
listComposite.setLayout(GridLayoutFactory.fillDefaults().spacing(0, 0).create());
|
||||
selIndex = -1;
|
||||
scrollBucket = 0;
|
||||
filterControl.attachListViewer(this);
|
||||
historySupported = false;
|
||||
setHistoryPreferenceName(getHistoryPreferenceName());
|
||||
}
|
||||
|
||||
private void createSash(final Composite listComp) {
|
||||
if (separatorIndex < 0 || !historySupported)
|
||||
return;
|
||||
sash = new Sash(listComp, SWT.BORDER | SWT.HORIZONTAL);
|
||||
sash.setLayoutData(GridDataFactory.fillDefaults().create());
|
||||
if (separatorIndex < listItems.length)
|
||||
sash.moveAbove(listItems[separatorIndex]);
|
||||
else
|
||||
sash.moveBelow(null);
|
||||
sash.addListener(SWT.Selection, new Listener() {
|
||||
@Override
|
||||
public void handleEvent(Event e) {
|
||||
separatorIndex = (e.y + itemH / 2) / itemH;
|
||||
}
|
||||
});
|
||||
sash.addMouseListener(new MouseListener() {
|
||||
@Override
|
||||
public void mouseUp(MouseEvent e) {
|
||||
setSeparatorIndex(separatorIndex); // call setter if it was overriden
|
||||
if (separatorIndex >= 0) {
|
||||
if (separatorIndex < listItems.length)
|
||||
sash.moveAbove(listItems[separatorIndex]);
|
||||
else
|
||||
sash.moveBelow(null);
|
||||
listComp.layout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDown(MouseEvent e) {
|
||||
sash.moveAbove(null); // keep on top so user see it when moving
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDoubleClick(MouseEvent e) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
sash.setToolTipText("Increase/Decrease size of recently used elements pane");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Control getControl() {
|
||||
return listScrolled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void inputChanged(Object input, Object oldInput) {
|
||||
super.inputChanged(input, oldInput);
|
||||
refreshAll();
|
||||
}
|
||||
|
||||
protected void refreshAll() {
|
||||
selIndex = -1;
|
||||
Control[] children = listComposite.getChildren();
|
||||
for (Control control : children) {
|
||||
control.dispose();
|
||||
}
|
||||
Object[] origElements = getElements();
|
||||
Object[] elements = filterElements(origElements);
|
||||
listItems = new ListItem[elements.length];
|
||||
if (elements.length > 0) {
|
||||
listItems[0] = createListItem(elements, 0);
|
||||
itemH = Math.max(listItems[0].computeSize(SWT.DEFAULT, SWT.DEFAULT).y, 16);
|
||||
for (int i = 1; i < elements.length; ++i) {
|
||||
listItems[i] = createListItem(elements, i);
|
||||
}
|
||||
createSash(listComposite);
|
||||
}
|
||||
listComposite.pack(true);
|
||||
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||
if (elements.length > maxScrollBucket) {
|
||||
Rectangle bounds = listItems[maxScrollBucket].getBounds();
|
||||
gd.heightHint = Math.max(bounds.y + bounds.height, itemH * (maxScrollBucket + 1));
|
||||
}
|
||||
listScrolled.setLayoutData(gd);
|
||||
listScrolled.layout(true);
|
||||
}
|
||||
|
||||
private ListItem createListItem(Object[] elements, int i) {
|
||||
ListItem item = new ListItem(listComposite, SWT.NONE, elements[i], i, (ILabelProvider) getLabelProvider(), modifier);
|
||||
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false);
|
||||
item.setLayoutData(gd);
|
||||
if (i <= maxScrollBucket) { // this is how many visible by default
|
||||
item.lazyInit();
|
||||
} else {
|
||||
gd.heightHint = itemH;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget doFindInputItem(Object element) {
|
||||
return doFindItem(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget doFindItem(Object element) {
|
||||
if (listItems == null)
|
||||
return null;
|
||||
for (ListItem listItem : listItems) {
|
||||
if (listItem.element.equals(element))
|
||||
return listItem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doUpdateItem(Widget item, Object element, boolean fullMap) {
|
||||
if (item instanceof ListItem) {
|
||||
((ListItem) item).lazyInit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List getSelectionFromWidget() {
|
||||
ArrayList<Object> arrayList = new ArrayList<>();
|
||||
if (selIndex >= 0)
|
||||
arrayList.add(listItems[selIndex].element);
|
||||
return arrayList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void internalRefresh(Object element) {
|
||||
if (element == null || element == getRoot()) {
|
||||
refreshAll();
|
||||
return;
|
||||
}
|
||||
ListItem item = (ListItem) doFindItem(element);
|
||||
ILabelProvider lp = (ILabelProvider) getLabelProvider();
|
||||
if (lp == null || item == null)
|
||||
return;
|
||||
item.setImage(lp.getImage(element));
|
||||
item.setText(lp.getText(element));
|
||||
}
|
||||
|
||||
private Object[] filterElements(Object[] elements) {
|
||||
Object[] topElements = elements.clone();
|
||||
if (getComparator() != null)
|
||||
getComparator().sort(this, elements);
|
||||
if (getTopComparator() != null)
|
||||
getTopComparator().sort(this, topElements);
|
||||
// only bottom part will be filtered
|
||||
Object[] result = elements;
|
||||
if (getFilters() != null) {
|
||||
for (ViewerFilter f : getFilters()) {
|
||||
result = f.filter(this, (Object) null, result);
|
||||
}
|
||||
}
|
||||
if (separatorIndex <= 0 || !historySupported)
|
||||
return result;
|
||||
if (separatorIndex >= topElements.length) {
|
||||
return topElements; // all elements will fit in top elements
|
||||
}
|
||||
ILaunchDescriptor[] descsCopy = new ILaunchDescriptor[separatorIndex + result.length];
|
||||
System.arraycopy(topElements, 0, descsCopy, 0, separatorIndex); // copy first N elements
|
||||
System.arraycopy(result, 0, descsCopy, separatorIndex, result.length); // copy all into rest
|
||||
return descsCopy;
|
||||
}
|
||||
|
||||
private Object[] getElements() {
|
||||
IStructuredContentProvider cp = (IStructuredContentProvider) getContentProvider();
|
||||
if (cp == null)
|
||||
return new Object[0];
|
||||
Object[] elements = cp.getElements(getInput());
|
||||
return elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal(Object element) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public void setDefaultSelection(StructuredSelection selection) {
|
||||
finalSelection = true;
|
||||
setSelection(selection, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setSelectionToWidget(List l, boolean reveal) {
|
||||
if (l.size() == 0) {
|
||||
return;
|
||||
}
|
||||
Object sel = l.get(0);
|
||||
Widget wid = doFindItem(sel);
|
||||
if (wid instanceof ListItem) {
|
||||
ListItem listItem = (ListItem) wid;
|
||||
listItem.setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
public int getSeparatorIndex() {
|
||||
return separatorIndex;
|
||||
}
|
||||
|
||||
public void setSeparatorIndex(int separatorIndex) {
|
||||
this.separatorIndex = separatorIndex;
|
||||
if (separatorIndex <= 0)
|
||||
return;
|
||||
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
|
||||
String prefName = getHistoryPreferenceName();
|
||||
if (prefName != null && store.getInt(prefName) != getSeparatorIndex()) {
|
||||
store.setValue(prefName, getSeparatorIndex());
|
||||
}
|
||||
}
|
||||
|
||||
protected String getHistoryPreferenceName() {
|
||||
return historyPref;
|
||||
}
|
||||
|
||||
public void setCellModifier(ICellModifier modifier) {
|
||||
this.modifier = modifier;
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
return listItems.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns top element (provider element) in the begging on non-history list
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Object getTopFilteredElement() {
|
||||
if (listItems.length > 0) {
|
||||
if (separatorIndex <= 0 || separatorIndex >= listItems.length || !historySupported)
|
||||
return listItems[0].element;
|
||||
else
|
||||
return listItems[separatorIndex].element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getTopElement() {
|
||||
if (listItems.length > 0) {
|
||||
return listItems[0].element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ViewerComparator getTopComparator() {
|
||||
return historyComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* ViewerComparator comparator labels of elements by default
|
||||
*
|
||||
* @param comp
|
||||
*/
|
||||
public void setHistoryComparator(ViewerComparator comp) {
|
||||
historyComparator = comp;
|
||||
}
|
||||
|
||||
public void setHistoryComparator(Comparator<?> comp) {
|
||||
historyComparator = comp == null ? null : new LaunchBarListViewerComparator(comp);
|
||||
}
|
||||
|
||||
public void setComparator(Comparator<?> comp) {
|
||||
setComparator(comp == null ? null : new LaunchBarListViewerComparator(comp));
|
||||
}
|
||||
|
||||
public boolean isHistorySupported() {
|
||||
return historySupported;
|
||||
}
|
||||
|
||||
public void setHistorySupported(boolean historySupported) {
|
||||
this.historySupported = historySupported;
|
||||
}
|
||||
|
||||
public void setHistoryPreferenceName(String historyPreferenceName) {
|
||||
this.historyPref = historyPreferenceName;
|
||||
if (historyPreferenceName != null) {
|
||||
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
|
||||
int separator = store.getInt(historyPreferenceName);
|
||||
if (separator <= 0)
|
||||
separator = 1;
|
||||
setSeparatorIndex(separator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* final selection will be set to true when user made a final selection in a list for example when double click on entry or
|
||||
* pressed enter key
|
||||
*/
|
||||
public boolean isFinalSelection() {
|
||||
return finalSelection;
|
||||
}
|
||||
|
||||
public void setFinalSelection(boolean finalSelection) {
|
||||
this.finalSelection = finalSelection;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Display display = Display.getDefault();
|
||||
Shell shell = new Shell();
|
||||
RowLayout rowLayout = new RowLayout();
|
||||
shell.setLayout(rowLayout);
|
||||
(new Label(shell, SWT.NULL)).setText("Hello");
|
||||
LaunchBarListViewer v = new LaunchBarListViewer(shell);
|
||||
v.setContentProvider(new ArrayContentProvider());
|
||||
v.setLabelProvider(new LabelProvider());
|
||||
v.setInput(new String[] { "aaa", "bbb", "ccc" });
|
||||
shell.pack();
|
||||
shell.open();
|
||||
// textUser.forceFocus();
|
||||
// Set up the event loop.
|
||||
while (!shell.isDisposed()) {
|
||||
if (!display.readAndDispatch()) {
|
||||
// If no more entries in event queue
|
||||
display.sleep();
|
||||
}
|
||||
}
|
||||
display.dispose();
|
||||
}
|
||||
|
||||
public void setFocus() {
|
||||
if (selIndex >= 0 && listItems != null && listItems.length < selIndex)
|
||||
listItems[selIndex].setFocus();
|
||||
else
|
||||
getControl().setFocus();
|
||||
}
|
||||
|
||||
public void setFilterVisible(boolean vis) {
|
||||
filterControl.setVisible(vis);
|
||||
}
|
||||
}
|
|
@ -184,7 +184,7 @@ public class TargetSelector extends CSelector {
|
|||
GridLayout buttonLayout = new GridLayout();
|
||||
buttonLayout.marginWidth = buttonLayout.marginHeight = 7;
|
||||
createButton.setLayout(buttonLayout);
|
||||
createButton.setBackground(white);
|
||||
createButton.setBackground(backgroundColor);
|
||||
createButton.addPaintListener(new PaintListener() {
|
||||
@Override
|
||||
public void paintControl(PaintEvent e) {
|
||||
|
@ -198,7 +198,7 @@ public class TargetSelector extends CSelector {
|
|||
final Label createLabel = new Label(createButton, SWT.None);
|
||||
createLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||
createLabel.setText("Create New Target...");
|
||||
createLabel.setBackground(white);
|
||||
createLabel.setBackground(backgroundColor);
|
||||
|
||||
MouseListener mouseListener = new MouseAdapter() {
|
||||
public void mouseUp(org.eclipse.swt.events.MouseEvent e) {
|
||||
|
|
Loading…
Add table
Reference in a new issue