1) Moved net.sourceforge.phpeclipse.ui\src\net\sourceforge\phpdt back to net.sourcefo...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / ui / actions / CustomFiltersActionGroup.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.ui.actions;
12
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.SortedSet;
22 import java.util.Stack;
23 import java.util.StringTokenizer;
24 import java.util.TreeSet;
25
26 //import net.sourceforge.phpdt.core.IJavaModel;
27 import net.sourceforge.phpdt.internal.ui.PHPUiImages;
28 import net.sourceforge.phpdt.internal.ui.filters.CustomFiltersDialog;
29 import net.sourceforge.phpdt.internal.ui.filters.FilterDescriptor;
30 import net.sourceforge.phpdt.internal.ui.filters.FilterMessages;
31 import net.sourceforge.phpdt.internal.ui.filters.NamePatternFilter;
32 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
33
34 import org.eclipse.jface.action.Action;
35 import org.eclipse.jface.action.ContributionItem;
36 import org.eclipse.jface.action.GroupMarker;
37 import org.eclipse.jface.action.IContributionItem;
38 import org.eclipse.jface.action.IMenuListener;
39 import org.eclipse.jface.action.IMenuManager;
40 import org.eclipse.jface.action.IToolBarManager;
41 import org.eclipse.jface.action.Separator;
42 import org.eclipse.jface.preference.IPreferenceStore;
43 //incastrix
44 //import org.eclipse.jface.text.Assert;
45 import org.eclipse.core.runtime.Assert;
46 //import org.eclipse.jface.viewers.IContentProvider;
47 //import org.eclipse.jface.viewers.ITreeContentProvider;
48 import org.eclipse.jface.viewers.StructuredViewer;
49 import org.eclipse.jface.viewers.ViewerFilter;
50 import org.eclipse.jface.window.Window;
51 import org.eclipse.swt.SWT;
52 import org.eclipse.swt.events.SelectionAdapter;
53 import org.eclipse.swt.events.SelectionEvent;
54 import org.eclipse.swt.widgets.Menu;
55 import org.eclipse.swt.widgets.MenuItem;
56 import org.eclipse.ui.IActionBars;
57 import org.eclipse.ui.IMemento;
58 //import org.eclipse.ui.IViewPart;
59 import org.eclipse.ui.actions.ActionGroup;
60
61 /**
62  * Action group to add the filter action to a view part's tool bar menu.
63  * <p>
64  * This class may be instantiated; it is not intended to be subclassed.
65  * </p>
66  * 
67  * @since 2.0
68  */
69 public class CustomFiltersActionGroup extends ActionGroup {
70
71         class ShowFilterDialogAction extends Action {
72                 ShowFilterDialogAction() {
73                         setText(FilterMessages
74                                         .getString("OpenCustomFiltersDialogAction.text")); //$NON-NLS-1$
75                         setImageDescriptor(PHPUiImages.DESC_ELCL_FILTER);
76                         setDisabledImageDescriptor(PHPUiImages.DESC_DLCL_FILTER);
77                 }
78
79                 public void run() {
80                         openDialog();
81                 }
82         }
83
84         /**
85          * Menu contribution item which shows and lets check and uncheck filters.
86          * 
87          * @since 3.0
88          */
89         class FilterActionMenuContributionItem extends ContributionItem {
90
91                 private int fItemNumber;
92
93                 private boolean fState;
94
95                 private String fFilterId;
96
97                 private String fFilterName;
98
99                 private CustomFiltersActionGroup fActionGroup;
100
101                 /**
102                  * Constructor for FilterActionMenuContributionItem.
103                  * 
104                  * @param actionGroup
105                  *            the action group
106                  * @param filterId
107                  *            the id of the filter
108                  * @param filterName
109                  *            the name of the filter
110                  * @param state
111                  *            the initial state of the filter
112                  * @param itemNumber
113                  *            the menu item index
114                  */
115                 public FilterActionMenuContributionItem(
116                                 CustomFiltersActionGroup actionGroup, String filterId,
117                                 String filterName, boolean state, int itemNumber) {
118                         super(filterId);
119                         Assert.isNotNull(actionGroup);
120                         Assert.isNotNull(filterId);
121                         Assert.isNotNull(filterName);
122                         fActionGroup = actionGroup;
123                         fFilterId = filterId;
124                         fFilterName = filterName;
125                         fState = state;
126                         fItemNumber = itemNumber;
127                 }
128
129                 /*
130                  * Overrides method from ContributionItem.
131                  */
132                 public void fill(Menu menu, int index) {
133                         MenuItem mi = new MenuItem(menu, SWT.CHECK, index);
134                         mi.setText("&" + fItemNumber + " " + fFilterName); //$NON-NLS-1$  //$NON-NLS-2$
135                         /*
136                          * XXX: Don't set the image - would look bad because other menu
137                          * items don't provide image XXX: Get working set specific image
138                          * name from XML - would need to cache icons
139                          */
140                         // mi.setImage(JavaPluginImages.get(JavaPluginImages.IMG_OBJS_JAVA_WORKING_SET));
141                         mi.setSelection(fState);
142                         mi.addSelectionListener(new SelectionAdapter() {
143                                 public void widgetSelected(SelectionEvent e) {
144                                         fState = !fState;
145                                         fActionGroup.setFilter(fFilterId, fState);
146                                 }
147                         });
148                 }
149
150                 /*
151                  * @see org.eclipse.jface.action.IContributionItem#isDynamic()
152                  */
153                 public boolean isDynamic() {
154                         return true;
155                 }
156         }
157
158         private static final String TAG_CUSTOM_FILTERS = "customFilters"; //$NON-NLS-1$
159
160         private static final String TAG_USER_DEFINED_PATTERNS_ENABLED = "userDefinedPatternsEnabled"; //$NON-NLS-1$
161
162         private static final String TAG_USER_DEFINED_PATTERNS = "userDefinedPatterns"; //$NON-NLS-1$
163
164         private static final String TAG_XML_DEFINED_FILTERS = "xmlDefinedFilters"; //$NON-NLS-1$
165
166         private static final String TAG_LRU_FILTERS = "lastRecentlyUsedFilters"; //$NON-NLS-1$
167
168         private static final String TAG_CHILD = "child"; //$NON-NLS-1$
169
170         private static final String TAG_PATTERN = "pattern"; //$NON-NLS-1$
171
172         private static final String TAG_FILTER_ID = "filterId"; //$NON-NLS-1$
173
174         private static final String TAG_IS_ENABLED = "isEnabled"; //$NON-NLS-1$
175
176         private static final String SEPARATOR = ","; //$NON-NLS-1$
177
178         private static final int MAX_FILTER_MENU_ENTRIES = 3;
179
180         private static final String RECENT_FILTERS_GROUP_NAME = "recentFiltersGroup"; //$NON-NLS-1$
181
182         private StructuredViewer fViewer;
183
184         private NamePatternFilter fPatternFilter;
185
186         private Map fInstalledBuiltInFilters;
187
188         private Map fEnabledFilterIds;
189
190         private boolean fUserDefinedPatternsEnabled;
191
192         private String[] fUserDefinedPatterns;
193
194         /**
195          * Recently changed filter Ids stack with oldest on top (i.e. at the end).
196          * 
197          * @since 3.0
198          */
199         private Stack fLRUFilterIdsStack;
200
201         /**
202          * Handle to menu manager to dynamically update the last recently used
203          * filters.
204          * 
205          * @since 3.0
206          */
207         private IMenuManager fMenuManager;
208
209         /**
210          * The menu listener which dynamically updates the last recently used
211          * filters.
212          * 
213          * @since 3.0
214          */
215         private IMenuListener fMenuListener;
216
217         /**
218          * Filter Ids used in the last view menu invocation.
219          * 
220          * @since 3.0
221          */
222         private String[] fFilterIdsUsedInLastViewMenu;
223
224         private HashMap fFilterDescriptorMap;
225
226         private String fTargetId;
227
228         /**
229          * Creates a new <code>CustomFiltersActionGroup</code>.
230          * 
231          * @param part
232          *            the view part that owns this action group
233          * @param viewer
234          *            the viewer to be filtered
235          */
236 //      public CustomFiltersActionGroup(IViewPart part, StructuredViewer viewer) {
237 //              this(part.getViewSite().getId(), viewer);
238 //      }
239
240         /**
241          * Creates a new <code>CustomFiltersActionGroup</code>.
242          * 
243          * @param ownerId
244          *            the id of this action group's owner
245          * @param viewer
246          *            the viewer to be filtered
247          */
248         public CustomFiltersActionGroup(String ownerId, StructuredViewer viewer) {
249                 Assert.isNotNull(ownerId);
250                 Assert.isNotNull(viewer);
251                 fTargetId = ownerId;
252                 fViewer = viewer;
253
254                 fLRUFilterIdsStack = new Stack();
255
256                 initializeWithPluginContributions();
257                 initializeWithViewDefaults();
258
259                 installFilters();
260         }
261
262         /*
263          * Method declared on ActionGroup.
264          */
265         public void fillActionBars(IActionBars actionBars) {
266                 fillToolBar(actionBars.getToolBarManager());
267                 fillViewMenu(actionBars.getMenuManager());
268         }
269
270 //      public String[] removeFiltersFor(Object parent, Object element,
271 //                      IContentProvider contentProvider) {
272 //              String[] enabledFilters = getEnabledFilterIds();
273 //              Set newFilters = new HashSet();
274 //              for (int i = 0; i < enabledFilters.length; i++) {
275 //                      String filterName = enabledFilters[i];
276 //                      ViewerFilter filter = (ViewerFilter) fInstalledBuiltInFilters
277 //                                      .get(filterName);
278 //                      if (filter == null)
279 //                              newFilters.add(filterName);
280 //                      else if (isSelected(parent, element, contentProvider, filter))
281 //                              newFilters.add(filterName);
282 //              }
283 //              if (newFilters.size() == enabledFilters.length)
284 //                      return new String[0];
285 //              return (String[]) newFilters.toArray(new String[newFilters.size()]);
286 //      }
287
288         public void setFilters(String[] newFilters) {
289                 setEnabledFilterIds(newFilters);
290                 updateViewerFilters(true);
291         }
292
293 //      private boolean isSelected(Object parent, Object element,
294 //                      IContentProvider contentProvider, ViewerFilter filter) {
295 //              if (contentProvider instanceof ITreeContentProvider) {
296 //                      // the element and all its parents have to be selected
297 //                      ITreeContentProvider provider = (ITreeContentProvider) contentProvider;
298 //                      while (element != null && !(element instanceof IJavaModel)) {
299 //                              if (!filter.select(fViewer, parent, element))
300 //                                      return false;
301 //                              element = provider.getParent(element);
302 //                      }
303 //                      return true;
304 //              }
305 //              return filter.select(fViewer, parent, element);
306 //      }
307
308         /**
309          * Sets the enable state of the given filter.
310          * 
311          * @param filterId
312          *            the id of the filter
313          * @param state
314          *            the filter state
315          */
316         private void setFilter(String filterId, boolean state) {
317                 // Renew filter id in LRU stack
318                 fLRUFilterIdsStack.remove(filterId);
319                 fLRUFilterIdsStack.add(0, filterId);
320
321                 fEnabledFilterIds.put(filterId, new Boolean(state));
322                 storeViewDefaults();
323
324                 updateViewerFilters(true);
325         }
326
327         private String[] getEnabledFilterIds() {
328                 Set enabledFilterIds = new HashSet(fEnabledFilterIds.size());
329                 Iterator iter = fEnabledFilterIds.entrySet().iterator();
330                 while (iter.hasNext()) {
331                         Map.Entry entry = (Map.Entry) iter.next();
332                         String id = (String) entry.getKey();
333                         boolean isEnabled = ((Boolean) entry.getValue()).booleanValue();
334                         if (isEnabled)
335                                 enabledFilterIds.add(id);
336                 }
337                 return (String[]) enabledFilterIds.toArray(new String[enabledFilterIds
338                                 .size()]);
339         }
340
341         private void setEnabledFilterIds(String[] enabledIds) {
342                 Iterator iter = fEnabledFilterIds.keySet().iterator();
343                 while (iter.hasNext()) {
344                         String id = (String) iter.next();
345                         fEnabledFilterIds.put(id, Boolean.FALSE);
346                 }
347                 for (int i = 0; i < enabledIds.length; i++)
348                         fEnabledFilterIds.put(enabledIds[i], Boolean.TRUE);
349         }
350
351         private void setUserDefinedPatterns(String[] patterns) {
352                 fUserDefinedPatterns = patterns;
353                 cleanUpPatternDuplicates();
354         }
355
356         /**
357          * Sets the recently changed filters.
358          * 
359          * @param changeHistory
360          *            the change history
361          * @since 3.0
362          */
363         private void setRecentlyChangedFilters(Stack changeHistory) {
364                 Stack oldestFirstStack = new Stack();
365
366                 int length = Math.min(changeHistory.size(), MAX_FILTER_MENU_ENTRIES);
367                 for (int i = 0; i < length; i++)
368                         oldestFirstStack.push(((FilterDescriptor) changeHistory.pop())
369                                         .getId());
370
371                 length = Math.min(fLRUFilterIdsStack.size(), MAX_FILTER_MENU_ENTRIES
372                                 - oldestFirstStack.size());
373                 int NEWEST = 0;
374                 for (int i = 0; i < length; i++) {
375                         Object filter = fLRUFilterIdsStack.remove(NEWEST);
376                         if (!oldestFirstStack.contains(filter))
377                                 oldestFirstStack.push(filter);
378                 }
379                 fLRUFilterIdsStack = oldestFirstStack;
380         }
381
382         private boolean areUserDefinedPatternsEnabled() {
383                 return fUserDefinedPatternsEnabled;
384         }
385
386         private void setUserDefinedPatternsEnabled(boolean state) {
387                 fUserDefinedPatternsEnabled = state;
388         }
389
390         private void fillToolBar(IToolBarManager tooBar) {
391         }
392
393         /**
394          * Fills the given view menu with the entries managed by the group.
395          * 
396          * @param viewMenu
397          *            the menu to fill
398          */
399         public void fillViewMenu(IMenuManager viewMenu) {
400                 /*
401                  * Don't change the separator group name. Using this name ensures that
402                  * other filters get contributed to the same group.
403                  */
404                 viewMenu.add(new Separator("filters")); //$NON-NLS-1$
405                 viewMenu.add(new GroupMarker(RECENT_FILTERS_GROUP_NAME));
406                 viewMenu.add(new ShowFilterDialogAction());
407
408                 fMenuManager = viewMenu;
409                 fMenuListener = new IMenuListener() {
410                         public void menuAboutToShow(IMenuManager manager) {
411                                 removePreviousLRUFilterActions(manager);
412                                 addLRUFilterActions(manager);
413                         }
414                 };
415                 fMenuManager.addMenuListener(fMenuListener);
416         }
417
418         private void removePreviousLRUFilterActions(IMenuManager mm) {
419                 if (fFilterIdsUsedInLastViewMenu == null)
420                         return;
421
422                 for (int i = 0; i < fFilterIdsUsedInLastViewMenu.length; i++)
423                         mm.remove(fFilterIdsUsedInLastViewMenu[i]);
424         }
425
426         private void addLRUFilterActions(IMenuManager mm) {
427                 if (fLRUFilterIdsStack.isEmpty()) {
428                         fFilterIdsUsedInLastViewMenu = null;
429                         return;
430                 }
431
432                 SortedSet sortedFilters = new TreeSet(fLRUFilterIdsStack);
433                 String[] recentlyChangedFilterIds = (String[]) sortedFilters
434                                 .toArray(new String[sortedFilters.size()]);
435
436                 fFilterIdsUsedInLastViewMenu = new String[recentlyChangedFilterIds.length];
437                 for (int i = 0; i < recentlyChangedFilterIds.length; i++) {
438                         String id = recentlyChangedFilterIds[i];
439                         fFilterIdsUsedInLastViewMenu[i] = id;
440                         boolean state = fEnabledFilterIds.containsKey(id)
441                                         && ((Boolean) fEnabledFilterIds.get(id)).booleanValue();
442                         FilterDescriptor filterDesc = (FilterDescriptor) fFilterDescriptorMap
443                                         .get(id);
444                         if (filterDesc != null) {
445                                 IContributionItem item = new FilterActionMenuContributionItem(
446                                                 this, id, filterDesc.getName(), state, i + 1);
447                                 mm.insertBefore(RECENT_FILTERS_GROUP_NAME, item);
448                         }
449                 }
450         }
451
452         /*
453          * Method declared on ActionGroup.
454          */
455         public void dispose() {
456                 if (fMenuManager != null)
457                         fMenuManager.removeMenuListener(fMenuListener);
458                 super.dispose();
459         }
460
461         private void initializeWithPluginContributions() {
462                 fUserDefinedPatterns = new String[0];
463                 fUserDefinedPatternsEnabled = false;
464
465                 FilterDescriptor[] filterDescs = FilterDescriptor
466                                 .getFilterDescriptors(fTargetId);
467                 fFilterDescriptorMap = new HashMap(filterDescs.length);
468                 fEnabledFilterIds = new HashMap(filterDescs.length);
469                 for (int i = 0; i < filterDescs.length; i++) {
470                         String id = filterDescs[i].getId();
471                         Boolean isEnabled = new Boolean(filterDescs[i].isEnabled());
472                         if (fEnabledFilterIds.containsKey(id))
473                                 PHPeclipsePlugin
474                                                 .logErrorMessage("WARNING: Duplicate id for extension-point \"net.sourceforge.phpdt.ui.javaElementFilters\""); //$NON-NLS-1$
475                         fEnabledFilterIds.put(id, isEnabled);
476                         fFilterDescriptorMap.put(id, filterDescs[i]);
477                 }
478         }
479
480         // ---------- viewer filter handling ----------
481
482         private void installFilters() {
483                 fInstalledBuiltInFilters = new HashMap(fEnabledFilterIds.size());
484                 fPatternFilter = new NamePatternFilter();
485                 fPatternFilter.setPatterns(getUserAndBuiltInPatterns());
486                 fViewer.addFilter(fPatternFilter);
487                 updateBuiltInFilters();
488         }
489
490         private void updateViewerFilters(boolean refresh) {
491                 String[] patterns = getUserAndBuiltInPatterns();
492                 fPatternFilter.setPatterns(patterns);
493                 fViewer.getControl().setRedraw(false);
494                 updateBuiltInFilters();
495                 if (refresh)
496                         fViewer.refresh();
497                 fViewer.getControl().setRedraw(true);
498         }
499
500         private void updateBuiltInFilters() {
501                 Set installedFilters = fInstalledBuiltInFilters.keySet();
502                 Set filtersToAdd = new HashSet(fEnabledFilterIds.size());
503                 Set filtersToRemove = new HashSet(fEnabledFilterIds.size());
504                 Iterator iter = fEnabledFilterIds.entrySet().iterator();
505                 while (iter.hasNext()) {
506                         Map.Entry entry = (Map.Entry) iter.next();
507                         String id = (String) entry.getKey();
508                         boolean isEnabled = ((Boolean) entry.getValue()).booleanValue();
509                         if (isEnabled && !installedFilters.contains(id))
510                                 filtersToAdd.add(id);
511                         else if (!isEnabled && installedFilters.contains(id))
512                                 filtersToRemove.add(id);
513                 }
514
515                 // Install the filters
516                 FilterDescriptor[] filterDescs = FilterDescriptor
517                                 .getFilterDescriptors(fTargetId);
518                 for (int i = 0; i < filterDescs.length; i++) {
519                         String id = filterDescs[i].getId();
520                         // just to double check - id should denote a custom filter anyway
521                         boolean isCustomFilter = filterDescs[i].isCustomFilter();
522                         if (isCustomFilter) {
523                                 if (filtersToAdd.contains(id)) {
524                                         ViewerFilter filter = filterDescs[i].createViewerFilter();
525                                         if (filter != null) {
526                                                 fViewer.addFilter(filter);
527                                                 fInstalledBuiltInFilters.put(id, filter);
528                                         }
529                                 }
530                                 if (filtersToRemove.contains(id)) {
531                                         fViewer
532                                                         .removeFilter((ViewerFilter) fInstalledBuiltInFilters
533                                                                         .get(id));
534                                         fInstalledBuiltInFilters.remove(id);
535                                 }
536                         }
537                 }
538         }
539
540         private String[] getUserAndBuiltInPatterns() {
541                 List patterns = new ArrayList(fUserDefinedPatterns.length);
542                 if (areUserDefinedPatternsEnabled())
543                         patterns.addAll(Arrays.asList(fUserDefinedPatterns));
544                 FilterDescriptor[] filterDescs = FilterDescriptor
545                                 .getFilterDescriptors(fTargetId);
546                 for (int i = 0; i < filterDescs.length; i++) {
547                         String id = filterDescs[i].getId();
548                         boolean isPatternFilter = filterDescs[i].isPatternFilter();
549                         Object isEnabled = fEnabledFilterIds.get(id);
550                         if (isEnabled != null && isPatternFilter
551                                         && ((Boolean) isEnabled).booleanValue())
552                                 patterns.add(filterDescs[i].getPattern());
553                 }
554                 return (String[]) patterns.toArray(new String[patterns.size()]);
555         }
556
557         // ---------- view kind/defaults persistency ----------
558
559         private void initializeWithViewDefaults() {
560                 // get default values for view
561                 IPreferenceStore store = PHPeclipsePlugin.getDefault()
562                                 .getPreferenceStore();
563
564                 // XXX: can be removed once bug 22533 is fixed.
565                 if (!store.contains(getPreferenceKey("TAG_DUMMY_TO_TEST_EXISTENCE")))//$NON-NLS-1$
566                         return;
567
568                 // XXX: Uncomment once bug 22533 is fixed.
569                 // if
570                 // (!store.contains(getPreferenceKey(TAG_USER_DEFINED_PATTERNS_ENABLED)))
571                 // return;
572
573                 fUserDefinedPatternsEnabled = store
574                                 .getBoolean(getPreferenceKey(TAG_USER_DEFINED_PATTERNS_ENABLED));
575                 setUserDefinedPatterns(CustomFiltersDialog.convertFromString(store
576                                 .getString(getPreferenceKey(TAG_USER_DEFINED_PATTERNS)),
577                                 SEPARATOR));
578
579                 Iterator iter = fEnabledFilterIds.keySet().iterator();
580                 while (iter.hasNext()) {
581                         String id = (String) iter.next();
582                         Boolean isEnabled = new Boolean(store.getBoolean(id));
583                         fEnabledFilterIds.put(id, isEnabled);
584                 }
585
586                 fLRUFilterIdsStack.clear();
587                 String lruFilterIds = store.getString(TAG_LRU_FILTERS);
588                 StringTokenizer tokenizer = new StringTokenizer(lruFilterIds, SEPARATOR);
589                 while (tokenizer.hasMoreTokens()) {
590                         String id = tokenizer.nextToken();
591                         if (fFilterDescriptorMap.containsKey(id)
592                                         && !fLRUFilterIdsStack.contains(id))
593                                 fLRUFilterIdsStack.push(id);
594                 }
595         }
596
597         private void storeViewDefaults() {
598                 // get default values for view
599                 IPreferenceStore store = PHPeclipsePlugin.getDefault()
600                                 .getPreferenceStore();
601
602                 // XXX: can be removed once bug 22533 is fixed.
603                 store
604                                 .setValue(
605                                                 getPreferenceKey("TAG_DUMMY_TO_TEST_EXISTENCE"), "storedViewPreferences");//$NON-NLS-1$//$NON-NLS-2$
606
607                 store.setValue(getPreferenceKey(TAG_USER_DEFINED_PATTERNS_ENABLED),
608                                 fUserDefinedPatternsEnabled);
609                 store.setValue(getPreferenceKey(TAG_USER_DEFINED_PATTERNS),
610                                 CustomFiltersDialog.convertToString(fUserDefinedPatterns,
611                                                 SEPARATOR));
612
613                 Iterator iter = fEnabledFilterIds.entrySet().iterator();
614                 while (iter.hasNext()) {
615                         Map.Entry entry = (Map.Entry) iter.next();
616                         String id = (String) entry.getKey();
617                         boolean isEnabled = ((Boolean) entry.getValue()).booleanValue();
618                         store.setValue(id, isEnabled);
619                 }
620
621                 StringBuffer buf = new StringBuffer(fLRUFilterIdsStack.size() * 20);
622                 iter = fLRUFilterIdsStack.iterator();
623                 while (iter.hasNext()) {
624                         buf.append((String) iter.next());
625                         buf.append(SEPARATOR);
626                 }
627                 store.setValue(TAG_LRU_FILTERS, buf.toString());
628         }
629
630         private String getPreferenceKey(String tag) {
631                 return "CustomFiltersActionGroup." + fTargetId + '.' + tag; //$NON-NLS-1$
632         }
633
634         // ---------- view instance persistency ----------
635
636         /**
637          * Saves the state of the custom filters in a memento.
638          * 
639          * @param memento
640          *            the memento into which the state is saved
641          */
642         public void saveState(IMemento memento) {
643                 IMemento customFilters = memento.createChild(TAG_CUSTOM_FILTERS);
644                 customFilters.putString(TAG_USER_DEFINED_PATTERNS_ENABLED, new Boolean(
645                                 fUserDefinedPatternsEnabled).toString());
646                 saveUserDefinedPatterns(customFilters);
647                 saveXmlDefinedFilters(customFilters);
648                 saveLRUFilters(customFilters);
649         }
650
651         private void saveXmlDefinedFilters(IMemento memento) {
652                 if (fEnabledFilterIds != null && !fEnabledFilterIds.isEmpty()) {
653                         IMemento xmlDefinedFilters = memento
654                                         .createChild(TAG_XML_DEFINED_FILTERS);
655                         Iterator iter = fEnabledFilterIds.entrySet().iterator();
656                         while (iter.hasNext()) {
657                                 Map.Entry entry = (Map.Entry) iter.next();
658                                 String id = (String) entry.getKey();
659                                 Boolean isEnabled = (Boolean) entry.getValue();
660                                 IMemento child = xmlDefinedFilters.createChild(TAG_CHILD);
661                                 child.putString(TAG_FILTER_ID, id);
662                                 child.putString(TAG_IS_ENABLED, isEnabled.toString());
663                         }
664                 }
665         }
666
667         /**
668          * Stores the last recently used filter Ids into the given memento
669          * 
670          * @param memento
671          *            the memento into which to store the LRU filter Ids
672          * @since 3.0
673          */
674         private void saveLRUFilters(IMemento memento) {
675                 if (fLRUFilterIdsStack != null && !fLRUFilterIdsStack.isEmpty()) {
676                         IMemento lruFilters = memento.createChild(TAG_LRU_FILTERS);
677                         Iterator iter = fLRUFilterIdsStack.iterator();
678                         while (iter.hasNext()) {
679                                 String id = (String) iter.next();
680                                 IMemento child = lruFilters.createChild(TAG_CHILD);
681                                 child.putString(TAG_FILTER_ID, id);
682                         }
683                 }
684         }
685
686         private void saveUserDefinedPatterns(IMemento memento) {
687                 if (fUserDefinedPatterns != null && fUserDefinedPatterns.length > 0) {
688                         IMemento userDefinedPatterns = memento
689                                         .createChild(TAG_USER_DEFINED_PATTERNS);
690                         for (int i = 0; i < fUserDefinedPatterns.length; i++) {
691                                 IMemento child = userDefinedPatterns.createChild(TAG_CHILD);
692                                 child.putString(TAG_PATTERN, fUserDefinedPatterns[i]);
693                         }
694                 }
695         }
696
697         /**
698          * Restores the state of the filter actions from a memento.
699          * <p>
700          * Note: This method does not refresh the viewer.
701          * </p>
702          * 
703          * @param memento
704          *            the memento from which the state is restored
705          */
706         public void restoreState(IMemento memento) {
707                 if (memento == null)
708                         return;
709                 IMemento customFilters = memento.getChild(TAG_CUSTOM_FILTERS);
710                 if (customFilters == null)
711                         return;
712                 String userDefinedPatternsEnabled = customFilters
713                                 .getString(TAG_USER_DEFINED_PATTERNS_ENABLED);
714                 if (userDefinedPatternsEnabled == null)
715                         return;
716
717                 fUserDefinedPatternsEnabled = Boolean.valueOf(
718                                 userDefinedPatternsEnabled).booleanValue();
719                 restoreUserDefinedPatterns(customFilters);
720                 restoreXmlDefinedFilters(customFilters);
721                 restoreLRUFilters(customFilters);
722
723                 updateViewerFilters(false);
724         }
725
726         private void restoreUserDefinedPatterns(IMemento memento) {
727                 IMemento userDefinedPatterns = memento
728                                 .getChild(TAG_USER_DEFINED_PATTERNS);
729                 if (userDefinedPatterns != null) {
730                         IMemento children[] = userDefinedPatterns.getChildren(TAG_CHILD);
731                         String[] patterns = new String[children.length];
732                         for (int i = 0; i < children.length; i++)
733                                 patterns[i] = children[i].getString(TAG_PATTERN);
734
735                         setUserDefinedPatterns(patterns);
736                 } else
737                         setUserDefinedPatterns(new String[0]);
738         }
739
740         private void restoreXmlDefinedFilters(IMemento memento) {
741                 IMemento xmlDefinedFilters = memento.getChild(TAG_XML_DEFINED_FILTERS);
742                 if (xmlDefinedFilters != null) {
743                         IMemento[] children = xmlDefinedFilters.getChildren(TAG_CHILD);
744                         for (int i = 0; i < children.length; i++) {
745                                 String id = children[i].getString(TAG_FILTER_ID);
746                                 Boolean isEnabled = new Boolean(children[i]
747                                                 .getString(TAG_IS_ENABLED));
748                                 fEnabledFilterIds.put(id, isEnabled);
749                         }
750                 }
751         }
752
753         private void restoreLRUFilters(IMemento memento) {
754                 IMemento lruFilters = memento.getChild(TAG_LRU_FILTERS);
755                 fLRUFilterIdsStack.clear();
756                 if (lruFilters != null) {
757                         IMemento[] children = lruFilters.getChildren(TAG_CHILD);
758                         for (int i = 0; i < children.length; i++) {
759                                 String id = children[i].getString(TAG_FILTER_ID);
760                                 if (fFilterDescriptorMap.containsKey(id)
761                                                 && !fLRUFilterIdsStack.contains(id))
762                                         fLRUFilterIdsStack.push(id);
763                         }
764                 }
765         }
766
767         private void cleanUpPatternDuplicates() {
768                 if (!areUserDefinedPatternsEnabled())
769                         return;
770                 List userDefinedPatterns = new ArrayList(Arrays
771                                 .asList(fUserDefinedPatterns));
772                 FilterDescriptor[] filters = FilterDescriptor
773                                 .getFilterDescriptors(fTargetId);
774
775                 for (int i = 0; i < filters.length; i++) {
776                         if (filters[i].isPatternFilter()) {
777                                 String pattern = filters[i].getPattern();
778                                 if (userDefinedPatterns.contains(pattern)) {
779                                         fEnabledFilterIds.put(filters[i].getId(), Boolean.TRUE);
780                                         boolean hasMore = true;
781                                         while (hasMore)
782                                                 hasMore = userDefinedPatterns.remove(pattern);
783                                 }
784                         }
785                 }
786                 fUserDefinedPatterns = (String[]) userDefinedPatterns
787                                 .toArray(new String[userDefinedPatterns.size()]);
788                 setUserDefinedPatternsEnabled(fUserDefinedPatternsEnabled
789                                 && fUserDefinedPatterns.length > 0);
790         }
791
792         // ---------- dialog related code ----------
793
794         private void openDialog() {
795                 CustomFiltersDialog dialog = new CustomFiltersDialog(fViewer
796                                 .getControl().getShell(), fTargetId,
797                                 areUserDefinedPatternsEnabled(), fUserDefinedPatterns,
798                                 getEnabledFilterIds());
799
800                 if (dialog.open() == Window.OK) {
801                         setEnabledFilterIds(dialog.getEnabledFilterIds());
802                         setUserDefinedPatternsEnabled(dialog
803                                         .areUserDefinedPatternsEnabled());
804                         setUserDefinedPatterns(dialog.getUserDefinedPatterns());
805                         setRecentlyChangedFilters(dialog.getFilterDescriptorChangeHistory());
806
807                         storeViewDefaults();
808
809                         updateViewerFilters(true);
810                 }
811         }
812 }