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.settings.storage.fontscolors;
043:
044: import java.util.Set;
045: import org.netbeans.modules.editor.settings.storage.*;
046: import java.awt.Color;
047: import java.io.IOException;
048: import java.util.Collections;
049: import java.util.Enumeration;
050: import java.util.HashMap;
051: import java.util.List;
052: import java.util.Map;
053: import java.util.logging.Level;
054: import java.util.logging.Logger;
055: import javax.swing.text.AttributeSet;
056: import javax.swing.text.SimpleAttributeSet;
057: import javax.swing.text.StyleConstants;
058: import org.netbeans.api.editor.mimelookup.MimePath;
059: import org.netbeans.api.editor.settings.EditorStyleConstants;
060: import org.netbeans.modules.editor.settings.storage.spi.StorageDescription;
061: import org.netbeans.modules.editor.settings.storage.spi.StorageReader;
062: import org.netbeans.modules.editor.settings.storage.spi.StorageWriter;
063: import org.openide.filesystems.FileObject;
064: import org.openide.filesystems.FileSystem;
065: import org.openide.filesystems.FileUtil;
066: import org.openide.filesystems.Repository;
067: import org.openide.xml.XMLUtil;
068: import org.w3c.dom.Document;
069: import org.w3c.dom.Element;
070: import org.w3c.dom.Node;
071: import org.xml.sax.Attributes;
072: import org.xml.sax.SAXException;
073:
074: /**
075: *
076: * @author Jan Jancura, Vita Stejskal
077: */
078: public final class ColoringStorage implements
079: StorageDescription<String, AttributeSet>,
080: StorageImpl.Operations<String, AttributeSet> {
081:
082: // -J-Dorg.netbeans.modules.editor.settings.storage.ColoringStorage.level=FINE
083: private static final Logger LOG = Logger
084: .getLogger(ColoringStorage.class.getName());
085:
086: public static final String ID = "FontsColors"; //NOI18N
087: /* test */static final String MIME_TYPE = "text/x-nbeditor-fontcolorsettings"; //NOI18N
088:
089: public ColoringStorage(boolean tokenColoringStorage) {
090: this .tokenColoringStorage = tokenColoringStorage;
091: }
092:
093: // ---------------------------------------------------------
094: // StorageDescription implementation
095: // ---------------------------------------------------------
096:
097: public ColoringStorage() {
098: this (true);
099: }
100:
101: public String getId() {
102: return ID;
103: }
104:
105: public boolean isUsingProfiles() {
106: return true;
107: }
108:
109: public String getMimeType() {
110: return MIME_TYPE;
111: }
112:
113: public String getLegacyFileName() {
114: return null;
115: }
116:
117: public StorageReader<String, AttributeSet> createReader(
118: FileObject f, String mimePath) {
119: throw new UnsupportedOperationException("Should not be called.");
120: }
121:
122: public StorageWriter<String, AttributeSet> createWriter(
123: FileObject f, String mimePath) {
124: throw new UnsupportedOperationException("Should not be called.");
125: }
126:
127: // ---------------------------------------------------------
128: // StorageDescription implementation
129: // ---------------------------------------------------------
130:
131: public Map<String, AttributeSet> load(MimePath mimePath,
132: String profile, boolean defaults) {
133: assert mimePath != null : "The parameter mimePath must not be null"; //NOI18N
134: assert profile != null : "The parameter profile must not be null"; //NOI18N
135:
136: FileObject baseFolder = Repository.getDefault()
137: .getDefaultFileSystem().findResource("Editors"); //NOI18N
138: Map<String, List<Object[]>> files = new HashMap<String, List<Object[]>>();
139: SettingsType.Locator locator = SettingsType.getLocator(this );
140: locator.scan(baseFolder, mimePath.getPath(), profile, true,
141: true, !defaults, false, files);
142:
143: assert files.size() <= 1 : "Too many results in the scan"; //NOI18N
144:
145: List<Object[]> profileInfos = files.get(profile);
146: if (profileInfos == null) {
147: return Collections.<String, AttributeSet> emptyMap();
148: }
149:
150: List<Object[]> filesForLocalization;
151: if (!profile.equals(EditorSettingsImpl.DEFAULT_PROFILE)) {
152: // If non-default profile load the default profile supplied by modules
153: // to find the localizing bundles.
154: Map<String, List<Object[]>> defaultProfileModulesFiles = new HashMap<String, List<Object[]>>();
155: locator.scan(baseFolder, mimePath.getPath(),
156: EditorSettingsImpl.DEFAULT_PROFILE, true, true,
157: false, false, defaultProfileModulesFiles);
158: filesForLocalization = defaultProfileModulesFiles
159: .get(EditorSettingsImpl.DEFAULT_PROFILE);
160:
161: // if there is no default profile (eg. in tests)
162: if (filesForLocalization == null) {
163: filesForLocalization = Collections
164: .<Object[]> emptyList();
165: }
166: } else {
167: filesForLocalization = profileInfos;
168: }
169:
170: Map<String, SimpleAttributeSet> fontsColorsMap = new HashMap<String, SimpleAttributeSet>();
171: for (Object[] info : profileInfos) {
172: assert info.length == 5;
173: FileObject profileHome = (FileObject) info[0];
174: FileObject settingFile = (FileObject) info[1];
175: boolean modulesFile = ((Boolean) info[2]).booleanValue();
176: boolean legacyFile = ((Boolean) info[4]).booleanValue();
177:
178: // Skip files with wrong type of colorings
179: boolean isTokenColoringFile = isTokenColoringFile(settingFile);
180: if (isTokenColoringFile != tokenColoringStorage) {
181: continue;
182: }
183:
184: // Load colorings from the settingFile
185: ColoringsReader reader = new ColoringsReader(settingFile,
186: mimePath.getPath());
187: Utils.load(settingFile, reader, !legacyFile);
188: Map<String, SimpleAttributeSet> sets = reader.getAdded();
189:
190: // Process loaded colorings
191: for (SimpleAttributeSet as : sets.values()) {
192: String name = (String) as
193: .getAttribute(StyleConstants.NameAttribute);
194: String translatedName = null;
195: SimpleAttributeSet previous = fontsColorsMap.get(name);
196:
197: if (previous == null && !modulesFile
198: && tokenColoringStorage) {
199: // User files normally don't define extra colorings unless
200: // for example loading a settings file from an older version
201: // of Netbeans (or in a completely new profile!!). In this case
202: // try simple heuristic for translating the name and if it does
203: // not work leave the name alone.
204: int idx = name.indexOf('-'); //NOI18N
205: if (idx != -1) {
206: translatedName = name.substring(idx + 1);
207: previous = fontsColorsMap.get(translatedName);
208: if (previous != null) {
209: // heuristics worked, fix the name and load the coloring
210: as.addAttribute(
211: StyleConstants.NameAttribute,
212: translatedName);
213: name = translatedName;
214: }
215: }
216: }
217:
218: if (previous == null) {
219: // Find display name
220: String displayName = findDisplayName(name,
221: settingFile, filesForLocalization);
222:
223: if (displayName == null && !modulesFile) {
224: if (translatedName != null) {
225: displayName = findDisplayName(
226: translatedName, settingFile,
227: filesForLocalization);
228: }
229: if (displayName == null) {
230: // This coloring came from a user (no modules equivalent)
231: // and has no suitable display name. Probably an obsolete
232: // coloring from previous version, we will ignore it.
233: if (LOG.isLoggable(Level.FINE)) {
234: LOG
235: .fine("Ignoring an extra coloring '"
236: + name
237: + "' that was not defined by modules."); //NOI18N
238: }
239: continue;
240: } else {
241: // fix the name
242: as.addAttribute(
243: StyleConstants.NameAttribute,
244: translatedName);
245: name = translatedName;
246: }
247: }
248:
249: if (displayName == null) {
250: displayName = name;
251: }
252:
253: as.addAttribute(EditorStyleConstants.DisplayName,
254: displayName);
255: as.addAttribute(ATTR_MODULE_SUPPLIED, modulesFile);
256:
257: fontsColorsMap.put(name, as);
258: } else {
259: // the scanner alwyas returns modules files first, followed by user files
260: // when a coloring was defined in a user file it must not be merged
261: // with its default version supplied by modules
262: boolean moduleSupplied = (Boolean) previous
263: .getAttribute(ATTR_MODULE_SUPPLIED);
264: if (moduleSupplied == modulesFile) {
265: mergeAttributeSets(previous, as);
266: } else {
267: // Copy over the display name and the link to the default coloring
268: as
269: .addAttribute(
270: EditorStyleConstants.DisplayName,
271: previous
272: .getAttribute(EditorStyleConstants.DisplayName));
273: Object df = previous
274: .getAttribute(EditorStyleConstants.Default);
275: if (df != null) {
276: as.addAttribute(
277: EditorStyleConstants.Default, df);
278: }
279: as.addAttribute(ATTR_MODULE_SUPPLIED,
280: modulesFile);
281:
282: fontsColorsMap.put(name, as);
283: }
284: }
285: }
286: }
287:
288: return Utils.immutize(fontsColorsMap, ATTR_MODULE_SUPPLIED);
289: }
290:
291: public boolean save(MimePath mimePath, String profile,
292: boolean defaults,
293: final Map<String, AttributeSet> fontColors,
294: final Map<String, AttributeSet> defaultFontColors)
295: throws IOException {
296: assert mimePath != null : "The parameter mimePath must not be null"; //NOI18N
297: assert profile != null : "The parameter profile must not be null"; //NOI18N
298:
299: final FileSystem sfs = Repository.getDefault()
300: .getDefaultFileSystem();
301: final String settingFileName = SettingsType.getLocator(this )
302: .getWritableFileName(
303: mimePath.getPath(),
304: profile,
305: tokenColoringStorage ? "-tokenColorings"
306: : "-highlights", //NOI18N
307: defaults);
308:
309: sfs.runAtomicAction(new FileSystem.AtomicAction() {
310: public void run() throws IOException {
311: FileObject baseFolder = sfs.findResource("Editors"); //NOI18N
312: FileObject f = FileUtil.createData(baseFolder,
313: settingFileName);
314: f.setAttribute(FA_TYPE,
315: tokenColoringStorage ? FAV_TOKEN
316: : FAV_HIGHLIGHT);
317:
318: Map<String, AttributeSet> added = new HashMap<String, AttributeSet>();
319: Map<String, AttributeSet> removed = new HashMap<String, AttributeSet>();
320: Utils.diff(defaultFontColors, fontColors, added,
321: removed);
322:
323: ColoringsWriter writer = new ColoringsWriter();
324: writer.setAdded(added);
325: writer.setRemoved(removed.keySet());
326:
327: Utils.save(f, writer);
328: }
329: });
330:
331: return true; // reset the cache, to force reloading from files next time colorings are accessed
332: }
333:
334: public void delete(MimePath mimePath, String profile,
335: boolean defaults) throws IOException {
336: assert mimePath != null : "The parameter mimePath must not be null"; //NOI18N
337: assert profile != null : "The parameter profile must not be null"; //NOI18N
338:
339: FileSystem sfs = Repository.getDefault().getDefaultFileSystem();
340: FileObject baseFolder = sfs.findResource("Editors"); //NOI18N
341: Map<String, List<Object[]>> files = new HashMap<String, List<Object[]>>();
342: SettingsType.getLocator(this ).scan(baseFolder,
343: mimePath.getPath(), profile, true, defaults, !defaults,
344: false, files);
345:
346: assert files.size() <= 1 : "Too many results in the scan"; //NOI18N
347:
348: final List<Object[]> profileInfos = files.get(profile);
349: if (profileInfos != null) {
350: sfs.runAtomicAction(new FileSystem.AtomicAction() {
351: public void run() throws IOException {
352: for (Object[] info : profileInfos) {
353: FileObject settingFile = (FileObject) info[1];
354:
355: // Skip files with wrong type of colorings
356: boolean isTokenColoringFile = isTokenColoringFile(settingFile);
357: if (isTokenColoringFile != tokenColoringStorage) {
358: continue;
359: }
360:
361: settingFile.delete();
362: }
363: }
364: });
365: }
366: }
367:
368: // ---------------------------------------------------------
369: // private implementation
370: // ---------------------------------------------------------
371:
372: private static final String HIGHLIGHTING_FILE_NAME = "editorColoring.xml"; // NOI18N
373:
374: private static final String E_ROOT = "fontscolors"; //NOI18N
375: private static final String E_FONTCOLOR = "fontcolor"; //NOI18N
376: private static final String E_FONT = "font"; //NOI18N
377: private static final String A_NAME = "name"; //NOI18N
378: private static final String A_FOREGROUND = "foreColor"; //NOI18N
379: private static final String A_BACKGROUND = "bgColor"; //NOI18N
380: private static final String A_STRIKETHROUGH = "strikeThrough"; //NOI18N
381: private static final String A_WAVEUNDERLINE = "waveUnderlined"; //NOI18N
382: private static final String A_UNDERLINE = "underline"; //NOI18N
383: private static final String A_DEFAULT = "default"; //NOI18N
384: private static final String A_SIZE = "size"; //NOI18N
385: private static final String A_STYLE = "style"; //NOI18N
386: private static final String V_BOLD_ITALIC = "bold+italic"; //NOI18N
387: private static final String V_BOLD = "bold"; //NOI18N
388: private static final String V_ITALIC = "italic"; //NOI18N
389: private static final String V_PLAIN = "plain"; //NOI18N
390:
391: private static final String PUBLIC_ID = "-//NetBeans//DTD Editor Fonts and Colors settings 1.1//EN"; //NOI18N
392: private static final String SYSTEM_ID = "http://www.netbeans.org/dtds/EditorFontsColors-1_1.dtd"; //NOI18N
393:
394: private static final String FA_TYPE = "nbeditor-settings-ColoringType"; //NOI18N
395: private static final String FAV_TOKEN = "token"; //NOI18N
396: private static final String FAV_HIGHLIGHT = "highlight"; //NOI18N
397:
398: private static final Object ATTR_MODULE_SUPPLIED = new Object();
399:
400: private final boolean tokenColoringStorage;
401:
402: private static String findDisplayName(String name,
403: FileObject settingFile, List<Object[]> filesForLocalization) {
404: // Try the settingFile first
405: String displayName = Utils.getLocalizedName(settingFile, name,
406: null, true);
407:
408: // Then try all module files from the default profile
409: if (displayName == null) {
410: for (Object[] locFileInfo : filesForLocalization) {
411: FileObject locFile = (FileObject) locFileInfo[1];
412: displayName = Utils.getLocalizedName(locFile, name,
413: null, true);
414: if (displayName != null) {
415: break;
416: }
417: }
418: }
419:
420: return displayName;
421: }
422:
423: private static void mergeAttributeSets(SimpleAttributeSet original,
424: AttributeSet toMerge) {
425: for (Enumeration names = toMerge.getAttributeNames(); names
426: .hasMoreElements();) {
427: Object key = names.nextElement();
428: Object value = toMerge.getAttribute(key);
429: original.addAttribute(key, value);
430: }
431: }
432:
433: private static class ColoringsReader extends
434: StorageReader<String, SimpleAttributeSet> {
435:
436: private final Map<String, SimpleAttributeSet> colorings = new HashMap<String, SimpleAttributeSet>();
437: private SimpleAttributeSet attribs = null;
438:
439: public ColoringsReader(FileObject f, String mimePath) {
440: super (f, mimePath);
441: }
442:
443: public @Override
444: Map<String, SimpleAttributeSet> getAdded() {
445: return colorings;
446: }
447:
448: public @Override
449: Set<String> getRemoved() {
450: return Collections.<String> emptySet();
451: }
452:
453: public @Override
454: void startElement(String uri, String localName, String name,
455: Attributes attributes) throws SAXException {
456: try {
457: if (name.equals(E_ROOT)) {
458: // We don't read anythhing from the root element
459:
460: } else if (name.equals(E_FONTCOLOR)) {
461: assert attribs == null;
462: attribs = new SimpleAttributeSet();
463: String value;
464:
465: String nameAttributeValue = attributes
466: .getValue(A_NAME);
467: attribs.addAttribute(StyleConstants.NameAttribute,
468: nameAttributeValue);
469:
470: value = attributes.getValue(A_BACKGROUND);
471: if (value != null) {
472: attribs.addAttribute(StyleConstants.Background,
473: stringToColor(value));
474: }
475:
476: value = attributes.getValue(A_FOREGROUND);
477: if (value != null) {
478: attribs.addAttribute(StyleConstants.Foreground,
479: stringToColor(value));
480: }
481:
482: value = attributes.getValue(A_UNDERLINE);
483: if (value != null) {
484: attribs.addAttribute(StyleConstants.Underline,
485: stringToColor(value));
486: }
487:
488: value = attributes.getValue(A_STRIKETHROUGH);
489: if (value != null) {
490: attribs.addAttribute(
491: StyleConstants.StrikeThrough,
492: stringToColor(value));
493: }
494:
495: value = attributes.getValue(A_WAVEUNDERLINE);
496: if (value != null) {
497: attribs
498: .addAttribute(
499: EditorStyleConstants.WaveUnderlineColor,
500: stringToColor(value));
501: }
502:
503: value = attributes.getValue(A_DEFAULT);
504: if (value != null) {
505: attribs.addAttribute(
506: EditorStyleConstants.Default, value);
507: }
508:
509: colorings.put(nameAttributeValue, attribs);
510:
511: } else if (name.equals(E_FONT)) {
512: assert attribs != null;
513: String value;
514:
515: value = attributes.getValue(A_NAME);
516: if (value != null) {
517: attribs.addAttribute(StyleConstants.FontFamily,
518: value);
519: }
520:
521: value = attributes.getValue(A_SIZE);
522: if (value != null) {
523: try {
524: attribs.addAttribute(
525: StyleConstants.FontSize, Integer
526: .decode(value));
527: } catch (NumberFormatException ex) {
528: LOG
529: .log(
530: Level.WARNING,
531: value
532: + " is not a valid Integer; parsing attribute "
533: + A_SIZE + //NOI18N
534: getProcessedFile()
535: .getPath(),
536: ex);
537: }
538: }
539:
540: value = attributes.getValue(A_STYLE);
541: if (value != null) {
542: attribs
543: .addAttribute(StyleConstants.Bold,
544: Boolean.valueOf(value
545: .indexOf(V_BOLD) >= 0));
546: attribs
547: .addAttribute(
548: StyleConstants.Italic,
549: Boolean
550: .valueOf(value
551: .indexOf(V_ITALIC) >= 0));
552: }
553: }
554: } catch (Exception ex) {
555: LOG.log(Level.WARNING, "Can't parse colorings file "
556: + getProcessedFile().getPath(), ex); //NOI18N
557: }
558: }
559:
560: public @Override
561: void endElement(String uri, String localName, String name)
562: throws SAXException {
563: if (name.equals(E_FONTCOLOR)) {
564: // reset the attribs
565: attribs = null;
566: }
567: }
568: } // End of ColoringsReader class
569:
570: private static final class ColoringsWriter extends
571: StorageWriter<String, AttributeSet> {
572:
573: public ColoringsWriter() {
574: super ();
575: }
576:
577: public Document getDocument() {
578: Document doc = XMLUtil.createDocument(E_ROOT, null,
579: PUBLIC_ID, SYSTEM_ID);
580: Node root = doc.getElementsByTagName(E_ROOT).item(0);
581:
582: for (AttributeSet category : getAdded().values()) {
583: Element fontColor = doc.createElement(E_FONTCOLOR);
584: root.appendChild(fontColor);
585: fontColor.setAttribute(A_NAME, (String) category
586: .getAttribute(StyleConstants.NameAttribute));
587:
588: if (category.isDefined(StyleConstants.Foreground)) {
589: fontColor
590: .setAttribute(
591: A_FOREGROUND,
592: colorToString((Color) category
593: .getAttribute(StyleConstants.Foreground)));
594: }
595: if (category.isDefined(StyleConstants.Background)) {
596: fontColor
597: .setAttribute(
598: A_BACKGROUND,
599: colorToString((Color) category
600: .getAttribute(StyleConstants.Background)));
601: }
602: if (category.isDefined(StyleConstants.StrikeThrough)) {
603: fontColor
604: .setAttribute(
605: A_STRIKETHROUGH,
606: colorToString((Color) category
607: .getAttribute(StyleConstants.StrikeThrough)));
608: }
609: if (category
610: .isDefined(EditorStyleConstants.WaveUnderlineColor)) {
611: fontColor
612: .setAttribute(
613: A_WAVEUNDERLINE,
614: colorToString((Color) category
615: .getAttribute(EditorStyleConstants.WaveUnderlineColor)));
616: }
617: if (category.isDefined(StyleConstants.Underline)) {
618: fontColor
619: .setAttribute(
620: A_UNDERLINE,
621: colorToString((Color) category
622: .getAttribute(StyleConstants.Underline)));
623: }
624: if (category.isDefined(EditorStyleConstants.Default)) {
625: fontColor
626: .setAttribute(
627: A_DEFAULT,
628: (String) category
629: .getAttribute(EditorStyleConstants.Default));
630: }
631:
632: if (category.isDefined(StyleConstants.FontFamily)
633: || category.isDefined(StyleConstants.FontSize)
634: || category.isDefined(StyleConstants.Bold)
635: || category.isDefined(StyleConstants.Italic)) {
636: Element font = doc.createElement(E_FONT);
637: fontColor.appendChild(font);
638:
639: if (category.isDefined(StyleConstants.FontFamily)) {
640: font
641: .setAttribute(
642: A_NAME,
643: (String) category
644: .getAttribute(StyleConstants.FontFamily));
645: }
646: if (category.isDefined(StyleConstants.FontSize)) {
647: font.setAttribute(A_SIZE, ((Integer) category
648: .getAttribute(StyleConstants.FontSize))
649: .toString());
650: }
651: if (category.isDefined(StyleConstants.Bold)
652: || category
653: .isDefined(StyleConstants.Italic)) {
654: Boolean bold = Boolean.FALSE, italic = Boolean.FALSE;
655:
656: if (category.isDefined(StyleConstants.Bold)) {
657: bold = (Boolean) category
658: .getAttribute(StyleConstants.Bold);
659: }
660: if (category.isDefined(StyleConstants.Italic)) {
661: italic = (Boolean) category
662: .getAttribute(StyleConstants.Italic);
663: }
664:
665: font.setAttribute(A_STYLE,
666: bold.booleanValue() ? (italic
667: .booleanValue() ? V_BOLD_ITALIC
668: : V_BOLD) : (italic
669: .booleanValue() ? V_ITALIC
670: : V_PLAIN));
671: }
672: }
673: }
674:
675: return doc;
676: }
677: } // End of ColoringsWriter class
678:
679: private static boolean isTokenColoringFile(FileObject f) {
680: Object typeValue = f.getAttribute(FA_TYPE);
681: if (typeValue instanceof String) {
682: return typeValue.equals(FAV_TOKEN);
683: } else {
684: return !f.getNameExt().equals(HIGHLIGHTING_FILE_NAME);
685: }
686: }
687:
688: private static final Map<Color, String> colorToName = new HashMap<Color, String>();
689: private static final Map<String, Color> nameToColor = new HashMap<String, Color>();
690:
691: static {
692: colorToName.put(Color.black, "black");
693: nameToColor.put("black", Color.black);
694: colorToName.put(Color.blue, "blue");
695: nameToColor.put("blue", Color.blue);
696: colorToName.put(Color.cyan, "cyan");
697: nameToColor.put("cyan", Color.cyan);
698: colorToName.put(Color.darkGray, "darkGray");
699: nameToColor.put("darkGray", Color.darkGray);
700: colorToName.put(Color.gray, "gray");
701: nameToColor.put("gray", Color.gray);
702: colorToName.put(Color.green, "green");
703: nameToColor.put("green", Color.green);
704: colorToName.put(Color.lightGray, "lightGray");
705: nameToColor.put("lightGray", Color.lightGray);
706: colorToName.put(Color.magenta, "magenta");
707: nameToColor.put("magenta", Color.magenta);
708: colorToName.put(Color.orange, "orange");
709: nameToColor.put("orange", Color.orange);
710: colorToName.put(Color.pink, "pink");
711: nameToColor.put("pink", Color.pink);
712: colorToName.put(Color.red, "red");
713: nameToColor.put("red", Color.red);
714: colorToName.put(Color.white, "white");
715: nameToColor.put("white", Color.white);
716: colorToName.put(Color.yellow, "yellow");
717: nameToColor.put("yellow", Color.yellow);
718: }
719:
720: private static String colorToString(Color color) {
721: if (colorToName.containsKey(color))
722: return (String) colorToName.get(color);
723: return Integer.toHexString(color.getRGB());
724: }
725:
726: private static Color stringToColor(String color) throws Exception {
727: if (nameToColor.containsKey(color))
728: return (Color) nameToColor.get(color);
729: try {
730: return new Color((int) Long.parseLong(color, 16));
731: } catch (NumberFormatException ex) {
732: throw new Exception();
733: }
734: }
735: }
|