001: /*
002: * Copyright (c) 2001, Jacob Smullyan.
003: *
004: * This is part of SkunkDAV, a WebDAV client. See http://skunkdav.sourceforge.net/
005: * for the latest version.
006: *
007: * SkunkDAV is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License as published
009: * by the Free Software Foundation; either version 2, or (at your option)
010: * any later version.
011: *
012: * SkunkDAV is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with SkunkDAV; see the file COPYING. If not, write to the Free
019: * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
020: * 02111-1307, USA.
021: */
022:
023: package org.skunk.swing.text.syntax;
024:
025: import java.io.BufferedReader;
026: import java.io.BufferedWriter;
027: import java.io.IOException;
028: import java.io.InputStream;
029: import java.io.InputStreamReader;
030: import java.io.Serializable;
031: import java.io.StringReader;
032: import java.io.StringWriter;
033: import java.util.HashMap;
034: import java.util.Iterator;
035: import java.util.StringTokenizer;
036: import org.skunk.trace.Debug;
037:
038: public class FileMode implements Serializable {
039: static final long serialVersionUID = 8155220627611660623L;
040:
041: private String modeName;
042: private String[] extensions;
043: private static ModeMapContainer modeMapContainer;
044: private boolean shouldHighlight = true;
045: private boolean canHighlight = false;
046:
047: static {
048: modeMapContainer = new ModeMapContainer();
049: initDefaultModes(modeMapContainer);
050: }
051:
052: public static void initDefaultModes(ModeMapContainer container) {
053: InputStream in = FileMode.class
054: .getResourceAsStream("default.modes");
055: BufferedReader breader = new BufferedReader(
056: new InputStreamReader(in));
057: try {
058: container.readConfig(breader);
059: } catch (IOException oyVeh) {
060: if (Debug.DEBUG) {
061: Debug.trace(FileMode.class, Debug.DP2, oyVeh);
062: }
063: }
064: // container.clear();
065: // FileMode javaMode=container.getMode("java", true);
066: // javaMode.addExtension(".java");
067: // javaMode.canHighlight=true;
068: // FileMode plainMode=container.getMode("plain", true);
069: // plainMode.setShouldHighlight(false);
070: // plainMode.addExtension(".txt");
071: // plainMode.canHighlight=false;
072: // FileMode pythonMode=container.getMode("python", true);
073: // pythonMode.setShouldHighlight(true);
074: // pythonMode.addExtension(".py");
075: // pythonMode.canHighlight=true;
076: // FileMode HtmlMode=container.getMode("HTML", true);
077: // HtmlMode.setShouldHighlight(true);
078: // HtmlMode.canHighlight=true;
079: // HtmlMode.addExtensions(new String[] {".html", ".htm"});
080: // FileMode StmlMode=container.getMode("STML", true);
081: // StmlMode.canHighlight=true;
082: // StmlMode.setShouldHighlight(true);
083: // StmlMode.addExtensions(new String[] {".comp", ".dcmp"});
084: // FileMode javascriptMode=container.getMode("javascript", true);
085: // javascriptMode.addExtension(".js");
086: // javascriptMode.canHighlight=true;
087: // javascriptMode.setShouldHighlight(true);
088: }
089:
090: public static ModeMapContainer getModeMapContainer() {
091: return modeMapContainer;
092: }
093:
094: public static FileMode getMode(String modeName, boolean create) {
095: return FileMode.modeMapContainer.getMode(modeName, create);
096: }
097:
098: public static FileMode getMode(String modeName) {
099: return FileMode.modeMapContainer.getMode(modeName, true);
100: }
101:
102: public static FileMode getModeForFilename(String filename) {
103: return FileMode.modeMapContainer.getModeForFilename(filename);
104: }
105:
106: public final static Iterator modes() {
107: return FileMode.modeMapContainer.modes();
108: }
109:
110: public final static Iterator modeNames() {
111: return FileMode.modeMapContainer.modeNames();
112: }
113:
114: private FileMode(String modeName, String[] extensions) {
115: this .modeName = modeName;
116: this .extensions = extensions;
117: }
118:
119: public final String getName() {
120: return modeName;
121: }
122:
123: public final String[] getExtensions() {
124: return this .extensions;
125: }
126:
127: public final boolean getShouldHighlight() {
128: return this .shouldHighlight;
129: }
130:
131: public final void setShouldHighlight(boolean shouldHighlight) {
132: this .shouldHighlight = shouldHighlight;
133: }
134:
135: public final boolean getCanHighlight() {
136: return this .canHighlight;
137: }
138:
139: public final void addExtension(String extension) {
140: if (extensions == null) {
141: extensions = new String[] { extension };
142: } else {
143: String[] tmp = extensions;
144: int oldLen = tmp.length;
145: extensions = new String[oldLen + 1];
146: System.arraycopy(tmp, 0, extensions, 0, oldLen);
147: extensions[oldLen] = extension;
148: }
149: }
150:
151: public final void addExtensions(String[] extensionArray) {
152: int newLen = extensionArray.length;
153: if (extensions == null) {
154: extensions = new String[newLen];
155: System.arraycopy(extensionArray, 0, extensions, 0, newLen);
156: } else {
157: String[] tmp = extensions;
158: int oldLen = tmp.length;
159: extensions = new String[oldLen + extensionArray.length];
160: System.arraycopy(tmp, 0, extensions, 0, oldLen);
161: System.arraycopy(extensionArray, 0, extensions, oldLen,
162: newLen);
163: }
164: }
165:
166: public final void removeExtension(String extension) {
167: if (extensions != null) {
168: int extIsReal = -1;
169: for (int i = 0; i < extensions.length; i++) {
170: if (extensions[i].equals(extension)) {
171: extIsReal = i;
172: break;
173: }
174: }
175: if (extIsReal < 0)
176: return;
177: String[] tmp = new String[extensions.length - 1];
178: System.arraycopy(extensions, 0, tmp, 0, extIsReal);
179: System.arraycopy(extensions, extIsReal + 1, tmp, extIsReal,
180: tmp.length - extIsReal);
181: extensions = tmp;
182: }
183: }
184:
185: public final String toString() {
186: StringBuffer sb = new StringBuffer("FileMode ")
187: .append(modeName).append(" [");
188: if (extensions != null) {
189: for (int i = 0; i < extensions.length; i++) {
190: if (i > 0)
191: sb.append(", ");
192: sb.append("\"");
193: sb.append(extensions[i]);
194: sb.append("\"");
195: }
196: }
197: sb.append("]");
198: return sb.toString();
199: }
200:
201: public final int hashCode() {
202: return modeName.hashCode();
203: }
204:
205: /**
206: * wrapper for static member, for configuration package
207: */
208: public static final class ModeMapContainer implements Serializable {
209: static final long serialVersionUID = 507341428772651975L;
210: public static final String MODE_MAP_PROPERTY = "modeMap";
211: public static final String CONFIG_DATA_PROPERTY = "configData";
212: private static final String CONFIG_BOILERPLATE = "###############################################################"
213: + "\n"
214: + "# MODE SHOULD_HIGHLIGHT CAN_HIGHLIGHT EXTENSIONS #"
215: + "\n"
216: + "###############################################################"
217: + "\n";
218: private static final int CONFIG_TAB_SIZE = 17;
219:
220: private HashMap modeMap;
221:
222: public ModeMapContainer(HashMap modeMap) {
223: setModeMap(modeMap);
224: }
225:
226: public ModeMapContainer() {
227: this (new HashMap());
228: }
229:
230: public final HashMap getModeMap() {
231: return modeMap;
232: }
233:
234: public final void setModeMap(HashMap modeMap) {
235: this .modeMap = modeMap;
236: }
237:
238: public final FileMode getMode(String modeName, boolean create) {
239: if (this .modeMap.containsKey(modeName))
240: return (FileMode) this .modeMap.get(modeName);
241: else if (create) {
242: FileMode fm = new FileMode(modeName, null);
243: this .modeMap.put(modeName, fm);
244: return fm;
245: } else
246: return null;
247: }
248:
249: public final FileMode getMode(String modeName) {
250: return this .getMode(modeName, true);
251: }
252:
253: public final FileMode getModeForFilename(String filename) {
254: for (Iterator it = modeMap.keySet().iterator(); it
255: .hasNext();) {
256: Object fmkey = it.next();
257: FileMode fm = (FileMode) modeMap.get(fmkey);
258: String[] exts = fm.getExtensions();
259: if (exts == null)
260: continue;
261: for (int i = 0; i < exts.length; i++) {
262: if (filename.endsWith(exts[i]))
263: return fm;
264: }
265: }
266: return null;
267: }
268:
269: public final Iterator modes() {
270: return this .modeMap.values().iterator();
271: }
272:
273: public final Iterator modeNames() {
274: return modeMap.keySet().iterator();
275: }
276:
277: protected final void clear() {
278: this .modeMap.clear();
279: }
280:
281: public final String getConfigData() {
282: StringWriter sw = new StringWriter();
283: try {
284: writeConfig(new BufferedWriter(sw));
285: } catch (IOException oyVeh) {
286: return null;
287: }
288: return sw.getBuffer().toString();
289: }
290:
291: public final void setConfigData(String configData,
292: boolean clearOut) {
293: if (clearOut)
294: clear();
295: setConfigData(configData);
296: }
297:
298: public final void setConfigData(String configData) {
299: StringReader sr = new StringReader(configData);
300: try {
301: readConfig(new BufferedReader(sr));
302: } catch (IOException oyVeh) {
303: //will already be logged
304: }
305: }
306:
307: /**
308: * writes the state of the file mode set in a config file format to the stream.
309: * @param brighter the stream to which to write
310: */
311: public void writeConfig(BufferedWriter brighter)
312: throws IOException {
313: StringBuffer sb = new StringBuffer(CONFIG_BOILERPLATE);
314: for (Iterator it = modeMap.keySet().iterator(); it
315: .hasNext();) {
316: FileMode fm = (FileMode) modeMap.get(it.next());
317: sb.append(pad(fm.getName(), CONFIG_TAB_SIZE));
318: sb.append(pad(new Boolean(fm.getShouldHighlight())
319: .toString(), CONFIG_TAB_SIZE));
320: sb.append(pad(new Boolean(fm.getCanHighlight())
321: .toString(), CONFIG_TAB_SIZE));
322: String[] ext = fm.getExtensions();
323: for (int i = 0; i < ext.length; i++) {
324: if (i > 0)
325: sb.append(" ");
326: sb.append(ext[i]);
327: }
328: sb.append("\n");
329: }
330: try {
331: brighter.write(sb.toString(), 0, sb.length());
332: brighter.flush();
333: brighter.close();
334: } catch (IOException oyVeh) {
335: if (Debug.DEBUG)
336: Debug.trace(this , Debug.DP2, oyVeh);
337: throw oyVeh;
338: }
339: }
340:
341: private String pad(String s, int length) {
342: StringBuffer sb = new StringBuffer(s);
343: while (sb.length() < length)
344: sb.append(" ");
345: return sb.toString();
346: }
347:
348: /**
349: * sets the mode set according the config information in the stream,
350: * in the same format generated by writeConfig (and in "default.modes", the
351: * default config file).
352: * @param breader the stream from which to read the config information.
353: */
354: public void readConfig(BufferedReader breader)
355: throws IOException {
356: clear();
357: try {
358: String line;
359: while ((line = breader.readLine()) != null) {
360: if (line.trim().startsWith("#"))
361: continue;
362: StringTokenizer st = new StringTokenizer(line);
363: String name = st.nextToken();
364: boolean should = new Boolean(st.nextToken())
365: .booleanValue();
366: boolean can = new Boolean(st.nextToken())
367: .booleanValue();
368: String[] exts = new String[st.countTokens()];
369: for (int i = 0; i < exts.length; i++) {
370: exts[i] = st.nextToken();
371: }
372: FileMode tmp = getMode(name, true);
373: tmp.setShouldHighlight(should);
374: tmp.canHighlight = can;
375: tmp.addExtensions(exts);
376: }
377: } catch (Exception oyVeh) {
378: if (Debug.DEBUG)
379: Debug.trace(ModeMapContainer.class, Debug.DP2,
380: oyVeh);
381: throw new IOException(oyVeh.getMessage());
382: }
383: }
384: }
385: }
386:
387: /* $Log: FileMode.java,v $
388: /* Revision 1.9 2001/02/16 18:15:10 smulloni
389: /* many fixes to TextEditorCustomizer. FileMode and SyntaxStyle now have a
390: /* configData property (they will probably be made into sibling classes).
391: /*
392: /* Revision 1.8 2001/02/14 21:41:19 smulloni
393: /* added javascript mode.
394: /*
395: /* Revision 1.7 2001/02/13 22:53:50 smulloni
396: /* adding a syntax highlighting mode for STML (Skunk Template Markup Language);
397: /* fixed a bug in SyntaxStyle in reading default.styles.
398: /*
399: /* Revision 1.6 2001/02/09 21:02:37 smulloni
400: /* added very primitive html mode.
401: /*
402: /* Revision 1.5 2001/02/08 20:23:43 smulloni
403: /* added a python mode
404: /*
405: /* Revision 1.4 2001/02/06 22:13:41 smulloni
406: /* first more-or-less working version of syntax highlighting, with customization.
407: /*
408: /* Revision 1.3 2001/02/06 00:11:18 smulloni
409: /* struggle, perhaps futile, with the TextEditorCustomizer and other implicated
410: /* classes
411: /*
412: /* Revision 1.2 2001/02/02 23:30:33 smulloni
413: /* adding customization features to the text editor.
414: /*
415: /* Revision 1.1 2001/01/30 23:05:09 smulloni
416: /* beginning of integration of syntax highlighting package into SimpleTextEditor.
417: /* */
|