Source Code Cross Referenced for FilteredItemsSelectionDialog.java in  » IDE-Eclipse » ui-workbench » org » eclipse » ui » dialogs » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » ui workbench » org.eclipse.ui.dialogs 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Copyright (c) 2000, 2007 IBM Corporation and others.
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         *  IBM Corporation - initial API and implementation 
0010:         *  Willian Mitsuda <wmitsuda@gmail.com> 
0011:         *     - Fix for bug 196553 - [Dialogs] Support IColorProvider/IFontProvider in FilteredItemsSelectionDialog
0012:
0013:         *******************************************************************************/package org.eclipse.ui.dialogs;
0014:
0015:        import java.io.IOException;
0016:        import java.io.StringReader;
0017:        import java.io.StringWriter;
0018:        import java.util.ArrayList;
0019:        import java.util.Arrays;
0020:        import java.util.Collections;
0021:        import java.util.Comparator;
0022:        import java.util.HashMap;
0023:        import java.util.HashSet;
0024:        import java.util.Iterator;
0025:        import java.util.LinkedList;
0026:        import java.util.List;
0027:        import java.util.Set;
0028:
0029:        import org.eclipse.core.commands.AbstractHandler;
0030:        import org.eclipse.core.commands.ExecutionEvent;
0031:        import org.eclipse.core.commands.IHandler;
0032:        import org.eclipse.core.runtime.Assert;
0033:        import org.eclipse.core.runtime.CoreException;
0034:        import org.eclipse.core.runtime.IProgressMonitor;
0035:        import org.eclipse.core.runtime.IStatus;
0036:        import org.eclipse.core.runtime.ListenerList;
0037:        import org.eclipse.core.runtime.ProgressMonitorWrapper;
0038:        import org.eclipse.core.runtime.Status;
0039:        import org.eclipse.core.runtime.SubProgressMonitor;
0040:        import org.eclipse.core.runtime.jobs.Job;
0041:        import org.eclipse.jface.action.Action;
0042:        import org.eclipse.jface.action.ActionContributionItem;
0043:        import org.eclipse.jface.action.IAction;
0044:        import org.eclipse.jface.action.IMenuListener;
0045:        import org.eclipse.jface.action.IMenuManager;
0046:        import org.eclipse.jface.action.MenuManager;
0047:        import org.eclipse.jface.dialogs.IDialogSettings;
0048:        import org.eclipse.jface.viewers.ContentViewer;
0049:        import org.eclipse.jface.viewers.DoubleClickEvent;
0050:        import org.eclipse.jface.viewers.IColorProvider;
0051:        import org.eclipse.jface.viewers.IContentProvider;
0052:        import org.eclipse.jface.viewers.IDoubleClickListener;
0053:        import org.eclipse.jface.viewers.IFontProvider;
0054:        import org.eclipse.jface.viewers.ILabelDecorator;
0055:        import org.eclipse.jface.viewers.ILabelProvider;
0056:        import org.eclipse.jface.viewers.ILabelProviderListener;
0057:        import org.eclipse.jface.viewers.ILazyContentProvider;
0058:        import org.eclipse.jface.viewers.ISelection;
0059:        import org.eclipse.jface.viewers.ISelectionChangedListener;
0060:        import org.eclipse.jface.viewers.IStructuredContentProvider;
0061:        import org.eclipse.jface.viewers.LabelProvider;
0062:        import org.eclipse.jface.viewers.LabelProviderChangedEvent;
0063:        import org.eclipse.jface.viewers.SelectionChangedEvent;
0064:        import org.eclipse.jface.viewers.StructuredSelection;
0065:        import org.eclipse.jface.viewers.TableViewer;
0066:        import org.eclipse.jface.viewers.Viewer;
0067:        import org.eclipse.jface.viewers.ViewerFilter;
0068:        import org.eclipse.osgi.util.NLS;
0069:        import org.eclipse.swt.SWT;
0070:        import org.eclipse.swt.custom.CLabel;
0071:        import org.eclipse.swt.custom.ViewForm;
0072:        import org.eclipse.swt.events.KeyAdapter;
0073:        import org.eclipse.swt.events.KeyEvent;
0074:        import org.eclipse.swt.events.ModifyEvent;
0075:        import org.eclipse.swt.events.ModifyListener;
0076:        import org.eclipse.swt.events.MouseAdapter;
0077:        import org.eclipse.swt.events.MouseEvent;
0078:        import org.eclipse.swt.events.SelectionAdapter;
0079:        import org.eclipse.swt.events.SelectionEvent;
0080:        import org.eclipse.swt.events.TraverseEvent;
0081:        import org.eclipse.swt.events.TraverseListener;
0082:        import org.eclipse.swt.graphics.Color;
0083:        import org.eclipse.swt.graphics.Font;
0084:        import org.eclipse.swt.graphics.GC;
0085:        import org.eclipse.swt.graphics.Image;
0086:        import org.eclipse.swt.graphics.Point;
0087:        import org.eclipse.swt.graphics.Rectangle;
0088:        import org.eclipse.swt.layout.GridData;
0089:        import org.eclipse.swt.layout.GridLayout;
0090:        import org.eclipse.swt.widgets.Composite;
0091:        import org.eclipse.swt.widgets.Control;
0092:        import org.eclipse.swt.widgets.Display;
0093:        import org.eclipse.swt.widgets.Event;
0094:        import org.eclipse.swt.widgets.Label;
0095:        import org.eclipse.swt.widgets.Menu;
0096:        import org.eclipse.swt.widgets.Shell;
0097:        import org.eclipse.swt.widgets.Text;
0098:        import org.eclipse.swt.widgets.ToolBar;
0099:        import org.eclipse.swt.widgets.ToolItem;
0100:        import org.eclipse.ui.ActiveShellExpression;
0101:        import org.eclipse.ui.IMemento;
0102:        import org.eclipse.ui.PlatformUI;
0103:        import org.eclipse.ui.WorkbenchException;
0104:        import org.eclipse.ui.XMLMemento;
0105:        import org.eclipse.ui.handlers.IHandlerActivation;
0106:        import org.eclipse.ui.handlers.IHandlerService;
0107:        import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
0108:        import org.eclipse.ui.internal.WorkbenchImages;
0109:        import org.eclipse.ui.internal.WorkbenchMessages;
0110:        import org.eclipse.ui.internal.WorkbenchPlugin;
0111:        import org.eclipse.ui.progress.UIJob;
0112:        import org.eclipse.ui.statushandlers.StatusManager;
0113:
0114:        /**
0115:         * Shows a list of items to the user with a text entry field for a string
0116:         * pattern used to filter the list of items.
0117:         * 
0118:         * @since 3.3
0119:         */
0120:        public abstract class FilteredItemsSelectionDialog extends
0121:                SelectionStatusDialog {
0122:
0123:            private static final String DIALOG_BOUNDS_SETTINGS = "DialogBoundsSettings"; //$NON-NLS-1$
0124:
0125:            private static final String SHOW_STATUS_LINE = "ShowStatusLine"; //$NON-NLS-1$
0126:
0127:            private static final String HISTORY_SETTINGS = "History"; //$NON-NLS-1$
0128:
0129:            private static final String DIALOG_HEIGHT = "DIALOG_HEIGHT"; //$NON-NLS-1$
0130:
0131:            private static final String DIALOG_WIDTH = "DIALOG_WIDTH"; //$NON-NLS-1$
0132:
0133:            /**
0134:             * Represents an empty selection in the pattern input field (used only for
0135:             * initial pattern).
0136:             */
0137:            public static final int NONE = 0;
0138:
0139:            /**
0140:             * Pattern input field selection where caret is at the beginning (used only
0141:             * for initial pattern).
0142:             */
0143:            public static final int CARET_BEGINNING = 1;
0144:
0145:            /**
0146:             * Represents a full selection in the pattern input field (used only for
0147:             * initial pattern).
0148:             */
0149:            public static final int FULL_SELECTION = 2;
0150:
0151:            private Text pattern;
0152:
0153:            private TableViewer list;
0154:
0155:            private DetailsContentViewer details;
0156:
0157:            /**
0158:             * It is a duplicate of a field in the CLabel class in DetailsContentViewer.
0159:             * It is maintained, because the <code>setDetailsLabelProvider()</code>
0160:             * could be called before content area is created.
0161:             */
0162:            private ILabelProvider detailsLabelProvider;
0163:
0164:            private ItemsListLabelProvider itemsListLabelProvider;
0165:
0166:            private MenuManager menuManager;
0167:
0168:            private boolean multi;
0169:
0170:            private ToolBar toolBar;
0171:
0172:            private ToolItem toolItem;
0173:
0174:            private Label progressLabel;
0175:
0176:            private ToggleStatusLineAction toggleStatusLineAction;
0177:
0178:            private RemoveHistoryItemAction removeHistoryItemAction;
0179:
0180:            private ActionContributionItem removeHistoryActionContributionItem;
0181:
0182:            private IStatus status;
0183:
0184:            private RefreshCacheJob refreshCacheJob;
0185:
0186:            private RefreshProgressMessageJob refreshProgressMessageJob = new RefreshProgressMessageJob();
0187:
0188:            private Object[] lastSelection;
0189:
0190:            private ContentProvider contentProvider;
0191:
0192:            private FilterHistoryJob filterHistoryJob;
0193:
0194:            private FilterJob filterJob;
0195:
0196:            private ItemsFilter filter;
0197:
0198:            private List lastCompletedResult;
0199:
0200:            private ItemsFilter lastCompletedFilter;
0201:
0202:            private String initialPatternText;
0203:
0204:            private int selectionMode;
0205:
0206:            private ItemsListSeparator itemsListSeparator;
0207:
0208:            private static final String EMPTY_STRING = ""; //$NON-NLS-1$
0209:
0210:            private boolean refreshWithLastSelection = false;
0211:
0212:            private IHandlerActivation showViewHandler;
0213:
0214:            /**
0215:             * Creates a new instance of the class.
0216:             * 
0217:             * @param shell
0218:             *            shell to parent the dialog on
0219:             * @param multi
0220:             *            indicates whether dialog allows to select more than one
0221:             *            position in its list of items
0222:             */
0223:            public FilteredItemsSelectionDialog(Shell shell, boolean multi) {
0224:                super (shell);
0225:                this .multi = multi;
0226:                filterHistoryJob = new FilterHistoryJob();
0227:                filterJob = new FilterJob();
0228:                contentProvider = new ContentProvider();
0229:                refreshCacheJob = new RefreshCacheJob();
0230:                itemsListSeparator = new ItemsListSeparator(
0231:                        WorkbenchMessages.FilteredItemsSelectionDialog_separatorLabel);
0232:                selectionMode = NONE;
0233:            }
0234:
0235:            /**
0236:             * Creates a new instance of the class. Created dialog won't allow to select
0237:             * more than one item.
0238:             * 
0239:             * @param shell
0240:             *            shell to parent the dialog on
0241:             */
0242:            public FilteredItemsSelectionDialog(Shell shell) {
0243:                this (shell, false);
0244:            }
0245:
0246:            /**
0247:             * Adds viewer filter to the dialog items list.
0248:             * 
0249:             * @param filter
0250:             *            the new filter
0251:             */
0252:            protected void addListFilter(ViewerFilter filter) {
0253:                contentProvider.addFilter(filter);
0254:            }
0255:
0256:            /**
0257:             * Sets a new label provider for items in the list.
0258:             * 
0259:             * @param listLabelProvider
0260:             *            the label provider for items in the list
0261:             */
0262:            public void setListLabelProvider(ILabelProvider listLabelProvider) {
0263:                getItemsListLabelProvider().setProvider(listLabelProvider);
0264:            }
0265:
0266:            /**
0267:             * Returns the label decorator for selected items in the list.
0268:             * 
0269:             * @return the label decorator for selected items in the list
0270:             */
0271:            private ILabelDecorator getListSelectionLabelDecorator() {
0272:                return getItemsListLabelProvider().getSelectionDecorator();
0273:            }
0274:
0275:            /**
0276:             * Sets the label decorator for selected items in the list.
0277:             * 
0278:             * @param listSelectionLabelDecorator
0279:             *            the label decorator for selected items in the list
0280:             */
0281:            public void setListSelectionLabelDecorator(
0282:                    ILabelDecorator listSelectionLabelDecorator) {
0283:                getItemsListLabelProvider().setSelectionDecorator(
0284:                        listSelectionLabelDecorator);
0285:            }
0286:
0287:            /**
0288:             * Returns the item list label provider.
0289:             * 
0290:             * @return the item list label provider
0291:             */
0292:            private ItemsListLabelProvider getItemsListLabelProvider() {
0293:                if (itemsListLabelProvider == null) {
0294:                    itemsListLabelProvider = new ItemsListLabelProvider(
0295:                            new LabelProvider(), null);
0296:                }
0297:                return itemsListLabelProvider;
0298:            }
0299:
0300:            /**
0301:             * Sets label provider for the details field.
0302:             * 
0303:             * For a single selection, the element sent to
0304:             * {@link ILabelProvider#getImage(Object)} and
0305:             * {@link ILabelProvider#getText(Object)} is the selected object, for
0306:             * multiple selection a {@link String} with amount of selected items is the
0307:             * element.
0308:             * 
0309:             * @see #getSelectedItems() getSelectedItems() can be used to retrieve
0310:             *      selected items and get the items count.
0311:             * 
0312:             * @param detailsLabelProvider
0313:             *            the label provider for the details field
0314:             */
0315:            public void setDetailsLabelProvider(
0316:                    ILabelProvider detailsLabelProvider) {
0317:                this .detailsLabelProvider = detailsLabelProvider;
0318:                if (details != null) {
0319:                    details.setLabelProvider(detailsLabelProvider);
0320:                }
0321:            }
0322:
0323:            private ILabelProvider getDetailsLabelProvider() {
0324:                if (detailsLabelProvider == null) {
0325:                    detailsLabelProvider = new LabelProvider();
0326:                }
0327:                return detailsLabelProvider;
0328:            }
0329:
0330:            /*
0331:             * (non-Javadoc)
0332:             * 
0333:             * @see org.eclipse.jface.window.Window#create()
0334:             */
0335:            public void create() {
0336:                super .create();
0337:                pattern.setFocus();
0338:            }
0339:
0340:            /**
0341:             * Restores dialog using persisted settings. The default implementation
0342:             * restores the status of the details line and the selection history.
0343:             * 
0344:             * @param settings
0345:             *            settings used to restore dialog
0346:             */
0347:            protected void restoreDialog(IDialogSettings settings) {
0348:                boolean toggleStatusLine = true;
0349:
0350:                if (settings.get(SHOW_STATUS_LINE) != null) {
0351:                    toggleStatusLine = settings.getBoolean(SHOW_STATUS_LINE);
0352:                }
0353:
0354:                toggleStatusLineAction.setChecked(toggleStatusLine);
0355:
0356:                details.setVisible(toggleStatusLine);
0357:
0358:                String setting = settings.get(HISTORY_SETTINGS);
0359:                if (setting != null) {
0360:                    try {
0361:                        IMemento memento = XMLMemento
0362:                                .createReadRoot(new StringReader(setting));
0363:                        this .contentProvider.loadHistory(memento);
0364:                    } catch (WorkbenchException e) {
0365:                        // Simply don't restore the settings
0366:                        StatusManager
0367:                                .getManager()
0368:                                .handle(
0369:                                        new Status(
0370:                                                IStatus.ERROR,
0371:                                                PlatformUI.PLUGIN_ID,
0372:                                                IStatus.ERROR,
0373:                                                WorkbenchMessages.FilteredItemsSelectionDialog_restoreError,
0374:                                                e));
0375:                    }
0376:                }
0377:            }
0378:
0379:            /*
0380:             * (non-Javadoc)
0381:             * 
0382:             * @see org.eclipse.jface.window.Window#close()
0383:             */
0384:            public boolean close() {
0385:                this .filterJob.cancel();
0386:                this .refreshCacheJob.cancel();
0387:                this .refreshProgressMessageJob.cancel();
0388:                if (showViewHandler != null) {
0389:                    IHandlerService service = (IHandlerService) PlatformUI
0390:                            .getWorkbench().getService(IHandlerService.class);
0391:                    service.deactivateHandler(showViewHandler);
0392:                    showViewHandler.getHandler().dispose();
0393:                    showViewHandler = null;
0394:                }
0395:                storeDialog(getDialogSettings());
0396:                return super .close();
0397:            }
0398:
0399:            /**
0400:             * Stores dialog settings.
0401:             * 
0402:             * @param settings
0403:             *            settings used to store dialog
0404:             */
0405:            protected void storeDialog(IDialogSettings settings) {
0406:                settings.put(SHOW_STATUS_LINE, toggleStatusLineAction
0407:                        .isChecked());
0408:
0409:                XMLMemento memento = XMLMemento
0410:                        .createWriteRoot(HISTORY_SETTINGS);
0411:                this .contentProvider.saveHistory(memento);
0412:                StringWriter writer = new StringWriter();
0413:                try {
0414:                    memento.save(writer);
0415:                    settings.put(HISTORY_SETTINGS, writer.getBuffer()
0416:                            .toString());
0417:                } catch (IOException e) {
0418:                    // Simply don't store the settings
0419:                    StatusManager
0420:                            .getManager()
0421:                            .handle(
0422:                                    new Status(
0423:                                            IStatus.ERROR,
0424:                                            PlatformUI.PLUGIN_ID,
0425:                                            IStatus.ERROR,
0426:                                            WorkbenchMessages.FilteredItemsSelectionDialog_storeError,
0427:                                            e));
0428:                }
0429:            }
0430:
0431:            private void createHeader(Composite parent) {
0432:                Composite header = new Composite(parent, SWT.NONE);
0433:
0434:                GridLayout layout = new GridLayout();
0435:                layout.numColumns = 2;
0436:                layout.marginWidth = 0;
0437:                layout.marginHeight = 0;
0438:                header.setLayout(layout);
0439:
0440:                Label label = new Label(header, SWT.NONE);
0441:                label
0442:                        .setText((getMessage() != null && getMessage().trim()
0443:                                .length() > 0) ? getMessage()
0444:                                : WorkbenchMessages.FilteredItemsSelectionDialog_patternLabel);
0445:                label.addTraverseListener(new TraverseListener() {
0446:                    public void keyTraversed(TraverseEvent e) {
0447:                        if (e.detail == SWT.TRAVERSE_MNEMONIC && e.doit) {
0448:                            e.detail = SWT.TRAVERSE_NONE;
0449:                            pattern.setFocus();
0450:                        }
0451:                    }
0452:                });
0453:
0454:                GridData gd = new GridData(GridData.FILL_HORIZONTAL);
0455:                label.setLayoutData(gd);
0456:
0457:                createViewMenu(header);
0458:                header.setLayoutData(gd);
0459:            }
0460:
0461:            private void createLabels(Composite parent) {
0462:                Composite labels = new Composite(parent, SWT.NONE);
0463:
0464:                GridLayout layout = new GridLayout();
0465:                layout.numColumns = 2;
0466:                layout.marginWidth = 0;
0467:                layout.marginHeight = 0;
0468:                labels.setLayout(layout);
0469:
0470:                Label listLabel = new Label(labels, SWT.NONE);
0471:                listLabel
0472:                        .setText(WorkbenchMessages.FilteredItemsSelectionDialog_listLabel);
0473:
0474:                listLabel.addTraverseListener(new TraverseListener() {
0475:                    public void keyTraversed(TraverseEvent e) {
0476:                        if (e.detail == SWT.TRAVERSE_MNEMONIC && e.doit) {
0477:                            e.detail = SWT.TRAVERSE_NONE;
0478:                            list.getTable().setFocus();
0479:                        }
0480:                    }
0481:                });
0482:
0483:                GridData gd = new GridData(GridData.FILL_HORIZONTAL);
0484:                listLabel.setLayoutData(gd);
0485:
0486:                progressLabel = new Label(labels, SWT.RIGHT);
0487:                progressLabel.setLayoutData(gd);
0488:
0489:                labels.setLayoutData(gd);
0490:            }
0491:
0492:            private void createViewMenu(Composite parent) {
0493:                toolBar = new ToolBar(parent, SWT.FLAT);
0494:                toolItem = new ToolItem(toolBar, SWT.PUSH, 0);
0495:
0496:                GridData data = new GridData();
0497:                data.horizontalAlignment = GridData.END;
0498:                toolBar.setLayoutData(data);
0499:
0500:                toolBar.addMouseListener(new MouseAdapter() {
0501:                    public void mouseDown(MouseEvent e) {
0502:                        showViewMenu();
0503:                    }
0504:                });
0505:
0506:                toolItem
0507:                        .setImage(WorkbenchImages
0508:                                .getImage(IWorkbenchGraphicConstants.IMG_LCL_VIEW_MENU));
0509:                toolItem
0510:                        .setToolTipText(WorkbenchMessages.FilteredItemsSelectionDialog_menu);
0511:                toolItem.addSelectionListener(new SelectionAdapter() {
0512:                    public void widgetSelected(SelectionEvent e) {
0513:                        showViewMenu();
0514:                    }
0515:                });
0516:
0517:                menuManager = new MenuManager();
0518:
0519:                fillViewMenu(menuManager);
0520:
0521:                IHandlerService service = (IHandlerService) PlatformUI
0522:                        .getWorkbench().getService(IHandlerService.class);
0523:                IHandler handler = new AbstractHandler() {
0524:                    /* (non-Javadoc)
0525:                     * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
0526:                     */
0527:                    public Object execute(ExecutionEvent event) {
0528:                        showViewMenu();
0529:                        return null;
0530:                    }
0531:                };
0532:                showViewHandler = service.activateHandler(
0533:                        "org.eclipse.ui.window.showViewMenu", handler, //$NON-NLS-1$
0534:                        new ActiveShellExpression(getShell()));
0535:            }
0536:
0537:            /**
0538:             * Fills the menu of the dialog.
0539:             * 
0540:             * @param menuManager
0541:             *            the menu manager
0542:             */
0543:            protected void fillViewMenu(IMenuManager menuManager) {
0544:                toggleStatusLineAction = new ToggleStatusLineAction();
0545:                menuManager.add(toggleStatusLineAction);
0546:            }
0547:
0548:            private void showViewMenu() {
0549:                Menu menu = menuManager.createContextMenu(getShell());
0550:                Rectangle bounds = toolItem.getBounds();
0551:                Point topLeft = new Point(bounds.x, bounds.y + bounds.height);
0552:                topLeft = toolBar.toDisplay(topLeft);
0553:                menu.setLocation(topLeft.x, topLeft.y);
0554:                menu.setVisible(true);
0555:            }
0556:
0557:            private void createPopupMenu() {
0558:                removeHistoryItemAction = new RemoveHistoryItemAction();
0559:                removeHistoryActionContributionItem = new ActionContributionItem(
0560:                        removeHistoryItemAction);
0561:
0562:                MenuManager manager = new MenuManager();
0563:                manager.add(removeHistoryActionContributionItem);
0564:                manager.addMenuListener(new IMenuListener() {
0565:                    public void menuAboutToShow(IMenuManager manager) {
0566:                        List selectedElements = ((StructuredSelection) list
0567:                                .getSelection()).toList();
0568:
0569:                        Object item = null;
0570:
0571:                        manager.remove(removeHistoryActionContributionItem);
0572:
0573:                        for (Iterator it = selectedElements.iterator(); it
0574:                                .hasNext();) {
0575:                            item = it.next();
0576:                            if (item instanceof  ItemsListSeparator
0577:                                    || !isHistoryElement(item)) {
0578:                                return;
0579:                            }
0580:                        }
0581:
0582:                        if (selectedElements.size() > 0) {
0583:                            removeHistoryItemAction
0584:                                    .setText(WorkbenchMessages.FilteredItemsSelectionDialog_removeItemsFromHistoryAction);
0585:
0586:                            manager.add(removeHistoryActionContributionItem);
0587:
0588:                        }
0589:                    }
0590:                });
0591:
0592:                Menu menu = manager.createContextMenu(getShell());
0593:                list.getTable().setMenu(menu);
0594:            }
0595:
0596:            /**
0597:             * Creates an extra content area, which will be located above the details.
0598:             * 
0599:             * @param parent
0600:             *            parent to create the dialog widgets in
0601:             * @return an extra content area
0602:             */
0603:            protected abstract Control createExtendedContentArea(
0604:                    Composite parent);
0605:
0606:            /*
0607:             * (non-Javadoc)
0608:             * 
0609:             * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
0610:             */
0611:            protected Control createDialogArea(Composite parent) {
0612:                Composite dialogArea = (Composite) super 
0613:                        .createDialogArea(parent);
0614:
0615:                Composite content = new Composite(dialogArea, SWT.NONE);
0616:                GridData gd = new GridData(GridData.FILL_BOTH);
0617:                content.setLayoutData(gd);
0618:
0619:                GridLayout layout = new GridLayout();
0620:                layout.numColumns = 1;
0621:                layout.marginWidth = 0;
0622:                layout.marginHeight = 0;
0623:                content.setLayout(layout);
0624:
0625:                createHeader(content);
0626:
0627:                pattern = new Text(content, SWT.SINGLE | SWT.BORDER);
0628:                gd = new GridData(GridData.FILL_HORIZONTAL);
0629:                pattern.setLayoutData(gd);
0630:
0631:                createLabels(content);
0632:
0633:                list = new TableViewer(content,
0634:                        (multi ? SWT.MULTI : SWT.SINGLE) | SWT.BORDER
0635:                                | SWT.V_SCROLL | SWT.VIRTUAL);
0636:                list.setContentProvider(contentProvider);
0637:                list.setLabelProvider(getItemsListLabelProvider());
0638:                list.setInput(new Object[0]);
0639:                list.setItemCount(contentProvider.getElements(null).length);
0640:                gd = new GridData(GridData.FILL_BOTH);
0641:                list.getTable().setLayoutData(gd);
0642:
0643:                createPopupMenu();
0644:
0645:                pattern.addModifyListener(new ModifyListener() {
0646:                    public void modifyText(ModifyEvent e) {
0647:                        applyFilter();
0648:                    }
0649:                });
0650:
0651:                pattern.addKeyListener(new KeyAdapter() {
0652:                    public void keyPressed(KeyEvent e) {
0653:                        if (e.keyCode == SWT.ARROW_DOWN) {
0654:                            if (list.getTable().getItemCount() > 0) {
0655:                                list.getTable().setFocus();
0656:                            }
0657:                        }
0658:                    }
0659:                });
0660:
0661:                list
0662:                        .addSelectionChangedListener(new ISelectionChangedListener() {
0663:                            public void selectionChanged(
0664:                                    SelectionChangedEvent event) {
0665:                                StructuredSelection selection = (StructuredSelection) event
0666:                                        .getSelection();
0667:                                handleSelected(selection);
0668:                            }
0669:                        });
0670:
0671:                list.addDoubleClickListener(new IDoubleClickListener() {
0672:                    public void doubleClick(DoubleClickEvent event) {
0673:                        handleDoubleClick();
0674:                    }
0675:                });
0676:
0677:                list.getTable().addKeyListener(new KeyAdapter() {
0678:                    public void keyPressed(KeyEvent e) {
0679:
0680:                        if (e.keyCode == SWT.DEL) {
0681:
0682:                            List selectedElements = ((StructuredSelection) list
0683:                                    .getSelection()).toList();
0684:
0685:                            Object item = null;
0686:                            boolean isSelectedHistory = true;
0687:
0688:                            for (Iterator it = selectedElements.iterator(); it
0689:                                    .hasNext();) {
0690:                                item = it.next();
0691:                                if (item instanceof  ItemsListSeparator
0692:                                        || !isHistoryElement(item)) {
0693:                                    isSelectedHistory = false;
0694:                                    break;
0695:                                }
0696:                            }
0697:                            if (isSelectedHistory)
0698:                                removeSelectedItems(selectedElements);
0699:
0700:                        }
0701:
0702:                        if (e.keyCode == SWT.ARROW_UP
0703:                                && (e.stateMask & SWT.SHIFT) != 0
0704:                                && (e.stateMask & SWT.CTRL) != 0) {
0705:                            StructuredSelection selection = (StructuredSelection) list
0706:                                    .getSelection();
0707:
0708:                            if (selection.size() == 1) {
0709:                                Object element = selection.getFirstElement();
0710:                                if (element.equals(list.getElementAt(0))) {
0711:                                    pattern.setFocus();
0712:                                }
0713:                                if (list.getElementAt(list.getTable()
0714:                                        .getSelectionIndex() - 1) instanceof  ItemsListSeparator)
0715:                                    list
0716:                                            .getTable()
0717:                                            .setSelection(
0718:                                                    list
0719:                                                            .getTable()
0720:                                                            .getSelectionIndex() - 1);
0721:                                list.getTable().notifyListeners(SWT.Selection,
0722:                                        new Event());
0723:
0724:                            }
0725:                        }
0726:
0727:                        if (e.keyCode == SWT.ARROW_DOWN
0728:                                && (e.stateMask & SWT.SHIFT) != 0
0729:                                && (e.stateMask & SWT.CTRL) != 0) {
0730:
0731:                            if (list.getElementAt(list.getTable()
0732:                                    .getSelectionIndex() + 1) instanceof  ItemsListSeparator)
0733:                                list
0734:                                        .getTable()
0735:                                        .setSelection(
0736:                                                list.getTable()
0737:                                                        .getSelectionIndex() + 1);
0738:                            list.getTable().notifyListeners(SWT.Selection,
0739:                                    new Event());
0740:                        }
0741:
0742:                    }
0743:                });
0744:
0745:                createExtendedContentArea(content);
0746:
0747:                details = new DetailsContentViewer(content, SWT.BORDER
0748:                        | SWT.FLAT);
0749:                details.setVisible(toggleStatusLineAction.isChecked());
0750:                details.setContentProvider(new NullContentProvider());
0751:                details.setLabelProvider(getDetailsLabelProvider());
0752:
0753:                applyDialogFont(content);
0754:
0755:                restoreDialog(getDialogSettings());
0756:
0757:                if (initialPatternText != null) {
0758:                    pattern.setText(initialPatternText);
0759:                }
0760:
0761:                switch (selectionMode) {
0762:                case CARET_BEGINNING:
0763:                    pattern.setSelection(0, 0);
0764:                    break;
0765:                case FULL_SELECTION:
0766:                    pattern.setSelection(0, initialPatternText.length());
0767:                    break;
0768:                }
0769:
0770:                // apply filter even if pattern is empty (display history)
0771:                applyFilter();
0772:
0773:                return dialogArea;
0774:            }
0775:
0776:            /**
0777:             * This method is a hook for subclasses to override default dialog behavior.
0778:             * The <code>handleDoubleClick()</code> method handles double clicks on
0779:             * the list of filtered elements.
0780:             * <p>
0781:             * Current implementation makes double-clicking on the list do the same as
0782:             * pressing <code>OK</code> button on the dialog.
0783:             */
0784:            protected void handleDoubleClick() {
0785:                okPressed();
0786:            }
0787:
0788:            /**
0789:             * Refreshes the details field according to the current selection in the
0790:             * items list.
0791:             */
0792:            private void refreshDetails() {
0793:                StructuredSelection selection = getSelectedItems();
0794:
0795:                switch (selection.size()) {
0796:                case 0:
0797:                    details.setInput(null);
0798:                    break;
0799:                case 1:
0800:                    details.setInput(selection.getFirstElement());
0801:                    break;
0802:                default:
0803:                    details
0804:                            .setInput(NLS
0805:                                    .bind(
0806:                                            WorkbenchMessages.FilteredItemsSelectionDialog_nItemsSelected,
0807:                                            new Integer(selection.size())));
0808:                    break;
0809:                }
0810:
0811:            }
0812:
0813:            /**
0814:             * Handle selection in the items list by updating labels of selected and
0815:             * unselected items and refresh the details field using the selection.
0816:             * 
0817:             * @param selection
0818:             *            the new selection
0819:             */
0820:            protected void handleSelected(StructuredSelection selection) {
0821:                IStatus status = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
0822:                        IStatus.OK, EMPTY_STRING, null);
0823:
0824:                if (selection.size() == 0) {
0825:                    status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
0826:                            IStatus.ERROR, EMPTY_STRING, null);
0827:
0828:                    if (lastSelection != null
0829:                            && getListSelectionLabelDecorator() != null) {
0830:                        list.update(lastSelection, null);
0831:                    }
0832:
0833:                    lastSelection = null;
0834:
0835:                } else {
0836:                    status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
0837:                            IStatus.ERROR, EMPTY_STRING, null);
0838:
0839:                    List items = selection.toList();
0840:
0841:                    Object item = null;
0842:                    IStatus tempStatus = null;
0843:
0844:                    for (Iterator it = items.iterator(); it.hasNext();) {
0845:                        Object o = it.next();
0846:
0847:                        if (o instanceof  ItemsListSeparator) {
0848:                            continue;
0849:                        }
0850:
0851:                        item = o;
0852:                        tempStatus = validateItem(item);
0853:
0854:                        if (tempStatus.isOK()) {
0855:                            status = new Status(IStatus.OK,
0856:                                    PlatformUI.PLUGIN_ID, IStatus.OK,
0857:                                    EMPTY_STRING, null);
0858:                        } else {
0859:                            status = tempStatus;
0860:                            // if any selected element is not valid status is set to
0861:                            // ERROR
0862:                            break;
0863:                        }
0864:                    }
0865:
0866:                    if (lastSelection != null
0867:                            && getListSelectionLabelDecorator() != null) {
0868:                        list.update(lastSelection, null);
0869:                    }
0870:
0871:                    if (getListSelectionLabelDecorator() != null) {
0872:                        list.update(items.toArray(), null);
0873:                    }
0874:
0875:                    lastSelection = items.toArray();
0876:                }
0877:
0878:                refreshDetails();
0879:                updateStatus(status);
0880:            }
0881:
0882:            /*
0883:             * (non-Javadoc)
0884:             * 
0885:             * @see org.eclipse.jface.window.Dialog#getDialogBoundsSettings()
0886:             */
0887:            protected IDialogSettings getDialogBoundsSettings() {
0888:                IDialogSettings settings = getDialogSettings();
0889:                IDialogSettings section = settings
0890:                        .getSection(DIALOG_BOUNDS_SETTINGS);
0891:                if (section == null) {
0892:                    section = settings.addNewSection(DIALOG_BOUNDS_SETTINGS);
0893:                    section.put(DIALOG_HEIGHT, 500);
0894:                    section.put(DIALOG_WIDTH, 600);
0895:                }
0896:                return section;
0897:            }
0898:
0899:            /**
0900:             * Returns the dialog settings. Returned object can't be null.
0901:             * 
0902:             * @return return dialog settings for this dialog
0903:             */
0904:            protected abstract IDialogSettings getDialogSettings();
0905:
0906:            /**
0907:             * Refreshes the dialog - has to be called in UI thread.
0908:             */
0909:            public void refresh() {
0910:                if (list != null && !list.getTable().isDisposed()) {
0911:
0912:                    List lastRefreshSelection = ((StructuredSelection) list
0913:                            .getSelection()).toList();
0914:
0915:                    list.setItemCount(contentProvider.getElements(null).length);
0916:                    list.refresh();
0917:
0918:                    if (list.getTable().getItemCount() > 0) {
0919:                        // preserve previous selection
0920:                        if (refreshWithLastSelection
0921:                                && lastRefreshSelection != null
0922:                                && lastRefreshSelection.size() > 0) {
0923:                            list.setSelection(new StructuredSelection(
0924:                                    lastRefreshSelection));
0925:                        } else {
0926:                            refreshWithLastSelection = true;
0927:                            list.getTable().setSelection(0);
0928:                            list.getTable().notifyListeners(SWT.Selection,
0929:                                    new Event());
0930:                        }
0931:                    } else {
0932:                        list.setSelection(StructuredSelection.EMPTY);
0933:                    }
0934:
0935:                }
0936:
0937:                scheduleProgressMessageRefresh();
0938:            }
0939:
0940:            /**
0941:             * Updates the progress label.
0942:             * 
0943:             * @deprecated
0944:             */
0945:            public void updateProgressLabel() {
0946:                scheduleProgressMessageRefresh();
0947:            }
0948:
0949:            /**
0950:             * Notifies the content provider - fires filtering of content provider
0951:             * elements. During the filtering, a separator between history and workspace
0952:             * matches is added.
0953:             * <p>
0954:             * This is a long running operation and should be called in a job.
0955:             * 
0956:             * @param checkDuplicates
0957:             *            <code>true</code> if data concerning elements duplication
0958:             *            should be computed - it takes much more time than the standard
0959:             *            filtering
0960:             * @param monitor
0961:             *            a progress monitor or <code>null</code> if no monitor is
0962:             *            available
0963:             */
0964:            public void reloadCache(boolean checkDuplicates,
0965:                    IProgressMonitor monitor) {
0966:                if (list != null && !list.getTable().isDisposed()
0967:                        && contentProvider != null) {
0968:                    contentProvider.reloadCache(checkDuplicates, monitor);
0969:                }
0970:            }
0971:
0972:            /**
0973:             * Schedule refresh job.
0974:             */
0975:            public void scheduleRefresh() {
0976:                refreshCacheJob.cancelAll();
0977:                refreshCacheJob.schedule();
0978:            }
0979:
0980:            /**
0981:             * Schedules progress message refresh.
0982:             */
0983:            public void scheduleProgressMessageRefresh() {
0984:                if (filterJob.getState() != Job.RUNNING
0985:                        && refreshProgressMessageJob.getState() != Job.RUNNING)
0986:                    refreshProgressMessageJob.scheduleProgressRefresh(null);
0987:            }
0988:
0989:            /*
0990:             * (non-Javadoc)
0991:             * 
0992:             * @see org.eclipse.ui.dialogs.SelectionStatusDialog#computeResult()
0993:             */
0994:            protected void computeResult() {
0995:
0996:                List selectedElements = ((StructuredSelection) list
0997:                        .getSelection()).toList();
0998:
0999:                List objectsToReturn = new ArrayList();
1000:
1001:                Object item = null;
1002:
1003:                for (Iterator it = selectedElements.iterator(); it.hasNext();) {
1004:                    item = it.next();
1005:
1006:                    if (!(item instanceof  ItemsListSeparator)) {
1007:                        accessedHistoryItem(item);
1008:                        objectsToReturn.add(item);
1009:                    }
1010:                }
1011:
1012:                setResult(objectsToReturn);
1013:            }
1014:
1015:            /*
1016:             * @see org.eclipse.ui.dialogs.SelectionStatusDialog#updateStatus(org.eclipse.core.runtime.IStatus)
1017:             */
1018:            protected void updateStatus(IStatus status) {
1019:                this .status = status;
1020:                super .updateStatus(status);
1021:            }
1022:
1023:            /*
1024:             * @see Dialog#okPressed()
1025:             */
1026:            protected void okPressed() {
1027:                if (status != null
1028:                        && (status.isOK() || status.getCode() == IStatus.INFO)) {
1029:                    super .okPressed();
1030:                }
1031:            }
1032:
1033:            /**
1034:             * Sets the initial pattern used by the filter. This text is copied into the
1035:             * selection input on the dialog. A full selection is used in the pattern
1036:             * input field.
1037:             * 
1038:             * @param text
1039:             *            initial pattern for the filter
1040:             * @see FilteredItemsSelectionDialog#FULL_SELECTION
1041:             */
1042:            public void setInitialPattern(String text) {
1043:                setInitialPattern(text, FULL_SELECTION);
1044:            }
1045:
1046:            /**
1047:             * Sets the initial pattern used by the filter. This text is copied into the
1048:             * selection input on the dialog. The <code>selectionMode</code> is used
1049:             * to choose selection type for the input field.
1050:             * 
1051:             * @param text
1052:             *            initial pattern for the filter
1053:             * @param selectionMode
1054:             *            one of: {@link FilteredItemsSelectionDialog#NONE},
1055:             *            {@link FilteredItemsSelectionDialog#CARET_BEGINNING},
1056:             *            {@link FilteredItemsSelectionDialog#FULL_SELECTION}
1057:             */
1058:            public void setInitialPattern(String text, int selectionMode) {
1059:                this .initialPatternText = text;
1060:                this .selectionMode = selectionMode;
1061:            }
1062:
1063:            /**
1064:             * Gets initial pattern.
1065:             * 
1066:             * @return initial pattern, or <code>null</code> if initial pattern is not
1067:             *         set
1068:             */
1069:            protected String getInitialPattern() {
1070:                return this .initialPatternText;
1071:            }
1072:
1073:            /**
1074:             * Returns the current selection.
1075:             * 
1076:             * @return the current selection
1077:             */
1078:            protected StructuredSelection getSelectedItems() {
1079:
1080:                StructuredSelection selection = (StructuredSelection) list
1081:                        .getSelection();
1082:
1083:                List selectedItems = selection.toList();
1084:                Object itemToRemove = null;
1085:
1086:                for (Iterator it = selection.iterator(); it.hasNext();) {
1087:                    Object item = it.next();
1088:                    if (item instanceof  ItemsListSeparator) {
1089:                        itemToRemove = item;
1090:                        break;
1091:                    }
1092:                }
1093:
1094:                if (itemToRemove == null)
1095:                    return new StructuredSelection(selectedItems);
1096:                // Create a new selection without the collision
1097:                List newItems = new ArrayList(selectedItems);
1098:                newItems.remove(itemToRemove);
1099:                return new StructuredSelection(newItems);
1100:
1101:            }
1102:
1103:            /**
1104:             * Validates the item. When items on the items list are selected or
1105:             * deselected, it validates each item in the selection and the dialog status
1106:             * depends on all validations.
1107:             * 
1108:             * @param item
1109:             *            an item to be checked
1110:             * @return status of the dialog to be set
1111:             */
1112:            protected abstract IStatus validateItem(Object item);
1113:
1114:            /**
1115:             * Creates an instance of a filter.
1116:             * 
1117:             * @return a filter for items on the items list. Can be <code>null</code>,
1118:             *         no filtering will be applied then, causing no item to be shown in
1119:             *         the list.
1120:             */
1121:            protected abstract ItemsFilter createFilter();
1122:
1123:            /**
1124:             * Applies the filter created by <code>createFilter()</code> method to the
1125:             * items list. When new filter is different than previous one it will cause
1126:             * refiltering.
1127:             */
1128:            protected void applyFilter() {
1129:
1130:                ItemsFilter newFilter = createFilter();
1131:
1132:                // don't apply filtering for patterns which mean the same, for example:
1133:                // *a**b and ***a*b
1134:                if (filter != null && filter.equalsFilter(newFilter)) {
1135:                    return;
1136:                }
1137:
1138:                filterHistoryJob.cancel();
1139:                filterJob.cancel();
1140:
1141:                this .filter = newFilter;
1142:
1143:                if (this .filter != null) {
1144:                    filterHistoryJob.schedule();
1145:                }
1146:            }
1147:
1148:            /**
1149:             * Returns comparator to sort items inside content provider. Returned object
1150:             * will be probably created as an anonymous class. Parameters passed to the
1151:             * <code>compare(java.lang.Object, java.lang.Object)</code> are going to
1152:             * be the same type as the one used in the content provider.
1153:             * 
1154:             * @return comparator to sort items content provider
1155:             */
1156:            protected abstract Comparator getItemsComparator();
1157:
1158:            /**
1159:             * Fills the content provider with matching items.
1160:             * 
1161:             * @param contentProvider
1162:             *            collector to add items to.
1163:             *            {@link FilteredItemsSelectionDialog.AbstractContentProvider#add(Object, FilteredItemsSelectionDialog.ItemsFilter)}
1164:             *            only adds items that pass the given <code>itemsFilter</code>.
1165:             * @param itemsFilter
1166:             *            the items filter
1167:             * @param progressMonitor
1168:             *            must be used to report search progress. The state of this
1169:             *            progress monitor reflects the state of the filtering process.
1170:             * @throws CoreException
1171:             */
1172:            protected abstract void fillContentProvider(
1173:                    AbstractContentProvider contentProvider,
1174:                    ItemsFilter itemsFilter, IProgressMonitor progressMonitor)
1175:                    throws CoreException;
1176:
1177:            /**
1178:             * Removes selected items from history.
1179:             * 
1180:             * @param items
1181:             *            items to be removed
1182:             */
1183:            private void removeSelectedItems(List items) {
1184:                for (Iterator iter = items.iterator(); iter.hasNext();) {
1185:                    Object item = iter.next();
1186:                    removeHistoryItem(item);
1187:                }
1188:                refreshWithLastSelection = false;
1189:                contentProvider.refresh();
1190:            }
1191:
1192:            /**
1193:             * Removes an item from history.
1194:             * 
1195:             * @param item
1196:             *            an item to remove
1197:             * @return removed item
1198:             */
1199:            protected Object removeHistoryItem(Object item) {
1200:                return contentProvider.removeHistoryElement(item);
1201:            }
1202:
1203:            /**
1204:             * Adds item to history.
1205:             * 
1206:             * @param item
1207:             *            the item to be added
1208:             */
1209:            protected void accessedHistoryItem(Object item) {
1210:                contentProvider.addHistoryElement(item);
1211:            }
1212:
1213:            /**
1214:             * Returns a history comparator.
1215:             * 
1216:             * @return decorated comparator
1217:             */
1218:            private Comparator getHistoryComparator() {
1219:                return new HistoryComparator();
1220:            }
1221:
1222:            /**
1223:             * Returns the history of selected elements.
1224:             * 
1225:             * @return history of selected elements, or <code>null</code> if it is not
1226:             *         set
1227:             */
1228:            protected SelectionHistory getSelectionHistory() {
1229:                return this .contentProvider.getSelectionHistory();
1230:            }
1231:
1232:            /**
1233:             * Sets new history.
1234:             * 
1235:             * @param selectionHistory
1236:             *            the history
1237:             */
1238:            protected void setSelectionHistory(SelectionHistory selectionHistory) {
1239:                if (this .contentProvider != null)
1240:                    this .contentProvider.setSelectionHistory(selectionHistory);
1241:            }
1242:
1243:            /**
1244:             * Indicates whether the given item is a history item.
1245:             * 
1246:             * @param item
1247:             *            the item to be investigated
1248:             * @return <code>true</code> if the given item exists in history,
1249:             *         <code>false</code> otherwise
1250:             */
1251:            public boolean isHistoryElement(Object item) {
1252:                return this .contentProvider.isHistoryElement(item);
1253:            }
1254:
1255:            /**
1256:             * Indicates whether the given item is a duplicate.
1257:             * 
1258:             * @param item
1259:             *            the item to be investigated
1260:             * @return <code>true</code> if the item is duplicate, <code>false</code>
1261:             *         otherwise
1262:             */
1263:            public boolean isDuplicateElement(Object item) {
1264:                return this .contentProvider.isDuplicateElement(item);
1265:            }
1266:
1267:            /**
1268:             * Sets separator label
1269:             * 
1270:             * @param separatorLabel
1271:             *            the label showed on separator
1272:             */
1273:            public void setSeparatorLabel(String separatorLabel) {
1274:                this .itemsListSeparator = new ItemsListSeparator(separatorLabel);
1275:            }
1276:
1277:            /**
1278:             * Returns name for then given object.
1279:             * 
1280:             * @param item
1281:             *            an object from the content provider. Subclasses should pay
1282:             *            attention to the passed argument. They should either only pass
1283:             *            objects of a known type (one used in content provider) or make
1284:             *            sure that passed parameter is the expected one (by type
1285:             *            checking like <code>instanceof</code> inside the method).
1286:             * @return name of the given item
1287:             */
1288:            public abstract String getElementName(Object item);
1289:
1290:            private class ToggleStatusLineAction extends Action {
1291:
1292:                /**
1293:                 * Creates a new instance of the class.
1294:                 */
1295:                public ToggleStatusLineAction() {
1296:                    super (
1297:                            WorkbenchMessages.FilteredItemsSelectionDialog_toggleStatusAction,
1298:                            IAction.AS_CHECK_BOX);
1299:                }
1300:
1301:                public void run() {
1302:                    details.setVisible(isChecked());
1303:                }
1304:            }
1305:
1306:            /**
1307:             * Only refreshes UI on the basis of an already sorted and filtered set of
1308:             * items.
1309:             * <p>
1310:             * Standard invocation scenario:
1311:             * <ol>
1312:             * <li>filtering job (<code>FilterJob</code> class extending
1313:             * <code>Job</code> class)</li>
1314:             * <li>cache refresh without checking for duplicates (<code>RefreshCacheJob</code>
1315:             * class extending <code>Job</code> class)</li>
1316:             * <li>UI refresh (<code>RefreshJob</code> class extending
1317:             * <code>UIJob</code> class)</li>
1318:             * <li>cache refresh with checking for duplicates (<cod>CacheRefreshJob</code>
1319:             * class extending <code>Job</code> class)</li>
1320:             * <li>UI refresh (<code>RefreshJob</code> class extending <code>UIJob</code>
1321:             * class)</li>
1322:             * </ol>
1323:             * The scenario is rather complicated, but it had to be applied, because:
1324:             * <ul>
1325:             * <li> refreshing cache is rather a long action and cannot be run in the UI -
1326:             * cannot be run in a UIJob</li>
1327:             * <li> refreshing cache checking for duplicates is twice as long as
1328:             * refreshing cache without checking for duplicates; results of the search
1329:             * could be displayed earlier</li>
1330:             * <li> refreshing the UI have to be run in a UIJob</li>
1331:             * </ul>
1332:             * 
1333:             * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.FilterJob
1334:             * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.RefreshJob
1335:             * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.RefreshCacheJob
1336:             */
1337:            private class RefreshJob extends UIJob {
1338:
1339:                /**
1340:                 * Creates a new instance of the class.
1341:                 */
1342:                public RefreshJob() {
1343:                    super (
1344:                            FilteredItemsSelectionDialog.this .getParentShell()
1345:                                    .getDisplay(),
1346:                            WorkbenchMessages.FilteredItemsSelectionDialog_refreshJob);
1347:                    setSystem(true);
1348:                }
1349:
1350:                /*
1351:                 * (non-Javadoc)
1352:                 * 
1353:                 * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
1354:                 */
1355:                public IStatus runInUIThread(IProgressMonitor monitor) {
1356:                    if (monitor.isCanceled())
1357:                        return new Status(IStatus.OK,
1358:                                WorkbenchPlugin.PI_WORKBENCH, IStatus.OK,
1359:                                EMPTY_STRING, null);
1360:
1361:                    if (FilteredItemsSelectionDialog.this  != null) {
1362:                        FilteredItemsSelectionDialog.this .refresh();
1363:                    }
1364:
1365:                    return new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
1366:                            IStatus.OK, EMPTY_STRING, null);
1367:                }
1368:
1369:            }
1370:
1371:            /**
1372:             * Refreshes the progress message cyclically with 500 milliseconds delay.
1373:             * <code>RefreshProgressMessageJob</code> is strictly connected with
1374:             * <code>GranualProgressMonitor</code> and use it to to get progress
1375:             * message and to decide about break of cyclical refresh.
1376:             */
1377:            private class RefreshProgressMessageJob extends UIJob {
1378:
1379:                private GranualProgressMonitor progressMonitor;
1380:
1381:                /**
1382:                 * Creates a new instance of the class.
1383:                 */
1384:                public RefreshProgressMessageJob() {
1385:                    super (
1386:                            FilteredItemsSelectionDialog.this .getParentShell()
1387:                                    .getDisplay(),
1388:                            WorkbenchMessages.FilteredItemsSelectionDialog_progressRefreshJob);
1389:                    setSystem(true);
1390:                }
1391:
1392:                /*
1393:                 * (non-Javadoc)
1394:                 * 
1395:                 * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
1396:                 */
1397:                public IStatus runInUIThread(IProgressMonitor monitor) {
1398:
1399:                    if (!progressLabel.isDisposed())
1400:                        progressLabel
1401:                                .setText(progressMonitor != null ? progressMonitor
1402:                                        .getMessage()
1403:                                        : EMPTY_STRING);
1404:
1405:                    if (progressMonitor == null || progressMonitor.isDone()) {
1406:                        return new Status(IStatus.CANCEL, PlatformUI.PLUGIN_ID,
1407:                                IStatus.CANCEL, EMPTY_STRING, null);
1408:                    }
1409:
1410:                    // Schedule cyclical with 500 milliseconds delay
1411:                    schedule(500);
1412:
1413:                    return new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
1414:                            IStatus.OK, EMPTY_STRING, null);
1415:                }
1416:
1417:                /**
1418:                 * Schedule progress refresh job.
1419:                 * 
1420:                 * @param progressMonitor
1421:                 *            used during refresh progress label
1422:                 */
1423:                public void scheduleProgressRefresh(
1424:                        GranualProgressMonitor progressMonitor) {
1425:                    this .progressMonitor = progressMonitor;
1426:                    // Schedule with initial delay to avoid flickering when the user
1427:                    // types quickly
1428:                    schedule(200);
1429:                }
1430:
1431:            }
1432:
1433:            /**
1434:             * A job responsible for computing filtered items list presented using
1435:             * <code>RefreshJob</code>.
1436:             * 
1437:             * @see RefreshJob
1438:             * 
1439:             */
1440:            private class RefreshCacheJob extends Job {
1441:
1442:                private RefreshJob refreshJob = new RefreshJob();
1443:
1444:                /**
1445:                 * Creates a new instance of the class.
1446:                 */
1447:                public RefreshCacheJob() {
1448:                    super (
1449:                            WorkbenchMessages.FilteredItemsSelectionDialog_cacheRefreshJob);
1450:                    setSystem(true);
1451:                }
1452:
1453:                /**
1454:                 * Stops the job and all sub-jobs.
1455:                 */
1456:                public void cancelAll() {
1457:                    cancel();
1458:                    refreshJob.cancel();
1459:                }
1460:
1461:                /*
1462:                 * (non-Javadoc)
1463:                 * 
1464:                 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
1465:                 */
1466:                protected IStatus run(IProgressMonitor monitor) {
1467:                    if (monitor.isCanceled()) {
1468:                        return new Status(IStatus.CANCEL,
1469:                                WorkbenchPlugin.PI_WORKBENCH, IStatus.CANCEL,
1470:                                EMPTY_STRING, null);
1471:                    }
1472:
1473:                    if (FilteredItemsSelectionDialog.this  != null) {
1474:                        GranualProgressMonitor wrappedMonitor = new GranualProgressMonitor(
1475:                                monitor);
1476:                        FilteredItemsSelectionDialog.this .reloadCache(true,
1477:                                wrappedMonitor);
1478:                    }
1479:
1480:                    if (!monitor.isCanceled()) {
1481:                        refreshJob.schedule();
1482:                    }
1483:
1484:                    return new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
1485:                            IStatus.OK, EMPTY_STRING, null);
1486:
1487:                }
1488:
1489:                /*
1490:                 * (non-Javadoc)
1491:                 * 
1492:                 * @see org.eclipse.core.runtime.jobs.Job#canceling()
1493:                 */
1494:                protected void canceling() {
1495:                    super .canceling();
1496:                    contentProvider.stopReloadingCache();
1497:                }
1498:
1499:            }
1500:
1501:            private class RemoveHistoryItemAction extends Action {
1502:
1503:                /**
1504:                 * Creates a new instance of the class.
1505:                 */
1506:                public RemoveHistoryItemAction() {
1507:                    super (
1508:                            WorkbenchMessages.FilteredItemsSelectionDialog_removeItemsFromHistoryAction);
1509:                }
1510:
1511:                /*
1512:                 * (non-Javadoc)
1513:                 * 
1514:                 * @see org.eclipse.jface.action.Action#run()
1515:                 */
1516:                public void run() {
1517:                    List selectedElements = ((StructuredSelection) list
1518:                            .getSelection()).toList();
1519:                    removeSelectedItems(selectedElements);
1520:                }
1521:            }
1522:
1523:            private class ItemsListLabelProvider extends LabelProvider
1524:                    implements  IColorProvider, IFontProvider,
1525:                    ILabelProviderListener {
1526:                private ILabelProvider provider;
1527:
1528:                private ILabelDecorator selectionDecorator;
1529:
1530:                // Need to keep our own list of listeners
1531:                private ListenerList listeners = new ListenerList();
1532:
1533:                /**
1534:                 * Creates a new instance of the class.
1535:                 * 
1536:                 * @param provider
1537:                 *            the label provider for all items, not <code>null</code>
1538:                 * @param selectionDecorator
1539:                 *            the decorator for selected items, can be <code>null</code>
1540:                 */
1541:                public ItemsListLabelProvider(ILabelProvider provider,
1542:                        ILabelDecorator selectionDecorator) {
1543:                    Assert.isNotNull(provider);
1544:                    this .provider = provider;
1545:                    this .selectionDecorator = selectionDecorator;
1546:
1547:                    provider.addListener(this );
1548:
1549:                    if (selectionDecorator != null) {
1550:                        selectionDecorator.addListener(this );
1551:                    }
1552:                }
1553:
1554:                /**
1555:                 * Sets new selection decorator.
1556:                 * 
1557:                 * @param newSelectionDecorator
1558:                 *            new label decorator for selected items in the list
1559:                 */
1560:                public void setSelectionDecorator(
1561:                        ILabelDecorator newSelectionDecorator) {
1562:                    if (selectionDecorator != null) {
1563:                        selectionDecorator.removeListener(this );
1564:                        selectionDecorator.dispose();
1565:                    }
1566:
1567:                    selectionDecorator = newSelectionDecorator;
1568:
1569:                    if (selectionDecorator != null) {
1570:                        selectionDecorator.addListener(this );
1571:                    }
1572:                }
1573:
1574:                /**
1575:                 * Gets selection decorator.
1576:                 * 
1577:                 * @return the label decorator for selected items in the list
1578:                 */
1579:                public ILabelDecorator getSelectionDecorator() {
1580:                    return selectionDecorator;
1581:                }
1582:
1583:                /**
1584:                 * Sets new label provider.
1585:                 * 
1586:                 * @param newProvider
1587:                 *            new label provider for items in the list, not
1588:                 *            <code>null</code>
1589:                 */
1590:                public void setProvider(ILabelProvider newProvider) {
1591:                    Assert.isNotNull(newProvider);
1592:                    provider.removeListener(this );
1593:                    provider.dispose();
1594:
1595:                    provider = newProvider;
1596:
1597:                    if (provider != null) {
1598:                        provider.addListener(this );
1599:                    }
1600:                }
1601:
1602:                /**
1603:                 * Gets the label provider.
1604:                 * 
1605:                 * @return the label provider for items in the list
1606:                 */
1607:                public ILabelProvider getProvider() {
1608:                    return provider;
1609:                }
1610:
1611:                /*
1612:                 * (non-Javadoc)
1613:                 * 
1614:                 * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
1615:                 */
1616:                public Image getImage(Object element) {
1617:                    if (element instanceof  ItemsListSeparator) {
1618:                        return WorkbenchImages
1619:                                .getImage(IWorkbenchGraphicConstants.IMG_OBJ_SEPARATOR);
1620:                    }
1621:
1622:                    return provider.getImage(element);
1623:                }
1624:
1625:                /*
1626:                 * (non-Javadoc)
1627:                 * 
1628:                 * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
1629:                 */
1630:                public String getText(Object element) {
1631:                    if (element instanceof  ItemsListSeparator) {
1632:                        return getSeparatorLabel(((ItemsListSeparator) element)
1633:                                .getName());
1634:                    }
1635:
1636:                    String str = provider.getText(element);
1637:
1638:                    if (selectionDecorator != null && element != null) {
1639:
1640:                        // ((StructuredSelection)list.getSelection()).toList().contains(element))
1641:                        // cannot be used - virtual tables produce cycles in
1642:                        // update item - get selection invocation scenarios
1643:
1644:                        int[] selectionIndices = list.getTable()
1645:                                .getSelectionIndices();
1646:                        List elements = Arrays.asList(contentProvider
1647:                                .getElements(null));
1648:                        for (int i = 0; i < selectionIndices.length; i++) {
1649:                            if (elements.size() > selectionIndices[i]
1650:                                    && element.equals(elements
1651:                                            .get(selectionIndices[i]))) {
1652:                                str = selectionDecorator.decorateText(str,
1653:                                        element);
1654:                                break;
1655:                            }
1656:                        }
1657:                    }
1658:                    return str;
1659:                }
1660:
1661:                private String getSeparatorLabel(String separatorLabel) {
1662:                    Rectangle rect = list.getTable().getBounds();
1663:
1664:                    int borderWidth = list.getTable().computeTrim(0, 0, 0, 0).width;
1665:
1666:                    int imageWidth = WorkbenchImages.getImage(
1667:                            IWorkbenchGraphicConstants.IMG_OBJ_SEPARATOR)
1668:                            .getBounds().width;
1669:
1670:                    int width = rect.width - borderWidth - imageWidth;
1671:
1672:                    GC gc = new GC(list.getTable());
1673:                    gc.setFont(list.getTable().getFont());
1674:
1675:                    int fSeparatorWidth = gc.getAdvanceWidth('-');
1676:                    int fMessageLength = gc.textExtent(separatorLabel).x;
1677:
1678:                    gc.dispose();
1679:
1680:                    StringBuffer dashes = new StringBuffer();
1681:                    int chars = (((width - fMessageLength) / fSeparatorWidth) / 2) - 2;
1682:                    for (int i = 0; i < chars; i++) {
1683:                        dashes.append('-');
1684:                    }
1685:
1686:                    StringBuffer result = new StringBuffer();
1687:                    result.append(dashes);
1688:                    result.append(" " + separatorLabel + " "); //$NON-NLS-1$//$NON-NLS-2$
1689:                    result.append(dashes);
1690:                    return result.toString().trim();
1691:                }
1692:
1693:                /*
1694:                 * (non-Javadoc)
1695:                 * 
1696:                 * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
1697:                 */
1698:                public void addListener(ILabelProviderListener listener) {
1699:                    listeners.add(listener);
1700:                }
1701:
1702:                /*
1703:                 * (non-Javadoc)
1704:                 * 
1705:                 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
1706:                 */
1707:                public void dispose() {
1708:                    provider.removeListener(this );
1709:                    provider.dispose();
1710:
1711:                    if (selectionDecorator != null) {
1712:                        selectionDecorator.removeListener(this );
1713:                        selectionDecorator.dispose();
1714:                    }
1715:
1716:                    super .dispose();
1717:                }
1718:
1719:                /*
1720:                 * (non-Javadoc)
1721:                 * 
1722:                 * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
1723:                 *      java.lang.String)
1724:                 */
1725:                public boolean isLabelProperty(Object element, String property) {
1726:                    if (provider.isLabelProperty(element, property)) {
1727:                        return true;
1728:                    }
1729:                    if (selectionDecorator != null
1730:                            && selectionDecorator.isLabelProperty(element,
1731:                                    property)) {
1732:                        return true;
1733:                    }
1734:                    return false;
1735:                }
1736:
1737:                /*
1738:                 * (non-Javadoc)
1739:                 * 
1740:                 * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
1741:                 */
1742:                public void removeListener(ILabelProviderListener listener) {
1743:                    listeners.remove(listener);
1744:                }
1745:
1746:                /*
1747:                 * (non-Javadoc)
1748:                 * 
1749:                 * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object)
1750:                 */
1751:                public Color getBackground(Object element) {
1752:                    if (element instanceof  ItemsListSeparator) {
1753:                        return null;
1754:                    }
1755:                    if (provider instanceof  IColorProvider) {
1756:                        return ((IColorProvider) provider)
1757:                                .getBackground(element);
1758:                    }
1759:                    return null;
1760:                }
1761:
1762:                /*
1763:                 * (non-Javadoc)
1764:                 * 
1765:                 * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object)
1766:                 */
1767:                public Color getForeground(Object element) {
1768:                    if (element instanceof  ItemsListSeparator) {
1769:                        return Display.getCurrent().getSystemColor(
1770:                                SWT.COLOR_WIDGET_NORMAL_SHADOW);
1771:                    }
1772:                    if (provider instanceof  IColorProvider) {
1773:                        return ((IColorProvider) provider)
1774:                                .getForeground(element);
1775:                    }
1776:                    return null;
1777:                }
1778:
1779:                /*
1780:                 * (non-Javadoc)
1781:                 * 
1782:                 * @see org.eclipse.jface.viewers.IFontProvider#getFont(java.lang.Object)
1783:                 */
1784:                public Font getFont(Object element) {
1785:                    if (element instanceof  ItemsListSeparator) {
1786:                        return null;
1787:                    }
1788:                    if (provider instanceof  IFontProvider) {
1789:                        return ((IFontProvider) provider).getFont(element);
1790:                    }
1791:                    return null;
1792:                }
1793:
1794:                /*
1795:                 * (non-Javadoc)
1796:                 * 
1797:                 * @see org.eclipse.jface.viewers.ILabelProviderListener#labelProviderChanged(org.eclipse.jface.viewers.LabelProviderChangedEvent)
1798:                 */
1799:                public void labelProviderChanged(LabelProviderChangedEvent event) {
1800:                    Object[] l = listeners.getListeners();
1801:                    for (int i = 0; i < listeners.size(); i++) {
1802:                        ((ILabelProviderListener) l[i])
1803:                                .labelProviderChanged(event);
1804:                    }
1805:                }
1806:            }
1807:
1808:            /**
1809:             * Used in ItemsListContentProvider, separates history and non-history
1810:             * items.
1811:             */
1812:            private class ItemsListSeparator {
1813:
1814:                private String name;
1815:
1816:                /**
1817:                 * Creates a new instance of the class.
1818:                 * 
1819:                 * @param name
1820:                 *            the name of the separator
1821:                 */
1822:                public ItemsListSeparator(String name) {
1823:                    this .name = name;
1824:                }
1825:
1826:                /**
1827:                 * Returns the name of this separator.
1828:                 * 
1829:                 * @return the name of the separator
1830:                 */
1831:                public String getName() {
1832:                    return name;
1833:                }
1834:            }
1835:
1836:            /**
1837:             * GranualProgressMonitor is used for monitoring progress of filtering
1838:             * process. It is used by <code>RefreshProgressMessageJob</code> to
1839:             * refresh progress message. State of this monitor illustrates state of
1840:             * filtering or cache refreshing process.
1841:             * 
1842:             * @see GranualProgressMonitor#internalWorked(double)
1843:             */
1844:            private class GranualProgressMonitor extends ProgressMonitorWrapper {
1845:
1846:                private String name;
1847:
1848:                private String subName;
1849:
1850:                private int totalWork;
1851:
1852:                private double worked;
1853:
1854:                private boolean done;
1855:
1856:                /**
1857:                 * Creates instance of <code>GranualProgressMonitor</code>.
1858:                 * 
1859:                 * @param monitor
1860:                 *            progress to be wrapped
1861:                 */
1862:                public GranualProgressMonitor(IProgressMonitor monitor) {
1863:                    super (monitor);
1864:                }
1865:
1866:                /**
1867:                 * Checks if filtering has been done
1868:                 * 
1869:                 * @return true if filtering work has been done false in other way
1870:                 */
1871:                public boolean isDone() {
1872:                    return done;
1873:                }
1874:
1875:                /*
1876:                 * (non-Javadoc)
1877:                 * 
1878:                 * @see org.eclipse.core.runtime.ProgressMonitorWrapper#setTaskName(java.lang.String)
1879:                 */
1880:                public void setTaskName(String name) {
1881:                    super .setTaskName(name);
1882:                    this .name = name;
1883:                    this .subName = null;
1884:                }
1885:
1886:                /*
1887:                 * (non-Javadoc)
1888:                 * 
1889:                 * @see org.eclipse.core.runtime.ProgressMonitorWrapper#subTask(java.lang.String)
1890:                 */
1891:                public void subTask(String name) {
1892:                    super .subTask(name);
1893:                    this .subName = name;
1894:                }
1895:
1896:                /*
1897:                 * (non-Javadoc)
1898:                 * 
1899:                 * @see org.eclipse.core.runtime.ProgressMonitorWrapper#beginTask(java.lang.String,
1900:                 *      int)
1901:                 */
1902:                public void beginTask(String name, int totalWork) {
1903:                    super .beginTask(name, totalWork);
1904:                    if (this .name == null)
1905:                        this .name = name;
1906:                    this .totalWork = totalWork;
1907:                    refreshProgressMessageJob.scheduleProgressRefresh(this );
1908:                }
1909:
1910:                /*
1911:                 * (non-Javadoc)
1912:                 * 
1913:                 * @see org.eclipse.core.runtime.ProgressMonitorWrapper#worked(int)
1914:                 */
1915:                public void worked(int work) {
1916:                    super .worked(work);
1917:                    internalWorked(work);
1918:                }
1919:
1920:                /*
1921:                 * (non-Javadoc)
1922:                 * 
1923:                 * @see org.eclipse.core.runtime.ProgressMonitorWrapper#done()
1924:                 */
1925:                public void done() {
1926:                    done = true;
1927:                    super .done();
1928:                }
1929:
1930:                /*
1931:                 * (non-Javadoc)
1932:                 * 
1933:                 * @see org.eclipse.core.runtime.ProgressMonitorWrapper#setCanceled(boolean)
1934:                 */
1935:                public void setCanceled(boolean b) {
1936:                    done = b;
1937:                    super .setCanceled(b);
1938:                }
1939:
1940:                /*
1941:                 * (non-Javadoc)
1942:                 * 
1943:                 * @see org.eclipse.core.runtime.ProgressMonitorWrapper#internalWorked(double)
1944:                 */
1945:                public void internalWorked(double work) {
1946:                    worked = worked + work;
1947:                }
1948:
1949:                private String getMessage() {
1950:                    if (done)
1951:                        return ""; //$NON-NLS-1$
1952:
1953:                    String message;
1954:
1955:                    if (name == null) {
1956:                        message = subName == null ? "" : subName; //$NON-NLS-1$
1957:                    } else {
1958:                        message = subName == null ? name
1959:                                : NLS
1960:                                        .bind(
1961:                                                WorkbenchMessages.FilteredItemsSelectionDialog_subtaskProgressMessage,
1962:                                                new Object[] { name, subName });
1963:                    }
1964:                    if (totalWork == 0)
1965:                        return message;
1966:
1967:                    return NLS
1968:                            .bind(
1969:                                    WorkbenchMessages.FilteredItemsSelectionDialog_taskProgressMessage,
1970:                                    new Object[] {
1971:                                            message,
1972:                                            new Integer(
1973:                                                    (int) ((worked * 100) / totalWork)) });
1974:
1975:                }
1976:
1977:            }
1978:
1979:            /**
1980:             * Filters items history and schedule filter job.
1981:             */
1982:            private class FilterHistoryJob extends Job {
1983:
1984:                /**
1985:                 * Filter used during the filtering process.
1986:                 */
1987:                private ItemsFilter itemsFilter;
1988:
1989:                /**
1990:                 * Creates new instance of receiver.
1991:                 */
1992:                public FilterHistoryJob() {
1993:                    super (
1994:                            WorkbenchMessages.FilteredItemsSelectionDialog_jobLabel);
1995:                    setSystem(true);
1996:                }
1997:
1998:                /*
1999:                 * (non-Javadoc)
2000:                 * 
2001:                 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
2002:                 */
2003:                protected IStatus run(IProgressMonitor monitor) {
2004:
2005:                    this .itemsFilter = filter;
2006:
2007:                    contentProvider.reset();
2008:
2009:                    refreshWithLastSelection = false;
2010:
2011:                    contentProvider.addHistoryItems(itemsFilter);
2012:
2013:                    if (!(lastCompletedFilter != null && lastCompletedFilter
2014:                            .isSubFilter(this .itemsFilter)))
2015:                        contentProvider.refresh();
2016:
2017:                    filterJob.schedule();
2018:
2019:                    return Status.OK_STATUS;
2020:                }
2021:
2022:            }
2023:
2024:            /**
2025:             * Filters items in indicated set and history. During filtering, it
2026:             * refreshes the dialog (progress monitor and elements list).
2027:             * 
2028:             * Depending on the filter, <code>FilterJob</code> decides which kind of
2029:             * search will be run inside <code>filterContent</code>. If the last
2030:             * filtering is done (last completed filter), is not null, and the new
2031:             * filter is a sub-filter ({@link FilteredItemsSelectionDialog.ItemsFilter#isSubFilter(FilteredItemsSelectionDialog.ItemsFilter)})
2032:             * of the last, then <code>FilterJob</code> only filters in the cache. If
2033:             * it is the first filtering or the new filter isn't a sub-filter of the
2034:             * last one, a full search is run.
2035:             */
2036:            private class FilterJob extends Job {
2037:
2038:                /**
2039:                 * Filter used during the filtering process.
2040:                 */
2041:                protected ItemsFilter itemsFilter;
2042:
2043:                /**
2044:                 * Creates new instance of FilterJob
2045:                 */
2046:                public FilterJob() {
2047:                    super (
2048:                            WorkbenchMessages.FilteredItemsSelectionDialog_jobLabel);
2049:                    setSystem(true);
2050:                }
2051:
2052:                /*
2053:                 * (non-Javadoc)
2054:                 * 
2055:                 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
2056:                 */
2057:                protected final IStatus run(IProgressMonitor parent) {
2058:                    GranualProgressMonitor monitor = new GranualProgressMonitor(
2059:                            parent);
2060:                    return doRun(monitor);
2061:                }
2062:
2063:                /**
2064:                 * Executes job using the given filtering progress monitor. A hook for
2065:                 * subclasses.
2066:                 * 
2067:                 * @param monitor
2068:                 *            progress monitor
2069:                 * @return result of the execution
2070:                 */
2071:                protected IStatus doRun(GranualProgressMonitor monitor) {
2072:                    try {
2073:                        internalRun(monitor);
2074:                    } catch (CoreException e) {
2075:                        cancel();
2076:                        return new Status(
2077:                                IStatus.ERROR,
2078:                                PlatformUI.PLUGIN_ID,
2079:                                IStatus.ERROR,
2080:                                WorkbenchMessages.FilteredItemsSelectionDialog_jobError,
2081:                                e);
2082:                    }
2083:                    return Status.OK_STATUS;
2084:                }
2085:
2086:                /**
2087:                 * Main method for the job.
2088:                 * 
2089:                 * @param monitor
2090:                 * @throws CoreException
2091:                 */
2092:                private void internalRun(GranualProgressMonitor monitor)
2093:                        throws CoreException {
2094:                    try {
2095:                        if (monitor.isCanceled())
2096:                            return;
2097:
2098:                        this .itemsFilter = filter;
2099:
2100:                        if (filter.getPattern().length() != 0) {
2101:                            filterContent(monitor);
2102:                        }
2103:
2104:                        if (monitor.isCanceled())
2105:                            return;
2106:
2107:                        contentProvider.refresh();
2108:                    } finally {
2109:                        monitor.done();
2110:                    }
2111:                }
2112:
2113:                /**
2114:                 * Filters items.
2115:                 * 
2116:                 * @param monitor
2117:                 *            for monitoring progress
2118:                 * @throws CoreException
2119:                 */
2120:                protected void filterContent(GranualProgressMonitor monitor)
2121:                        throws CoreException {
2122:
2123:                    if (lastCompletedFilter != null
2124:                            && lastCompletedFilter
2125:                                    .isSubFilter(this .itemsFilter)) {
2126:
2127:                        int length = lastCompletedResult.size() / 500;
2128:                        monitor
2129:                                .beginTask(
2130:                                        WorkbenchMessages.FilteredItemsSelectionDialog_cacheSearchJob_taskName,
2131:                                        length);
2132:
2133:                        for (int pos = 0; pos < lastCompletedResult.size(); pos++) {
2134:
2135:                            Object item = lastCompletedResult.get(pos);
2136:                            if (monitor.isCanceled())
2137:                                break;
2138:                            contentProvider.add(item, itemsFilter);
2139:
2140:                            if ((pos % 500) == 0) {
2141:                                monitor.worked(1);
2142:                            }
2143:                        }
2144:
2145:                    } else {
2146:
2147:                        lastCompletedFilter = null;
2148:                        lastCompletedResult = null;
2149:
2150:                        SubProgressMonitor subMonitor = null;
2151:                        if (monitor != null) {
2152:                            monitor
2153:                                    .beginTask(
2154:                                            WorkbenchMessages.FilteredItemsSelectionDialog_searchJob_taskName,
2155:                                            100);
2156:                            subMonitor = new SubProgressMonitor(monitor, 95);
2157:
2158:                        }
2159:
2160:                        fillContentProvider(contentProvider, itemsFilter,
2161:                                subMonitor);
2162:
2163:                        if (monitor != null && !monitor.isCanceled()) {
2164:                            monitor.worked(2);
2165:                            contentProvider.rememberResult(itemsFilter);
2166:                            monitor.worked(3);
2167:                        }
2168:                    }
2169:
2170:                }
2171:
2172:            }
2173:
2174:            /**
2175:             * History stores a list of key, object pairs. The list is bounded at a
2176:             * certain size. If the list exceeds this size the oldest element is removed
2177:             * from the list. An element can be added/renewed with a call to
2178:             * <code>accessed(Object)</code>.
2179:             * <p>
2180:             * The history can be stored to/loaded from an XML file.
2181:             */
2182:            protected static abstract class SelectionHistory {
2183:
2184:                private static final String DEFAULT_ROOT_NODE_NAME = "historyRootNode"; //$NON-NLS-1$
2185:
2186:                private static final String DEFAULT_INFO_NODE_NAME = "infoNode"; //$NON-NLS-1$
2187:
2188:                private static final int MAX_HISTORY_SIZE = 60;
2189:
2190:                private final List historyList;
2191:
2192:                private final String rootNodeName;
2193:
2194:                private final String infoNodeName;
2195:
2196:                private SelectionHistory(String rootNodeName,
2197:                        String infoNodeName) {
2198:
2199:                    historyList = Collections
2200:                            .synchronizedList(new LinkedList() {
2201:
2202:                                private static final long serialVersionUID = 0L;
2203:
2204:                                /*
2205:                                 * (non-Javadoc)
2206:                                 * 
2207:                                 * @see java.util.LinkedList#add(java.lang.Object)
2208:                                 */
2209:                                public boolean add(Object arg0) {
2210:                                    if (this .size() > MAX_HISTORY_SIZE)
2211:                                        this .removeFirst();
2212:                                    if (!this .contains(arg0))
2213:                                        return super .add(arg0);
2214:                                    return false;
2215:                                }
2216:
2217:                            });
2218:
2219:                    this .rootNodeName = rootNodeName;
2220:                    this .infoNodeName = infoNodeName;
2221:                }
2222:
2223:                /**
2224:                 * Creates new instance of <code>SelectionHistory</code>.
2225:                 */
2226:                public SelectionHistory() {
2227:                    this (DEFAULT_ROOT_NODE_NAME, DEFAULT_INFO_NODE_NAME);
2228:                }
2229:
2230:                /**
2231:                 * Adds object to history.
2232:                 * 
2233:                 * @param object
2234:                 *            the item to be added to the history
2235:                 */
2236:                public synchronized void accessed(Object object) {
2237:                    historyList.add(object);
2238:                }
2239:
2240:                /**
2241:                 * Returns <code>true</code> if history contains object.
2242:                 * 
2243:                 * @param object
2244:                 *            the item for which check will be executed
2245:                 * @return <code>true</code> if history contains object
2246:                 *         <code>false</code> in other way
2247:                 */
2248:                public synchronized boolean contains(Object object) {
2249:                    return historyList.contains(object);
2250:                }
2251:
2252:                /**
2253:                 * Returns <code>true</code> if history is empty.
2254:                 * 
2255:                 * @return <code>true</code> if history is empty
2256:                 */
2257:                public synchronized boolean isEmpty() {
2258:                    return historyList.isEmpty();
2259:                }
2260:
2261:                /**
2262:                 * Remove element from history.
2263:                 * 
2264:                 * @param element
2265:                 *            to remove form the history
2266:                 * @return <code>true</code> if this list contained the specified
2267:                 *         element
2268:                 */
2269:                public synchronized boolean remove(Object element) {
2270:                    return historyList.remove(element);
2271:                }
2272:
2273:                /**
2274:                 * Load history elements from memento.
2275:                 * 
2276:                 * @param memento
2277:                 *            memento from which the history will be retrieved
2278:                 */
2279:                public void load(IMemento memento) {
2280:
2281:                    XMLMemento historyMemento = (XMLMemento) memento
2282:                            .getChild(rootNodeName);
2283:
2284:                    if (historyMemento == null) {
2285:                        return;
2286:                    }
2287:
2288:                    IMemento[] mementoElements = historyMemento
2289:                            .getChildren(infoNodeName);
2290:                    for (int i = 0; i < mementoElements.length; ++i) {
2291:                        IMemento mementoElement = mementoElements[i];
2292:                        Object object = restoreItemFromMemento(mementoElement);
2293:                        if (object != null) {
2294:                            historyList.add(object);
2295:                        }
2296:                    }
2297:                }
2298:
2299:                /**
2300:                 * Save history elements to memento.
2301:                 * 
2302:                 * @param memento
2303:                 *            memento to which the history will be added
2304:                 */
2305:                public void save(IMemento memento) {
2306:
2307:                    IMemento historyMemento = memento.createChild(rootNodeName);
2308:
2309:                    Object[] items = getHistoryItems();
2310:                    for (int i = 0; i < items.length; i++) {
2311:                        Object item = items[i];
2312:                        IMemento elementMemento = historyMemento
2313:                                .createChild(infoNodeName);
2314:                        storeItemToMemento(item, elementMemento);
2315:                    }
2316:
2317:                }
2318:
2319:                /**
2320:                 * Gets array of history items.
2321:                 * 
2322:                 * @return array of history elements
2323:                 */
2324:                public synchronized Object[] getHistoryItems() {
2325:                    return historyList.toArray();
2326:                }
2327:
2328:                /**
2329:                 * Creates an object using given memento.
2330:                 * 
2331:                 * @param memento
2332:                 *            memento used for creating new object
2333:                 * 
2334:                 * @return the restored object
2335:                 */
2336:                protected abstract Object restoreItemFromMemento(
2337:                        IMemento memento);
2338:
2339:                /**
2340:                 * Store object in <code>IMemento</code>.
2341:                 * 
2342:                 * @param item
2343:                 *            the item to store
2344:                 * @param memento
2345:                 *            the memento to store to
2346:                 */
2347:                protected abstract void storeItemToMemento(Object item,
2348:                        IMemento memento);
2349:
2350:            }
2351:
2352:            /**
2353:             * Filters elements using SearchPattern by comparing the names of items with
2354:             * the filter pattern.
2355:             */
2356:            protected abstract class ItemsFilter {
2357:
2358:                protected SearchPattern patternMatcher;
2359:
2360:                /**
2361:                 * Creates new instance of ItemsFilter.
2362:                 */
2363:                public ItemsFilter() {
2364:                    this (new SearchPattern());
2365:                }
2366:
2367:                /**
2368:                 * Creates new instance of ItemsFilter.
2369:                 * 
2370:                 * @param searchPattern
2371:                 *            the pattern to be used when filtering
2372:                 */
2373:                public ItemsFilter(SearchPattern searchPattern) {
2374:                    patternMatcher = searchPattern;
2375:                    String stringPattern = ""; //$NON-NLS-1$
2376:                    if (pattern != null && !pattern.getText().equals("*")) { //$NON-NLS-1$
2377:                        stringPattern = pattern.getText();
2378:                    }
2379:                    patternMatcher.setPattern(stringPattern);
2380:                }
2381:
2382:                /**
2383:                 * Check if the given filter is a sub-filter of current filter. The
2384:                 * default implementation checks if the <code>SearchPattern</code>
2385:                 * from the current filter is a sub-pattern of the one from the provided
2386:                 * filter.
2387:                 * 
2388:                 * @param filter
2389:                 *            the filter to be checked, or <code>null</code>
2390:                 * @return <code>true</code> if the given filter is sub-filter of the
2391:                 *         current, <code>false</code> if the given filter isn't a
2392:                 *         sub-filter or is <code>null</code>
2393:                 * 
2394:                 * @see org.eclipse.ui.dialogs.SearchPattern#isSubPattern(org.eclipse.ui.dialogs.SearchPattern)
2395:                 */
2396:                public boolean isSubFilter(ItemsFilter filter) {
2397:                    if (filter != null) {
2398:                        return this .patternMatcher
2399:                                .isSubPattern(filter.patternMatcher);
2400:                    }
2401:                    return false;
2402:                }
2403:
2404:                /**
2405:                 * Checks whether the provided filter is equal to the current filter.
2406:                 * The default implementation checks if <code>SearchPattern</code>
2407:                 * from current filter is equal to the one from provided filter.
2408:                 * 
2409:                 * @param filter
2410:                 *            filter to be checked, or <code>null</code>
2411:                 * @return <code>true</code> if the given filter is equal to current
2412:                 *         filter, <code>false</code> if given filter isn't equal to
2413:                 *         current one or if it is <code>null</code>
2414:                 * 
2415:                 * @see org.eclipse.ui.dialogs.SearchPattern#equalsPattern(org.eclipse.ui.dialogs.SearchPattern)
2416:                 */
2417:                public boolean equalsFilter(ItemsFilter filter) {
2418:                    if (filter != null
2419:                            && filter.patternMatcher
2420:                                    .equalsPattern(this .patternMatcher)) {
2421:                        return true;
2422:                    }
2423:                    return false;
2424:                }
2425:
2426:                /**
2427:                 * Checks whether the pattern's match rule is camel case.
2428:                 * 
2429:                 * @return <code>true</code> if pattern's match rule is camel case,
2430:                 *         <code>false</code> otherwise
2431:                 */
2432:                public boolean isCamelCasePattern() {
2433:                    return patternMatcher.getMatchRule() == SearchPattern.RULE_CAMELCASE_MATCH;
2434:                }
2435:
2436:                /**
2437:                 * Returns the pattern string.
2438:                 * 
2439:                 * @return pattern for this filter
2440:                 * 
2441:                 * @see SearchPattern#getPattern()
2442:                 */
2443:                public String getPattern() {
2444:                    return patternMatcher.getPattern();
2445:                }
2446:
2447:                /**
2448:                 * Returns the rule to apply for matching keys.
2449:                 * 
2450:                 * @return match rule
2451:                 * 
2452:                 * @see SearchPattern#getMatchRule()
2453:                 */
2454:                public int getMatchRule() {
2455:                    return patternMatcher.getMatchRule();
2456:                }
2457:
2458:                /**
2459:                 * Matches text with filter.
2460:                 * 
2461:                 * @param text
2462:                 * @return <code>true</code> if text matches with filter pattern,
2463:                 *         <code>false</code> otherwise
2464:                 */
2465:                protected boolean matches(String text) {
2466:                    return patternMatcher.matches(text);
2467:                }
2468:
2469:                /**
2470:                 * General method for matching raw name pattern. Checks whether current
2471:                 * pattern is prefix of name provided item.
2472:                 * 
2473:                 * @param item
2474:                 *            item to check
2475:                 * @return <code>true</code> if current pattern is a prefix of name
2476:                 *         provided item, <code>false</code> if item's name is shorter
2477:                 *         than prefix or sequences of characters don't match.
2478:                 */
2479:                public boolean matchesRawNamePattern(Object item) {
2480:                    String prefix = patternMatcher.getPattern();
2481:                    String text = getElementName(item);
2482:
2483:                    if (text == null)
2484:                        return false;
2485:
2486:                    int textLength = text.length();
2487:                    int prefixLength = prefix.length();
2488:                    if (textLength < prefixLength) {
2489:                        return false;
2490:                    }
2491:                    for (int i = prefixLength - 1; i >= 0; i--) {
2492:                        if (Character.toLowerCase(prefix.charAt(i)) != Character
2493:                                .toLowerCase(text.charAt(i)))
2494:                            return false;
2495:                    }
2496:                    return true;
2497:                }
2498:
2499:                /**
2500:                 * Matches an item against filter conditions.
2501:                 * 
2502:                 * @param item
2503:                 * @return <code>true<code> if item matches against filter conditions, <code>false</code>
2504:                 *         otherwise
2505:                 */
2506:                public abstract boolean matchItem(Object item);
2507:
2508:                /**
2509:                 * Checks consistency of an item. Item is inconsistent if was changed or
2510:                 * removed.
2511:                 * 
2512:                 * @param item
2513:                 * @return <code>true</code> if item is consistent, <code>false</code>
2514:                 *         if item is inconsistent
2515:                 */
2516:                public abstract boolean isConsistentItem(Object item);
2517:
2518:            }
2519:
2520:            /**
2521:             * An interface to content providers for
2522:             * <code>FilterItemsSelectionDialog</code>.
2523:             */
2524:            protected abstract class AbstractContentProvider {
2525:                /**
2526:                 * Adds the item to the content provider iff the filter matches the
2527:                 * item. Otherwise does nothing.
2528:                 * 
2529:                 * @param item
2530:                 *            the item to add
2531:                 * @param itemsFilter
2532:                 *            the filter
2533:                 * 
2534:                 * @see FilteredItemsSelectionDialog.ItemsFilter#matchItem(Object)
2535:                 */
2536:                public abstract void add(Object item, ItemsFilter itemsFilter);
2537:            }
2538:
2539:            /**
2540:             * Collects filtered elements. Contains one synchronized, sorted set for
2541:             * collecting filtered elements. All collected elements are sorted using
2542:             * comparator. Comparator is returned by getElementComparator() method.
2543:             * Implementation of <code>ItemsFilter</code> is used to filter elements.
2544:             * The key function of filter used in to filtering is
2545:             * <code>matchElement(Object item)</code>.
2546:             * <p>
2547:             * The <code>ContentProvider</code> class also provides item filtering
2548:             * methods. The filtering has been moved from the standard TableView
2549:             * <code>getFilteredItems()</code> method to content provider, because
2550:             * <code>ILazyContentProvider</code> and virtual tables are used. This
2551:             * class is responsible for adding a separator below history items and
2552:             * marking each items as duplicate if its name repeats more than once on the
2553:             * filtered list.
2554:             */
2555:            private class ContentProvider extends AbstractContentProvider
2556:                    implements  IStructuredContentProvider, ILazyContentProvider {
2557:
2558:                private SelectionHistory selectionHistory;
2559:
2560:                /**
2561:                 * Raw result of the searching (unsorted, unfiltered).
2562:                 * <p>
2563:                 * Standard object flow:
2564:                 * <code>items -> lastSortedItems -> lastFilteredItems</code>
2565:                 */
2566:                private Set items;
2567:
2568:                /**
2569:                 * Items that are duplicates.
2570:                 */
2571:                private Set duplicates;
2572:
2573:                /**
2574:                 * List of <code>ViewerFilter</code>s to be used during filtering
2575:                 */
2576:                private List filters;
2577:
2578:                /**
2579:                 * Result of the last filtering.
2580:                 * <p>
2581:                 * Standard object flow:
2582:                 * <code>items -> lastSortedItems -> lastFilteredItems</code>
2583:                 */
2584:                private List lastFilteredItems;
2585:
2586:                /**
2587:                 * Result of the last sorting.
2588:                 * <p>
2589:                 * Standard object flow:
2590:                 * <code>items -> lastSortedItems -> lastFilteredItems</code>
2591:                 */
2592:                private List lastSortedItems;
2593:
2594:                /**
2595:                 * Used for <code>getFilteredItems()</code> method canceling (when the
2596:                 * job that invoked the method was canceled).
2597:                 * <p>
2598:                 * Method canceling could be based (only) on monitor canceling
2599:                 * unfortunately sometimes the method <code>getFilteredElements()</code>
2600:                 * could be run with a null monitor, the <code>reset</code> flag have
2601:                 * to be left intact.
2602:                 */
2603:                private boolean reset;
2604:
2605:                /**
2606:                 * Creates new instance of <code>ContentProvider</code>.
2607:                 * 
2608:                 * @param selectionHistory
2609:                 */
2610:                public ContentProvider(SelectionHistory selectionHistory) {
2611:                    this ();
2612:                    this .selectionHistory = selectionHistory;
2613:                }
2614:
2615:                /**
2616:                 * Creates new instance of <code>ContentProvider</code>.
2617:                 */
2618:                public ContentProvider() {
2619:                    this .items = Collections.synchronizedSet(new HashSet(2048));
2620:                    this .duplicates = Collections.synchronizedSet(new HashSet(
2621:                            256));
2622:                    this .lastFilteredItems = new ArrayList();
2623:                    this .lastSortedItems = Collections
2624:                            .synchronizedList(new ArrayList(2048));
2625:                }
2626:
2627:                /**
2628:                 * Sets selection history.
2629:                 * 
2630:                 * @param selectionHistory
2631:                 *            The selectionHistory to set.
2632:                 */
2633:                public void setSelectionHistory(
2634:                        SelectionHistory selectionHistory) {
2635:                    this .selectionHistory = selectionHistory;
2636:                }
2637:
2638:                /**
2639:                 * @return Returns the selectionHistory.
2640:                 */
2641:                public SelectionHistory getSelectionHistory() {
2642:                    return selectionHistory;
2643:                }
2644:
2645:                /**
2646:                 * Removes all content items and resets progress message.
2647:                 */
2648:                public void reset() {
2649:                    reset = true;
2650:                    this .items.clear();
2651:                    this .duplicates.clear();
2652:                    this .lastSortedItems.clear();
2653:                }
2654:
2655:                /**
2656:                 * Stops reloading cache - <code>getFilteredItems()</code> method.
2657:                 */
2658:                public void stopReloadingCache() {
2659:                    reset = true;
2660:                }
2661:
2662:                /**
2663:                 * Adds filtered item.
2664:                 * 
2665:                 * @param item
2666:                 * @param itemsFilter
2667:                 */
2668:                public void add(Object item, ItemsFilter itemsFilter) {
2669:                    if (itemsFilter == filter) {
2670:                        if (itemsFilter != null) {
2671:                            if (itemsFilter.matchItem(item)) {
2672:                                this .items.add(item);
2673:                            }
2674:                        } else {
2675:                            this .items.add(item);
2676:                        }
2677:                    }
2678:                }
2679:
2680:                /**
2681:                 * Add all history items to <code>contentProvider</code>.
2682:                 * 
2683:                 * @param itemsFilter
2684:                 */
2685:                public void addHistoryItems(ItemsFilter itemsFilter) {
2686:                    if (this .selectionHistory != null) {
2687:                        Object[] items = this .selectionHistory
2688:                                .getHistoryItems();
2689:                        for (int i = 0; i < items.length; i++) {
2690:                            Object item = items[i];
2691:                            if (itemsFilter == filter) {
2692:                                if (itemsFilter != null) {
2693:                                    if (itemsFilter.matchItem(item)) {
2694:                                        if (itemsFilter.isConsistentItem(item)) {
2695:                                            this .items.add(item);
2696:                                        } else {
2697:                                            this .selectionHistory.remove(item);
2698:                                        }
2699:                                    }
2700:                                }
2701:                            }
2702:                        }
2703:                    }
2704:                }
2705:
2706:                /**
2707:                 * Refresh dialog.
2708:                 */
2709:                public void refresh() {
2710:                    scheduleRefresh();
2711:                }
2712:
2713:                /**
2714:                 * Removes items from history and refreshes the view.
2715:                 * 
2716:                 * @param item
2717:                 *            to remove
2718:                 * 
2719:                 * @return removed item
2720:                 */
2721:                public Object removeHistoryElement(Object item) {
2722:                    if (this .selectionHistory != null)
2723:                        this .selectionHistory.remove(item);
2724:                    if (filter == null || filter.getPattern().length() == 0) {
2725:                        items.remove(item);
2726:                        duplicates.remove(item);
2727:                        this .lastSortedItems.remove(item);
2728:                    }
2729:
2730:                    synchronized (lastSortedItems) {
2731:                        Collections.sort(lastSortedItems,
2732:                                getHistoryComparator());
2733:                    }
2734:                    return item;
2735:                }
2736:
2737:                /**
2738:                 * Adds item to history and refresh view.
2739:                 * 
2740:                 * @param item
2741:                 *            to add
2742:                 */
2743:                public void addHistoryElement(Object item) {
2744:                    if (this .selectionHistory != null)
2745:                        this .selectionHistory.accessed(item);
2746:                    if (filter == null || !filter.matchItem(item)) {
2747:                        this .items.remove(item);
2748:                        this .duplicates.remove(item);
2749:                        this .lastSortedItems.remove(item);
2750:                    }
2751:                    synchronized (lastSortedItems) {
2752:                        Collections.sort(lastSortedItems,
2753:                                getHistoryComparator());
2754:                    }
2755:                    this .refresh();
2756:                }
2757:
2758:                /**
2759:                 * @param item
2760:                 * @return <code>true</code> if given item is part of the history
2761:                 */
2762:                public boolean isHistoryElement(Object item) {
2763:                    if (this .selectionHistory != null) {
2764:                        return this .selectionHistory.contains(item);
2765:                    }
2766:                    return false;
2767:                }
2768:
2769:                /**
2770:                 * Sets/unsets given item as duplicate.
2771:                 * 
2772:                 * @param item
2773:                 *            item to change
2774:                 * 
2775:                 * @param isDuplicate
2776:                 *            duplicate flag
2777:                 */
2778:                public void setDuplicateElement(Object item, boolean isDuplicate) {
2779:                    if (this .items.contains(item)) {
2780:                        if (isDuplicate)
2781:                            this .duplicates.add(item);
2782:                        else
2783:                            this .duplicates.remove(item);
2784:                    }
2785:                }
2786:
2787:                /**
2788:                 * Indicates whether given item is a duplicate.
2789:                 * 
2790:                 * @param item
2791:                 *            item to check
2792:                 * @return <code>true</code> if item is duplicate
2793:                 */
2794:                public boolean isDuplicateElement(Object item) {
2795:                    return duplicates.contains(item);
2796:                }
2797:
2798:                /**
2799:                 * Load history from memento.
2800:                 * 
2801:                 * @param memento
2802:                 *            memento from which the history will be retrieved
2803:                 */
2804:                public void loadHistory(IMemento memento) {
2805:                    if (this .selectionHistory != null)
2806:                        this .selectionHistory.load(memento);
2807:                }
2808:
2809:                /**
2810:                 * Save history to memento.
2811:                 * 
2812:                 * @param memento
2813:                 *            memento to which the history will be added
2814:                 */
2815:                public void saveHistory(IMemento memento) {
2816:                    if (this .selectionHistory != null)
2817:                        this .selectionHistory.save(memento);
2818:                }
2819:
2820:                /**
2821:                 * Gets sorted items.
2822:                 * 
2823:                 * @return sorted items
2824:                 */
2825:                private Object[] getSortedItems() {
2826:                    if (lastSortedItems.size() != items.size()) {
2827:                        synchronized (lastSortedItems) {
2828:                            lastSortedItems.clear();
2829:                            lastSortedItems.addAll(items);
2830:                            Collections.sort(lastSortedItems,
2831:                                    getHistoryComparator());
2832:                        }
2833:                    }
2834:                    return lastSortedItems.toArray();
2835:                }
2836:
2837:                /**
2838:                 * Remember result of filtering.
2839:                 * 
2840:                 * @param itemsFilter
2841:                 */
2842:                public void rememberResult(ItemsFilter itemsFilter) {
2843:                    List itemsList = Collections.synchronizedList(Arrays
2844:                            .asList(getSortedItems()));
2845:                    // synchronization
2846:                    if (itemsFilter == filter) {
2847:                        lastCompletedFilter = itemsFilter;
2848:                        lastCompletedResult = itemsList;
2849:                    }
2850:
2851:                }
2852:
2853:                /*
2854:                 * (non-Javadoc)
2855:                 * 
2856:                 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
2857:                 */
2858:                public Object[] getElements(Object inputElement) {
2859:                    return lastFilteredItems.toArray();
2860:                }
2861:
2862:                /*
2863:                 * (non-Javadoc)
2864:                 * 
2865:                 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
2866:                 */
2867:                public void dispose() {
2868:                }
2869:
2870:                /*
2871:                 * (non-Javadoc)
2872:                 * 
2873:                 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
2874:                 *      java.lang.Object, java.lang.Object)
2875:                 */
2876:                public void inputChanged(Viewer viewer, Object oldInput,
2877:                        Object newInput) {
2878:                }
2879:
2880:                /*
2881:                 * (non-Javadoc)
2882:                 * 
2883:                 * @see org.eclipse.jface.viewers.ILazyContentProvider#updateElement(int)
2884:                 */
2885:                public void updateElement(int index) {
2886:
2887:                    FilteredItemsSelectionDialog.this .list
2888:                            .replace(
2889:                                    (lastFilteredItems.size() > index) ? lastFilteredItems
2890:                                            .get(index)
2891:                                            : null, index);
2892:
2893:                }
2894:
2895:                /**
2896:                 * Main method responsible for getting the filtered items and checking
2897:                 * for duplicates. It is based on the
2898:                 * {@link ContentProvider#getFilteredItems(Object, IProgressMonitor)}.
2899:                 * 
2900:                 * @param checkDuplicates
2901:                 *            <code>true</code> if data concerning elements
2902:                 *            duplication should be computed - it takes much more time
2903:                 *            than standard filtering
2904:                 * 
2905:                 * @param monitor
2906:                 *            progress monitor
2907:                 */
2908:                public void reloadCache(boolean checkDuplicates,
2909:                        IProgressMonitor monitor) {
2910:
2911:                    reset = false;
2912:
2913:                    if (monitor != null) {
2914:                        // the work is divided into two actions of the same length
2915:                        int totalWork = checkDuplicates ? 200 : 100;
2916:
2917:                        monitor
2918:                                .beginTask(
2919:                                        WorkbenchMessages.FilteredItemsSelectionDialog_cacheRefreshJob,
2920:                                        totalWork);
2921:                    }
2922:
2923:                    // the TableViewer's root (the input) is treated as parent
2924:
2925:                    lastFilteredItems = Arrays.asList(getFilteredItems(list
2926:                            .getInput(),
2927:                            monitor != null ? new SubProgressMonitor(monitor,
2928:                                    100) : null));
2929:
2930:                    if (reset || (monitor != null && monitor.isCanceled())) {
2931:                        if (monitor != null)
2932:                            monitor.done();
2933:                        return;
2934:                    }
2935:
2936:                    if (checkDuplicates) {
2937:                        checkDuplicates(monitor);
2938:                    }
2939:                    if (monitor != null)
2940:                        monitor.done();
2941:                }
2942:
2943:                private void checkDuplicates(IProgressMonitor monitor) {
2944:                    synchronized (lastFilteredItems) {
2945:                        IProgressMonitor subMonitor = null;
2946:                        int reportEvery = lastFilteredItems.size() / 20;
2947:                        if (monitor != null) {
2948:                            subMonitor = new SubProgressMonitor(monitor, 100);
2949:                            subMonitor
2950:                                    .beginTask(
2951:                                            WorkbenchMessages.FilteredItemsSelectionDialog_cacheRefreshJob_checkDuplicates,
2952:                                            5);
2953:                        }
2954:                        HashMap helperMap = new HashMap();
2955:                        for (int i = 0; i < lastFilteredItems.size(); i++) {
2956:                            if (reset
2957:                                    || (subMonitor != null && subMonitor
2958:                                            .isCanceled()))
2959:                                return;
2960:                            Object item = lastFilteredItems.get(i);
2961:
2962:                            if (!(item instanceof  ItemsListSeparator)) {
2963:                                Object previousItem = helperMap.put(
2964:                                        getElementName(item), item);
2965:                                if (previousItem != null) {
2966:                                    setDuplicateElement(previousItem, true);
2967:                                    setDuplicateElement(item, true);
2968:                                } else {
2969:                                    setDuplicateElement(item, false);
2970:                                }
2971:                            }
2972:
2973:                            if (subMonitor != null && reportEvery != 0
2974:                                    && (i + 1) % reportEvery == 0)
2975:                                subMonitor.worked(1);
2976:                        }
2977:                        helperMap.clear();
2978:                    }
2979:                }
2980:
2981:                /**
2982:                 * Returns an array of items filtered using the provided
2983:                 * <code>ViewerFilter</code>s with a separator added.
2984:                 * 
2985:                 * @param parent
2986:                 *            the parent
2987:                 * @param monitor
2988:                 *            progress monitor, can be <code>null</code>
2989:                 * @return an array of filtered items
2990:                 */
2991:                protected Object[] getFilteredItems(Object parent,
2992:                        IProgressMonitor monitor) {
2993:                    int ticks = 100;
2994:
2995:                    if (monitor != null) {
2996:                        monitor
2997:                                .beginTask(
2998:                                        WorkbenchMessages.FilteredItemsSelectionDialog_cacheRefreshJob_getFilteredElements,
2999:                                        ticks);
3000:                        if (filters != null) {
3001:                            ticks /= (filters.size() + 2);
3002:                        } else {
3003:                            ticks /= 2;
3004:                        }
3005:                    }
3006:
3007:                    // get already sorted array
3008:                    Object[] filteredElements = getSortedItems();
3009:
3010:                    if (monitor != null) {
3011:                        monitor.worked(ticks);
3012:                    }
3013:
3014:                    // filter the elements using provided ViewerFilters
3015:                    if (filters != null && filteredElements != null) {
3016:                        for (Iterator iter = filters.iterator(); iter.hasNext();) {
3017:                            ViewerFilter f = (ViewerFilter) iter.next();
3018:                            filteredElements = f.filter(list, parent,
3019:                                    filteredElements);
3020:                            if (monitor != null)
3021:                                monitor.worked(ticks);
3022:                        }
3023:                    }
3024:
3025:                    if (filteredElements == null || monitor.isCanceled()) {
3026:                        if (monitor != null)
3027:                            monitor.done();
3028:                        return new Object[0];
3029:                    }
3030:
3031:                    ArrayList preparedElements = new ArrayList();
3032:                    boolean hasHistory = false;
3033:
3034:                    if (filteredElements.length > 0) {
3035:                        if (isHistoryElement(filteredElements[0])) {
3036:                            hasHistory = true;
3037:                        }
3038:                    }
3039:
3040:                    int reportEvery = filteredElements.length / ticks;
3041:
3042:                    // add separator
3043:                    for (int i = 0; i < filteredElements.length; i++) {
3044:                        Object item = filteredElements[i];
3045:
3046:                        if (hasHistory && !isHistoryElement(item)) {
3047:                            preparedElements.add(itemsListSeparator);
3048:                            hasHistory = false;
3049:                        }
3050:
3051:                        preparedElements.add(item);
3052:
3053:                        if (monitor != null && reportEvery != 0
3054:                                && ((i + 1) % reportEvery == 0))
3055:                            monitor.worked(1);
3056:                    }
3057:
3058:                    if (monitor != null)
3059:                        monitor.done();
3060:
3061:                    return preparedElements.toArray();
3062:                }
3063:
3064:                /**
3065:                 * Adds a filter to this content provider. For an example usage of such
3066:                 * filters look at the project <code>org.eclipse.ui.ide</code>, class
3067:                 * <code>org.eclipse.ui.dialogs.FilteredResourcesSelectionDialog.CustomWorkingSetFilter</code>.
3068:                 * 
3069:                 * 
3070:                 * @param filter
3071:                 *            the filter to be added
3072:                 */
3073:                public void addFilter(ViewerFilter filter) {
3074:                    if (filters == null) {
3075:                        filters = new ArrayList();
3076:                    }
3077:                    filters.add(filter);
3078:                    // currently filters are only added when dialog is restored
3079:                    // if it is changed, refreshing the whole TableViewer should be
3080:                    // added
3081:                }
3082:
3083:            }
3084:
3085:            /**
3086:             * A content provider that does nothing.
3087:             */
3088:            private class NullContentProvider implements  IContentProvider {
3089:
3090:                /*
3091:                 * (non-Javadoc)
3092:                 * 
3093:                 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
3094:                 */
3095:                public void dispose() {
3096:                }
3097:
3098:                /*
3099:                 * (non-Javadoc)
3100:                 * 
3101:                 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
3102:                 *      java.lang.Object, java.lang.Object)
3103:                 */
3104:                public void inputChanged(Viewer viewer, Object oldInput,
3105:                        Object newInput) {
3106:                }
3107:
3108:            }
3109:
3110:            /**
3111:             * DetailsContentViewer objects are wrappers for labels.
3112:             * DetailsContentViewer provides means to change label's image and text when
3113:             * the attached LabelProvider is updated.
3114:             */
3115:            private class DetailsContentViewer extends ContentViewer {
3116:
3117:                private CLabel label;
3118:
3119:                /**
3120:                 * Unfortunately, it was impossible to delegate displaying border to
3121:                 * label. The <code>ViewForm</code> is used because
3122:                 * <code>CLabel</code> displays shadow when border is present.
3123:                 */
3124:                private ViewForm viewForm;
3125:
3126:                /**
3127:                 * Constructs a new instance of this class given its parent and a style
3128:                 * value describing its behavior and appearance.
3129:                 * 
3130:                 * @param parent
3131:                 *            the parent component
3132:                 * @param style
3133:                 *            SWT style bits
3134:                 */
3135:                public DetailsContentViewer(Composite parent, int style) {
3136:                    viewForm = new ViewForm(parent, style);
3137:                    GridData gd = new GridData(GridData.FILL_HORIZONTAL);
3138:                    gd.horizontalSpan = 2;
3139:                    viewForm.setLayoutData(gd);
3140:                    label = new CLabel(viewForm, SWT.FLAT);
3141:                    label.setFont(parent.getFont());
3142:                    viewForm.setContent(label);
3143:                    hookControl(label);
3144:                }
3145:
3146:                /**
3147:                 * Shows/hides the content viewer.
3148:                 * 
3149:                 * @param visible
3150:                 *            if the content viewer should be visible.
3151:                 */
3152:                public void setVisible(boolean visible) {
3153:                    GridData gd = (GridData) viewForm.getLayoutData();
3154:                    gd.exclude = !visible;
3155:                    viewForm.getParent().layout();
3156:                }
3157:
3158:                /*
3159:                 * (non-Javadoc)
3160:                 * 
3161:                 * @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object,
3162:                 *      java.lang.Object)
3163:                 */
3164:                protected void inputChanged(Object input, Object oldInput) {
3165:                    if (oldInput == null) {
3166:                        if (input == null) {
3167:                            return;
3168:                        }
3169:                        refresh();
3170:                        return;
3171:                    }
3172:
3173:                    refresh();
3174:
3175:                }
3176:
3177:                /*
3178:                 * (non-Javadoc)
3179:                 * 
3180:                 * @see org.eclipse.jface.viewers.ContentViewer#handleLabelProviderChanged(org.eclipse.jface.viewers.LabelProviderChangedEvent)
3181:                 */
3182:                protected void handleLabelProviderChanged(
3183:                        LabelProviderChangedEvent event) {
3184:                    if (event != null) {
3185:                        refresh(event.getElements());
3186:                    }
3187:                }
3188:
3189:                /*
3190:                 * (non-Javadoc)
3191:                 * 
3192:                 * @see org.eclipse.jface.viewers.Viewer#getControl()
3193:                 */
3194:                public Control getControl() {
3195:                    return label;
3196:                }
3197:
3198:                /*
3199:                 * (non-Javadoc)
3200:                 * 
3201:                 * @see org.eclipse.jface.viewers.Viewer#getSelection()
3202:                 */
3203:                public ISelection getSelection() {
3204:                    // not supported
3205:                    return null;
3206:                }
3207:
3208:                /*
3209:                 * (non-Javadoc)
3210:                 * 
3211:                 * @see org.eclipse.jface.viewers.Viewer#refresh()
3212:                 */
3213:                public void refresh() {
3214:                    Object input = this .getInput();
3215:                    if (input != null) {
3216:                        ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();
3217:                        doRefresh(labelProvider.getText(input), labelProvider
3218:                                .getImage(input));
3219:                    } else {
3220:                        doRefresh(null, null);
3221:                    }
3222:                }
3223:
3224:                /**
3225:                 * Sets the given text and image to the label.
3226:                 * 
3227:                 * @param text
3228:                 *            the new text or null
3229:                 * @param image
3230:                 *            the new image
3231:                 */
3232:                private void doRefresh(String text, Image image) {
3233:                    label.setText(text);
3234:                    label.setImage(image);
3235:                }
3236:
3237:                /*
3238:                 * (non-Javadoc)
3239:                 * 
3240:                 * @see org.eclipse.jface.viewers.Viewer#setSelection(org.eclipse.jface.viewers.ISelection,
3241:                 *      boolean)
3242:                 */
3243:                public void setSelection(ISelection selection, boolean reveal) {
3244:                    // not supported
3245:                }
3246:
3247:                /**
3248:                 * Refreshes the label if currently chosen element is on the list.
3249:                 * 
3250:                 * @param objs
3251:                 *            list of changed object
3252:                 */
3253:                private void refresh(Object[] objs) {
3254:                    if (objs == null || getInput() == null) {
3255:                        return;
3256:                    }
3257:                    Object input = getInput();
3258:                    for (int i = 0; i < objs.length; i++) {
3259:                        if (objs[i].equals(input)) {
3260:                            refresh();
3261:                            break;
3262:                        }
3263:                    }
3264:                }
3265:            }
3266:
3267:            /**
3268:             * Compares items using camel case method.
3269:             */
3270:            private class CamelCaseComparator implements  Comparator {
3271:
3272:                /*
3273:                 * (non-Javadoc)
3274:                 * 
3275:                 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
3276:                 */
3277:                public int compare(Object o1, Object o2) {
3278:
3279:                    int leftCategory = getCamelCaseCategory(o1);
3280:                    int rightCategory = getCamelCaseCategory(o2);
3281:                    if (leftCategory < rightCategory)
3282:                        return -1;
3283:                    if (leftCategory > rightCategory)
3284:                        return +1;
3285:
3286:                    return getItemsComparator().compare(o1, o2);
3287:                }
3288:
3289:                private int getCamelCaseCategory(Object item) {
3290:                    if (filter == null)
3291:                        return 0;
3292:                    if (!filter.isCamelCasePattern())
3293:                        return 0;
3294:                    return filter.matchesRawNamePattern(item) ? 0 : 1;
3295:                }
3296:            }
3297:
3298:            /**
3299:             * Compares items according to the history.
3300:             */
3301:            private class HistoryComparator implements  Comparator {
3302:
3303:                private CamelCaseComparator camelCaseComparator;
3304:
3305:                /**
3306:                 * 
3307:                 */
3308:                public HistoryComparator() {
3309:                    this .camelCaseComparator = new CamelCaseComparator();
3310:                }
3311:
3312:                /*
3313:                 * (non-Javadoc)
3314:                 * 
3315:                 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
3316:                 */
3317:                public int compare(Object o1, Object o2) {
3318:                    if ((isHistoryElement(o1) && isHistoryElement(o2))
3319:                            || (!isHistoryElement(o1) && !isHistoryElement(o2)))
3320:                        return this .camelCaseComparator.compare(o1, o2);
3321:
3322:                    if (isHistoryElement(o1))
3323:                        return -2;
3324:                    if (isHistoryElement(o2))
3325:                        return +2;
3326:
3327:                    return 0;
3328:                }
3329:
3330:            }
3331:
3332:            /**
3333:             * Get the control where the search pattern is entered. Any filtering should
3334:             * be done using an {@link ItemsFilter}. This control should only be
3335:             * accessed for listeners that wish to handle events that do not affect
3336:             * filtering such as custom traversal.
3337:             * 
3338:             * @return Control or <code>null</code> if the pattern control has not
3339:             *         been created.
3340:             */
3341:            public Control getPatternControl() {
3342:                return pattern;
3343:            }
3344:
3345:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.