2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.modules.editor.options;
44
import java.io.IOException;
45
import java.util.ArrayList;
46
import java.util.Hashtable;
47
import java.util.Iterator;
48
import java.util.List;
50
import java.util.StringTokenizer;
51
import javax.swing.SwingUtilities;
52
import org.netbeans.editor.BaseKit;
53
import org.netbeans.editor.Settings;
54
import org.openide.NotifyDescriptor;
55
import org.openide.cookies.InstanceCookie;
56
import org.openide.filesystems.FileChangeAdapter;
57
import org.openide.filesystems.FileChangeListener;
58
import org.openide.filesystems.FileEvent;
59
import org.openide.filesystems.FileObject;
60
import org.openide.filesystems.Repository;
61
import org.openide.loaders.DataFolder;
62
import org.openide.loaders.DataObject;
63
import org.openide.loaders.DataObjectNotFoundException;
64
import org.openide.options.SystemOption;
65
import org.openide.util.NbBundle;
67
/** Editor Settings main node folder.
68
* In this folder are stored global options such as global keybindings.
69
* Mime options are lazily initialized after loading appropriate kit
70
* (NbEditorKit.java) or after request of Option window to show
72
* Initialization starts with loading user's setting from
73
* XML files and then initializer is added to Settings and reseted.
75
* @author Martin Roskanin
78
public class AllOptionsFolder{
80
/** folder for Editor Settings main node */
81
public static final String FOLDER = "Editors"; // NOI18N
82
public static final String OPTION_FILE_NAME = "Settings.settings"; // NOI18N
84
/** instance of this class */
85
private static AllOptionsFolder settingsFolder;
87
private static boolean baseInitialized = false;
89
private static MIMEOptionFolder mimeFolder;
91
// List of already initialized options
92
private static Map installedOptions = new Hashtable();
94
/** Listens to changes on the Modules folder */
95
private static FileChangeListener moduleRegListener;
98
/** Creates new AllOptionsFolder */
99
private AllOptionsFolder() {
102
/** Gets the singleton of global options MIME folder */
103
public MIMEOptionFolder getMIMEFolder(){
104
synchronized (Settings.class){
105
if (mimeFolder!=null) return mimeFolder;
107
FileObject f = Repository.getDefault().getDefaultFileSystem().
108
findResource(FOLDER+"/text/"+BaseOptions.BASE); //NOI18N
110
// MIME folder doesn't exist, let's create it
112
FileObject fo = Repository.getDefault().getDefaultFileSystem().
113
findResource(AllOptionsFolder.FOLDER);
114
String fName = "text/"+BaseOptions.BASE; //NOI18N
118
StringTokenizer stok = new StringTokenizer(fName,"/"); //NOI18N
119
while (stok.hasMoreElements()) {
120
String newFolder = stok.nextToken();
121
if (fo.getFileObject(newFolder) == null)
122
fo = fo.createFolder(newFolder);
124
fo = fo.getFileObject(newFolder);
126
}catch(IOException ioe){
127
ioe.printStackTrace();
130
f = Repository.getDefault().getDefaultFileSystem().
131
findResource(AllOptionsFolder.FOLDER+"/text/"+BaseOptions.BASE); //NOI18N
137
DataObject d = DataObject.find(f);
138
DataFolder df = (DataFolder)d.getCookie(DataFolder.class);
140
mimeFolder = new MIMEOptionFolder(df, getBase());
143
} catch (org.openide.loaders.DataObjectNotFoundException ex) {
144
ex.printStackTrace();
152
/** Returns list of installed Options. Values = options classes */
153
public List getInstalledOptions(){
155
// first XMLized options
157
List retList = new ArrayList();
158
String[] MIMES = new String[] {"text", "application"}; //#25246 application/xml-dtd // NOI18N
159
for (int in = 0; in<MIMES.length; in++) {
160
FileObject mainFolderFO = Repository.getDefault().getDefaultFileSystem().
161
findResource(AllOptionsFolder.FOLDER+"/" + MIMES[in]); //NOI18N
162
if (mainFolderFO != null){
163
DataFolder mainFolder = DataFolder.findFolder(mainFolderFO);
164
if (mainFolder != null){
165
DataObject subFolders[] = mainFolder.getChildren();
166
for (int i=0; i<subFolders.length; i++){
167
if (!(subFolders[i] instanceof DataFolder)) continue;
168
DataFolder subFolder = (DataFolder) subFolders[i];
169
FileObject optionInstance = Repository.getDefault().getDefaultFileSystem().
170
findResource(subFolder.getPrimaryFile().getPath()+"/"+AllOptionsFolder.OPTION_FILE_NAME); // NOI18N
171
if (optionInstance == null) continue;
173
DataObject optionDO = DataObject.find(optionInstance);
174
if (optionDO == null) continue;
175
InstanceCookie ic = (InstanceCookie)optionDO.getCookie(InstanceCookie.class);
176
if (ic == null) continue;
177
BaseOptions bo = AllOptionsFolder.getDefault().getBO(ic);
178
if (bo == null) continue;
179
retList.add(bo.getClass());
180
}catch(DataObjectNotFoundException donf){
181
donf.printStackTrace();
188
// Now old SystemOptions options
189
AllOptions allOptions
190
= (AllOptions)AllOptions.findObject(AllOptions.class, true);
192
if (allOptions == null) return retList;
194
SystemOption[] sos = allOptions.getOptions();
195
if (sos == null) return retList;
197
for (int i=0; i<sos.length; i++){
199
if (!(sos[i] instanceof BaseOptions)) continue;
201
BaseOptions bo = (BaseOptions) sos[i];
202
if (retList.contains(bo.getClass())) retList.remove(bo.getClass());
203
if (BaseKit.getKit(bo.getKitClass()).getContentType() != null){
204
retList.add(bo.getClass());
205
processInitializers(bo, false);
207
final String kitClazz = bo.getKitClass().toString();
208
SwingUtilities.invokeLater(
211
NotifyDescriptor msg = new NotifyDescriptor.Message(
213
NbBundle.getMessage( AllOptionsFolder.class, "ERR_NoContentTypeDefined", kitClazz),
214
NotifyDescriptor.WARNING_MESSAGE
217
org.openide.DialogDisplayer.getDefault().notify(msg);
227
public static void unregisterModuleRegListener(){
228
FileObject moduleRegistry = Repository.getDefault().getDefaultFileSystem().findResource("Modules"); //NOI18N
230
if (moduleRegistry !=null){ //NOI18N
231
if (moduleRegListener!=null)
232
moduleRegistry.removeFileChangeListener(moduleRegListener);
236
/** Creates the only instance of AllOptionsFolder. */
237
public static AllOptionsFolder getDefault(){
238
synchronized (Settings.class) {
239
if (settingsFolder == null) {
240
settingsFolder = new AllOptionsFolder();
242
// attach listeners for module registry for listening on addition or removal of modules in IDE
243
if(moduleRegListener == null) {
244
moduleRegListener = new FileChangeAdapter() {
245
public void fileChanged(FileEvent fe){
250
FileObject moduleRegistry = Repository.getDefault().getDefaultFileSystem().findResource("Modules"); //NOI18N
252
if (moduleRegistry !=null){ //NOI18N
253
moduleRegistry.addFileChangeListener(moduleRegListener);
258
return settingsFolder;
262
/** Getter for KeyBingings */
263
public List getKeyBindingList() {
264
return getBase().getKeyBindingList();
267
/** Setter for KeyBindings */
268
public void setKeyBindingList(List list) {
269
getBase().setKeyBindingList(list);
272
public boolean isToolbarVisible() {
273
return getBase().isToolbarVisible();
276
public void setToolbarVisible(boolean toolbarVisible) {
277
getBase().setToolbarVisible(toolbarVisible);
280
public boolean getLineNumberVisible(){
281
return getBase().getLineNumberVisible();
284
public void setLineNumberVisible(boolean lineVisible) {
285
getBase().setLineNumberVisible(lineVisible);
288
public boolean isTextAntialiasing() {
289
return getBase().isTextAntialiasing();
292
public void setTextAntialiasing(boolean textAntialiasing) {
293
getBase().setTextAntialiasing(textAntialiasing);
296
/** Loads default global keyBindings List and initializes it.
297
* It is used mainly by other options for initializing global keyBindings */
298
protected void loadDefaultKeyBindings(){
299
getBase().getKeyBindingList();
302
/** Returns kitClass of uninstalled option */
303
private static Class uninstallOption(){
304
List updatedInstalledOptions = AllOptionsFolder.getDefault().getInstalledOptions();
305
synchronized (Settings.class){
306
Iterator i = installedOptions.keySet().iterator();
308
Object obj = i.next();
309
if(obj instanceof Class){
310
if (!updatedInstalledOptions.contains(obj)){
311
installedOptions.remove(obj);
320
private static void updateOptions(){
322
List installedOpts = new ArrayList(installedOptions.values());
323
Iterator i = installedOpts.iterator();
325
Object obj = i.next();
326
if (obj instanceof BaseOptions){
327
BaseOptions bo = (BaseOptions)obj;
329
bo.initPopupMenuItems();
335
/** Returns true if BaseOptions has been initialized */
336
public boolean baseInitialized(){
337
return baseInitialized;
340
/** Gets the singleton of BaseOptions and register it in Settings initializer,
341
* if it wasn't been done before. */
342
private BaseOptions getBase(){
344
BaseOptions ret = (BaseOptions)BaseOptions.findObject(BaseOptions.class, true);
346
synchronized (Settings.class){
347
if (baseInitialized == false){
348
// Add the initializer for the base options. It will not be removed
349
Settings.addInitializer(ret.getSettingsInitializer(),
350
Settings.OPTION_LEVEL);
351
baseInitialized = true;
359
/** Gets the instance of BaseOptions from InstanceCookie */
360
protected BaseOptions getBO(InstanceCookie ic){
362
BaseOptions ret = null;
364
synchronized (Settings.class){
365
ret = (installedOptions.get(ic.instanceClass()) instanceof BaseOptions) ? (BaseOptions) installedOptions.get(ic.instanceClass())
368
}catch(ClassNotFoundException cnfe){
369
cnfe.printStackTrace();
371
}catch(IOException ioex){
372
ioex.printStackTrace();
377
/** Create the instance of appropriate BaseOption subclass */
378
private void initInstance(InstanceCookie ic){
381
synchronized (Settings.class){
382
if (installedOptions.containsKey(ic.instanceClass())) {
385
optionObj = ic.instanceCreate();
386
if (!(optionObj instanceof BaseOptions)) return;
387
installedOptions.put(ic.instanceClass(), (BaseOptions)optionObj);
389
processInitializers((BaseOptions)optionObj, false);
390
}catch(ClassNotFoundException cnfe){
391
cnfe.printStackTrace();
392
}catch(IOException ioex){
393
ioex.printStackTrace();
398
* Lazily inits MIME Option class. Calls <code>loadMIMEOption(kitClass, true)</code>.
400
* @param kitClass The editor kit class you want to load options for.
402
* @deprecated See {@link loadMimeOption(Class, boolean)} for details.
404
public void loadMIMEOption(Class kitClass){
405
loadMIMEOption(kitClass, true);
409
* Lazily inits MIME Option class. If processOldTypeOption is true initializers
410
* for this option will be processed.
412
* @param kitClass The editor kit class you want to load options for.
413
* @param processOldTypeOptions Internal magic, if you really want to call
414
* this method, you should probably set this to <code>true</code>.
416
* @deprecated There is no reason you should call this method. It should have
417
* never been made public. Use <code>MimeLookup.getLookup(MimePath.parse(your-mime-type)).lookup(BaseOptions.class)</code>
418
* for accessing <code>BaseOptions</code> for your mime type.
420
public void loadMIMEOption(Class kitClass, boolean processOldTypeOption){
421
String contentType = BaseKit.getKit(kitClass).getContentType();
422
if (contentType == null) return;
423
FileObject optionFO = Repository.getDefault().getDefaultFileSystem().
424
findResource(FOLDER+"/"+contentType+"/"+OPTION_FILE_NAME); //NOI18N
425
if (optionFO == null) {
426
// old type of BaseOptions.
427
// Options weren't transfered to XML form for this kitClass yet.
428
// We have to find them via BaseOptions.getOptions and process initializers.
429
if (processOldTypeOption){
430
BaseOptions oldBO = BaseOptions.getOptions(kitClass);
432
boolean process = false;
433
synchronized (Settings.class){
434
if (!installedOptions.containsKey(kitClass)){
435
installedOptions.put(kitClass, oldBO);
440
processInitializers(oldBO, false);
448
DataObject optionDO = DataObject.find(optionFO);
449
if (optionDO == null) return;
451
InstanceCookie ic = (InstanceCookie)optionDO.getCookie(InstanceCookie.class);
452
if (ic == null) return;
456
}catch(DataObjectNotFoundException donf){
457
donf.printStackTrace();
461
/** Updates MIME option initializer. Loads user's settings stored in XML
462
* files and updates Setting's initializers via reset method */
463
private void processInitializers(BaseOptions bo, boolean remove) {
464
//synchronized (BaseKit.class){
465
synchronized (Settings.class){
466
Settings.Initializer si = bo.getSettingsInitializer();
467
// Remove the old one
468
Settings.removeInitializer(si.getName());
469
if (!remove) { // add the new one
470
Settings.addInitializer(si, Settings.OPTION_LEVEL);
473
// load all settings of this mime type from XML files
474
bo.loadXMLSettings();
476
//initialize popup menu
477
bo.initPopupMenuItems();
479
/* Reset the settings so that the new initializers take effect
480
* or the old are removed. */