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