/** | |
* Copyright (c) 2009 Thales Corporate Services S.A.S. | |
* 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: | |
* Thales Corporate Services S.A.S - initial API and implementation | |
*/ | |
package org.eclipse.egf.core.ui.wizard; | |
import java.io.IOException; | |
import java.io.StringReader; | |
import java.io.StringWriter; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.Collections; | |
import java.util.Comparator; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.LinkedList; | |
import java.util.List; | |
import java.util.Set; | |
import org.eclipse.core.commands.AbstractHandler; | |
import org.eclipse.core.commands.ExecutionEvent; | |
import org.eclipse.core.commands.IHandler; | |
import org.eclipse.core.runtime.Assert; | |
import org.eclipse.core.runtime.CoreException; | |
import org.eclipse.core.runtime.IProgressMonitor; | |
import org.eclipse.core.runtime.IStatus; | |
import org.eclipse.core.runtime.ListenerList; | |
import org.eclipse.core.runtime.NullProgressMonitor; | |
import org.eclipse.core.runtime.ProgressMonitorWrapper; | |
import org.eclipse.core.runtime.Status; | |
import org.eclipse.core.runtime.SubProgressMonitor; | |
import org.eclipse.core.runtime.jobs.Job; | |
import org.eclipse.jface.action.Action; | |
import org.eclipse.jface.action.ActionContributionItem; | |
import org.eclipse.jface.action.IAction; | |
import org.eclipse.jface.action.IMenuListener; | |
import org.eclipse.jface.action.IMenuManager; | |
import org.eclipse.jface.action.LegacyActionTools; | |
import org.eclipse.jface.action.MenuManager; | |
import org.eclipse.jface.dialogs.IDialogSettings; | |
import org.eclipse.jface.resource.JFaceResources; | |
import org.eclipse.jface.viewers.ContentViewer; | |
import org.eclipse.jface.viewers.DoubleClickEvent; | |
import org.eclipse.jface.viewers.IColorProvider; | |
import org.eclipse.jface.viewers.IContentProvider; | |
import org.eclipse.jface.viewers.IDoubleClickListener; | |
import org.eclipse.jface.viewers.IFontProvider; | |
import org.eclipse.jface.viewers.ILabelDecorator; | |
import org.eclipse.jface.viewers.ILabelProvider; | |
import org.eclipse.jface.viewers.ILabelProviderListener; | |
import org.eclipse.jface.viewers.ILazyContentProvider; | |
import org.eclipse.jface.viewers.ISelection; | |
import org.eclipse.jface.viewers.ISelectionChangedListener; | |
import org.eclipse.jface.viewers.IStructuredContentProvider; | |
import org.eclipse.jface.viewers.LabelProvider; | |
import org.eclipse.jface.viewers.LabelProviderChangedEvent; | |
import org.eclipse.jface.viewers.SelectionChangedEvent; | |
import org.eclipse.jface.viewers.StructuredSelection; | |
import org.eclipse.jface.viewers.StyledCellLabelProvider; | |
import org.eclipse.jface.viewers.StyledString; | |
import org.eclipse.jface.viewers.TableViewer; | |
import org.eclipse.jface.viewers.Viewer; | |
import org.eclipse.jface.viewers.ViewerCell; | |
import org.eclipse.jface.viewers.ViewerFilter; | |
import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider; | |
import org.eclipse.jface.wizard.WizardPage; | |
import org.eclipse.osgi.util.NLS; | |
import org.eclipse.swt.SWT; | |
import org.eclipse.swt.accessibility.ACC; | |
import org.eclipse.swt.accessibility.AccessibleAdapter; | |
import org.eclipse.swt.accessibility.AccessibleEvent; | |
import org.eclipse.swt.custom.CLabel; | |
import org.eclipse.swt.custom.ViewForm; | |
import org.eclipse.swt.events.KeyAdapter; | |
import org.eclipse.swt.events.KeyEvent; | |
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.graphics.Font; | |
import org.eclipse.swt.graphics.FontData; | |
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.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.Menu; | |
import org.eclipse.swt.widgets.Table; | |
import org.eclipse.swt.widgets.Text; | |
import org.eclipse.swt.widgets.ToolBar; | |
import org.eclipse.swt.widgets.ToolItem; | |
import org.eclipse.ui.ActiveShellExpression; | |
import org.eclipse.ui.IMemento; | |
import org.eclipse.ui.IWorkbenchCommandConstants; | |
import org.eclipse.ui.IWorkbenchPreferenceConstants; | |
import org.eclipse.ui.PlatformUI; | |
import org.eclipse.ui.WorkbenchException; | |
import org.eclipse.ui.XMLMemento; | |
import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog; | |
import org.eclipse.ui.dialogs.SearchPattern; | |
import org.eclipse.ui.handlers.IHandlerActivation; | |
import org.eclipse.ui.handlers.IHandlerService; | |
import org.eclipse.ui.internal.IWorkbenchGraphicConstants; | |
import org.eclipse.ui.internal.WorkbenchImages; | |
import org.eclipse.ui.internal.WorkbenchMessages; | |
import org.eclipse.ui.internal.WorkbenchPlugin; | |
import org.eclipse.ui.progress.UIJob; | |
import org.eclipse.ui.statushandlers.StatusManager; | |
/** | |
* @author Xavier Maysonnave | |
* | |
*/ | |
public abstract class FilteredItemsSelectionWizardPage extends WizardPage { | |
private static final String DIALOG_BOUNDS_SETTINGS = "DialogBoundsSettings"; //$NON-NLS-1$ | |
private static final String SHOW_STATUS_LINE = "ShowStatusLine"; //$NON-NLS-1$ | |
private static final String HISTORY_SETTINGS = "History"; //$NON-NLS-1$ | |
private static final String DIALOG_HEIGHT = "DIALOG_HEIGHT"; //$NON-NLS-1$ | |
private static final String DIALOG_WIDTH = "DIALOG_WIDTH"; //$NON-NLS-1$ | |
/** | |
* Represents an empty selection in the pattern input field (used only for | |
* initial pattern). | |
*/ | |
public static final int NONE = 0; | |
/** | |
* Pattern input field selection where caret is at the beginning (used only | |
* for initial pattern). | |
*/ | |
public static final int CARET_BEGINNING = 1; | |
/** | |
* Represents a full selection in the pattern input field (used only for | |
* initial pattern). | |
*/ | |
public static final int FULL_SELECTION = 2; | |
// the final collection of selected elements, or null if this dialog was | |
// canceled | |
private Object[] result; | |
private Text pattern; | |
private TableViewer list; | |
private DetailsContentViewer details; | |
/** | |
* It is a duplicate of a field in the CLabel class in DetailsContentViewer. | |
* It is maintained, because the <code>setDetailsLabelProvider()</code> | |
* could be called before content area is created. | |
*/ | |
private ILabelProvider detailsLabelProvider; | |
private ItemsListLabelProvider itemsListLabelProvider; | |
private MenuManager menuManager; | |
private boolean multi; | |
private ToolBar toolBar; | |
private ToolItem toolItem; | |
private Label progressLabel; | |
private ToggleStatusLineAction toggleStatusLineAction; | |
private RemoveHistoryItemAction removeHistoryItemAction; | |
private ActionContributionItem removeHistoryActionContributionItem; | |
private RefreshCacheJob refreshCacheJob; | |
private RefreshProgressMessageJob refreshProgressMessageJob; | |
private Object[] currentSelection; | |
private ContentProvider contentProvider; | |
private FilterHistoryJob filterHistoryJob; | |
private FilterJob filterJob; | |
private ItemsFilter filter; | |
private List lastCompletedResult; | |
private ItemsFilter lastCompletedFilter; | |
private String initialPatternText; | |
private int selectionMode; | |
private ItemsListSeparator itemsListSeparator; | |
private static final String EMPTY_STRING = ""; //$NON-NLS-1$ | |
private boolean refreshWithLastSelection = false; | |
private IHandlerActivation showViewHandler; | |
/** | |
* Applies the dialog font to all controls that currently have the default | |
* font. | |
* | |
* @param control | |
* the control to apply the font to. Font will also be applied to | |
* its children. If the control is <code>null</code> nothing | |
* happens. | |
*/ | |
public static void applyDialogFont(Control control) { | |
if (control == null || dialogFontIsDefault()) { | |
return; | |
} | |
Font dialogFont = JFaceResources.getDialogFont(); | |
applyDialogFont(control, dialogFont); | |
} | |
/** | |
* Return whether or not the dialog font is currently the same as the | |
* default font. | |
* | |
* @return boolean if the two are the same | |
*/ | |
protected static boolean dialogFontIsDefault() { | |
FontData[] dialogFontData = JFaceResources.getFontRegistry().getFontData(JFaceResources.DIALOG_FONT); | |
FontData[] defaultFontData = JFaceResources.getFontRegistry().getFontData(JFaceResources.DEFAULT_FONT); | |
return Arrays.equals(dialogFontData, defaultFontData); | |
} | |
/** | |
* Sets the dialog font on the control and any of its children if their font | |
* is not otherwise set. | |
* | |
* @param control | |
* the control to apply the font to. Font will also be applied to | |
* its children. | |
* @param dialogFont | |
* the dialog font to set | |
*/ | |
private static void applyDialogFont(Control control, Font dialogFont) { | |
if (hasDefaultFont(control)) { | |
control.setFont(dialogFont); | |
} | |
if (control instanceof Composite) { | |
Control[] children = ((Composite) control).getChildren(); | |
for (int i = 0; i < children.length; i++) { | |
applyDialogFont(children[i], dialogFont); | |
} | |
} | |
} | |
/** | |
* Return whether or not this control has the same font as it's default. | |
* | |
* @param control | |
* Control | |
* @return boolean | |
*/ | |
private static boolean hasDefaultFont(Control control) { | |
FontData[] controlFontData = control.getFont().getFontData(); | |
FontData[] defaultFontData = getDefaultFont(control).getFontData(); | |
if (controlFontData.length == defaultFontData.length) { | |
for (int i = 0; i < controlFontData.length; i++) { | |
if (controlFontData[i].equals(defaultFontData[i])) { | |
continue; | |
} | |
return false; | |
} | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Get the default font for this type of control. | |
* | |
* @param control | |
* @return the default font | |
*/ | |
private static Font getDefaultFont(Control control) { | |
String fontName = "DEFAULT_FONT_" + control.getClass().getName(); //$NON-NLS-1$ | |
if (JFaceResources.getFontRegistry().hasValueFor(fontName)) { | |
return JFaceResources.getFontRegistry().get(fontName); | |
} | |
Font cached = control.getFont(); | |
control.setFont(null); | |
Font defaultFont = control.getFont(); | |
control.setFont(cached); | |
JFaceResources.getFontRegistry().put(fontName, defaultFont.getFontData()); | |
return defaultFont; | |
} | |
/** | |
* An interface to content providers for | |
* <code>FilterItemsSelectionDialog</code>. | |
*/ | |
protected abstract class AbstractContentProvider { | |
/** | |
* Adds the item to the content provider iff the filter matches the | |
* item. Otherwise does nothing. | |
* | |
* @param item | |
* the item to add | |
* @param itemsFilter | |
* the filter | |
* | |
* @see FilteredItemsSelectionDialog.ItemsFilter#matchItem(Object) | |
*/ | |
public abstract void add(Object item, ItemsFilter itemsFilter); | |
} | |
/** | |
* Compares items using camel case method. | |
*/ | |
private class CamelCaseComparator implements Comparator { | |
/* | |
* (non-Javadoc) | |
* | |
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) | |
*/ | |
public int compare(Object o1, Object o2) { | |
int leftCategory = getCamelCaseCategory(o1); | |
int rightCategory = getCamelCaseCategory(o2); | |
if (leftCategory < rightCategory) | |
return -1; | |
if (leftCategory > rightCategory) | |
return +1; | |
return getItemsComparator().compare(o1, o2); | |
} | |
private int getCamelCaseCategory(Object item) { | |
if (filter == null) | |
return 0; | |
if (!filter.isCamelCasePattern()) | |
return 0; | |
return filter.matchesRawNamePattern(item) ? 0 : 1; | |
} | |
} | |
/** | |
* Collects filtered elements. Contains one synchronized, sorted set for | |
* collecting filtered elements. All collected elements are sorted using | |
* comparator. Comparator is returned by getElementComparator() method. | |
* Implementation of <code>ItemsFilter</code> is used to filter elements. | |
* The key function of filter used in to filtering is | |
* <code>matchElement(Object item)</code>. | |
* <p> | |
* The <code>ContentProvider</code> class also provides item filtering | |
* methods. The filtering has been moved from the standard TableView | |
* <code>getFilteredItems()</code> method to content provider, because | |
* <code>ILazyContentProvider</code> and virtual tables are used. This | |
* class is responsible for adding a separator below history items and | |
* marking each items as duplicate if its name repeats more than once on the | |
* filtered list. | |
*/ | |
private class ContentProvider extends AbstractContentProvider implements IStructuredContentProvider, ILazyContentProvider { | |
private SelectionHistory selectionHistory; | |
/** | |
* Raw result of the searching (unsorted, unfiltered). | |
* <p> | |
* Standard object flow: | |
* <code>items -> lastSortedItems -> lastFilteredItems</code> | |
*/ | |
private Set items; | |
/** | |
* Items that are duplicates. | |
*/ | |
private Set duplicates; | |
/** | |
* List of <code>ViewerFilter</code>s to be used during filtering | |
*/ | |
private List filters; | |
/** | |
* Result of the last filtering. | |
* <p> | |
* Standard object flow: | |
* <code>items -> lastSortedItems -> lastFilteredItems</code> | |
*/ | |
private List lastFilteredItems; | |
/** | |
* Result of the last sorting. | |
* <p> | |
* Standard object flow: | |
* <code>items -> lastSortedItems -> lastFilteredItems</code> | |
*/ | |
private List lastSortedItems; | |
/** | |
* Used for <code>getFilteredItems()</code> method canceling (when the | |
* job that invoked the method was canceled). | |
* <p> | |
* Method canceling could be based (only) on monitor canceling | |
* unfortunately sometimes the method <code>getFilteredElements()</code> | |
* could be run with a null monitor, the <code>reset</code> flag have | |
* to be left intact. | |
*/ | |
private boolean reset; | |
/** | |
* Creates new instance of <code>ContentProvider</code>. | |
*/ | |
public ContentProvider() { | |
this.items = Collections.synchronizedSet(new HashSet(2048)); | |
this.duplicates = Collections.synchronizedSet(new HashSet(256)); | |
this.lastFilteredItems = new ArrayList(); | |
this.lastSortedItems = Collections.synchronizedList(new ArrayList(2048)); | |
} | |
/** | |
* Sets selection history. | |
* | |
* @param selectionHistory | |
* The selectionHistory to set. | |
*/ | |
public void setSelectionHistory(SelectionHistory selectionHistory) { | |
this.selectionHistory = selectionHistory; | |
} | |
/** | |
* @return Returns the selectionHistory. | |
*/ | |
public SelectionHistory getSelectionHistory() { | |
return selectionHistory; | |
} | |
/** | |
* Removes all content items and resets progress message. | |
*/ | |
public void reset() { | |
reset = true; | |
this.items.clear(); | |
this.duplicates.clear(); | |
this.lastSortedItems.clear(); | |
} | |
/** | |
* Stops reloading cache - <code>getFilteredItems()</code> method. | |
*/ | |
public void stopReloadingCache() { | |
reset = true; | |
} | |
/** | |
* Adds filtered item. | |
* | |
* @param item | |
* @param itemsFilter | |
*/ | |
public void add(Object item, ItemsFilter itemsFilter) { | |
if (itemsFilter == filter) { | |
if (itemsFilter != null) { | |
if (itemsFilter.matchItem(item)) { | |
this.items.add(item); | |
} | |
} else { | |
this.items.add(item); | |
} | |
} | |
} | |
/** | |
* Add all history items to <code>contentProvider</code>. | |
* | |
* @param itemsFilter | |
*/ | |
public void addHistoryItems(ItemsFilter itemsFilter) { | |
if (this.selectionHistory != null) { | |
Object[] items = this.selectionHistory.getHistoryItems(); | |
for (int i = 0; i < items.length; i++) { | |
Object item = items[i]; | |
if (itemsFilter == filter) { | |
if (itemsFilter != null) { | |
if (itemsFilter.matchItem(item)) { | |
if (itemsFilter.isConsistentItem(item)) { | |
this.items.add(item); | |
} else { | |
this.selectionHistory.remove(item); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Refresh dialog. | |
*/ | |
public void refresh() { | |
scheduleRefresh(); | |
} | |
/** | |
* Removes items from history and refreshes the view. | |
* | |
* @param item | |
* to remove | |
* | |
* @return removed item | |
*/ | |
public Object removeHistoryElement(Object item) { | |
if (this.selectionHistory != null) | |
this.selectionHistory.remove(item); | |
if (filter == null || filter.getPattern().length() == 0) { | |
items.remove(item); | |
duplicates.remove(item); | |
this.lastSortedItems.remove(item); | |
} | |
synchronized (lastSortedItems) { | |
Collections.sort(lastSortedItems, getHistoryComparator()); | |
} | |
return item; | |
} | |
/** | |
* Adds item to history and refresh view. | |
* | |
* @param item | |
* to add | |
*/ | |
public void addHistoryElement(Object item) { | |
if (this.selectionHistory != null) | |
this.selectionHistory.accessed(item); | |
if (filter == null || !filter.matchItem(item)) { | |
this.items.remove(item); | |
this.duplicates.remove(item); | |
this.lastSortedItems.remove(item); | |
} | |
synchronized (lastSortedItems) { | |
Collections.sort(lastSortedItems, getHistoryComparator()); | |
} | |
this.refresh(); | |
} | |
/** | |
* @param item | |
* @return <code>true</code> if given item is part of the history | |
*/ | |
public boolean isHistoryElement(Object item) { | |
if (this.selectionHistory != null) { | |
return this.selectionHistory.contains(item); | |
} | |
return false; | |
} | |
/** | |
* Sets/unsets given item as duplicate. | |
* | |
* @param item | |
* item to change | |
* | |
* @param isDuplicate | |
* duplicate flag | |
*/ | |
public void setDuplicateElement(Object item, boolean isDuplicate) { | |
if (this.items.contains(item)) { | |
if (isDuplicate) | |
this.duplicates.add(item); | |
else | |
this.duplicates.remove(item); | |
} | |
} | |
/** | |
* Indicates whether given item is a duplicate. | |
* | |
* @param item | |
* item to check | |
* @return <code>true</code> if item is duplicate | |
*/ | |
public boolean isDuplicateElement(Object item) { | |
return duplicates.contains(item); | |
} | |
/** | |
* Load history from memento. | |
* | |
* @param memento | |
* memento from which the history will be retrieved | |
*/ | |
public void loadHistory(IMemento memento) { | |
if (this.selectionHistory != null) | |
this.selectionHistory.load(memento); | |
} | |
/** | |
* Save history to memento. | |
* | |
* @param memento | |
* memento to which the history will be added | |
*/ | |
public void saveHistory(IMemento memento) { | |
if (this.selectionHistory != null) | |
this.selectionHistory.save(memento); | |
} | |
/** | |
* Gets sorted items. | |
* | |
* @return sorted items | |
*/ | |
private Object[] getSortedItems() { | |
if (lastSortedItems.size() != items.size()) { | |
synchronized (lastSortedItems) { | |
lastSortedItems.clear(); | |
lastSortedItems.addAll(items); | |
Collections.sort(lastSortedItems, getHistoryComparator()); | |
} | |
} | |
return lastSortedItems.toArray(); | |
} | |
/** | |
* Remember result of filtering. | |
* | |
* @param itemsFilter | |
*/ | |
public void rememberResult(ItemsFilter itemsFilter) { | |
List itemsList = Collections.synchronizedList(Arrays.asList(getSortedItems())); | |
// synchronization | |
if (itemsFilter == filter) { | |
lastCompletedFilter = itemsFilter; | |
lastCompletedResult = itemsList; | |
} | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) | |
*/ | |
public Object[] getElements(Object inputElement) { | |
return lastFilteredItems.toArray(); | |
} | |
public int getNumberOfElements() { | |
return lastFilteredItems.size(); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.IContentProvider#dispose() | |
*/ | |
public void dispose() { | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, | |
* java.lang.Object, java.lang.Object) | |
*/ | |
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.ILazyContentProvider#updateElement(int) | |
*/ | |
public void updateElement(int index) { | |
FilteredItemsSelectionWizardPage.this.list.replace((lastFilteredItems.size() > index) ? lastFilteredItems.get(index) : null, index); | |
} | |
/** | |
* Main method responsible for getting the filtered items and checking | |
* for duplicates. It is based on the {@link FilteredItemsSelectionDialog.ContentProvider#getFilteredItems(Object, IProgressMonitor)}. | |
* | |
* @param checkDuplicates | |
* <code>true</code> if data concerning elements | |
* duplication should be computed - it takes much more time | |
* than standard filtering | |
* | |
* @param monitor | |
* progress monitor | |
*/ | |
public void reloadCache(boolean checkDuplicates, IProgressMonitor monitor) { | |
reset = false; | |
if (monitor != null) { | |
// the work is divided into two actions of the same length | |
int totalWork = checkDuplicates ? 200 : 100; | |
monitor.beginTask(WorkbenchMessages.FilteredItemsSelectionDialog_cacheRefreshJob, totalWork); | |
} | |
// the TableViewer's root (the input) is treated as parent | |
lastFilteredItems = Arrays.asList(getFilteredItems(list.getInput(), monitor != null ? new SubProgressMonitor(monitor, 100) : null)); | |
if (reset || (monitor != null && monitor.isCanceled())) { | |
if (monitor != null) | |
monitor.done(); | |
return; | |
} | |
if (checkDuplicates) { | |
checkDuplicates(monitor); | |
} | |
if (monitor != null) | |
monitor.done(); | |
} | |
private void checkDuplicates(IProgressMonitor monitor) { | |
synchronized (lastFilteredItems) { | |
IProgressMonitor subMonitor = null; | |
int reportEvery = lastFilteredItems.size() / 20; | |
if (monitor != null) { | |
subMonitor = new SubProgressMonitor(monitor, 100); | |
subMonitor.beginTask(WorkbenchMessages.FilteredItemsSelectionDialog_cacheRefreshJob_checkDuplicates, 5); | |
} | |
HashMap helperMap = new HashMap(); | |
for (int i = 0; i < lastFilteredItems.size(); i++) { | |
if (reset || (subMonitor != null && subMonitor.isCanceled())) | |
return; | |
Object item = lastFilteredItems.get(i); | |
if (!(item instanceof ItemsListSeparator)) { | |
Object previousItem = helperMap.put(getElementName(item), item); | |
if (previousItem != null) { | |
setDuplicateElement(previousItem, true); | |
setDuplicateElement(item, true); | |
} else { | |
setDuplicateElement(item, false); | |
} | |
} | |
if (subMonitor != null && reportEvery != 0 && (i + 1) % reportEvery == 0) | |
subMonitor.worked(1); | |
} | |
helperMap.clear(); | |
} | |
} | |
/** | |
* Returns an array of items filtered using the provided | |
* <code>ViewerFilter</code>s with a separator added. | |
* | |
* @param parent | |
* the parent | |
* @param monitor | |
* progress monitor, can be <code>null</code> | |
* @return an array of filtered items | |
*/ | |
protected Object[] getFilteredItems(Object parent, IProgressMonitor monitor) { | |
int ticks = 100; | |
if (monitor == null) { | |
monitor = new NullProgressMonitor(); | |
} | |
monitor.beginTask(WorkbenchMessages.FilteredItemsSelectionDialog_cacheRefreshJob_getFilteredElements, ticks); | |
if (filters != null) { | |
ticks /= (filters.size() + 2); | |
} else { | |
ticks /= 2; | |
} | |
// get already sorted array | |
Object[] filteredElements = getSortedItems(); | |
monitor.worked(ticks); | |
// filter the elements using provided ViewerFilters | |
if (filters != null && filteredElements != null) { | |
for (Iterator iter = filters.iterator(); iter.hasNext();) { | |
ViewerFilter f = (ViewerFilter) iter.next(); | |
filteredElements = f.filter(list, parent, filteredElements); | |
monitor.worked(ticks); | |
} | |
} | |
if (filteredElements == null || monitor.isCanceled()) { | |
monitor.done(); | |
return new Object[0]; | |
} | |
ArrayList preparedElements = new ArrayList(); | |
boolean hasHistory = false; | |
if (filteredElements.length > 0) { | |
if (isHistoryElement(filteredElements[0])) { | |
hasHistory = true; | |
} | |
} | |
int reportEvery = filteredElements.length / ticks; | |
// add separator | |
for (int i = 0; i < filteredElements.length; i++) { | |
Object item = filteredElements[i]; | |
if (hasHistory && !isHistoryElement(item)) { | |
preparedElements.add(itemsListSeparator); | |
hasHistory = false; | |
} | |
preparedElements.add(item); | |
if (reportEvery != 0 && ((i + 1) % reportEvery == 0)) { | |
monitor.worked(1); | |
} | |
} | |
monitor.done(); | |
return preparedElements.toArray(); | |
} | |
/** | |
* Adds a filter to this content provider. For an example usage of such | |
* filters look at the project <code>org.eclipse.ui.ide</code>, class | |
* <code>org.eclipse.ui.dialogs.FilteredResourcesSelectionDialog.CustomWorkingSetFilter</code>. | |
* | |
* | |
* @param filter | |
* the filter to be added | |
*/ | |
public void addFilter(ViewerFilter filter) { | |
if (filters == null) { | |
filters = new ArrayList(); | |
} | |
filters.add(filter); | |
// currently filters are only added when dialog is restored | |
// if it is changed, refreshing the whole TableViewer should be | |
// added | |
} | |
} | |
/** | |
* DetailsContentViewer objects are wrappers for labels. | |
* DetailsContentViewer provides means to change label's image and text when | |
* the attached LabelProvider is updated. | |
*/ | |
private class DetailsContentViewer extends ContentViewer { | |
private CLabel label; | |
/** | |
* Unfortunately, it was impossible to delegate displaying border to | |
* label. The <code>ViewForm</code> is used because | |
* <code>CLabel</code> displays shadow when border is present. | |
*/ | |
private ViewForm viewForm; | |
/** | |
* Constructs a new instance of this class given its parent and a style | |
* value describing its behavior and appearance. | |
* | |
* @param parent | |
* the parent component | |
* @param style | |
* SWT style bits | |
*/ | |
public DetailsContentViewer(Composite parent, int style) { | |
viewForm = new ViewForm(parent, style); | |
GridData gd = new GridData(GridData.FILL_HORIZONTAL); | |
gd.horizontalSpan = 2; | |
viewForm.setLayoutData(gd); | |
label = new CLabel(viewForm, SWT.FLAT); | |
label.setFont(parent.getFont()); | |
viewForm.setContent(label); | |
hookControl(label); | |
} | |
/** | |
* Shows/hides the content viewer. | |
* | |
* @param visible | |
* if the content viewer should be visible. | |
*/ | |
public void setVisible(boolean visible) { | |
GridData gd = (GridData) viewForm.getLayoutData(); | |
gd.exclude = !visible; | |
viewForm.getParent().layout(); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object, | |
* java.lang.Object) | |
*/ | |
protected void inputChanged(Object input, Object oldInput) { | |
if (oldInput == null) { | |
if (input == null) { | |
return; | |
} | |
refresh(); | |
return; | |
} | |
refresh(); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.ContentViewer#handleLabelProviderChanged(org.eclipse.jface.viewers.LabelProviderChangedEvent) | |
*/ | |
protected void handleLabelProviderChanged(LabelProviderChangedEvent event) { | |
if (event != null) { | |
refresh(event.getElements()); | |
} | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.Viewer#getControl() | |
*/ | |
public Control getControl() { | |
return label; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.Viewer#getSelection() | |
*/ | |
public ISelection getSelection() { | |
// not supported | |
return null; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.Viewer#refresh() | |
*/ | |
public void refresh() { | |
Object input = this.getInput(); | |
if (input != null) { | |
ILabelProvider labelProvider = (ILabelProvider) getLabelProvider(); | |
doRefresh(labelProvider.getText(input), labelProvider.getImage(input)); | |
} else { | |
doRefresh(null, null); | |
} | |
} | |
/** | |
* Sets the given text and image to the label. | |
* | |
* @param text | |
* the new text or null | |
* @param image | |
* the new image | |
*/ | |
private void doRefresh(String text, Image image) { | |
label.setText(text); | |
label.setImage(image); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.Viewer#setSelection(org.eclipse.jface.viewers.ISelection, | |
* boolean) | |
*/ | |
public void setSelection(ISelection selection, boolean reveal) { | |
// not supported | |
} | |
/** | |
* Refreshes the label if currently chosen element is on the list. | |
* | |
* @param objs | |
* list of changed object | |
*/ | |
private void refresh(Object[] objs) { | |
if (objs == null || getInput() == null) { | |
return; | |
} | |
Object input = getInput(); | |
for (int i = 0; i < objs.length; i++) { | |
if (objs[i].equals(input)) { | |
refresh(); | |
break; | |
} | |
} | |
} | |
} | |
private static boolean showColoredLabels() { | |
return PlatformUI.getPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.USE_COLORED_LABELS); | |
} | |
private class ItemsListLabelProvider extends StyledCellLabelProvider implements ILabelProviderListener { | |
private ILabelProvider provider; | |
private ILabelDecorator selectionDecorator; | |
// Need to keep our own list of listeners | |
private ListenerList listeners = new ListenerList(); | |
/** | |
* Creates a new instance of the class. | |
* | |
* @param provider | |
* the label provider for all items, not <code>null</code> | |
* @param selectionDecorator | |
* the decorator for selected items, can be <code>null</code> | |
*/ | |
public ItemsListLabelProvider(ILabelProvider provider, ILabelDecorator selectionDecorator) { | |
Assert.isNotNull(provider); | |
this.provider = provider; | |
this.selectionDecorator = selectionDecorator; | |
setOwnerDrawEnabled(showColoredLabels() && provider instanceof IStyledLabelProvider); | |
provider.addListener(this); | |
if (selectionDecorator != null) { | |
selectionDecorator.addListener(this); | |
} | |
} | |
/** | |
* Sets new selection decorator. | |
* | |
* @param newSelectionDecorator | |
* new label decorator for selected items in the list | |
*/ | |
public void setSelectionDecorator(ILabelDecorator newSelectionDecorator) { | |
if (selectionDecorator != null) { | |
selectionDecorator.removeListener(this); | |
selectionDecorator.dispose(); | |
} | |
selectionDecorator = newSelectionDecorator; | |
if (selectionDecorator != null) { | |
selectionDecorator.addListener(this); | |
} | |
} | |
/** | |
* Gets selection decorator. | |
* | |
* @return the label decorator for selected items in the list | |
*/ | |
public ILabelDecorator getSelectionDecorator() { | |
return selectionDecorator; | |
} | |
/** | |
* Sets new label provider. | |
* | |
* @param newProvider | |
* new label provider for items in the list, not | |
* <code>null</code> | |
*/ | |
public void setProvider(ILabelProvider newProvider) { | |
Assert.isNotNull(newProvider); | |
provider.removeListener(this); | |
provider.dispose(); | |
provider = newProvider; | |
if (provider != null) { | |
provider.addListener(this); | |
} | |
setOwnerDrawEnabled(showColoredLabels() && provider instanceof IStyledLabelProvider); | |
} | |
private Image getImage(Object element) { | |
if (element instanceof ItemsListSeparator) { | |
return WorkbenchImages.getImage(IWorkbenchGraphicConstants.IMG_OBJ_SEPARATOR); | |
} | |
return provider.getImage(element); | |
} | |
private boolean isSelected(Object element) { | |
if (element != null && currentSelection != null) { | |
for (int i = 0; i < currentSelection.length; i++) { | |
if (element.equals(currentSelection[i])) | |
return true; | |
} | |
} | |
return false; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object) | |
*/ | |
private String getText(Object element) { | |
if (element instanceof ItemsListSeparator) { | |
return getSeparatorLabel(((ItemsListSeparator) element).getName()); | |
} | |
String str = provider.getText(element); | |
if (selectionDecorator != null && isSelected(element)) { | |
return selectionDecorator.decorateText(str.toString(), element); | |
} | |
return str; | |
} | |
private StyledString getStyledText(Object element, IStyledLabelProvider provider) { | |
StyledString string = provider.getStyledText(element); | |
if (selectionDecorator != null && isSelected(element)) { | |
String decorated = selectionDecorator.decorateText(string.getString(), element); | |
return StyledCellLabelProvider.styleDecoratedString(decorated, null, string); | |
// no need to add colors when element is selected | |
} | |
return string; | |
} | |
public void update(ViewerCell cell) { | |
Object element = cell.getElement(); | |
if (!(element instanceof ItemsListSeparator) && provider instanceof IStyledLabelProvider) { | |
IStyledLabelProvider styledLabelProvider = (IStyledLabelProvider) provider; | |
StyledString styledString = getStyledText(element, styledLabelProvider); | |
cell.setText(styledString.getString()); | |
cell.setStyleRanges(styledString.getStyleRanges()); | |
cell.setImage(styledLabelProvider.getImage(element)); | |
} else { | |
cell.setText(getText(element)); | |
cell.setImage(getImage(element)); | |
} | |
cell.setFont(getFont(element)); | |
cell.setForeground(getForeground(element)); | |
cell.setBackground(getBackground(element)); | |
super.update(cell); | |
} | |
private String getSeparatorLabel(String separatorLabel) { | |
Rectangle rect = list.getTable().getBounds(); | |
int borderWidth = list.getTable().computeTrim(0, 0, 0, 0).width; | |
int imageWidth = WorkbenchImages.getImage(IWorkbenchGraphicConstants.IMG_OBJ_SEPARATOR).getBounds().width; | |
int width = rect.width - borderWidth - imageWidth; | |
GC gc = new GC(list.getTable()); | |
gc.setFont(list.getTable().getFont()); | |
int fSeparatorWidth = gc.getAdvanceWidth('-'); | |
int fMessageLength = gc.textExtent(separatorLabel).x; | |
gc.dispose(); | |
StringBuffer dashes = new StringBuffer(); | |
int chars = (((width - fMessageLength) / fSeparatorWidth) / 2) - 2; | |
for (int i = 0; i < chars; i++) { | |
dashes.append('-'); | |
} | |
StringBuffer result = new StringBuffer(); | |
result.append(dashes); | |
result.append(" " + separatorLabel + " "); //$NON-NLS-1$//$NON-NLS-2$ | |
result.append(dashes); | |
return result.toString().trim(); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener) | |
*/ | |
public void addListener(ILabelProviderListener listener) { | |
listeners.add(listener); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose() | |
*/ | |
public void dispose() { | |
provider.removeListener(this); | |
provider.dispose(); | |
if (selectionDecorator != null) { | |
selectionDecorator.removeListener(this); | |
selectionDecorator.dispose(); | |
} | |
super.dispose(); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, | |
* java.lang.String) | |
*/ | |
public boolean isLabelProperty(Object element, String property) { | |
if (provider.isLabelProperty(element, property)) { | |
return true; | |
} | |
if (selectionDecorator != null && selectionDecorator.isLabelProperty(element, property)) { | |
return true; | |
} | |
return false; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener) | |
*/ | |
public void removeListener(ILabelProviderListener listener) { | |
listeners.remove(listener); | |
} | |
private Color getBackground(Object element) { | |
if (element instanceof ItemsListSeparator) { | |
return null; | |
} | |
if (provider instanceof IColorProvider) { | |
return ((IColorProvider) provider).getBackground(element); | |
} | |
return null; | |
} | |
private Color getForeground(Object element) { | |
if (element instanceof ItemsListSeparator) { | |
return Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); | |
} | |
if (provider instanceof IColorProvider) { | |
return ((IColorProvider) provider).getForeground(element); | |
} | |
return null; | |
} | |
private Font getFont(Object element) { | |
if (element instanceof ItemsListSeparator) { | |
return null; | |
} | |
if (provider instanceof IFontProvider) { | |
return ((IFontProvider) provider).getFont(element); | |
} | |
return null; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.ILabelProviderListener#labelProviderChanged(org.eclipse.jface.viewers.LabelProviderChangedEvent) | |
*/ | |
public void labelProviderChanged(LabelProviderChangedEvent event) { | |
Object[] l = listeners.getListeners(); | |
for (int i = 0; i < listeners.size(); i++) { | |
((ILabelProviderListener) l[i]).labelProviderChanged(event); | |
} | |
} | |
} | |
/** | |
* Only refreshes UI on the basis of an already sorted and filtered set of | |
* items. | |
* <p> | |
* Standard invocation scenario: | |
* <ol> | |
* <li>filtering job (<code>FilterJob</code> class extending | |
* <code>Job</code> class)</li> | |
* <li>cache refresh without checking for duplicates (<code>RefreshCacheJob</code> | |
* class extending <code>Job</code> class)</li> | |
* <li>UI refresh (<code>RefreshJob</code> class extending | |
* <code>UIJob</code> class)</li> | |
* <li>cache refresh with checking for duplicates (<cod>CacheRefreshJob</code> | |
* class extending <code>Job</code> class)</li> | |
* <li>UI refresh (<code>RefreshJob</code> class extending <code>UIJob</code> | |
* class)</li> | |
* </ol> | |
* The scenario is rather complicated, but it had to be applied, because: | |
* <ul> | |
* <li> refreshing cache is rather a long action and cannot be run in the UI - | |
* cannot be run in a UIJob</li> | |
* <li> refreshing cache checking for duplicates is twice as long as | |
* refreshing cache without checking for duplicates; results of the search | |
* could be displayed earlier</li> | |
* <li> refreshing the UI have to be run in a UIJob</li> | |
* </ul> | |
* | |
* @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.FilterJob | |
* @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.RefreshJob | |
* @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.RefreshCacheJob | |
*/ | |
private class RefreshJob extends UIJob { | |
/** | |
* Creates a new instance of the class. | |
*/ | |
public RefreshJob() { | |
super(FilteredItemsSelectionWizardPage.this.getShell().getDisplay(), WorkbenchMessages.FilteredItemsSelectionDialog_refreshJob); | |
setSystem(true); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public IStatus runInUIThread(IProgressMonitor monitor) { | |
if (monitor.isCanceled()) | |
return new Status(IStatus.OK, WorkbenchPlugin.PI_WORKBENCH, IStatus.OK, EMPTY_STRING, null); | |
if (FilteredItemsSelectionWizardPage.this != null) { | |
FilteredItemsSelectionWizardPage.this.refresh(); | |
} | |
return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK, EMPTY_STRING, null); | |
} | |
} | |
/** | |
* Refreshes the progress message cyclically with 500 milliseconds delay. | |
* <code>RefreshProgressMessageJob</code> is strictly connected with | |
* <code>GranualProgressMonitor</code> and use it to to get progress | |
* message and to decide about break of cyclical refresh. | |
*/ | |
private class RefreshProgressMessageJob extends UIJob { | |
private GranualProgressMonitor progressMonitor; | |
/** | |
* Creates a new instance of the class. | |
*/ | |
public RefreshProgressMessageJob() { | |
super(FilteredItemsSelectionWizardPage.this.getShell().getDisplay(), WorkbenchMessages.FilteredItemsSelectionDialog_progressRefreshJob); | |
setSystem(true); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public IStatus runInUIThread(IProgressMonitor monitor) { | |
if (!progressLabel.isDisposed()) | |
progressLabel.setText(progressMonitor != null ? progressMonitor.getMessage() : EMPTY_STRING); | |
if (progressMonitor == null || progressMonitor.isDone()) { | |
return new Status(IStatus.CANCEL, PlatformUI.PLUGIN_ID, IStatus.CANCEL, EMPTY_STRING, null); | |
} | |
// Schedule cyclical with 500 milliseconds delay | |
schedule(500); | |
return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK, EMPTY_STRING, null); | |
} | |
/** | |
* Schedule progress refresh job. | |
* | |
* @param progressMonitor | |
* used during refresh progress label | |
*/ | |
public void scheduleProgressRefresh(GranualProgressMonitor progressMonitor) { | |
this.progressMonitor = progressMonitor; | |
// Schedule with initial delay to avoid flickering when the user | |
// types quickly | |
schedule(200); | |
} | |
} | |
/** | |
* A job responsible for computing filtered items list presented using | |
* <code>RefreshJob</code>. | |
* | |
* @see FilteredItemsSelectionDialog.RefreshJob | |
* | |
*/ | |
private class RefreshCacheJob extends Job { | |
private RefreshJob refreshJob = new RefreshJob(); | |
/** | |
* Creates a new instance of the class. | |
*/ | |
public RefreshCacheJob() { | |
super(WorkbenchMessages.FilteredItemsSelectionDialog_cacheRefreshJob); | |
setSystem(true); | |
} | |
/** | |
* Stops the job and all sub-jobs. | |
*/ | |
public void cancelAll() { | |
cancel(); | |
refreshJob.cancel(); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
protected IStatus run(IProgressMonitor monitor) { | |
if (monitor.isCanceled()) { | |
return new Status(IStatus.CANCEL, WorkbenchPlugin.PI_WORKBENCH, IStatus.CANCEL, EMPTY_STRING, null); | |
} | |
if (FilteredItemsSelectionWizardPage.this != null) { | |
GranualProgressMonitor wrappedMonitor = new GranualProgressMonitor(monitor); | |
FilteredItemsSelectionWizardPage.this.reloadCache(true, wrappedMonitor); | |
} | |
if (!monitor.isCanceled()) { | |
refreshJob.schedule(); | |
} | |
return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK, EMPTY_STRING, null); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.jobs.Job#canceling() | |
*/ | |
protected void canceling() { | |
super.canceling(); | |
contentProvider.stopReloadingCache(); | |
} | |
} | |
private class ToggleStatusLineAction extends Action { | |
/** | |
* Creates a new instance of the class. | |
*/ | |
public ToggleStatusLineAction() { | |
super(WorkbenchMessages.FilteredItemsSelectionDialog_toggleStatusAction, IAction.AS_CHECK_BOX); | |
} | |
public void run() { | |
details.setVisible(isChecked()); | |
} | |
} | |
private class RemoveHistoryItemAction extends Action { | |
/** | |
* Creates a new instance of the class. | |
*/ | |
public RemoveHistoryItemAction() { | |
super(WorkbenchMessages.FilteredItemsSelectionDialog_removeItemsFromHistoryAction); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.action.Action#run() | |
*/ | |
public void run() { | |
List selectedElements = ((StructuredSelection) list.getSelection()).toList(); | |
removeSelectedItems(selectedElements); | |
} | |
} | |
/** | |
* A content provider that does nothing. | |
*/ | |
private class NullContentProvider implements IContentProvider { | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.IContentProvider#dispose() | |
*/ | |
public void dispose() { | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, | |
* java.lang.Object, java.lang.Object) | |
*/ | |
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { | |
} | |
} | |
/** | |
* Used in ItemsListContentProvider, separates history and non-history | |
* items. | |
*/ | |
private class ItemsListSeparator { | |
private String name; | |
/** | |
* Creates a new instance of the class. | |
* | |
* @param name | |
* the name of the separator | |
*/ | |
public ItemsListSeparator(String name) { | |
this.name = name; | |
} | |
/** | |
* Returns the name of this separator. | |
* | |
* @return the name of the separator | |
*/ | |
public String getName() { | |
return name; | |
} | |
} | |
/** | |
* Compares items according to the history. | |
*/ | |
private class HistoryComparator implements Comparator { | |
private CamelCaseComparator camelCaseComparator; | |
/** | |
* | |
*/ | |
public HistoryComparator() { | |
this.camelCaseComparator = new CamelCaseComparator(); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) | |
*/ | |
public int compare(Object o1, Object o2) { | |
if ((isHistoryElement(o1) && isHistoryElement(o2)) || (!isHistoryElement(o1) && !isHistoryElement(o2))) | |
return this.camelCaseComparator.compare(o1, o2); | |
if (isHistoryElement(o1)) | |
return -2; | |
if (isHistoryElement(o2)) | |
return +2; | |
return 0; | |
} | |
} | |
/** | |
* GranualProgressMonitor is used for monitoring progress of filtering | |
* process. It is used by <code>RefreshProgressMessageJob</code> to | |
* refresh progress message. State of this monitor illustrates state of | |
* filtering or cache refreshing process. | |
* | |
*/ | |
private class GranualProgressMonitor extends ProgressMonitorWrapper { | |
private String name; | |
private String subName; | |
private int totalWork; | |
private double worked; | |
private boolean done; | |
/** | |
* Creates instance of <code>GranualProgressMonitor</code>. | |
* | |
* @param monitor | |
* progress to be wrapped | |
*/ | |
public GranualProgressMonitor(IProgressMonitor monitor) { | |
super(monitor); | |
} | |
/** | |
* Checks if filtering has been done | |
* | |
* @return true if filtering work has been done false in other way | |
*/ | |
public boolean isDone() { | |
return done; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.ProgressMonitorWrapper#setTaskName(java.lang.String) | |
*/ | |
public void setTaskName(String name) { | |
super.setTaskName(name); | |
this.name = name; | |
this.subName = null; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.ProgressMonitorWrapper#subTask(java.lang.String) | |
*/ | |
public void subTask(String name) { | |
super.subTask(name); | |
this.subName = name; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.ProgressMonitorWrapper#beginTask(java.lang.String, | |
* int) | |
*/ | |
public void beginTask(String name, int totalWork) { | |
super.beginTask(name, totalWork); | |
if (this.name == null) | |
this.name = name; | |
this.totalWork = totalWork; | |
refreshProgressMessageJob.scheduleProgressRefresh(this); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.ProgressMonitorWrapper#worked(int) | |
*/ | |
public void worked(int work) { | |
super.worked(work); | |
internalWorked(work); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.ProgressMonitorWrapper#done() | |
*/ | |
public void done() { | |
done = true; | |
super.done(); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.ProgressMonitorWrapper#setCanceled(boolean) | |
*/ | |
public void setCanceled(boolean b) { | |
done = b; | |
super.setCanceled(b); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.ProgressMonitorWrapper#internalWorked(double) | |
*/ | |
public void internalWorked(double work) { | |
worked = worked + work; | |
} | |
private String getMessage() { | |
if (done) | |
return ""; //$NON-NLS-1$ | |
String message; | |
if (name == null) { | |
message = subName == null ? "" : subName; //$NON-NLS-1$ | |
} else { | |
message = subName == null ? name : NLS.bind(WorkbenchMessages.FilteredItemsSelectionDialog_subtaskProgressMessage, new Object[] { name, subName }); | |
} | |
if (totalWork == 0) | |
return message; | |
return NLS.bind(WorkbenchMessages.FilteredItemsSelectionDialog_taskProgressMessage, new Object[] { message, new Integer((int) ((worked * 100) / totalWork)) }); | |
} | |
} | |
/** | |
* Filters items history and schedule filter job. | |
*/ | |
private class FilterHistoryJob extends Job { | |
/** | |
* Filter used during the filtering process. | |
*/ | |
private ItemsFilter itemsFilter; | |
/** | |
* Creates new instance of receiver. | |
*/ | |
public FilterHistoryJob() { | |
super(WorkbenchMessages.FilteredItemsSelectionDialog_jobLabel); | |
setSystem(true); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
protected IStatus run(IProgressMonitor monitor) { | |
this.itemsFilter = filter; | |
contentProvider.reset(); | |
refreshWithLastSelection = false; | |
contentProvider.addHistoryItems(itemsFilter); | |
if (!(lastCompletedFilter != null && lastCompletedFilter.isSubFilter(this.itemsFilter))) | |
contentProvider.refresh(); | |
filterJob.schedule(); | |
return Status.OK_STATUS; | |
} | |
} | |
/** | |
* Filters items in indicated set and history. During filtering, it | |
* refreshes the dialog (progress monitor and elements list). | |
* | |
* Depending on the filter, <code>FilterJob</code> decides which kind of | |
* search will be run inside <code>filterContent</code>. If the last | |
* filtering is done (last completed filter), is not null, and the new | |
* filter is a sub-filter ({@link FilteredItemsSelectionDialog.ItemsFilter#isSubFilter(FilteredItemsSelectionDialog.ItemsFilter)}) | |
* of the last, then <code>FilterJob</code> only filters in the cache. If | |
* it is the first filtering or the new filter isn't a sub-filter of the | |
* last one, a full search is run. | |
*/ | |
private class FilterJob extends Job { | |
/** | |
* Filter used during the filtering process. | |
*/ | |
protected ItemsFilter itemsFilter; | |
/** | |
* Creates new instance of FilterJob | |
*/ | |
public FilterJob() { | |
super(WorkbenchMessages.FilteredItemsSelectionDialog_jobLabel); | |
setSystem(true); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
protected final IStatus run(IProgressMonitor parent) { | |
GranualProgressMonitor monitor = new GranualProgressMonitor(parent); | |
return doRun(monitor); | |
} | |
/** | |
* Executes job using the given filtering progress monitor. A hook for | |
* subclasses. | |
* | |
* @param monitor | |
* progress monitor | |
* @return result of the execution | |
*/ | |
protected IStatus doRun(GranualProgressMonitor monitor) { | |
try { | |
internalRun(monitor); | |
} catch (CoreException e) { | |
cancel(); | |
return new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR, WorkbenchMessages.FilteredItemsSelectionDialog_jobError, e); | |
} | |
return Status.OK_STATUS; | |
} | |
/** | |
* Main method for the job. | |
* | |
* @param monitor | |
* @throws CoreException | |
*/ | |
private void internalRun(GranualProgressMonitor monitor) throws CoreException { | |
try { | |
if (monitor.isCanceled()) | |
return; | |
this.itemsFilter = filter; | |
if (filter.getPattern().length() != 0) { | |
filterContent(monitor); | |
} | |
if (monitor.isCanceled()) | |
return; | |
contentProvider.refresh(); | |
} finally { | |
monitor.done(); | |
} | |
} | |
/** | |
* Filters items. | |
* | |
* @param monitor | |
* for monitoring progress | |
* @throws CoreException | |
*/ | |
protected void filterContent(GranualProgressMonitor monitor) throws CoreException { | |
if (lastCompletedFilter != null && lastCompletedFilter.isSubFilter(this.itemsFilter)) { | |
int length = lastCompletedResult.size() / 500; | |
monitor.beginTask(WorkbenchMessages.FilteredItemsSelectionDialog_cacheSearchJob_taskName, length); | |
for (int pos = 0; pos < lastCompletedResult.size(); pos++) { | |
Object item = lastCompletedResult.get(pos); | |
if (monitor.isCanceled()) | |
break; | |
contentProvider.add(item, itemsFilter); | |
if ((pos % 500) == 0) { | |
monitor.worked(1); | |
} | |
} | |
} else { | |
lastCompletedFilter = null; | |
lastCompletedResult = null; | |
SubProgressMonitor subMonitor = null; | |
if (monitor != null) { | |
monitor.beginTask(WorkbenchMessages.FilteredItemsSelectionDialog_searchJob_taskName, 100); | |
subMonitor = new SubProgressMonitor(monitor, 95); | |
} | |
fillContentProvider(contentProvider, itemsFilter, subMonitor); | |
if (monitor != null && !monitor.isCanceled()) { | |
monitor.worked(2); | |
contentProvider.rememberResult(itemsFilter); | |
monitor.worked(3); | |
} | |
} | |
} | |
} | |
/** | |
* History stores a list of key, object pairs. The list is bounded at a | |
* certain size. If the list exceeds this size the oldest element is removed | |
* from the list. An element can be added/renewed with a call to | |
* <code>accessed(Object)</code>. | |
* <p> | |
* The history can be stored to/loaded from an XML file. | |
*/ | |
protected static abstract class SelectionHistory { | |
private static final String DEFAULT_ROOT_NODE_NAME = "historyRootNode"; //$NON-NLS-1$ | |
private static final String DEFAULT_INFO_NODE_NAME = "infoNode"; //$NON-NLS-1$ | |
private static final int MAX_HISTORY_SIZE = 60; | |
private final List historyList; | |
private final String rootNodeName; | |
private final String infoNodeName; | |
private SelectionHistory(String rootNodeName, String infoNodeName) { | |
historyList = Collections.synchronizedList(new LinkedList() { | |
private static final long serialVersionUID = 0L; | |
/* | |
* (non-Javadoc) | |
* | |
* @see java.util.LinkedList#add(java.lang.Object) | |
*/ | |
public boolean add(Object arg0) { | |
if (this.size() >= MAX_HISTORY_SIZE) | |
this.removeFirst(); | |
if (!this.contains(arg0)) | |
return super.add(arg0); | |
return false; | |
} | |
}); | |
this.rootNodeName = rootNodeName; | |
this.infoNodeName = infoNodeName; | |
} | |
/** | |
* Creates new instance of <code>SelectionHistory</code>. | |
*/ | |
public SelectionHistory() { | |
this(DEFAULT_ROOT_NODE_NAME, DEFAULT_INFO_NODE_NAME); | |
} | |
/** | |
* Adds object to history. | |
* | |
* @param object | |
* the item to be added to the history | |
*/ | |
public synchronized void accessed(Object object) { | |
historyList.add(object); | |
} | |
/** | |
* Returns <code>true</code> if history contains object. | |
* | |
* @param object | |
* the item for which check will be executed | |
* @return <code>true</code> if history contains object | |
* <code>false</code> in other way | |
*/ | |
public synchronized boolean contains(Object object) { | |
return historyList.contains(object); | |
} | |
/** | |
* Returns <code>true</code> if history is empty. | |
* | |
* @return <code>true</code> if history is empty | |
*/ | |
public synchronized boolean isEmpty() { | |
return historyList.isEmpty(); | |
} | |
/** | |
* Remove element from history. | |
* | |
* @param element | |
* to remove form the history | |
* @return <code>true</code> if this list contained the specified | |
* element | |
*/ | |
public synchronized boolean remove(Object element) { | |
return historyList.remove(element); | |
} | |
/** | |
* Load history elements from memento. | |
* | |
* @param memento | |
* memento from which the history will be retrieved | |
*/ | |
public void load(IMemento memento) { | |
XMLMemento historyMemento = (XMLMemento) memento.getChild(rootNodeName); | |
if (historyMemento == null) { | |
return; | |
} | |
IMemento[] mementoElements = historyMemento.getChildren(infoNodeName); | |
for (int i = 0; i < mementoElements.length; ++i) { | |
IMemento mementoElement = mementoElements[i]; | |
Object object = restoreItemFromMemento(mementoElement); | |
if (object != null) { | |
historyList.add(object); | |
} | |
} | |
} | |
/** | |
* Save history elements to memento. | |
* | |
* @param memento | |
* memento to which the history will be added | |
*/ | |
public void save(IMemento memento) { | |
IMemento historyMemento = memento.createChild(rootNodeName); | |
Object[] items = getHistoryItems(); | |
for (int i = 0; i < items.length; i++) { | |
Object item = items[i]; | |
IMemento elementMemento = historyMemento.createChild(infoNodeName); | |
storeItemToMemento(item, elementMemento); | |
} | |
} | |
/** | |
* Gets array of history items. | |
* | |
* @return array of history elements | |
*/ | |
public synchronized Object[] getHistoryItems() { | |
return historyList.toArray(); | |
} | |
/** | |
* Creates an object using given memento. | |
* | |
* @param memento | |
* memento used for creating new object | |
* | |
* @return the restored object | |
*/ | |
protected abstract Object restoreItemFromMemento(IMemento memento); | |
/** | |
* Store object in <code>IMemento</code>. | |
* | |
* @param item | |
* the item to store | |
* @param memento | |
* the memento to store to | |
*/ | |
protected abstract void storeItemToMemento(Object item, IMemento memento); | |
} | |
/** | |
* Filters elements using SearchPattern by comparing the names of items with | |
* the filter pattern. | |
*/ | |
protected abstract class ItemsFilter { | |
protected SearchPattern patternMatcher; | |
/** | |
* Creates new instance of ItemsFilter. | |
*/ | |
public ItemsFilter() { | |
this(new SearchPattern()); | |
} | |
/** | |
* Creates new instance of ItemsFilter. | |
* | |
* @param searchPattern | |
* the pattern to be used when filtering | |
*/ | |
public ItemsFilter(SearchPattern searchPattern) { | |
patternMatcher = searchPattern; | |
String stringPattern = ""; //$NON-NLS-1$ | |
if (pattern != null && !pattern.getText().equals("*")) { //$NON-NLS-1$ | |
stringPattern = pattern.getText(); | |
} | |
patternMatcher.setPattern(stringPattern); | |
} | |
/** | |
* Check if the given filter is a sub-filter of this filter. The default | |
* implementation checks if the <code>SearchPattern</code> from the | |
* given filter is a sub-pattern of the one from this filter. | |
* <p> | |
* <i>WARNING: This method is <b>not</b> defined in reading order, i.e. | |
* <code>a.isSubFilter(b)</code> is <code>true</code> iff | |
* <code>b</code> is a sub-filter of <code>a</code>, and not | |
* vice-versa. </i> | |
* </p> | |
* | |
* @param filter | |
* the filter to be checked, or <code>null</code> | |
* @return <code>true</code> if the given filter is sub-filter of this | |
* filter, <code>false</code> if the given filter isn't a | |
* sub-filter or is <code>null</code> | |
* | |
* @see org.eclipse.ui.dialogs.SearchPattern#isSubPattern(org.eclipse.ui.dialogs.SearchPattern) | |
*/ | |
public boolean isSubFilter(ItemsFilter filter) { | |
if (filter != null) { | |
return this.patternMatcher.isSubPattern(filter.patternMatcher); | |
} | |
return false; | |
} | |
/** | |
* Checks whether the provided filter is equal to the current filter. | |
* The default implementation checks if <code>SearchPattern</code> | |
* from current filter is equal to the one from provided filter. | |
* | |
* @param filter | |
* filter to be checked, or <code>null</code> | |
* @return <code>true</code> if the given filter is equal to current | |
* filter, <code>false</code> if given filter isn't equal to | |
* current one or if it is <code>null</code> | |
* | |
* @see org.eclipse.ui.dialogs.SearchPattern#equalsPattern(org.eclipse.ui.dialogs.SearchPattern) | |
*/ | |
public boolean equalsFilter(ItemsFilter filter) { | |
if (filter != null && filter.patternMatcher.equalsPattern(this.patternMatcher)) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Checks whether the pattern's match rule is camel case. | |
* | |
* @return <code>true</code> if pattern's match rule is camel case, | |
* <code>false</code> otherwise | |
*/ | |
public boolean isCamelCasePattern() { | |
return patternMatcher.getMatchRule() == SearchPattern.RULE_CAMELCASE_MATCH; | |
} | |
/** | |
* Returns the pattern string. | |
* | |
* @return pattern for this filter | |
* | |
* @see SearchPattern#getPattern() | |
*/ | |
public String getPattern() { | |
return patternMatcher.getPattern(); | |
} | |
/** | |
* Returns the rule to apply for matching keys. | |
* | |
* @return an implementation-specific match rule | |
* | |
* @see SearchPattern#getMatchRule() for match rules returned by the | |
* default implementation | |
*/ | |
public int getMatchRule() { | |
return patternMatcher.getMatchRule(); | |
} | |
/** | |
* Matches text with filter. | |
* | |
* @param text | |
* the text to match with the filter | |
* @return <code>true</code> if text matches with filter pattern, | |
* <code>false</code> otherwise | |
*/ | |
protected boolean matches(String text) { | |
return patternMatcher.matches(text); | |
} | |
/** | |
* General method for matching raw name pattern. Checks whether current | |
* pattern is prefix of name provided item. | |
* | |
* @param item | |
* item to check | |
* @return <code>true</code> if current pattern is a prefix of name | |
* provided item, <code>false</code> if item's name is shorter | |
* than prefix or sequences of characters don't match. | |
*/ | |
public boolean matchesRawNamePattern(Object item) { | |
String prefix = patternMatcher.getPattern(); | |
String text = getElementName(item); | |
if (text == null) | |
return false; | |
int textLength = text.length(); | |
int prefixLength = prefix.length(); | |
if (textLength < prefixLength) { | |
return false; | |
} | |
for (int i = prefixLength - 1; i >= 0; i--) { | |
if (Character.toLowerCase(prefix.charAt(i)) != Character.toLowerCase(text.charAt(i))) | |
return false; | |
} | |
return true; | |
} | |
/** | |
* Matches an item against filter conditions. | |
* | |
* @param item | |
* @return <code>true<code> if item matches against filter conditions, <code>false</code> | |
* otherwise | |
*/ | |
public abstract boolean matchItem(Object item); | |
/** | |
* Checks consistency of an item. Item is inconsistent if was changed or | |
* removed. | |
* | |
* @param item | |
* @return <code>true</code> if item is consistent, <code>false</code> | |
* if item is inconsistent | |
*/ | |
public abstract boolean isConsistentItem(Object item); | |
} | |
/** | |
* Creates a new wizard page with the given name, and | |
* with no title or image. | |
* | |
* @param pageName | |
* the name of the page | |
*/ | |
protected FilteredItemsSelectionWizardPage(String pageId, boolean multi) { | |
super(pageId); | |
this.multi = multi; | |
contentProvider = new ContentProvider(); | |
itemsListSeparator = new ItemsListSeparator(WorkbenchMessages.FilteredItemsSelectionDialog_separatorLabel); | |
selectionMode = NONE; | |
} | |
/** | |
* Returns the list of selections made by the user, or <code>null</code> | |
* if the selection was canceled. | |
* | |
* @return the array of selected elements, or <code>null</code> if Cancel | |
* was pressed | |
*/ | |
public Object[] getResult() { | |
return result; | |
} | |
/** | |
* Set the selections made by the user, or <code>null</code> if the | |
* selection was canceled. | |
* | |
* @param newResult | |
* list of selected elements, or <code>null</code> if Cancel | |
* was pressed | |
*/ | |
protected void setResult(List newResult) { | |
if (newResult == null) { | |
result = null; | |
} else { | |
result = new Object[newResult.size()]; | |
newResult.toArray(result); | |
} | |
} | |
/** | |
* Adds viewer filter to the dialog items list. | |
* | |
* @param filter | |
* the new filter | |
*/ | |
protected void addListFilter(ViewerFilter filter) { | |
contentProvider.addFilter(filter); | |
} | |
/** | |
* Sets a new label provider for items in the list. If the label provider | |
* also implements {@link org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider .IStyledLabelProvider}, the style text labels provided by it will be used | |
* provided that the corresponding preference is set. | |
* | |
* @see IWorkbenchPreferenceConstants#USE_COLORED_LABELS | |
* | |
* @param listLabelProvider | |
* the label provider for items in the list | |
*/ | |
public void setListLabelProvider(ILabelProvider listLabelProvider) { | |
getItemsListLabelProvider().setProvider(listLabelProvider); | |
} | |
/** | |
* Returns the label decorator for selected items in the list. | |
* | |
* @return the label decorator for selected items in the list | |
*/ | |
private ILabelDecorator getListSelectionLabelDecorator() { | |
return getItemsListLabelProvider().getSelectionDecorator(); | |
} | |
/** | |
* Sets the label decorator for selected items in the list. | |
* | |
* @param listSelectionLabelDecorator | |
* the label decorator for selected items in the list | |
*/ | |
public void setListSelectionLabelDecorator(ILabelDecorator listSelectionLabelDecorator) { | |
getItemsListLabelProvider().setSelectionDecorator(listSelectionLabelDecorator); | |
} | |
/** | |
* Returns the item list label provider. | |
* | |
* @return the item list label provider | |
*/ | |
private ItemsListLabelProvider getItemsListLabelProvider() { | |
if (itemsListLabelProvider == null) { | |
itemsListLabelProvider = new ItemsListLabelProvider(new LabelProvider(), null); | |
} | |
return itemsListLabelProvider; | |
} | |
/** | |
* Sets label provider for the details field. | |
* | |
* For a single selection, the element sent to {@link ILabelProvider#getImage(Object)} and {@link ILabelProvider#getText(Object)} is the selected object, for | |
* multiple selection a {@link String} with amount of selected items is the | |
* element. | |
* | |
* @see #getSelectedItems() getSelectedItems() can be used to retrieve | |
* selected items and get the items count. | |
* | |
* @param detailsLabelProvider | |
* the label provider for the details field | |
*/ | |
public void setDetailsLabelProvider(ILabelProvider detailsLabelProvider) { | |
this.detailsLabelProvider = detailsLabelProvider; | |
if (details != null) { | |
details.setLabelProvider(detailsLabelProvider); | |
} | |
} | |
private ILabelProvider getDetailsLabelProvider() { | |
if (detailsLabelProvider == null) { | |
detailsLabelProvider = new LabelProvider(); | |
} | |
return detailsLabelProvider; | |
} | |
/** | |
* Restores dialog using persisted settings. The default implementation | |
* restores the status of the details line and the selection history. | |
* | |
* @param settings | |
* settings used to restore dialog | |
*/ | |
protected void restoreDialog(IDialogSettings settings) { | |
boolean toggleStatusLine = true; | |
if (settings.get(SHOW_STATUS_LINE) != null) { | |
toggleStatusLine = settings.getBoolean(SHOW_STATUS_LINE); | |
} | |
toggleStatusLineAction.setChecked(toggleStatusLine); | |
details.setVisible(toggleStatusLine); | |
String setting = settings.get(HISTORY_SETTINGS); | |
if (setting != null) { | |
try { | |
IMemento memento = XMLMemento.createReadRoot(new StringReader(setting)); | |
this.contentProvider.loadHistory(memento); | |
} catch (WorkbenchException e) { | |
// Simply don't restore the settings | |
StatusManager.getManager().handle(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR, WorkbenchMessages.FilteredItemsSelectionDialog_restoreError, e)); | |
} | |
} | |
} | |
@Override | |
public void dispose() { | |
filterJob.cancel(); | |
refreshCacheJob.cancel(); | |
refreshProgressMessageJob.cancel(); | |
if (showViewHandler != null) { | |
IHandlerService service = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class); | |
service.deactivateHandler(showViewHandler); | |
showViewHandler.getHandler().dispose(); | |
showViewHandler = null; | |
} | |
storeDialog(getDialogSettings()); | |
super.dispose(); | |
} | |
/** | |
* Stores dialog settings. | |
* | |
* @param settings | |
* settings used to store dialog | |
*/ | |
protected void storeDialog(IDialogSettings settings) { | |
settings.put(SHOW_STATUS_LINE, toggleStatusLineAction.isChecked()); | |
XMLMemento memento = XMLMemento.createWriteRoot(HISTORY_SETTINGS); | |
this.contentProvider.saveHistory(memento); | |
StringWriter writer = new StringWriter(); | |
try { | |
memento.save(writer); | |
settings.put(HISTORY_SETTINGS, writer.getBuffer().toString()); | |
} catch (IOException e) { | |
// Simply don't store the settings | |
StatusManager.getManager().handle(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR, WorkbenchMessages.FilteredItemsSelectionDialog_storeError, e)); | |
} | |
} | |
protected String getHeaderMessage() { | |
return WorkbenchMessages.FilteredItemsSelectionDialog_patternLabel; | |
} | |
/** | |
* Create a new header which is labelled by headerLabel. | |
* | |
* @param parent | |
* @return Label the label of the header | |
*/ | |
private Label createHeader(Composite parent) { | |
Composite header = new Composite(parent, SWT.NONE); | |
GridLayout layout = new GridLayout(); | |
layout.numColumns = 2; | |
layout.marginWidth = 0; | |
layout.marginHeight = 0; | |
header.setLayout(layout); | |
Label headerLabel = new Label(header, SWT.NONE); | |
headerLabel.setText(getHeaderMessage()); | |
headerLabel.addTraverseListener(new TraverseListener() { | |
public void keyTraversed(TraverseEvent e) { | |
if (e.detail == SWT.TRAVERSE_MNEMONIC && e.doit) { | |
e.detail = SWT.TRAVERSE_NONE; | |
pattern.setFocus(); | |
} | |
} | |
}); | |
GridData gd = new GridData(GridData.FILL_HORIZONTAL); | |
headerLabel.setLayoutData(gd); | |
createViewMenu(header); | |
header.setLayoutData(gd); | |
return headerLabel; | |
} | |
/** | |
* Create the labels for the list and the progress. Return the list label. | |
* | |
* @param parent | |
* @return Label | |
*/ | |
private Label createLabels(Composite parent) { | |
Composite labels = new Composite(parent, SWT.NONE); | |
GridLayout layout = new GridLayout(); | |
layout.numColumns = 2; | |
layout.marginWidth = 0; | |
layout.marginHeight = 0; | |
labels.setLayout(layout); | |
Label listLabel = new Label(labels, SWT.NONE); | |
listLabel.setText(WorkbenchMessages.FilteredItemsSelectionDialog_listLabel); | |
listLabel.addTraverseListener(new TraverseListener() { | |
public void keyTraversed(TraverseEvent e) { | |
if (e.detail == SWT.TRAVERSE_MNEMONIC && e.doit) { | |
e.detail = SWT.TRAVERSE_NONE; | |
list.getTable().setFocus(); | |
} | |
} | |
}); | |
GridData gd = new GridData(GridData.FILL_HORIZONTAL); | |
listLabel.setLayoutData(gd); | |
progressLabel = new Label(labels, SWT.RIGHT); | |
progressLabel.setLayoutData(gd); | |
labels.setLayoutData(gd); | |
return listLabel; | |
} | |
private void createViewMenu(Composite parent) { | |
toolBar = new ToolBar(parent, SWT.FLAT); | |
toolItem = new ToolItem(toolBar, SWT.PUSH, 0); | |
GridData data = new GridData(); | |
data.horizontalAlignment = GridData.END; | |
toolBar.setLayoutData(data); | |
toolBar.addMouseListener(new MouseAdapter() { | |
public void mouseDown(MouseEvent e) { | |
showViewMenu(); | |
} | |
}); | |
toolItem.setImage(WorkbenchImages.getImage(IWorkbenchGraphicConstants.IMG_LCL_VIEW_MENU)); | |
toolItem.setToolTipText(WorkbenchMessages.FilteredItemsSelectionDialog_menu); | |
toolItem.addSelectionListener(new SelectionAdapter() { | |
public void widgetSelected(SelectionEvent e) { | |
showViewMenu(); | |
} | |
}); | |
menuManager = new MenuManager(); | |
fillViewMenu(menuManager); | |
IHandlerService service = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class); | |
IHandler handler = new AbstractHandler() { | |
public Object execute(ExecutionEvent event) { | |
showViewMenu(); | |
return null; | |
} | |
}; | |
showViewHandler = service.activateHandler(IWorkbenchCommandConstants.WINDOW_SHOW_VIEW_MENU, handler, new ActiveShellExpression(FilteredItemsSelectionWizardPage.this.getShell())); | |
} | |
/** | |
* Fills the menu of the dialog. | |
* | |
* @param menuManager | |
* the menu manager | |
*/ | |
protected void fillViewMenu(IMenuManager menuManager) { | |
toggleStatusLineAction = new ToggleStatusLineAction(); | |
menuManager.add(toggleStatusLineAction); | |
} | |
private void showViewMenu() { | |
Menu menu = menuManager.createContextMenu(FilteredItemsSelectionWizardPage.this.getShell()); | |
Rectangle bounds = toolItem.getBounds(); | |
Point topLeft = new Point(bounds.x, bounds.y + bounds.height); | |
topLeft = toolBar.toDisplay(topLeft); | |
menu.setLocation(topLeft.x, topLeft.y); | |
menu.setVisible(true); | |
} | |
/** | |
* Hook that allows to add actions to the context menu. | |
* <p> | |
* Subclasses may extend in order to add other actions.</p> | |
* | |
* @param menuManager | |
* the context menu manager | |
* @since 3.5 | |
*/ | |
protected void fillContextMenu(IMenuManager menuManager) { | |
List selectedElements = ((StructuredSelection) list.getSelection()).toList(); | |
Object item = null; | |
for (Iterator it = selectedElements.iterator(); it.hasNext();) { | |
item = it.next(); | |
if (item instanceof ItemsListSeparator || !isHistoryElement(item)) { | |
return; | |
} | |
} | |
if (selectedElements.size() > 0) { | |
removeHistoryItemAction.setText(WorkbenchMessages.FilteredItemsSelectionDialog_removeItemsFromHistoryAction); | |
menuManager.add(removeHistoryActionContributionItem); | |
} | |
} | |
private void createPopupMenu() { | |
removeHistoryItemAction = new RemoveHistoryItemAction(); | |
removeHistoryActionContributionItem = new ActionContributionItem(removeHistoryItemAction); | |
MenuManager manager = new MenuManager(); | |
manager.setRemoveAllWhenShown(true); | |
manager.addMenuListener(new IMenuListener() { | |
public void menuAboutToShow(IMenuManager manager) { | |
fillContextMenu(manager); | |
} | |
}); | |
final Table table = list.getTable(); | |
Menu menu = manager.createContextMenu(table); | |
table.setMenu(menu); | |
} | |
/** | |
* Creates an extra content area, which will be located above the details. | |
* | |
* @param parent | |
* parent to create the dialog widgets in | |
* @return an extra content area | |
*/ | |
protected abstract Control createExtendedContentArea(Composite parent); | |
public void createControl(Composite parent) { | |
refreshProgressMessageJob = new RefreshProgressMessageJob(); | |
filterHistoryJob = new FilterHistoryJob(); | |
filterJob = new FilterJob(); | |
refreshCacheJob = new RefreshCacheJob(); | |
Composite content = new Composite(parent, SWT.NONE); | |
GridData gd = new GridData(GridData.FILL_BOTH); | |
content.setLayoutData(gd); | |
GridLayout layout = new GridLayout(); | |
layout.numColumns = 1; | |
layout.marginWidth = 0; | |
layout.marginHeight = 0; | |
content.setLayout(layout); | |
final Label headerLabel = createHeader(content); | |
pattern = new Text(content, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL); | |
pattern.getAccessible().addAccessibleListener(new AccessibleAdapter() { | |
public void getName(AccessibleEvent e) { | |
e.result = LegacyActionTools.removeMnemonics(headerLabel.getText()); | |
} | |
}); | |
gd = new GridData(GridData.FILL_HORIZONTAL); | |
pattern.setLayoutData(gd); | |
final Label listLabel = createLabels(content); | |
list = new TableViewer(content, (multi ? SWT.MULTI : SWT.SINGLE) | SWT.BORDER | SWT.V_SCROLL | SWT.VIRTUAL); | |
list.getTable().getAccessible().addAccessibleListener(new AccessibleAdapter() { | |
public void getName(AccessibleEvent e) { | |
if (e.childID == ACC.CHILDID_SELF) { | |
e.result = LegacyActionTools.removeMnemonics(listLabel.getText()); | |
} | |
} | |
}); | |
list.setContentProvider(contentProvider); | |
list.setLabelProvider(getItemsListLabelProvider()); | |
list.setInput(new Object[0]); | |
list.setItemCount(contentProvider.getNumberOfElements()); | |
list.addSelectionChangedListener(new ISelectionChangedListener() { | |
public void selectionChanged(SelectionChangedEvent event) { | |
setPageComplete(validatePage()); | |
} | |
}); | |
gd = new GridData(GridData.FILL_BOTH); | |
applyDialogFont(list.getTable()); | |
gd.heightHint = list.getTable().getItemHeight() * 15; | |
list.getTable().setLayoutData(gd); | |
createPopupMenu(); | |
pattern.addModifyListener(new ModifyListener() { | |
public void modifyText(ModifyEvent e) { | |
applyFilter(); | |
} | |
}); | |
pattern.addKeyListener(new KeyAdapter() { | |
public void keyPressed(KeyEvent e) { | |
if (e.keyCode == SWT.ARROW_DOWN) { | |
if (list.getTable().getItemCount() > 0) { | |
list.getTable().setFocus(); | |
} | |
} | |
} | |
}); | |
list.addSelectionChangedListener(new ISelectionChangedListener() { | |
public void selectionChanged(SelectionChangedEvent event) { | |
StructuredSelection selection = (StructuredSelection) event.getSelection(); | |
handleSelected(selection); | |
} | |
}); | |
list.addDoubleClickListener(new IDoubleClickListener() { | |
public void doubleClick(DoubleClickEvent event) { | |
handleDoubleClick(); | |
} | |
}); | |
list.getTable().addKeyListener(new KeyAdapter() { | |
public void keyPressed(KeyEvent e) { | |
if (e.keyCode == SWT.DEL) { | |
List selectedElements = ((StructuredSelection) list.getSelection()).toList(); | |
Object item = null; | |
boolean isSelectedHistory = true; | |
for (Iterator it = selectedElements.iterator(); it.hasNext();) { | |
item = it.next(); | |
if (item instanceof ItemsListSeparator || !isHistoryElement(item)) { | |
isSelectedHistory = false; | |
break; | |
} | |
} | |
if (isSelectedHistory) | |
removeSelectedItems(selectedElements); | |
} | |
if (e.keyCode == SWT.ARROW_UP && (e.stateMask & SWT.SHIFT) != 0 && (e.stateMask & SWT.CTRL) != 0) { | |
StructuredSelection selection = (StructuredSelection) list.getSelection(); | |
if (selection.size() == 1) { | |
Object element = selection.getFirstElement(); | |
if (element.equals(list.getElementAt(0))) { | |
pattern.setFocus(); | |
} | |
if (list.getElementAt(list.getTable().getSelectionIndex() - 1) instanceof ItemsListSeparator) | |
list.getTable().setSelection(list.getTable().getSelectionIndex() - 1); | |
list.getTable().notifyListeners(SWT.Selection, new Event()); | |
} | |
} | |
if (e.keyCode == SWT.ARROW_DOWN && (e.stateMask & SWT.SHIFT) != 0 && (e.stateMask & SWT.CTRL) != 0) { | |
if (list.getElementAt(list.getTable().getSelectionIndex() + 1) instanceof ItemsListSeparator) | |
list.getTable().setSelection(list.getTable().getSelectionIndex() + 1); | |
list.getTable().notifyListeners(SWT.Selection, new Event()); | |
} | |
} | |
}); | |
createExtendedContentArea(content); | |
details = new DetailsContentViewer(content, SWT.BORDER | SWT.FLAT); | |
details.setVisible(toggleStatusLineAction.isChecked()); | |
details.setContentProvider(new NullContentProvider()); | |
details.setLabelProvider(getDetailsLabelProvider()); | |
applyDialogFont(content); | |
restoreDialog(getDialogSettings()); | |
if (initialPatternText != null) { | |
pattern.setText(initialPatternText); | |
} | |
switch (selectionMode) { | |
case CARET_BEGINNING: | |
pattern.setSelection(0, 0); | |
break; | |
case FULL_SELECTION: | |
pattern.setSelection(0, initialPatternText.length()); | |
break; | |
} | |
// apply filter even if pattern is empty (display history) | |
applyFilter(); | |
setPageComplete(validatePage()); | |
setControl(content); | |
} | |
protected boolean validatePage() { | |
List selectedElements = ((StructuredSelection) list.getSelection()).toList(); | |
return selectedElements != null && selectedElements.size() > 0; | |
} | |
/** | |
* This method is a hook for subclasses to override default dialog behavior. | |
* The <code>handleDoubleClick()</code> method handles double clicks on | |
* the list of filtered elements. | |
* <p> | |
*/ | |
protected void handleDoubleClick() { | |
// DO nothing | |
} | |
/** | |
* Refreshes the details field according to the current selection in the | |
* items list. | |
*/ | |
private void refreshDetails() { | |
StructuredSelection selection = getSelectedItems(); | |
switch (selection.size()) { | |
case 0: | |
details.setInput(null); | |
break; | |
case 1: | |
details.setInput(selection.getFirstElement()); | |
break; | |
default: | |
details.setInput(NLS.bind(WorkbenchMessages.FilteredItemsSelectionDialog_nItemsSelected, new Integer(selection.size()))); | |
break; | |
} | |
} | |
/** | |
* Handle selection in the items list by updating labels of selected and | |
* unselected items and refresh the details field using the selection. | |
* | |
* @param selection | |
* the new selection | |
*/ | |
protected void handleSelected(StructuredSelection selection) { | |
IStatus status = new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK, EMPTY_STRING, null); | |
Object[] lastSelection = currentSelection; | |
currentSelection = selection.toArray(); | |
if (selection.size() == 0) { | |
status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR, EMPTY_STRING, null); | |
if (lastSelection != null && getListSelectionLabelDecorator() != null) { | |
list.update(lastSelection, null); | |
} | |
currentSelection = null; | |
} else { | |
status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR, EMPTY_STRING, null); | |
List items = selection.toList(); | |
Object item = null; | |
IStatus tempStatus = null; | |
for (Iterator it = items.iterator(); it.hasNext();) { | |
Object o = it.next(); | |
if (o instanceof ItemsListSeparator) { | |
continue; | |
} | |
item = o; | |
tempStatus = validateItem(item); | |
if (tempStatus.isOK()) { | |
status = new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK, EMPTY_STRING, null); | |
} else { | |
status = tempStatus; | |
// if any selected element is not valid status is set to | |
// ERROR | |
break; | |
} | |
} | |
if (lastSelection != null && getListSelectionLabelDecorator() != null) { | |
list.update(lastSelection, null); | |
} | |
if (getListSelectionLabelDecorator() != null) { | |
list.update(currentSelection, null); | |
} | |
} | |
refreshDetails(); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.jface.window.Dialog#getDialogBoundsSettings() | |
*/ | |
protected IDialogSettings getDialogBoundsSettings() { | |
IDialogSettings settings = getDialogSettings(); | |
IDialogSettings section = settings.getSection(DIALOG_BOUNDS_SETTINGS); | |
if (section == null) { | |
section = settings.addNewSection(DIALOG_BOUNDS_SETTINGS); | |
section.put(DIALOG_HEIGHT, 500); | |
section.put(DIALOG_WIDTH, 600); | |
} | |
return section; | |
} | |
/** | |
* Returns the dialog settings. Returned object can't be null. | |
* | |
* @return return dialog settings for this dialog | |
*/ | |
protected abstract IDialogSettings getDialogSettings(); | |
/** | |
* Refreshes the dialog - has to be called in UI thread. | |
*/ | |
public void refresh() { | |
if (list != null && !list.getTable().isDisposed()) { | |
List lastRefreshSelection = ((StructuredSelection) list.getSelection()).toList(); | |
list.getTable().deselectAll(); | |
list.setItemCount(contentProvider.getNumberOfElements()); | |
list.refresh(); | |
if (list.getTable().getItemCount() > 0) { | |
// preserve previous selection | |
if (refreshWithLastSelection && lastRefreshSelection != null && lastRefreshSelection.size() > 0) { | |
list.setSelection(new StructuredSelection(lastRefreshSelection)); | |
} else { | |
refreshWithLastSelection = true; | |
list.getTable().setSelection(0); | |
list.getTable().notifyListeners(SWT.Selection, new Event()); | |
} | |
} else { | |
list.setSelection(StructuredSelection.EMPTY); | |
} | |
} | |
scheduleProgressMessageRefresh(); | |
} | |
/** | |
* Updates the progress label. | |
* | |
* @deprecated | |
*/ | |
public void updateProgressLabel() { | |
scheduleProgressMessageRefresh(); | |
} | |
/** | |
* Notifies the content provider - fires filtering of content provider | |
* elements. During the filtering, a separator between history and workspace | |
* matches is added. | |
* <p> | |
* This is a long running operation and should be called in a job. | |
* | |
* @param checkDuplicates | |
* <code>true</code> if data concerning elements duplication | |
* should be computed - it takes much more time than the standard | |
* filtering | |
* @param monitor | |
* a progress monitor or <code>null</code> if no monitor is | |
* available | |
*/ | |
public void reloadCache(boolean checkDuplicates, IProgressMonitor monitor) { | |
if (list != null && !list.getTable().isDisposed() && contentProvider != null) { | |
contentProvider.reloadCache(checkDuplicates, monitor); | |
} | |
} | |
/** | |
* Schedule refresh job. | |
*/ | |
public void scheduleRefresh() { | |
refreshCacheJob.cancelAll(); | |
refreshCacheJob.schedule(); | |
} | |
/** | |
* Schedules progress message refresh. | |
*/ | |
public void scheduleProgressMessageRefresh() { | |
if (filterJob.getState() != Job.RUNNING && refreshProgressMessageJob.getState() != Job.RUNNING) | |
refreshProgressMessageJob.scheduleProgressRefresh(null); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.ui.dialogs.SelectionStatusDialog#computeResult() | |
*/ | |
protected void computeResult() { | |
List selectedElements = ((StructuredSelection) list.getSelection()).toList(); | |
List objectsToReturn = new ArrayList(); | |
Object item = null; | |
for (Iterator it = selectedElements.iterator(); it.hasNext();) { | |
item = it.next(); | |
if (!(item instanceof ItemsListSeparator)) { | |
accessedHistoryItem(item); | |
objectsToReturn.add(item); | |
} | |
} | |
setResult(objectsToReturn); | |
} | |
/** | |
* Sets the initial pattern used by the filter. This text is copied into the | |
* selection input on the dialog. A full selection is used in the pattern | |
* input field. | |
* | |
* @param text | |
* initial pattern for the filter | |
* @see FilteredItemsSelectionDialog#FULL_SELECTION | |
*/ | |
public void setInitialPattern(String text) { | |
setInitialPattern(text, FULL_SELECTION); | |
} | |
/** | |
* Sets the initial pattern used by the filter. This text is copied into the | |
* selection input on the dialog. The <code>selectionMode</code> is used | |
* to choose selection type for the input field. | |
* | |
* @param text | |
* initial pattern for the filter | |
* @param selectionMode | |
* one of: {@link FilteredItemsSelectionDialog#NONE}, {@link FilteredItemsSelectionDialog#CARET_BEGINNING}, {@link FilteredItemsSelectionDialog#FULL_SELECTION} | |
*/ | |
public void setInitialPattern(String text, int selectionMode) { | |
this.initialPatternText = text; | |
this.selectionMode = selectionMode; | |
} | |
/** | |
* Gets initial pattern. | |
* | |
* @return initial pattern, or <code>null</code> if initial pattern is not | |
* set | |
*/ | |
protected String getInitialPattern() { | |
return this.initialPatternText; | |
} | |
/** | |
* Returns the current selection. | |
* | |
* @return the current selection | |
*/ | |
protected StructuredSelection getSelectedItems() { | |
StructuredSelection selection = (StructuredSelection) list.getSelection(); | |
List selectedItems = selection.toList(); | |
Object itemToRemove = null; | |
for (Iterator it = selection.iterator(); it.hasNext();) { | |
Object item = it.next(); | |
if (item instanceof ItemsListSeparator) { | |
itemToRemove = item; | |
break; | |
} | |
} | |
if (itemToRemove == null) | |
return new StructuredSelection(selectedItems); | |
// Create a new selection without the collision | |
List newItems = new ArrayList(selectedItems); | |
newItems.remove(itemToRemove); | |
return new StructuredSelection(newItems); | |
} | |
/** | |
* Validates the item. When items on the items list are selected or | |
* deselected, it validates each item in the selection and the dialog status | |
* depends on all validations. | |
* | |
* @param item | |
* an item to be checked | |
* @return status of the dialog to be set | |
*/ | |
protected abstract IStatus validateItem(Object item); | |
/** | |
* Creates an instance of a filter. | |
* | |
* @return a filter for items on the items list. Can be <code>null</code>, | |
* no filtering will be applied then, causing no item to be shown in | |
* the list. | |
*/ | |
protected abstract ItemsFilter createFilter(); | |
/** | |
* Applies the filter created by <code>createFilter()</code> method to the | |
* items list. When new filter is different than previous one it will cause | |
* refiltering. | |
*/ | |
protected void applyFilter() { | |
ItemsFilter newFilter = createFilter(); | |
// don't apply filtering for patterns which mean the same, for example: | |
// *a**b and ***a*b | |
if (filter != null && filter.equalsFilter(newFilter)) { | |
return; | |
} | |
filterHistoryJob.cancel(); | |
filterJob.cancel(); | |
this.filter = newFilter; | |
if (this.filter != null) { | |
filterHistoryJob.schedule(); | |
} | |
} | |
/** | |
* Returns comparator to sort items inside content provider. Returned object | |
* will be probably created as an anonymous class. Parameters passed to the | |
* <code>compare(java.lang.Object, java.lang.Object)</code> are going to | |
* be the same type as the one used in the content provider. | |
* | |
* @return comparator to sort items content provider | |
*/ | |
protected abstract Comparator getItemsComparator(); | |
/** | |
* Fills the content provider with matching items. | |
* | |
* @param contentProvider | |
* collector to add items to. {@link FilteredItemsSelectionDialog.AbstractContentProvider#add(Object, FilteredItemsSelectionDialog.ItemsFilter)} only adds items that pass the given <code>itemsFilter</code>. | |
* @param itemsFilter | |
* the items filter | |
* @param progressMonitor | |
* must be used to report search progress. The state of this | |
* progress monitor reflects the state of the filtering process. | |
* @throws CoreException | |
*/ | |
protected abstract void fillContentProvider(AbstractContentProvider contentProvider, ItemsFilter itemsFilter, IProgressMonitor progressMonitor) throws CoreException; | |
/** | |
* Removes selected items from history. | |
* | |
* @param items | |
* items to be removed | |
*/ | |
private void removeSelectedItems(List items) { | |
for (Iterator iter = items.iterator(); iter.hasNext();) { | |
Object item = iter.next(); | |
removeHistoryItem(item); | |
} | |
refreshWithLastSelection = false; | |
contentProvider.refresh(); | |
} | |
/** | |
* Removes an item from history. | |
* | |
* @param item | |
* an item to remove | |
* @return removed item | |
*/ | |
protected Object removeHistoryItem(Object item) { | |
return contentProvider.removeHistoryElement(item); | |
} | |
/** | |
* Adds item to history. | |
* | |
* @param item | |
* the item to be added | |
*/ | |
protected void accessedHistoryItem(Object item) { | |
contentProvider.addHistoryElement(item); | |
} | |
/** | |
* Returns a history comparator. | |
* | |
* @return decorated comparator | |
*/ | |
private Comparator getHistoryComparator() { | |
return new HistoryComparator(); | |
} | |
/** | |
* Returns the history of selected elements. | |
* | |
* @return history of selected elements, or <code>null</code> if it is not | |
* set | |
*/ | |
protected SelectionHistory getSelectionHistory() { | |
return this.contentProvider.getSelectionHistory(); | |
} | |
/** | |
* Sets new history. | |
* | |
* @param selectionHistory | |
* the history | |
*/ | |
protected void setSelectionHistory(SelectionHistory selectionHistory) { | |
if (this.contentProvider != null) | |
this.contentProvider.setSelectionHistory(selectionHistory); | |
} | |
/** | |
* Indicates whether the given item is a history item. | |
* | |
* @param item | |
* the item to be investigated | |
* @return <code>true</code> if the given item exists in history, | |
* <code>false</code> otherwise | |
*/ | |
public boolean isHistoryElement(Object item) { | |
return this.contentProvider.isHistoryElement(item); | |
} | |
/** | |
* Indicates whether the given item is a duplicate. | |
* | |
* @param item | |
* the item to be investigated | |
* @return <code>true</code> if the item is duplicate, <code>false</code> | |
* otherwise | |
*/ | |
public boolean isDuplicateElement(Object item) { | |
return this.contentProvider.isDuplicateElement(item); | |
} | |
/** | |
* Sets separator label | |
* | |
* @param separatorLabel | |
* the label showed on separator | |
*/ | |
public void setSeparatorLabel(String separatorLabel) { | |
this.itemsListSeparator = new ItemsListSeparator(separatorLabel); | |
} | |
/** | |
* Returns name for then given object. | |
* | |
* @param item | |
* an object from the content provider. Subclasses should pay | |
* attention to the passed argument. They should either only pass | |
* objects of a known type (one used in content provider) or make | |
* sure that passed parameter is the expected one (by type | |
* checking like <code>instanceof</code> inside the method). | |
* @return name of the given item | |
*/ | |
public abstract String getElementName(Object item); | |
} |