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