KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > debug > internal > ui > views > variables > details > DetailPaneManager


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.debug.internal.ui.views.variables.details;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Collection JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.LinkedHashSet JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.Set JavaDoc;
22 import java.util.StringTokenizer JavaDoc;
23 import java.util.Map.Entry;
24
25 import org.eclipse.core.expressions.EvaluationContext;
26 import org.eclipse.core.expressions.EvaluationResult;
27 import org.eclipse.core.expressions.Expression;
28 import org.eclipse.core.expressions.ExpressionConverter;
29 import org.eclipse.core.expressions.ExpressionTagNames;
30 import org.eclipse.core.expressions.IEvaluationContext;
31 import org.eclipse.core.runtime.CoreException;
32 import org.eclipse.core.runtime.IConfigurationElement;
33 import org.eclipse.core.runtime.IExtensionPoint;
34 import org.eclipse.core.runtime.IStatus;
35 import org.eclipse.core.runtime.Platform;
36 import org.eclipse.core.runtime.Status;
37 import org.eclipse.debug.internal.core.IConfigurationElementConstants;
38 import org.eclipse.debug.internal.ui.DebugUIPlugin;
39 import org.eclipse.debug.ui.IDebugUIConstants;
40 import org.eclipse.debug.ui.IDetailPane;
41 import org.eclipse.debug.ui.IDetailPaneFactory;
42 import org.eclipse.jface.viewers.IStructuredSelection;
43
44 /**
45  * Organizes the detail factories contributed through the extension point and keeps
46  * track of the detail panes the factories produce. Accessed as a singleton through
47  * the <code>getDefault()</code> method.
48  *
49  * @see IDetailPaneFactory
50  * @see IDetailPane
51  * @since 3.3
52  */

53 public class DetailPaneManager {
54     
55     /**
56      * Acts as a proxy between the detail pane manager and the factories contributed
57      * to the extension point. Only loads information from the plug-in xml and only
58      * instantiates the specified factory if required (lazy loading).
59      */

60     private class DetailPaneFactoryExtension implements IDetailPaneFactory{
61
62         private IConfigurationElement fConfigElement;
63         private IDetailPaneFactory fFactory;
64         private Expression fEnablementExpression;
65         
66         public DetailPaneFactoryExtension(IConfigurationElement configElement){
67             fConfigElement = configElement;
68         }
69         
70         /**
71          * Instantiates the factory and asks it to produce the IDetailPane for
72          * the given ID
73          */

74         public IDetailPane createDetailPane(String JavaDoc paneID){
75             if (getFactory() != null){
76                 return getFactory().createDetailPane(paneID);
77             }
78             return null;
79         }
80
81         /**
82          * Instantiates the factory and asks it for the set of detail pane
83          * IDs that the factory can produce for the given selection.
84          */

85         public Set JavaDoc getDetailPaneTypes(IStructuredSelection selection){
86             if (getFactory() != null){
87                 return getFactory().getDetailPaneTypes(selection);
88             }
89             return new HashSet JavaDoc(0);
90         }
91         
92         /**
93          * Instantiates the factory and asks it for the detail pane ID
94          * that the factory considers the default for the given selection.
95          */

96         public String JavaDoc getDefaultDetailPane(IStructuredSelection selection) {
97             if (getFactory() != null){
98                 return getFactory().getDefaultDetailPane(selection);
99             }
100             return null;
101         }
102
103         /**
104          * Instantiates the factory and asks it to produce the name of the detail pane
105          * for the given ID.
106          */

107         public String JavaDoc getDetailPaneName(String JavaDoc paneID) {
108             if (getFactory() != null){
109                 return getFactory().getDetailPaneName(paneID);
110             }
111             return null;
112         }
113         
114         /**
115          * Instantiates the factory and asks it to produce the description of the
116          * detail pane for the given ID.
117          */

118         public String JavaDoc getDetailPaneDescription(String JavaDoc paneID) {
119             if (getFactory() != null){
120                 return getFactory().getDetailPaneDescription(paneID);
121             }
122             return null;
123         }
124         
125         /**
126          * Returns the instantiated factory specified by the class property.
127          */

128         private IDetailPaneFactory getFactory(){
129             if (fFactory != null) return fFactory;
130             try{
131                 Object JavaDoc obj = fConfigElement.createExecutableExtension(IConfigurationElementConstants.CLASS);
132                 if(obj instanceof IDetailPaneFactory) {
133                     fFactory = (IDetailPaneFactory)obj;
134                 } else {
135                     throw new CoreException(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.INTERNAL_ERROR, "org.eclipse.debug.ui.detailFactories extension failed to load a detail factory because the specified class does not implement org.eclipse.debug.ui.IDetailPaneFactory. Class specified was: " + obj, null)); //$NON-NLS-1$
136
}
137             } catch (CoreException e){
138                 DebugUIPlugin.log(e.getStatus());
139                 fFactory = null;
140             }
141             return fFactory;
142         }
143         
144         /**
145          * Checks if the enablement expression for the factory evaluates to true for the
146          * given selection.
147          */

148         public boolean isEnabled(IStructuredSelection selection) {
149             boolean enabled = false;
150             // Only the default factory should be enabled for null selections
151
if (selection == null || selection.isEmpty()){
152                 return "org.eclipse.debug.ui.defaultDetailPaneFactory".equals(fConfigElement.getAttribute(IConfigurationElementConstants.ID)); //$NON-NLS-1$
153
}
154             Expression expression = getEnablementExpression();
155             if (expression != null) {
156                 List JavaDoc list = selection.toList();
157                 IEvaluationContext context = new EvaluationContext(null, list);
158                 context.addVariable("selection", list); //$NON-NLS-1$
159
enabled = evalEnablementExpression(context, expression);
160             } else {
161                 enabled = true;
162             }
163             return enabled;
164         }
165         
166         /**
167          * Evaluate the given expression within the given context and return
168          * the result. Returns <code>true</code> iff result is either TRUE or NOT_LOADED.
169          * This allows optimistic inclusion of shortcuts before plug-ins are loaded.
170          * Returns <code>false</code> if expression is <code>null</code>.
171          *
172          * @param exp the enablement expression to evaluate or <code>null</code>
173          * @param context the context of the evaluation. Usually, the
174          * user's selection.
175          * @return the result of evaluating the expression
176          */

177         private boolean evalEnablementExpression(IEvaluationContext context, Expression exp) {
178             try{
179                 if (exp != null){
180                     EvaluationResult result = exp.evaluate(context);
181                     if (result == EvaluationResult.TRUE || result == EvaluationResult.NOT_LOADED){
182                         return true;
183                     }
184                 }
185             } catch (CoreException e){
186                 DebugUIPlugin.log(e.getStatus());
187             }
188             return false;
189         }
190         
191         /**
192          * Returns an expression that represents the enablement logic for the
193          * detail pane factory or <code>null</code> if none.
194          *
195          * @return an evaluatable expression or <code>null</code>
196          */

197         private Expression getEnablementExpression(){
198             // all of this stuff is optional, so...tedious testing is required
199
if (fEnablementExpression == null) {
200                 try{
201                     IConfigurationElement[] elements = fConfigElement.getChildren(ExpressionTagNames.ENABLEMENT);
202                     IConfigurationElement enablement = elements.length > 0 ? elements[0] : null;
203                     if (enablement != null) {
204                         fEnablementExpression = ExpressionConverter.getDefault().perform(enablement);
205                     }
206                 } catch (CoreException e){
207                     DebugUIPlugin.log(e.getStatus());
208                     fEnablementExpression = null;
209                 }
210             }
211             return fEnablementExpression;
212         }
213     
214     }
215     
216     /**
217      * There should only ever be once instance of this manager for the workbench.
218      */

219     private static DetailPaneManager fgSingleton;
220     
221     /**
222      * Maps the IDs of types of detail panes to the factory that can create them.
223      * There can currently only be one factory for a given type of details pane.
224      */

225     private Map JavaDoc fFactoriesByPaneID;
226     
227     /**
228      * Maps a Set of detail pane id's to the one detail pane id that is preferred.
229      */

230     private Map JavaDoc fPreferredDetailPanes;
231     
232     /**
233      * The set of all factories that have been loaded from the extension point.
234      */

235     private Collection JavaDoc fKnownFactories;
236     
237     /**
238      * Preference key for storing the preferred detail panes map.
239      * @see {@link #storePreferredDetailsAreas()}
240      * @see {@link #loadPreferredDetailsAreas()}
241      */

242     public static final String JavaDoc PREF_DETAIL_AREAS = "preferredDetailPanes"; //$NON-NLS-1$
243

244     private DetailPaneManager(){
245         fFactoriesByPaneID = new HashMap JavaDoc();
246     }
247     
248     public static DetailPaneManager getDefault(){
249         if (fgSingleton == null) fgSingleton = new DetailPaneManager();
250         return fgSingleton;
251     }
252
253     /**
254      * Returns the ID of the preferred detail pane for the given selection.
255      *
256      * @param selection The selection to display in the detail pane
257      * @return The ID of the preferred detail pane or null
258      */

259     public String JavaDoc getPreferredPaneFromSelection(IStructuredSelection selection){
260         Collection JavaDoc possibleFactories = getEnabledFactories(selection);
261         Set JavaDoc possiblePaneIDs = getPossiblePaneIDs(possibleFactories, selection);
262         return chooseDetailsAreaIDInSet(possiblePaneIDs, possibleFactories, selection);
263     }
264     
265     /**
266      * Returns the set of all possible detail panes the can display the given
267      * selection.
268      *
269      * @param selection The selection to display in the detail pane
270      * @return The set of IDs of all possible detail panes for the given selection
271      */

272     public Set JavaDoc getAvailablePaneIDs(IStructuredSelection selection){
273         Collection JavaDoc possibleFactories = getEnabledFactories(selection);
274         return getPossiblePaneIDs(possibleFactories, selection);
275     }
276     
277     /**
278      * Given the ID of a details pane, this method will try to find the factory
279      * that creates it and return an instantiation of that area.
280      * <p>
281      * This method will not call the init() method of the IDetailsPane.
282      * </p>
283      *
284      * @param ID The ID of the requested pane
285      * @return The instantiated pane or null
286      */

287     public IDetailPane getDetailPaneFromID(String JavaDoc ID){
288         IDetailPaneFactory factory = (IDetailPaneFactory)fFactoriesByPaneID.get(ID);
289         if (factory != null){
290             return factory.createDetailPane(ID);
291         }
292         return null;
293     }
294     
295     /**
296      * Given the ID of a details pane, this method will try to find the factory
297      * that creates it and ask it for the name of the details pane.
298      *
299      * @param ID The ID of the requested pane
300      * @return The name of the details pane or null
301      */

302     public String JavaDoc getNameFromID(String JavaDoc ID){
303         IDetailPaneFactory factory = (IDetailPaneFactory)fFactoriesByPaneID.get(ID);
304         if (factory != null){
305             return factory.getDetailPaneName(ID);
306         }
307         return null;
308     }
309     
310     /**
311      * Given the ID of a details pane, this method will try to find the factory
312      * that creates it and ask it for the description of the details pane.
313      *
314      * @param ID The ID of the requested pane
315      * @return The description of the details pane or null
316      */

317     public String JavaDoc getDescriptionFromID(String JavaDoc ID){
318         IDetailPaneFactory factory = (IDetailPaneFactory)fFactoriesByPaneID.get(ID);
319         if (factory != null){
320             return factory.getDetailPaneDescription(ID);
321         }
322         return null;
323     }
324     
325     
326     /**
327      * Returns the set of IDetailPaneFactories (they will be DetailPaneFactoryDelegates) that were
328      * contributed to the extension point and are enabled for the given selection
329      * (enabled if the factory does not have an enablement expression or if the
330      * enablement expression evaluates to true).
331      *
332      * @return The factories enabled for the selection or an empty collection.
333      */

334     private Collection JavaDoc getEnabledFactories(IStructuredSelection selection){
335         Collection JavaDoc factoriesForSelection = new ArrayList JavaDoc();
336         if (fKnownFactories == null) initializeDetailFactories();
337         Iterator JavaDoc iter = fKnownFactories.iterator();
338         while (iter.hasNext()) {
339             IDetailPaneFactory currentFactory = (IDetailPaneFactory) iter.next();
340             if (currentFactory instanceof DetailPaneFactoryExtension){
341                 if (((DetailPaneFactoryExtension)currentFactory).isEnabled(selection)){
342                     factoriesForSelection.add(currentFactory);
343                 }
344             }
345         }
346         return factoriesForSelection;
347     }
348     
349     /**
350      * Produces the set of IDs for all possible detail panes that can be used to display
351      * the given selection.
352      *
353      * @param factoriesToQuery The collection of factories to check
354      * @param selection The selection to be displayed
355      * @return Set of pane IDs or an empty set
356      */

357     private Set JavaDoc getPossiblePaneIDs(Collection JavaDoc factoriesToQuery, IStructuredSelection selection){
358         Set JavaDoc idsForSelection = new LinkedHashSet JavaDoc();
359         Iterator JavaDoc factoryIter = factoriesToQuery.iterator();
360         while (factoryIter.hasNext()) {
361             IDetailPaneFactory currentFactory = (IDetailPaneFactory) factoryIter.next();
362             Iterator JavaDoc detailAreaTypes = currentFactory.getDetailPaneTypes(selection).iterator();
363             while (detailAreaTypes.hasNext()) {
364                 String JavaDoc currentAreaTypeID = (String JavaDoc) detailAreaTypes.next();
365                 fFactoriesByPaneID.put(currentAreaTypeID, currentFactory);
366                 idsForSelection.add(currentAreaTypeID);
367             }
368         }
369         return idsForSelection;
370     }
371
372     /**
373      * Given a set of possible detail pane IDs, this method will determine which pane is
374      * preferred and should be used to display the selection. This method chooses a pane
375      * by storing previous choices and can be set using a context menu.
376      *
377      * @param possiblePaneIDs The set of possible detail pane IDs
378      * @return The preferred detail pane ID or null
379      */

380     private String JavaDoc chooseDetailsAreaIDInSet(Set JavaDoc possiblePaneIDs, Collection JavaDoc enabledFactories, IStructuredSelection selection){
381         if (possiblePaneIDs == null || possiblePaneIDs.isEmpty()){
382             return null;
383         }
384         
385         String JavaDoc preferredID = getUserPreferredDetailPane(possiblePaneIDs);
386         
387         if (preferredID == null){
388             // If there is no preferred pane already set, check the factories to see there is a default pane
389
Iterator JavaDoc factoryIterator = enabledFactories.iterator();
390             while (preferredID == null && factoryIterator.hasNext()) {
391                 IDetailPaneFactory currentFactory = (IDetailPaneFactory) factoryIterator.next();
392                 preferredID = currentFactory.getDefaultDetailPane(selection);
393             }
394             // If the factories don't have a default, try to choose the DefaultDetailPane
395
if (preferredID == null){
396                 Iterator JavaDoc paneIterator = possiblePaneIDs.iterator();
397                 // If the DefaultDetailPane is not in the set, just use the first in the set
398
preferredID = (String JavaDoc)paneIterator.next();
399                 while (paneIterator.hasNext() && preferredID != DefaultDetailPaneFactory.DEFAULT_DETAIL_PANE_ID) {
400                     String JavaDoc currentID = (String JavaDoc) paneIterator.next();
401                     if (currentID.equals(DefaultDetailPaneFactory.DEFAULT_DETAIL_PANE_ID)){
402                         preferredID = currentID;
403                     }
404                 }
405             }
406             setPreferredDetailPane(possiblePaneIDs, preferredID);
407         }
408
409         return preferredID;
410     }
411     
412     /**
413      * Initializes the collection of known factories from extension point contributions.
414      */

415     private synchronized void initializeDetailFactories(){
416         if (fKnownFactories == null){
417             fKnownFactories = new ArrayList JavaDoc();
418             IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.EXTENSION_POINT_DETAIL_FACTORIES);
419             IConfigurationElement[] infos = extensionPoint.getConfigurationElements();
420             DetailPaneFactoryExtension delegate = null;
421             for(int i = 0; i < infos.length; i++) {
422                 delegate = new DetailPaneFactoryExtension(infos[i]);
423                 fKnownFactories.add(delegate);
424             }
425         }
426     }
427     
428     /**
429      * Returns the preferred pane ID from the given set if the mapping has been set.
430      *
431      * @param possibleDetailsAreaIDs Set of possible pane IDs
432      * @return The preferred ID or null
433      */

434     public String JavaDoc getUserPreferredDetailPane(Set JavaDoc possibleDetailsAreaIDs){
435         if (fPreferredDetailPanes == null){
436             loadPreferredDetailsAreas();
437         }
438         return (String JavaDoc)fPreferredDetailPanes.get(possibleDetailsAreaIDs);
439         
440     }
441     
442     /**
443      * Adds or updates the mapping to set which pane ID is preferred for a certain
444      * set of possible IDs.
445      *
446      * @param possibleDetailsAreaIDs The set of possible IDs
447      * @param preferredDetailsAreaID The preferred ID in the set.
448      */

449     public void setPreferredDetailPane(Set JavaDoc possibleDetailsAreaIDs, String JavaDoc preferredDetailsAreaID){
450         if (possibleDetailsAreaIDs == null) return;
451         if (fPreferredDetailPanes == null){
452             loadPreferredDetailsAreas();
453         }
454         String JavaDoc currentKey = (String JavaDoc)fPreferredDetailPanes.get(possibleDetailsAreaIDs);
455         if (currentKey == null || !currentKey.equals(preferredDetailsAreaID)){
456             fPreferredDetailPanes.put(possibleDetailsAreaIDs, preferredDetailsAreaID);
457             storePreferredDetailsAreas();
458         }
459         
460     }
461     
462     /**
463      * Stores the map of preferred detail pane IDs to the preference store in the format:
464      *
465      * Key1A,Key1B:Value1|Key2A,Key2B,Key2C:Value2|
466      *
467      * Where the sub keys (Key1A, Key1B, etc.) are the elements of the set used at the
468      * key in the mapping and the values are the associated String value in the mapping.
469      */

470     private void storePreferredDetailsAreas() {
471         StringBuffer JavaDoc buffer= new StringBuffer JavaDoc();
472         Iterator JavaDoc iter = fPreferredDetailPanes.entrySet().iterator();
473         while (iter.hasNext()) {
474             Entry entry = (Entry) iter.next();
475             Iterator JavaDoc setIter = ((Set JavaDoc)entry.getKey()).iterator();
476             while (setIter.hasNext()) {
477                 String JavaDoc currentID = (String JavaDoc) setIter.next();
478                 buffer.append(currentID);
479                 buffer.append(',');
480             }
481             buffer.deleteCharAt(buffer.length()-1);
482             buffer.append(':');
483             buffer.append(entry.getValue());
484             buffer.append('|');
485         }
486         DebugUIPlugin.getDefault().getPluginPreferences().setValue(PREF_DETAIL_AREAS, buffer.toString());
487     }
488     
489     /**
490      * Loads the map of preferred detail pane IDs from the preference store.
491      *
492      * @see DetailPaneManager#storePreferredDetailsArea()
493      */

494     private void loadPreferredDetailsAreas() {
495         fPreferredDetailPanes = new HashMap JavaDoc();
496         String JavaDoc preferenceValue = DebugUIPlugin.getDefault().getPluginPreferences().getString(PREF_DETAIL_AREAS);
497         StringTokenizer JavaDoc entryTokenizer = new StringTokenizer JavaDoc(preferenceValue,"|"); //$NON-NLS-1$
498
while (entryTokenizer.hasMoreTokens()){
499             String JavaDoc token = entryTokenizer.nextToken();
500             int valueStart = token.indexOf(':');
501             StringTokenizer JavaDoc keyTokenizer = new StringTokenizer JavaDoc(token.substring(0,valueStart),","); //$NON-NLS-1$
502
Set JavaDoc keys = new LinkedHashSet JavaDoc();
503             while (keyTokenizer.hasMoreTokens()){
504                 keys.add(keyTokenizer.nextToken());
505             }
506             fPreferredDetailPanes.put(keys, token.substring(valueStart+1));
507         }
508     }
509
510 }
511
Popular Tags