001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.editor.options;
043:
044: import java.awt.Color;
045: import java.awt.Font;
046: import java.util.Map;
047: import java.util.HashMap;
048: import java.util.Iterator;
049: import java.util.logging.Logger;
050: import javax.swing.KeyStroke;
051: import org.netbeans.editor.MultiKeyBinding;
052: import java.util.List;
053: import java.util.StringTokenizer;
054: import java.util.ArrayList;
055: import java.awt.Insets;
056: import org.w3c.dom.Document;
057: import org.openide.xml.XMLUtil;
058: import org.openide.filesystems.FileLock;
059: import java.io.IOException;
060: import org.openide.filesystems.FileObject;
061: import org.openide.loaders.DataObject;
062: import java.util.Enumeration;
063: import org.openide.cookies.InstanceCookie;
064: import org.openide.util.actions.SystemAction;
065: import java.util.Set;
066: import java.awt.Dimension;
067:
068: /** Various utilities for Editor Options.
069: *
070: * @author Martin Roskanin
071: * @since 08/2001
072: */
073: public class OptionUtilities {
074:
075: private static final Logger LOG = Logger
076: .getLogger(OptionUtilities.class.getName());
077:
078: // the name of default folder for storing default maps such as macros, abbrevs...
079: public static final String DEFAULT_FOLDER = "Defaults"; //NOI18N
080:
081: private OptionUtilities() {
082: // instantiation has no sense
083: }
084:
085: private static String wrap(String s) {
086: return (s.length() == 1) ? "0" + s : s; // NOI18N
087: }
088:
089: /** Converts Color to hexadecimal String representation */
090: public static String color2String(Color c) {
091: StringBuffer sb = new StringBuffer();
092: sb.append("#"); // NOI18N
093: sb.append(wrap(Integer.toHexString(c.getRed()).toUpperCase()));
094: sb
095: .append(wrap(Integer.toHexString(c.getGreen())
096: .toUpperCase()));
097: sb.append(wrap(Integer.toHexString(c.getBlue()).toUpperCase()));
098: return sb.toString();
099: }
100:
101: /** Converts a String to an integer and returns the specified opaque Color. */
102: public static Color string2Color(String s) {
103: try {
104: return Color.decode(s);
105: } catch (NumberFormatException nfe) {
106: return null;
107: }
108: }
109:
110: /** Converts String to integer */
111: public static int string2Int(String s) {
112: try {
113: return Integer.parseInt(s);
114: } catch (NumberFormatException nfe) {
115: return -1;
116: }
117: }
118:
119: /** Decodes font style from string representation */
120: public static int getFontStyle(String s) {
121: s = s.toLowerCase();
122: int ret = Font.PLAIN;
123: if (s.indexOf("bold") != -1)
124: ret |= Font.BOLD; //NOI18N
125: if (s.indexOf("italic") != -1)
126: ret |= Font.ITALIC; //NOI18N
127: return ret;
128: }
129:
130: /** Encodes font style to string representation */
131: public static String style2String(int i) {
132: if (Font.BOLD == i)
133: return "bold"; // NOI18N
134: if (Font.ITALIC == i)
135: return "italic"; // NOI18N
136: if ((Font.BOLD + Font.ITALIC) == i)
137: return "bold-italic"; // NOI18N
138: return "plain"; // NOI18N
139: }
140:
141: /** Gets changed values of newMap against the oldMap.
142: * If allowNewKey is false then diff will contain only
143: * changed oldMap keys
144: */
145: public static Map getMapDiff(Map oldMap, Map newMap,
146: boolean allowNewKeys) {
147: Map ret = new HashMap();
148:
149: for (Iterator i = newMap.keySet().iterator(); i.hasNext();) {
150: Object key = (Object) i.next();
151: Object value = newMap.get(key);
152: // if value in newMap is different from oldMap, put it to return Map
153: if (!value.equals(oldMap.get(key)))
154: ret.put(key, newMap.get(key));
155: // or we can add some new key if allowNewKeys is true
156: else if (allowNewKeys && !oldMap.containsKey(key))
157: ret.put(key, newMap.get(key));
158: }
159:
160: for (Iterator i = oldMap.keySet().iterator(); i.hasNext();) {
161: String key = (String) i.next();
162: Object value = oldMap.get(key);
163: // all deleted keys
164: if (!newMap.containsKey(key))
165: ret.put(key, "");
166: }
167:
168: return ret;
169: }
170:
171: /**
172: * Creates textual representation of KeyStroke[].
173: * @deprecated Without any replacement.
174: */
175: public static String keysToString(KeyStroke[] stroke) {
176: if (stroke == null)
177: return "NULL"; // NOI18N
178: StringBuffer sb = new StringBuffer();
179:
180: for (int i = 0; i < stroke.length; i++) {
181: sb
182: .append(org.openide.util.Utilities
183: .keyToString(stroke[i]));
184: if (i < stroke.length - 1)
185: sb.append("$"); // NOI18N
186: }
187:
188: return sb.toString();
189: }
190:
191: /**
192: * Creates textual representation of KeyStroke.
193: * @deprecated Use <code>org.openide.util.Utilities.keyToString(KeyStroke)</code>.
194: */
195: public static String keyToString(KeyStroke stroke) {
196: if (stroke == null)
197: return "NULL"; // NOI18N
198: return org.openide.util.Utilities.keyToString(stroke);
199: }
200:
201: /**
202: * Converts textual representatin of Keystroke
203: * @deprecated Use <code>org.openide.util.Utilities.stringToKey(String)</code>.
204: */
205: public static KeyStroke stringToKey(String s) {
206: if (s.equals("NULL"))
207: return null; // NOI18N
208: return org.openide.util.Utilities.stringToKey(s);
209: }
210:
211: /**
212: * Converts textual representatin of Keystroke[]
213: * @deprecated Without any replacement.
214: */
215: public static KeyStroke[] stringToKeys(String s) {
216: if (s.equals("NULL"))
217: return null; // NOI18N
218:
219: StringTokenizer st = new StringTokenizer(s.toUpperCase(), "$"); // NOI18N
220: ArrayList arr = new ArrayList();
221:
222: while (st.hasMoreElements()) {
223: s = st.nextToken();
224: KeyStroke k = org.openide.util.Utilities.stringToKey(s);
225: if (k == null)
226: return null;
227: arr.add(k);
228: }
229:
230: return (KeyStroke[]) arr.toArray(new KeyStroke[arr.size()]);
231: }
232:
233: /** @deprecated Without any replacement. */
234: public static void printDefaultAbbrevs(Map map) {
235: System.out
236: .println("-----------------------------------------------------------"); // NOI18N
237: System.out.println("<?xml version=\"1.0\"?>"); // NOI18N
238: System.out.println("<!DOCTYPE catalog PUBLIC \""
239: + AbbrevsMIMEProcessor.PUBLIC_ID + "\""); // NOI18N
240: System.out.println(" \"" + AbbrevsMIMEProcessor.SYSTEM_ID
241: + "\">"); // NOI18N
242: System.out.println("");
243: System.out.println("<" + AbbrevsMIMEOptionFile.TAG_ROOT + ">"); // NOI18N
244: for (Iterator i = map.keySet().iterator(); i.hasNext();) {
245: String key = (String) i.next();
246: String value = (String) map.get(key);
247: System.out.println("<" + AbbrevsMIMEOptionFile.TAG_ABBREV
248: + " " + AbbrevsMIMEOptionFile.ATTR_KEY + "=\""
249: + key
250: + "\">" // NOI18N
251: + value + "</" + AbbrevsMIMEOptionFile.TAG_ABBREV
252: + ">"); // NOI18N
253: }
254: System.out.println("</" + AbbrevsMIMEOptionFile.TAG_ROOT + ">"); // NOI18N
255: }
256:
257: /**
258: * Prints given Abbreviations Map to XML file with given FO.
259: * @deprecated Without any replacement.
260: */
261: public static void printDefaultAbbrevs(Map map, FileObject file) {
262: Document doc = XMLUtil.createDocument(
263: AbbrevsMIMEOptionFile.TAG_ROOT, null,
264: AbbrevsMIMEProcessor.PUBLIC_ID,
265: AbbrevsMIMEProcessor.SYSTEM_ID);
266: org.w3c.dom.Element rootElem = doc.getDocumentElement();
267:
268: // save XML
269: for (Iterator i = map.keySet().iterator(); i.hasNext();) {
270: String key = (String) i.next();
271: if (map.get(key) instanceof String) {
272:
273: String action = (String) map.get(key);
274:
275: org.w3c.dom.Element abbrevElem = doc
276: .createElement(AbbrevsMIMEOptionFile.TAG_ABBREV);
277: abbrevElem.setAttribute(AbbrevsMIMEOptionFile.ATTR_KEY,
278: key);
279: abbrevElem.appendChild(doc.createTextNode(action));
280: rootElem.appendChild(abbrevElem);
281:
282: }
283: }
284:
285: doc.getDocumentElement().normalize();
286:
287: try {
288: FileLock lock = file.lock();
289: try {
290: XMLUtil.write(doc, file.getOutputStream(lock), "UTF-8"); // NOI18N
291: } catch (Exception e) {
292: e.printStackTrace();
293: } finally {
294: lock.releaseLock();
295: }
296: } catch (IOException ioe) {
297: ioe.printStackTrace();
298: }
299: }
300:
301: /** Prints given Macro Map to XML file with given FO */
302: public static void printDefaultMacros(Map map, FileObject file) {
303: Document doc = XMLUtil.createDocument(
304: MacrosMIMEOptionFile.TAG_ROOT, null,
305: MacrosMIMEProcessor.PUBLIC_ID,
306: MacrosMIMEProcessor.SYSTEM_ID);
307: org.w3c.dom.Element rootElem = doc.getDocumentElement();
308:
309: // save XML
310: for (Iterator i = map.keySet().iterator(); i.hasNext();) {
311: String key = (String) i.next();
312: if (map.get(key) instanceof String) {
313:
314: String action = (String) map.get(key);
315:
316: org.w3c.dom.Element macroElem = doc
317: .createElement(MacrosMIMEOptionFile.TAG_MACRO);
318: macroElem.setAttribute(MacrosMIMEOptionFile.ATTR_NAME,
319: key);
320: macroElem.appendChild(doc.createTextNode(action));
321: rootElem.appendChild(macroElem);
322: }
323: }
324:
325: doc.getDocumentElement().normalize();
326:
327: try {
328: FileLock lock = file.lock();
329: try {
330: XMLUtil.write(doc, file.getOutputStream(lock), "UTF-8"); // NOI18N
331: } catch (Exception e) {
332: e.printStackTrace();
333: } finally {
334: lock.releaseLock();
335: }
336: } catch (IOException ioe) {
337: ioe.printStackTrace();
338: }
339: }
340:
341: /**
342: * Prints given KeyBindings List to XML file with given FO
343: * @deprecated Without any replacement.
344: */
345: public static void printDefaultKeyBindings(List list,
346: FileObject file) {
347: Map map = makeKeyBindingsMap(list);
348: Document doc = XMLUtil.createDocument(
349: KeyBindingsMIMEOptionFile.TAG_ROOT, null,
350: KeyBindingsMIMEProcessor.PUBLIC_ID,
351: KeyBindingsMIMEProcessor.SYSTEM_ID);
352: org.w3c.dom.Element rootElem = doc.getDocumentElement();
353:
354: // save XML
355: for (Iterator i = map.keySet().iterator(); i.hasNext();) {
356: String key = (String) i.next();
357: if (map.get(key) instanceof MultiKeyBinding) {
358:
359: MultiKeyBinding mkb = (MultiKeyBinding) map.get(key);
360: if (mkb == null)
361: continue;
362:
363: org.w3c.dom.Element keybElem = doc
364: .createElement(KeyBindingsMIMEOptionFile.TAG_BIND);
365: keybElem.setAttribute(
366: KeyBindingsMIMEOptionFile.ATTR_KEY, key);
367: keybElem.setAttribute(
368: KeyBindingsMIMEOptionFile.ATTR_ACTION_NAME,
369: mkb.actionName);
370: rootElem.appendChild(keybElem);
371: }
372: }
373:
374: doc.getDocumentElement().normalize();
375:
376: try {
377: FileLock lock = file.lock();
378: try {
379: XMLUtil.write(doc, file.getOutputStream(lock), "UTF-8"); // NOI18N
380: } catch (Exception e) {
381: e.printStackTrace();
382: } finally {
383: lock.releaseLock();
384: }
385: } catch (IOException ioe) {
386: ioe.printStackTrace();
387: }
388: }
389:
390: /** Coverts Insets to String representation */
391: public static String insetsToString(Insets ins) {
392: StringBuffer sb = new StringBuffer();
393: sb.append(ins.top);
394: sb.append(',');
395:
396: sb.append(ins.left);
397: sb.append(',');
398:
399: sb.append(ins.bottom);
400: sb.append(',');
401:
402: sb.append(ins.right);
403:
404: return sb.toString();
405: }
406:
407: /** Converts textual representation of Insets */
408: public static Insets parseInsets(String s) {
409: StringTokenizer st = new StringTokenizer(s, ","); // NOI18N
410:
411: int arr[] = new int[4];
412: int i = 0;
413: while (st.hasMoreElements()) {
414: if (i > 3)
415: return null;
416: try {
417: arr[i] = Integer.parseInt(st.nextToken());
418: } catch (NumberFormatException nfe) {
419: return null;
420: }
421: i++;
422: }
423: if (i != 4)
424: return null;
425: return new Insets(arr[0], arr[1], arr[2], arr[3]);
426: }
427:
428: /** Coverts Insets to String representation */
429: public static String dimensionToString(Dimension dim) {
430: StringBuffer sb = new StringBuffer();
431: sb.append(dim.width);
432: sb.append(',');
433:
434: sb.append(dim.height);
435:
436: return sb.toString();
437: }
438:
439: /** Converts textual representation of Insets */
440: public static Dimension parseDimension(String s) {
441: StringTokenizer st = new StringTokenizer(s, ","); // NOI18N
442:
443: int arr[] = new int[2];
444: int i = 0;
445: while (st.hasMoreElements()) {
446: if (i > 1)
447: return null;
448: try {
449: arr[i] = Integer.parseInt(st.nextToken());
450: } catch (NumberFormatException nfe) {
451: return null;
452: }
453: i++;
454: }
455: if (i != 2)
456: return null;
457: return new Dimension(arr[0], arr[1]);
458: }
459:
460: /**
461: * Converts KeyBings List to KeyBindings Map
462: * Map.key is the textual representation of keystroke(s)
463: * @deprecated Without any replacement.
464: */
465: public static Map<String, MultiKeyBinding> makeKeyBindingsMap(
466: List propList) {
467: Map<String, MultiKeyBinding> ret = new HashMap<String, MultiKeyBinding>();
468:
469: boolean output = true;
470: for (int i = 0; i < propList.size(); i++) {
471: Object obj = propList.get(i);
472: if (!(obj instanceof org.netbeans.editor.MultiKeyBinding)) {
473: if (!org.netbeans.editor.MultiKeyBinding.class
474: .getClassLoader().equals(
475: obj.getClass().getClassLoader())) {
476: if (output) {
477: System.err.println("Different classloaders:");
478: System.err
479: .println(org.netbeans.editor.MultiKeyBinding.class
480: .getClassLoader());
481: System.err.println(obj.getClass()
482: .getClassLoader());
483: output = false;
484: }
485: }
486:
487: continue;
488: }
489: MultiKeyBinding mkb = (MultiKeyBinding) obj;
490: String fileName = (mkb.keys == null) ? OptionUtilities
491: .keyToString(mkb.key) : OptionUtilities
492: .keysToString(mkb.keys);
493: if (fileName != null) {
494: ret.put(fileName, mkb);
495: }
496: }
497: return ret;
498: }
499:
500: /** Gets popup menu items (DataObjects) stored in base popup folder
501: */
502: public static List getGlobalPopupMenuItems() {
503: return getGlobalMenuItems("Popup"); //NOI18N
504: }
505:
506: /** Retrieves a list of BaseOptions.BASE MultiPropertyFolder items */
507: public static List getGlobalMenuItems(String folderName) {
508: MIMEOptionFolder mimeFolder = AllOptionsFolder.getDefault()
509: .getMIMEFolder();
510: if (mimeFolder == null)
511: return new ArrayList();
512: MultiPropertyFolder mpf = mimeFolder.getMPFolder(folderName,
513: false); //NOI18N
514: if (mpf != null) {
515: return mpf.getProperties();
516: }
517: return new ArrayList();
518: }
519:
520: public static List getPopupStrings(List popup) {
521: return getPopupStrings(popup, false);
522: }
523:
524: /** Creates String representation of popup from DO representation
525: * @param addSeparatorInstance if true the result list will use instance of JSeparator in case of separator,
526: * if false null will be used
527: */
528: public static List getPopupStrings(List popup,
529: boolean addSeparatorInstance) {
530: List retList = new ArrayList();
531: for (int i = 0; i < popup.size(); i++) {
532: if (!(popup.get(i) instanceof DataObject))
533: continue;
534:
535: DataObject dob = (DataObject) popup.get(i);
536: InstanceCookie ic = (InstanceCookie) dob
537: .getCookie(InstanceCookie.class);
538:
539: if (ic != null) {
540:
541: try {
542: if (SystemAction.class.isAssignableFrom(ic
543: .instanceClass())) {
544: retList.add(ic.instanceName());
545: } else if (javax.swing.Action.class
546: .isAssignableFrom(ic.instanceClass())) {
547: retList.add(ic.instanceCreate());
548: }
549: if (javax.swing.JSeparator.class
550: .isAssignableFrom(ic.instanceClass())) {
551: retList
552: .add(addSeparatorInstance ? new javax.swing.JSeparator()
553: : null);
554: }
555: } catch (IOException ioe) {
556: ioe.printStackTrace();
557: } catch (ClassNotFoundException cnfe) {
558: cnfe.printStackTrace();
559: }
560: } else {
561: if ("org-openide-windows-TopComponent".equals(dob
562: .getName())) { //NOI18N
563: retList.add(dob.getName().replace('-', '.'));
564: } else {
565: retList.add(dob.getName());
566: }
567: }
568: }
569:
570: return retList;
571: }
572:
573: }
|