KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > AbstractMode


1 /*
2  * AbstractMode.java
3  *
4  * Copyright (C) 1998-2003 Peter Graves
5  * $Id: AbstractMode.java,v 1.20 2003/10/15 14:52:25 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j;
23
24 import java.awt.Color JavaDoc;
25 import java.awt.event.MouseEvent JavaDoc;
26 import java.util.List JavaDoc;
27 import javax.swing.JCheckBoxMenuItem JavaDoc;
28 import javax.swing.JMenuItem JavaDoc;
29 import javax.swing.JPopupMenu JavaDoc;
30
31 /**
32  * <p>
33  * AbstractMode provides an interface for implementing specific modes. A mode
34  * is a set of rules to define the way that the editor behaves. This includes
35  * key mappings, menu generation, context menu handling, toolbar generation, a
36  * sidebar component, tooltips, colors, indentation, and general properties.
37  * All modes should extend AbstractMode and are encouraged to override the
38  * methods that are pertinent to that mode. The default implementation given
39  * in AbstractMode will suffice for the rest.
40  * </p>
41  * <p>
42  * Any class extending AbstractMode must add its id and displayName to the
43  * <code>Constants</code> class.
44  * </p>
45  *
46  * ***More on overriding AbstractMode goes here***
47  *
48  * @future #createBuffer(File)
49  *
50  * @see Constants
51  */

52 public abstract class AbstractMode implements Constants, Mode
53 {
54     private static final Preferences preferences = Editor.preferences();
55
56     protected KeyMap keyMap;
57     protected File keyMapFile;
58     protected PropertyList properties;
59     protected Keywords keywords;
60
61     private final int id;
62     private final String JavaDoc displayName;
63
64     protected AbstractMode(int id, String JavaDoc displayName)
65     {
66         this.id = id;
67         this.displayName = displayName;
68         if (Editor.isLispInitialized()) {
69             String JavaDoc hook =
70                 displayName.toLowerCase().replace(' ', '-') + "-mode-hook";
71             Editor.invokeHook(hook);
72         }
73     }
74
75     /**
76      * Returns the unique identifier of this mode. All ids should be defined
77      * in <code>Constants</code>.
78      *
79      * @return The unique identifier of this mode.
80      * @see Constants
81      */

82     public final int getId()
83     {
84         return id;
85     }
86
87     /**
88      * Returns the display name of this mode. Display names should be defined
89      * in <code>Constants</code>.
90      *
91      * @return The display name of this mode.
92      * @see Constants
93      */

94     public final String JavaDoc getDisplayName()
95     {
96         return displayName;
97     }
98
99     /**
100      * Creates a Buffer for the given <code>File</code>. For now, all this
101      * implementation does is return null.
102      *
103      * @future Currently most of the code for creating buffers lies in
104      * Buffer.createBuffer. Ideally, this default implementation
105      * would create a Buffer for the "normal" case, and each mode
106      * that requires a specific Buffer would override this method.
107      *
108      * @param file
109      * @return null
110      * @see org.armedbear.j.mail.SendMailMode#createBuffer(File)
111      */

112     public Buffer createBuffer(File file)
113     {
114         return null;
115     }
116
117     /**
118      * Returns a <code>Formatter</code> for the given <code>Buffer</code>.
119      *
120      * @param buffer The <code>Buffer</code> that is to be formatted
121      * according to this mode.
122      * @return A <code>Formatter</code> for the given mode.
123      * (The default is a PlainTextFormatter.)
124      */

125     public Formatter getFormatter(Buffer buffer)
126     {
127         return new PlainTextFormatter(buffer);
128     }
129
130     /**
131      * Returns the display name for this mode.
132      *
133      * @return The display name for this mode.
134      */

135     public final String JavaDoc toString()
136     {
137         return displayName;
138     }
139
140     // Should never return null.
141
public synchronized final KeyMap getKeyMap()
142     {
143         if (keyMap == null) {
144             if (!loadKeyMapForMode()) {
145                 keyMap = new KeyMap();
146                 setKeyMapDefaults(keyMap);
147             }
148         }
149         return keyMap;
150     }
151
152     private boolean loadKeyMapForMode()
153     {
154         keyMap = null;
155         String JavaDoc filename = preferences.getStringProperty(getFullKey("keyMap"));
156         if (filename != null) {
157             keyMapFile = File.getInstance(filename);
158             if (keyMapFile != null) {
159                 keyMap = new KeyMap();
160                 if (keyMap.load(keyMapFile))
161                     return true;
162             }
163         }
164         keyMap = null;
165         keyMapFile = null;
166         return false;
167     }
168
169     protected void setKeyMapDefaults(KeyMap km)
170     {
171         // Default implementation just leaves keymap empty.
172
}
173
174     public File getKeyMapFile()
175     {
176         return keyMapFile;
177     }
178
179     public synchronized final void useDefaultKeyMap()
180     {
181         keyMap = new KeyMap();
182         setKeyMapDefaults(keyMap);
183     }
184
185     public synchronized final void deleteKeyMap()
186     {
187         keyMap = null;
188     }
189
190     public String JavaDoc getMenuName()
191     {
192         return "Default";
193     }
194
195     public MenuBar createMenuBar(Frame frame)
196     {
197         MenuBar menuBar = new MenuBar("Default");
198         menuBar.add(new Menu("File", 'F'));
199         menuBar.add(new Menu("Edit", 'E'));
200         menuBar.add(new Menu("View", 'V'));
201         menuBar.add(new Menu("Search", 'S'));
202         menuBar.add(new Menu("Go", 'G'));
203         menuBar.add(new Menu("Mode", 'M'));
204         menuBar.add(new Menu("Lisp", 'L'));
205         menuBar.add(new Menu("Help", 'H'));
206         return menuBar;
207     }
208
209     public void populateMenu(Editor editor, Menu menu)
210     {
211         final String JavaDoc text = menu.getText();
212         if (text == "File")
213             populateFileMenu(editor, menu);
214         else if (text == "Edit")
215             populateEditMenu(editor, menu);
216         else if (text == "View")
217             populateViewMenu(editor, menu);
218         else if (text == "Search")
219             populateSearchMenu(editor, menu);
220         else if (text == "Go")
221             populateGoMenu(editor, menu);
222         else if (text == "Mode") {
223             populateModeMenu(editor, menu);
224             if (menu.getMenuComponentCount() == 0)
225                 menu.add(new JMenuItem JavaDoc("This menu isn't here yet!")).setEnabled(false);
226         } else if (text == "Lisp")
227             populateLispMenu(editor, menu);
228         else if (text == "Help")
229             populateHelpMenu(editor, menu);
230     }
231
232     private static void populateFileMenu(Editor editor, Menu menu)
233     {
234         final boolean isNotReadOnly = !editor.getBuffer().isReadOnly();
235         menu.add(editor, "New", 'N', "newBuffer");
236         menu.add(editor, "Open...", 'O', "openFile");
237         menu.add(editor, "Recent Files...", 'R', "recentFiles");
238         menu.addSeparator();
239         menu.add(editor, "Save", 'S', "save", isNotReadOnly);
240         menu.add(editor, "Save As...", 'E', "saveAs");
241         menu.add(editor, "Save a Copy...", 'Y', "saveCopy");
242         menu.add(editor, "Save All", 'A', "saveAll");
243         menu.add(editor, "Close", 'C', "killBuffer");
244         menu.add(editor, "Close All", 'L', "closeAll");
245         menu.add(editor, "Close Others", 'H', "closeOthers");
246         menu.add(editor, "Revert", 'V', "revertBuffer");
247         menu.add(editor, "Set Encoding", 'G', "setEncoding");
248         menu.addSeparator();
249         menu.add(editor, "Properties", 'I', "properties");
250         menu.addSeparator();
251         menu.add(editor, "Next Buffer", 'T', "nextBuffer");
252         menu.add(editor, "Previous Buffer", 'R', "prevBuffer");
253         menu.addSeparator();
254         menu.add(editor, "New Frame", 'M', "newFrame");
255         menu.add(editor, "Execute Command...", 'D', "executeCommand");
256         menu.addSeparator();
257         menu.add(editor, "Print...", 'P', "print");
258         menu.addSeparator();
259         menu.add(editor, "Save Session", 'S', "saveSession");
260         menu.add(editor, "Load Session...", 'L', "loadSession");
261         menu.addSeparator();
262         menu.add(editor, "Save All/Exit", '/', "saveAllExit");
263         menu.add(editor, "Exit", 'X', "quit");
264     }
265
266     private static void populateEditMenu(Editor editor, Menu menu)
267     {
268         final boolean isNotReadOnly = !editor.getBuffer().isReadOnly();
269         menu.add(editor, "Undo", 'U', "undo");
270         menu.add(editor, "Redo", 'O', "redo");
271         menu.addSeparator();
272         menu.add(editor, "Cut", 'T', "killRegion", isNotReadOnly);
273         menu.add(editor, "Cut Append", 'D', "killAppend", isNotReadOnly);
274         menu.add(editor, "Copy", 'C', "copyRegion");
275         menu.add(editor, "Copy Append", 'A', "copyAppend");
276         menu.add(editor, "Paste", 'P', "paste", isNotReadOnly);
277         menu.add(editor, "Cycle Paste", 'Y', "cyclePaste", isNotReadOnly);
278         menu.addSeparator();
279         menu.add(editor, "Cycle Tab Width", 'B', "cycleTabWidth");
280         menu.add(editor, "Cycle Indent Size", 'N', "cycleIndentSize");
281         menu.add(editor, "Indent", 'I', "indentLineOrRegion", isNotReadOnly);
282         menu.addSeparator();
283         menu.add(editor, "Upper Case", 'R', "upperCaseRegion", isNotReadOnly);
284         menu.add(editor, "Lower Case", 'L', "lowerCaseRegion", isNotReadOnly);
285     }
286
287     private static void populateViewMenu(Editor editor, Menu menu)
288     {
289         JCheckBoxMenuItem JavaDoc toolbarMenuItem = new JCheckBoxMenuItem JavaDoc("Toolbar");
290         toolbarMenuItem.setMnemonic('T');
291         toolbarMenuItem.setActionCommand("toggleToolbar");
292         toolbarMenuItem.addActionListener(editor.getDispatcher());
293         toolbarMenuItem.setSelected(editor.getFrame().getShowToolbar());
294         menu.add(toolbarMenuItem);
295         JCheckBoxMenuItem JavaDoc sidebarMenuItem = new JCheckBoxMenuItem JavaDoc("Sidebar");
296         sidebarMenuItem.setMnemonic('S');
297         sidebarMenuItem.setActionCommand("toggleSidebar");
298         sidebarMenuItem.addActionListener(editor.getDispatcher());
299         sidebarMenuItem.setSelected(editor.getSidebar() != null);
300         menu.add(sidebarMenuItem);
301         menu.addSeparator();
302         menu.add(editor, "Split Window", 'W', "splitWindow");
303         menu.add(editor, "Unsplit Window", 'U', "unsplitWindow");
304         menu.add(editor, "Close Window", 'C', "killWindow");
305     }
306
307     protected void populateSearchMenu(Editor editor, Menu menu)
308     {
309         final File dir = editor.getCurrentDirectory();
310         final boolean local = (dir != null && dir.isLocal());
311         if (Editor.preferences().getBooleanProperty(Property.USE_INCREMENTAL_FIND))
312             menu.add(editor, "Incremental Find...", 'I', "incrementalFind");
313         menu.add(editor, "Find...", 'F', "find");
314         menu.add(editor, "Find Next", 'T', "findNext");
315         menu.add(editor, "Find Previous", 'R', "findPrev");
316         menu.add(editor, "Find in Files...", 'S', "findInFiles", local);
317         menu.addSeparator();
318         menu.add(editor, "List Occurrences of Last Pattern", 'L', "listOccurrences",
319                  editor.getLastSearch() != null);
320         menu.add(editor, "List Occurrences of Pattern in Files", 'O', "listFiles",
321                  FindInFiles.getFindInFiles() != null);
322         menu.addSeparator();
323         final boolean isNotReadOnly = !editor.getBuffer().isReadOnly();
324         if (!(editor.getBuffer() instanceof Directory))
325             menu.add(editor, "Replace...", 'P', "replace", isNotReadOnly);
326         menu.add(editor, "Replace in Files...", 'E', "replaceInFiles", local);
327         if (!(editor.getBuffer() instanceof Directory)) {
328             menu.addSeparator();
329             menu.add(editor, "Find Tag...", 'A', "findTag");
330         }
331     }
332
333     private static void populateGoMenu(Editor editor, Menu menu)
334     {
335         menu.add(editor, "Go to Line...", 'L', "jumpToLine");
336         menu.add(editor, "Go to Column...", 'C', "jumpToColumn");
337         menu.add(editor, "Go to Offset...", 'O', "jumpToOffset");
338         if (editor.getModeId() == HTML_MODE)
339             menu.add(editor, "Go to Matching HTML", 'M', "htmlFindMatch");
340         else
341             menu.add(editor, "Go to Matching Character", 'M', "findMatchingChar");
342         menu.add(editor, "Go to Tag", 'A', "findTagAtDot");
343         menu.add(editor, "Go to Next Occurrence of Word", 'T', "findNextWord");
344         menu.add(editor, "Go to Previous Occurrence of Word", 'R', "findPrevWord");
345         if (editor.getBuffer().getBooleanProperty(Property.SHOW_CHANGE_MARKS)) {
346             menu.add(editor, "Go to Next Change", 'H', "nextChange");
347             menu.add(editor, "Go to Previous Change", 'G', "previousChange");
348         }
349         menu.addSeparator();
350         menu.add(editor, "Push Position", 'U', "pushPosition");
351         menu.add(editor, "Pop Position", 'P', "popPosition");
352     }
353
354     public void populateModeMenu(Editor editor, Menu menu)
355     {
356     }
357
358     public void populateLispMenu(Editor editor, Menu menu)
359     {
360         menu.add(editor, "Run Lisp as Separate Process", 'L', "lisp");
361         menu.add(editor, "Run Embedded Lisp", 'E', "jlisp");
362     }
363
364     private static void populateHelpMenu(Editor editor, Menu menu)
365     {
366         menu.add(editor, "Help", 'P', "help");
367         menu.add(editor, "Apropos...", 'A', "apropos");
368         menu.add(editor, "Key Bindings", 'B', "listBindings");
369         menu.add(editor, "Describe Key...", 'K', "describeKey");
370         menu.add(editor, "Where is...", 'W', "whereIs");
371         menu.add(editor, "About J", 'O', "about");
372     }
373
374     public JPopupMenu JavaDoc getContextMenu(Editor editor)
375     {
376         final JPopupMenu JavaDoc popup = new JPopupMenu JavaDoc();
377         addDefaultContextMenuItems(editor, popup);
378         popup.pack();
379         return popup;
380     }
381
382     protected void addDefaultContextMenuItems(Editor editor, JPopupMenu JavaDoc popup)
383     {
384         final Buffer buffer = editor.getBuffer();
385         final Dispatcher dispatcher = editor.getDispatcher();
386
387         JMenuItem JavaDoc menuItem;
388
389         if (buffer.supportsUndo()) {
390             menuItem = new JMenuItem JavaDoc();
391             menuItem.setText("Undo");
392             menuItem.setActionCommand("undo");
393             menuItem.addActionListener(dispatcher);
394             if (!buffer.canUndo())
395                 menuItem.setEnabled(false);
396             popup.add(menuItem);
397
398             menuItem = new JMenuItem JavaDoc();
399             menuItem.setText("Redo");
400             menuItem.setActionCommand("redo");
401             menuItem.addActionListener(dispatcher);
402             if (!buffer.canRedo())
403                 menuItem.setEnabled(false);
404             popup.add(menuItem);
405
406             popup.addSeparator();
407         }
408
409         menuItem = new JMenuItem JavaDoc();
410         menuItem.setText(editor.getMark() == null ? "Cut line" : "Cut");
411         menuItem.setActionCommand("killRegion");
412         menuItem.addActionListener(dispatcher);
413         if (buffer.isReadOnly())
414             menuItem.setEnabled(false);
415         popup.add(menuItem);
416
417         menuItem = new JMenuItem JavaDoc();
418         menuItem.setText(editor.getMark() == null ? "Copy line" : "Copy");
419         menuItem.setActionCommand("copyRegion");
420         menuItem.addActionListener(dispatcher);
421         if (editor.getMark() == null && editor.getDotLine().isBlank())
422             menuItem.setEnabled(false);
423         popup.add(menuItem);
424
425         menuItem = new JMenuItem JavaDoc("Paste");
426         menuItem.setActionCommand("paste");
427         menuItem.addActionListener(dispatcher);
428         if (!editor.canPaste())
429             menuItem.setEnabled(false);
430         popup.add(menuItem);
431
432         // List occurrences.
433
menuItem = new JMenuItem JavaDoc();
434         menuItem.setActionCommand("listOccurrencesOfPatternAtDot");
435         menuItem.addActionListener(dispatcher);
436         Search search = editor.getSearchAtDot();
437         if (search != null) {
438             if (editor.getMark() != null)
439                 menuItem.setText("List occurrences of selected text");
440             else
441                 menuItem.setText("List occurrences of \"" + search.getPattern() + "\"");
442         } else {
443             menuItem.setText("List occurences of pattern under cursor");
444             menuItem.setEnabled(false);
445         }
446         popup.addSeparator();
447         popup.add(menuItem);
448
449         // Find tag.
450
if (buffer.isTaggable()) {
451             menuItem = new JMenuItem JavaDoc();
452             menuItem.setActionCommand("findTagAtDot");
453             menuItem.addActionListener(dispatcher);
454             if (editor.getMark() == null) {
455                 Expression expr = getExpressionAtDot(editor, false);
456                 if (expr != null)
457                     menuItem.setText("Find tag \"" + expr.getName() + "\"");
458             } else {
459                 menuItem.setText("Find tag under cursor");
460                 menuItem.setEnabled(false);
461             }
462             popup.add(menuItem);
463         }
464
465         // Folding.
466
popup.addSeparator();
467         addContextMenuItem("Fold", "fold", popup, dispatcher);
468         addContextMenuItem("Unfold", "unfold", popup, dispatcher);
469         addContextMenuItem("Unfold all", "unfoldAll", popup, dispatcher);
470
471         // Properties.
472
if (buffer.getFile() != null && !(buffer instanceof Directory)) {
473             popup.addSeparator();
474             addContextMenuItem("Properties", "properties", popup, dispatcher);
475         }
476     }
477
478     protected JMenuItem JavaDoc addContextMenuItem(String JavaDoc text, String JavaDoc command,
479         JPopupMenu JavaDoc popup, Dispatcher dispatcher)
480     {
481         JMenuItem JavaDoc menuItem = new JMenuItem JavaDoc(text);
482         menuItem.setActionCommand(command);
483         menuItem.addActionListener(dispatcher);
484         popup.add(menuItem);
485         return menuItem;
486     }
487
488     public ToolBar getToolBar(Frame frame)
489     {
490         ToolBar tb = getCustomToolBar(frame);
491         if (tb != null)
492             return tb;
493         return getDefaultToolBar(frame);
494     }
495
496     protected ToolBar getCustomToolBar(Frame frame)
497     {
498         String JavaDoc filename =
499             Editor.preferences().getStringProperty(getFullKey("toolbar"));
500         if (filename != null) {
501             File file = File.getInstance(filename);
502             if (file != null && file.isFile()) {
503                 ToolBar tb = ToolBar.createToolBar(frame, file);
504                 if (tb != null)
505                     return tb;
506             }
507         }
508         return null;
509     }
510
511     protected ToolBar getDefaultToolBar(Frame frame)
512     {
513         return frame.getDefaultToolBar();
514     }
515
516     public NavigationComponent getSidebarComponent(Editor editor)
517     {
518         if (isTaggable())
519             return new SidebarTagList(editor.getSidebar(), editor);
520         else
521             return null;
522     }
523
524     /**
525      * {@inheritDoc}
526      * The default is <code>null</code>.
527      *
528      * @param buffer {@inheritDoc}
529      * @return {@inheritDoc}
530      */

531     public Tagger getTagger(SystemBuffer buffer)
532     {
533         return null;
534     }
535
536     /**
537      * {@inheritDoc}
538      * The default is <code>false</code>.
539      *
540      * @return {@inheritDoc}
541      */

542     public boolean isTaggable()
543     {
544         return false;
545     }
546
547     /**
548      * {@inheritDoc}
549      * The default is <code>false</code>.
550      *
551      * @return {@inheritDoc}
552      */

553     public boolean hasQualifiedNames()
554     {
555         return false;
556     }
557
558     /**
559      * {@inheritDoc}
560      * The default is <code>true</code> if <code>s</code> contains either
561      * a period '.' or a double colon "::".
562      *
563      * @param s {@inheritDoc}
564      * @return {@inheritDoc}
565      */

566     public boolean isQualifiedName(String JavaDoc s)
567     {
568         return s.indexOf('.') >= 0 || s.indexOf("::") >= 0;
569     }
570
571     /**
572      * {@inheritDoc}
573      * The default is <code>false</code>.
574      *
575      * @return {@inheritDoc}
576      */

577     public boolean canIndent()
578     {
579         return false;
580     }
581
582     /**
583      * {@inheritDoc}
584      * The default is <code>false</code>.
585      *
586      * @return {@inheritDoc}
587      */

588     public boolean canIndentPaste()
589     {
590         return canIndent();
591     }
592
593     public boolean acceptsLinePaste(Editor editor)
594     {
595         return true;
596     }
597
598     /**
599      * {@inheritDoc}
600      * The default is 0.
601      *
602      * @param line {@inheritDoc}
603      * @param buffer {@inheritDoc}
604      * @return {@inheritDoc}
605      */

606     public int getCorrectIndentation(Line line, Buffer buffer)
607     {
608         return 0;
609     }
610
611     /**
612      * {@inheritDoc}
613      * The default is to return an instance of
614      * {@link DefaultSyntaxIterator DefaultSyntaxIterator}.
615      *
616      * @param pos {@inheritDoc}
617      * @return {@inheritDoc}
618      */

619     public SyntaxIterator getSyntaxIterator(Position pos)
620     {
621         return new DefaultSyntaxIterator(pos);
622     }
623
624     /**
625      * {@inheritDoc}
626      * The default is <code>null</code>.
627      *
628      * @return {@inheritDoc}
629      */

630     public String JavaDoc getCommentStart()
631     {
632         return null;
633     }
634
635     /**
636      * {@inheritDoc}
637      * The default is <code>null</code>.
638      *
639      * @return {@inheritDoc}
640      */

641     public String JavaDoc getCommentEnd()
642     {
643         return null;
644     }
645
646     public boolean getBooleanProperty(Property property)
647     {
648         String JavaDoc key = property.key();
649
650         // Look for mode-specific setting in preferences.
651
String JavaDoc s = preferences.getStringProperty(getFullKey(key));
652
653         if (s == null) {
654             // No mode-specific setting in preferences.
655
// Look in property list for mode.
656
// (Property list for mode overrides global preference!)
657
if (properties != null) {
658                 Object JavaDoc value = properties.getProperty(property);
659                 if (value instanceof Boolean JavaDoc)
660                     return ((Boolean JavaDoc) value).booleanValue();
661             }
662
663             // Not in property list for mode.
664
// Look for global setting in preferences.
665
s = preferences.getStringProperty(key);
666         }
667
668         if (s != null) {
669             s = s.trim();
670             if (s.equals("true") || s.equals("1"))
671                 return true;
672             if (s.equals("false") || s.equals("0"))
673                 return false;
674         }
675
676         // Not in preferences or property list for mode.
677
// Use hard-coded default.
678
return ((Boolean JavaDoc)getDefaultValue(property)).booleanValue();
679     }
680
681     public int getIntegerProperty(Property property)
682     {
683         String JavaDoc key = property.key();
684
685         // Look for mode-specific setting in preferences.
686
String JavaDoc s = preferences.getStringProperty(getFullKey(key));
687
688         if (s == null) {
689             // No mode-specific setting in preferences.
690
// Look in property list for mode.
691
// (Property list for mode overrides global preference!)
692
if (properties != null) {
693                 Object JavaDoc value = properties.getProperty(property);
694                 if (value instanceof Integer JavaDoc)
695                     return ((Integer JavaDoc) value).intValue();
696             }
697
698             // Not in property list for mode.
699
// Look for global setting in preferences.
700
s = preferences.getStringProperty(key);
701         }
702
703         if (s != null) {
704             try {
705                 return Integer.parseInt(s.trim());
706             }
707             catch (NumberFormatException JavaDoc e) {}
708         }
709
710         // Not in preferences or property list for mode.
711
// Use hard-coded default.
712
return ((Integer JavaDoc)getDefaultValue(property)).intValue();
713     }
714
715     public String JavaDoc getStringProperty(Property property)
716     {
717         String JavaDoc key = property.key();
718
719         // Look for mode-specific setting in preferences.
720
String JavaDoc s = preferences.getStringProperty(getFullKey(key));
721
722         if (s == null) {
723             // No mode-specific setting in preferences.
724
// Look in property list for mode.
725
// (Property list for mode overrides global preference!)
726
if (properties != null) {
727                 Object JavaDoc value = properties.getProperty(property);
728                 if (value instanceof String JavaDoc)
729                     return (String JavaDoc) value;
730             }
731
732             // Not in property list for mode.
733
// Look for global setting in preferences.
734
s = preferences.getStringProperty(key);
735         }
736
737         if (s != null)
738             return s;
739
740         // Not in preferences or property list for mode.
741
// Use hard-coded default.
742
return (String JavaDoc) getDefaultValue(property); // May be null.
743
}
744
745     public Color JavaDoc getColorProperty(Property property)
746     {
747         String JavaDoc key = property.key();
748
749         // Look for mode-specific setting in preferences.
750
String JavaDoc value = preferences.getStringProperty(getFullKey(key));
751
752         if (value == null) {
753             // We don't check the mode-specific properties list here. Is that
754
// correct?
755

756             // Look for global setting in preferences.
757
value = preferences.getStringProperty(key);
758         }
759
760         if (value != null)
761             return Utilities.getColor(value);
762         else
763             return null;
764     }
765
766     /**
767      * Sets the given property name to the given property value. The property
768      * can then be accessed by calling
769      * {@link getStringProperty(Property) getStringProperty}.
770      *
771      * @param property the property to set.
772      * @param value the value to set it to.
773      */

774     public void setProperty(Property property, String JavaDoc value)
775     {
776         if (properties == null)
777             properties = new PropertyList();
778         properties.setProperty(property, value);
779     }
780
781     /**
782      * Sets the given property name to the given property value. The property
783      * can then be accessed by calling
784      * {@link getBooleanProperty(Property) getBooleanProperty}.
785      *
786      * @param property the property to set.
787      * @param value the value to set it to.
788      */

789     public void setProperty(Property property, boolean value)
790     {
791         if (properties == null)
792             properties = new PropertyList();
793         properties.setProperty(property, value);
794     }
795
796     /**
797      * Sets the given property name to the given property value. The property
798      * can then be accessed by calling
799      * {@link getIntegerProperty(Property) getIntegerProperty}.
800      *
801      * @param property the property to set.
802      * @param value the value to set it to.
803      */

804     public void setProperty(Property property, int value)
805     {
806         if (properties == null)
807             properties = new PropertyList();
808         properties.setProperty(property, value);
809     }
810
811     /**
812      * Returns the default value for the given <code>Property</code>.
813      *
814      * @param property the <code>Property</code> to get the default value for.
815      * @return the default value.
816      */

817     protected Object JavaDoc getDefaultValue(Property property)
818     {
819         return property.getDefaultValue();
820     }
821
822     public final boolean accepts(String JavaDoc filename)
823     {
824         return Editor.getModeList().modeAccepts(id, filename);
825     }
826
827     protected String JavaDoc getFullKey(String JavaDoc key)
828     {
829         FastStringBuffer sb = new FastStringBuffer(this.getClass().getName());
830         sb.append('.');
831         sb.append(key);
832         final String JavaDoc fullKey = sb.toString().toLowerCase();
833         if (fullKey.startsWith("org.armedbear.j.mail."))
834             return fullKey.substring(21);
835         else if (fullKey.startsWith("org.armedbear.j."))
836             return fullKey.substring(16);
837         else
838             return fullKey;
839     }
840
841     /**
842      * {@inheritDoc}
843      * The default is the result of Character.isJavaIdentifierStart(char).
844      *
845      * @return {@inheritDoc}
846      */

847     public boolean isIdentifierStart(char c)
848     {
849         return Character.isJavaIdentifierStart(c);
850     }
851
852     /**
853      * {@inheritDoc}
854      * The default is the result of Character.isJavaIdentifierPart(char).
855      *
856      * @return {@inheritDoc}
857      */

858     public boolean isIdentifierPart(char c)
859     {
860         return Character.isJavaIdentifierPart(c);
861     }
862
863     /**
864      * {@inheritDoc}
865      * The default implementation considers both single and double quotes
866      * (which is wrong for Lisp) and only looks at the current line (which
867      * is wrong for C and C++).
868      *
869      * @param buffer {@inheritDoc}
870      * @param pos {@inheritDoc}
871      * @return {@inheritDoc}
872      */

873     public boolean isInQuote(Buffer buffer, Position pos)
874     {
875         // The default implementation considers both single and double quotes
876
// (which is wrong for Lisp) and only looks at the current line (which
877
// is wrong for C and C++).
878
Line line = pos.getLine();
879         int offset = pos.getOffset();
880         boolean inQuote = false;
881         char quoteChar = '\0';
882         for (int i = 0; i < offset; i++) {
883             char c = line.charAt(i);
884             if (c == '\\') {
885                 // Escape.
886
++i;
887             } else if (inQuote) {
888                 if (c == quoteChar)
889                     inQuote = false;
890             } else {
891                 if (c == '"' || c == '\'') {
892                     inQuote = true;
893                     quoteChar = c;
894                 }
895             }
896         }
897         return inQuote;
898     }
899
900     /**
901      * {@inheritDoc}
902      * The default is <code>false</code>.
903      *
904      * @param buffer {@inheritDoc}
905      * @param pos {@inheritDoc}
906      * @return {@inheritDoc}
907      */

908     public boolean isInComment(Buffer buffer, Position pos)
909     {
910         return false;
911     }
912
913     /**
914      * {@inheritDoc}
915      * The default is <code>false</code>.
916      *
917      * @param line {@inheritDoc}
918      * @return {@inheritDoc}
919      */

920     public boolean isCommentLine(Line line)
921     {
922         return false;
923     }
924
925     /**
926      * {@inheritDoc}
927      * The default is to return the original character.
928      *
929      * @param editor {@inheritDoc}
930      * @param c {@inheritDoc}
931      * @return {@inheritDoc}
932      */

933     public char fixCase(Editor editor, char c)
934     {
935         return c;
936     }
937
938     /**
939      * {@inheritDoc}
940      * The default is to return the tag before the cursor position, if the
941      * buffer has tags.
942      *
943      * @param editor {@inheritDoc}
944      * @param verbose {@inheritDoc}
945      * @return {@inheritDoc}
946      */

947     public String JavaDoc getContextString(Editor editor, boolean verbose)
948     {
949         final List JavaDoc tags = editor.getBuffer().getTags();
950         if (tags != null) {
951             Position pos = editor.getDot();
952             if (pos != null) {
953                 LocalTag tag = null;
954                 // Find the tag before the cursor position.
955
final int target = pos.lineNumber();
956                 final int limit = tags.size();
957                 for (int i = 0; i < limit; i++) {
958                     LocalTag nextTag = (LocalTag) tags.get(i);
959                     if (nextTag.lineNumber() > target)
960                         break;
961                     else
962                         tag = nextTag;
963                 }
964                 if (tag != null)
965                     return verbose ? tag.getLongName() : tag.getMethodName();
966             }
967         }
968         return null;
969     }
970
971     /**
972      * {@inheritDoc}
973      * The default is <code>null</code>.
974      *
975      * @param editor {@inheritDoc}
976      * @param pos {@inheritDoc}
977      * @return {@inheritDoc}
978      */

979     public String JavaDoc getMouseMovedContextString(Editor editor, Position pos)
980     {
981         return null;
982     }
983
984     /**
985      * {@inheritDoc}
986      * The default is <code>null</code>.
987      *
988      * @param editor {@inheritDoc}
989      * @param e {@inheritDoc}
990      * @return {@inheritDoc}
991      */

992     public String JavaDoc getToolTipText(Editor editor, MouseEvent JavaDoc e)
993     {
994         return null;
995     }
996
997     /**
998      * {@inheritDoc}
999      * The default is to do nothing.
1000     *
1001     * @param buffer {@inheritDoc}
1002     * @param file {@inheritDoc}
1003     * @return {@inheritDoc}
1004     */

1005    public void loadFile(Buffer buffer, File file)
1006    {
1007    }
1008
1009    public boolean confirmClose(Editor editor, Buffer buffer)
1010    {
1011        if (!buffer.isModified())
1012            return true;
1013        if (buffer.getFile() == null)
1014            return true;
1015        return CloseBufferConfirmationDialog.confirmClose(editor, buffer);
1016    }
1017
1018    public boolean isKeyword(String JavaDoc s)
1019    {
1020        if (keywords != null)
1021            return keywords.isKeyword(s);
1022        return false;
1023    }
1024
1025    public Expression getExpressionAtDot(Editor editor, boolean exact)
1026    {
1027        if (editor.getDot() == null)
1028            return null;
1029        final Position begin;
1030        if (editor.getMark() != null) {
1031            // Start at beginning of marked block.
1032
Region r = new Region(editor);
1033            begin = r.getBegin();
1034        } else
1035            begin = editor.getDot();
1036        Line line = begin.getLine();
1037        int offset = begin.getOffset();
1038        if (offset < line.length() && isIdentifierStart(line.charAt(offset))) {
1039            String JavaDoc identifier = getIdentifier(line, offset);
1040            if (identifier != null)
1041                return new Expression(identifier);
1042        }
1043        // Try moving to the left.
1044
while (--offset >= 0) {
1045            char c = line.charAt(offset);
1046            if (isIdentifierStart(c)) {
1047                String JavaDoc identifier = getIdentifier(line, offset);
1048                if (identifier != null)
1049                    return new Expression(identifier);
1050            }
1051        }
1052        // Nothing there. Go back to starting point and try moving right.
1053
offset = begin.getOffset();
1054        while (++offset < line.length()) {
1055            char c = line.charAt(offset);
1056            if (isIdentifierStart(c)) {
1057                String JavaDoc identifier = getIdentifier(line, offset);
1058                if (identifier != null)
1059                    return new Expression(identifier);
1060            }
1061        }
1062        return null;
1063    }
1064
1065    public final String JavaDoc getIdentifier(Position pos)
1066    {
1067        return getIdentifier(pos.getLine(), pos.getOffset());
1068    }
1069
1070    public final String JavaDoc getIdentifier(Line line, int offset)
1071    {
1072        int limit = line.length();
1073        if (offset < limit) {
1074            char c = line.charAt(offset);
1075            if (isIdentifierPart(c)) {
1076                while (offset > 0) {
1077                    --offset;
1078                    c = line.charAt(offset);
1079                    if (!isIdentifierPart(c)) {
1080                        ++offset;
1081                        break;
1082                    }
1083                }
1084                // Now we're looking at the first character of the identifier.
1085
c = line.charAt(offset);
1086                if (isIdentifierStart(c)) {
1087                    FastStringBuffer sb = new FastStringBuffer(c);
1088                    while (++offset < limit) {
1089                        c = line.charAt(offset);
1090                        if (isIdentifierPart(c))
1091                            sb.append(c);
1092                        else
1093                            break;
1094                    }
1095                    return sb.toString();
1096                }
1097            }
1098        }
1099        return null;
1100    }
1101
1102    public Position findIdentifierStart(Line line, int offset)
1103    {
1104        if (!isIdentifierPart(line.charAt(offset)))
1105            return null;
1106        int start = offset;
1107        while (--offset >= 0) {
1108            if (!isIdentifierPart(line.charAt(offset)))
1109                break;
1110            start = offset;
1111        }
1112        return new Position(line, start);
1113    }
1114}
1115
Popular Tags