KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > ide > ChooseWorkspaceData


1 /*******************************************************************************
2  * Copyright (c) 2004, 2006 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.ui.internal.ide;
12
13 import java.io.File JavaDoc;
14 import java.io.FileReader JavaDoc;
15 import java.io.IOException JavaDoc;
16 import java.io.Reader JavaDoc;
17 import java.net.URL JavaDoc;
18 import java.util.StringTokenizer JavaDoc;
19
20 import org.eclipse.core.runtime.Path;
21 import org.eclipse.core.runtime.Platform;
22 import org.eclipse.core.runtime.preferences.ConfigurationScope;
23 import org.eclipse.jface.preference.IPreferenceStore;
24 import org.eclipse.osgi.service.datalocation.Location;
25 import org.eclipse.ui.IMemento;
26 import org.eclipse.ui.WorkbenchException;
27 import org.eclipse.ui.XMLMemento;
28 import org.eclipse.ui.ide.IDE;
29 import org.eclipse.ui.preferences.ScopedPreferenceStore;
30 import org.osgi.service.prefs.BackingStoreException;
31 import org.osgi.service.prefs.Preferences;
32
33 /**
34  * This class stores the information behind the "Launch Workspace" dialog. The
35  * class is able to read and write itself to a well known configuration file.
36  */

37 public class ChooseWorkspaceData {
38     /**
39      * The default max length of the recent workspace mru list.
40      */

41     private static final int RECENT_MAX_LENGTH = 5;
42
43     /**
44      * The directory within the config area that will be used for the
45      * receiver's persisted data.
46      */

47     private static final String JavaDoc PERS_FOLDER = "org.eclipse.ui.ide"; //$NON-NLS-1$
48

49     /**
50      * The name of the file within the config area that will be used for
51      * the recever's persisted data.
52      * @see PERS_FOLDER
53      */

54     private static final String JavaDoc PERS_FILENAME = "recentWorkspaces.xml"; //$NON-NLS-1$
55

56     /**
57      * In the past a file was used to store persist these values. This file was written
58      * with this value as its protocol identifier.
59      */

60     private static final int PERS_ENCODING_VERSION = 1;
61
62     /**
63      * This is the first version of the encode/decode protocol that uses the config area
64      * preference store for persistence. The only encoding done is to convert the recent
65      * workspace list into a comma-separated list.
66      */

67     private static final int PERS_ENCODING_VERSION_CONFIG_PREFS = 2;
68     
69     /**
70      * This is the second version of the encode/decode protocol that uses the
71      * confi area preferences store for persistence. This version is the same as
72      * the previous version except it uses a \n character to seperate the path
73      * entries instead of commas. (see bug 98467)
74      *
75      * @since 3.3.1
76      */

77     private static final int PERS_ENCODING_VERSION_CONFIG_PREFS_NO_COMMAS = 3;
78
79     private boolean showDialog = true;
80
81     private String JavaDoc initialDefault;
82
83     private String JavaDoc selection;
84
85     private String JavaDoc[] recentWorkspaces;
86
87     // xml tags
88
private static interface XML {
89         public static final String JavaDoc PROTOCOL = "protocol"; //$NON-NLS-1$
90

91         public static final String JavaDoc VERSION = "version"; //$NON-NLS-1$
92

93         public static final String JavaDoc ALWAYS_ASK = "alwaysAsk"; //$NON-NLS-1$
94

95         public static final String JavaDoc SHOW_DIALOG = "showDialog"; //$NON-NLS-1$
96

97         public static final String JavaDoc WORKSPACE = "workspace"; //$NON-NLS-1$
98

99         public static final String JavaDoc RECENT_WORKSPACES = "recentWorkspaces"; //$NON-NLS-1$
100

101         public static final String JavaDoc MAX_LENGTH = "maxLength"; //$NON-NLS-1$
102

103         public static final String JavaDoc PATH = "path"; //$NON-NLS-1$
104
}
105
106     /**
107      * Creates a new instance, loading persistent data if its found.
108      */

109     public ChooseWorkspaceData(String JavaDoc initialDefault) {
110         readPersistedData();
111         setInitialDefault(initialDefault);
112     }
113
114     /**
115      * Creates a new instance, loading persistent data if its found.
116      */

117     public ChooseWorkspaceData(URL JavaDoc instanceUrl) {
118         readPersistedData();
119         if (instanceUrl != null) {
120             setInitialDefault(new File JavaDoc(instanceUrl.getFile()).toString());
121         }
122     }
123
124     /**
125      * Return the folder to be used as a default if no other information
126      * exists. Does not return null.
127      */

128     public String JavaDoc getInitialDefault() {
129         if (initialDefault == null) {
130             setInitialDefault(System.getProperty("user.dir") //$NON-NLS-1$
131
+ File.separator + "workspace"); //$NON-NLS-1$
132
}
133         return initialDefault;
134     }
135
136     /**
137      * Set this data's initialDefault parameter to a properly formatted version
138      * of the argument directory string. The proper format is to the platform
139      * appropriate separator character without meaningless leading or trailing
140      * separator characters.
141      */

142     private void setInitialDefault(String JavaDoc dir) {
143         if (dir == null || dir.length() <= 0) {
144             initialDefault = null;
145             return;
146         }
147
148         dir = new Path(dir).toOSString();
149         while (dir.charAt(dir.length() - 1) == File.separatorChar) {
150             dir = dir.substring(0, dir.length() - 1);
151         }
152         initialDefault = dir;
153     }
154
155     /**
156      * Return the currently selected workspace or null if nothing is selected.
157      */

158     public String JavaDoc getSelection() {
159         return selection;
160     }
161
162     /**
163      * Return the currently selected workspace or null if nothing is selected.
164      */

165     public boolean getShowDialog() {
166         return showDialog;
167     }
168
169     /**
170      * Return an array of recent workspaces sorted with the most recently used at
171      * the start.
172      */

173     public String JavaDoc[] getRecentWorkspaces() {
174         return recentWorkspaces;
175     }
176
177     /**
178      * The argument workspace has been selected, update the receiver. Does not
179      * persist the new values.
180      */

181     public void workspaceSelected(String JavaDoc dir) {
182         // this just stores the selection, it is not inserted and persisted
183
// until the workspace is actually selected
184
selection = dir;
185     }
186
187     /**
188      * Toggle value of the showDialog persistent setting.
189      */

190     public void toggleShowDialog() {
191         showDialog = !showDialog;
192     }
193
194     /**
195      * Update the persistent store. Call this function after the currently
196      * selected value has been found to be ok.
197      */

198     public void writePersistedData() {
199         // 1. get config pref node
200
Preferences node = new ConfigurationScope().getNode(IDEWorkbenchPlugin.IDE_WORKBENCH);
201
202         // 2. get value for showDialog
203
node.putBoolean(
204                 IDE.Preferences.SHOW_WORKSPACE_SELECTION_DIALOG,
205                 showDialog);
206
207         // 3. use value of numRecent to create proper length array
208
node.putInt(IDE.Preferences.MAX_RECENT_WORKSPACES,
209                 recentWorkspaces.length);
210
211         // move the new selection to the front of the list
212
if (selection != null) {
213             String JavaDoc oldEntry = recentWorkspaces[0];
214             recentWorkspaces[0] = selection;
215             for (int i = 1; i < recentWorkspaces.length && oldEntry != null; ++i) {
216                 if (selection.equals(oldEntry)) {
217                     break;
218                 }
219                 String JavaDoc tmp = recentWorkspaces[i];
220                 recentWorkspaces[i] = oldEntry;
221                 oldEntry = tmp;
222             }
223         }
224
225         // 4. store values of recent workspaces into array
226
String JavaDoc encodedRecentWorkspaces = encodeStoredWorkspacePaths(recentWorkspaces);
227         node.put(IDE.Preferences.RECENT_WORKSPACES,
228                 encodedRecentWorkspaces);
229
230         // 5. store the protocol version used to encode the list
231
node.putInt(IDE.Preferences.RECENT_WORKSPACES_PROTOCOL,
232                 PERS_ENCODING_VERSION_CONFIG_PREFS_NO_COMMAS);
233
234         // 6. store the node
235
try {
236             node.flush();
237         } catch (BackingStoreException e) {
238             // do nothing
239
}
240     }
241
242     /**
243      * Look for and read data that might have been persisted from some previous
244      * run. Leave the receiver in a default state if no persistent data is
245      * found.
246      *
247      * @return true if a file was successfully read and false otherwise
248      */

249     private boolean readPersistedData_file() {
250         URL JavaDoc persUrl = null;
251
252         Location configLoc = Platform.getConfigurationLocation();
253         if (configLoc != null) {
254             persUrl = getPersistenceUrl(configLoc.getURL(), false);
255         }
256
257         try {
258             // inside try to get the safe default creation in the finally
259
// clause
260
if (persUrl == null) {
261                 return false;
262             }
263
264             // E.g.,
265
// <launchWorkspaceData>
266
// <protocol version="1"/>
267
// <alwaysAsk showDialog="1"/>
268
// <recentWorkspaces maxLength="5">
269
// <workspace path="C:\eclipse\workspace0"/>
270
// <workspace path="C:\eclipse\workspace1"/>
271
// </recentWorkspaces>
272
// </launchWorkspaceData>
273

274             Reader JavaDoc reader = new FileReader JavaDoc(persUrl.getFile());
275             XMLMemento memento = XMLMemento.createReadRoot(reader);
276             if (memento == null || !compatibleFileProtocol(memento)) {
277                 return false;
278             }
279
280             IMemento alwaysAskTag = memento.getChild(XML.ALWAYS_ASK);
281             showDialog = alwaysAskTag == null ? true : alwaysAskTag.getInteger(
282                     XML.SHOW_DIALOG).intValue() == 1;
283
284             IMemento recent = memento.getChild(XML.RECENT_WORKSPACES);
285             if (recent == null) {
286                 return false;
287             }
288
289             Integer JavaDoc maxLength = recent.getInteger(XML.MAX_LENGTH);
290             int max = RECENT_MAX_LENGTH;
291             if (maxLength != null) {
292                 max = maxLength.intValue();
293             }
294
295             IMemento indices[] = recent.getChildren(XML.WORKSPACE);
296             if (indices == null || indices.length <= 0) {
297                 return false;
298             }
299
300             // if a user has edited maxLength to be shorter than the listed
301
// indices, accept the list (its tougher for them to retype a long
302
// list of paths than to update a max number)
303
max = Math.max(max, indices.length);
304
305             recentWorkspaces = new String JavaDoc[max];
306             for (int i = 0; i < indices.length; ++i) {
307                 String JavaDoc path = indices[i].getString(XML.PATH);
308                 if (path == null) {
309                     break;
310                 }
311                 recentWorkspaces[i] = path;
312             }
313         } catch (IOException JavaDoc e) {
314             // cannot log because instance area has not been set
315
return false;
316         } catch (WorkbenchException e) {
317             // cannot log because instance area has not been set
318
return false;
319         } finally {
320             // create safe default if needed
321
if (recentWorkspaces == null) {
322                 recentWorkspaces = new String JavaDoc[RECENT_MAX_LENGTH];
323             }
324         }
325
326         return true;
327     }
328
329     /**
330      * Return the current (persisted) value of the "showDialog on startup"
331      * preference. Return the global default if the file cannot be accessed.
332      */

333     public static boolean getShowDialogValue() {
334         // TODO See the long comment in #readPersistedData -- when the
335
// transition time is over this method can be changed to
336
// read the preference directly.
337

338         ChooseWorkspaceData data = new ChooseWorkspaceData(""); //$NON-NLS-1$
339

340         // return either the value in the file or true, which is the global
341
// default
342
return data.readPersistedData() ? data.showDialog : true;
343     }
344
345     /**
346      * Return the current (persisted) value of the "showDialog on startup"
347      * preference. Return the global default if the file cannot be accessed.
348      */

349     public static void setShowDialogValue(boolean showDialog) {
350         // TODO See the long comment in #readPersistedData -- when the
351
// transition time is over this method can be changed to
352
// read the preference directly.
353

354         ChooseWorkspaceData data = new ChooseWorkspaceData(""); //$NON-NLS-1$
355

356         // update the value and write the new settings
357
data.showDialog = showDialog;
358         data.writePersistedData();
359     }
360
361     /**
362      * Look in the config area preference store for the list of recently used
363      * workspaces.
364      *
365      * NOTE: During the transition phase the file will be checked if no config
366      * preferences are found.
367      *
368      * @return true if the values were successfully retrieved and false
369      * otherwise
370      */

371     public boolean readPersistedData() {
372         IPreferenceStore store = new ScopedPreferenceStore(
373                 new ConfigurationScope(), IDEWorkbenchPlugin.IDE_WORKBENCH);
374
375         // The old way was to store this information in a file, the new is to
376
// use the configuration area preference store. To help users with the
377
// transition, this code always looks for values in the preference
378
// store; they are used if found. If there aren't any related
379
// preferences, then the file method is used instead. This class always
380
// writes to the preference store, so the fall-back should be needed no
381
// more than once per-user, per-configuration.
382

383         // This code always sets the value of the protocol to a non-zero value
384
// (currently at 2). If the value comes back as the default (0), then
385
// none of the preferences were set, revert to the file method.
386

387         int protocol = store
388                 .getInt(IDE.Preferences.RECENT_WORKSPACES_PROTOCOL);
389         if (protocol == IPreferenceStore.INT_DEFAULT_DEFAULT
390                 && readPersistedData_file()) {
391             return true;
392         }
393
394         // 2. get value for showDialog
395
showDialog = store
396                 .getBoolean(IDE.Preferences.SHOW_WORKSPACE_SELECTION_DIALOG);
397
398         // 3. use value of numRecent to create proper length array
399
int max = store
400                 .getInt(IDE.Preferences.MAX_RECENT_WORKSPACES);
401         max = Math.max(max, RECENT_MAX_LENGTH);
402
403         // 4. load values of recent workspaces into array
404
String JavaDoc workspacePathPref = store
405                 .getString(IDE.Preferences.RECENT_WORKSPACES);
406         recentWorkspaces = decodeStoredWorkspacePaths(protocol, max, workspacePathPref);
407
408         return true;
409     }
410
411     /**
412      * The the list of recent workspaces must be stored as a string in the preference node.
413      */

414     private static String JavaDoc encodeStoredWorkspacePaths(String JavaDoc[] recent) {
415         StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
416
417         String JavaDoc path = null;
418         for (int i = 0; i < recent.length; ++i) {
419             if (recent[i] == null) {
420                 break;
421             }
422
423             // as of 3.3.1 pump this out using newlines instead of commas
424
if (path != null) {
425                 buff.append("\n"); //$NON-NLS-1$
426
}
427
428             path = recent[i];
429             buff.append(path);
430         }
431
432         return buff.toString();
433     }
434
435     /**
436      * The the preference for recent workspaces must be converted from the
437      * storage string into an array.
438      */

439     private static String JavaDoc[] decodeStoredWorkspacePaths(int protocol, int max,
440             String JavaDoc prefValue) {
441         String JavaDoc[] paths = new String JavaDoc[max];
442         if (prefValue == null || prefValue.length() <= 0) {
443             return paths;
444         }
445
446         // if we're using the latest version of the protocol use the newline as a
447
// token. Otherwise use the older comma.
448
String JavaDoc tokens = null;
449         switch (protocol) {
450             case PERS_ENCODING_VERSION_CONFIG_PREFS_NO_COMMAS :
451                 tokens = "\n"; //$NON-NLS-1$
452
break;
453             case PERS_ENCODING_VERSION_CONFIG_PREFS :
454                 tokens = ","; //$NON-NLS-1$
455
break;
456         }
457         if (tokens == null) // unknown version? corrupt file? we can't log it
458
// because we dont have a workspace yet...
459
return new String JavaDoc[0];
460             
461
462         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(prefValue, tokens);
463         for (int i = 0; i < paths.length && tokenizer.hasMoreTokens(); ++i) {
464             paths[i] = tokenizer.nextToken();
465         }
466
467         return paths;
468     }
469
470     /**
471      * Return true if the protocol used to encode the argument memento is
472      * compatible with the receiver's implementation and false otherwise.
473      */

474     private static boolean compatibleFileProtocol(IMemento memento) {
475         IMemento protocolMemento = memento.getChild(XML.PROTOCOL);
476         if (protocolMemento == null) {
477             return false;
478         }
479
480         Integer JavaDoc version = protocolMemento.getInteger(XML.VERSION);
481         return version != null && version.intValue() == PERS_ENCODING_VERSION;
482     }
483
484     /**
485      * The workspace data is stored in the well known file pointed to by the result
486      * of this method.
487      * @param create If the directory and file does not exist this parameter
488      * controls whether it will be created.
489      * @return An url to the file and null if it does not exist or could not
490      * be created.
491      */

492     private static URL JavaDoc getPersistenceUrl(URL JavaDoc baseUrl, boolean create) {
493         if (baseUrl == null) {
494             return null;
495         }
496
497         try {
498             // make sure the directory exists
499
URL JavaDoc url = new URL JavaDoc(baseUrl, PERS_FOLDER);
500             File JavaDoc dir = new File JavaDoc(url.getFile());
501             if (!dir.exists() && (!create || !dir.mkdir())) {
502                 return null;
503             }
504
505             // make sure the file exists
506
url = new URL JavaDoc(dir.toURL(), PERS_FILENAME);
507             File JavaDoc persFile = new File JavaDoc(url.getFile());
508             if (!persFile.exists() && (!create || !persFile.createNewFile())) {
509                 return null;
510             }
511
512             return persFile.toURL();
513         } catch (IOException JavaDoc e) {
514             // cannot log because instance area has not been set
515
return null;
516         }
517     }
518 }
519
Popular Tags