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