0001:/*
0002: * Copyright (c) 2001, Jacob Smullyan.
0003: *
0004: * This is part of SkunkDAV, a WebDAV client. See http://skunkdav.sourceforge.net/
0005: * for the latest version.
0006: *
0007: * SkunkDAV is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License as published
0009: * by the Free Software Foundation; either version 2, or (at your option)
0010: * any later version.
0011: *
0012: * SkunkDAV is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015: * General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * along with SkunkDAV; see the file COPYING. If not, write to the Free
0019: * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
0020: * 02111-1307, USA.
0021:*/
0022:
0023:package org.skunk.dav.client.gui;
0024:
0025:import java.awt.Color;
0026:import java.awt.Dimension;
0027:import java.awt.Font;
0028:import java.awt.GraphicsEnvironment;
0029:import java.awt.GridBagConstraints;
0030:import java.awt.GridBagLayout;
0031:import java.awt.Insets;
0032:import java.awt.event.ActionEvent;
0033:import java.awt.event.ActionListener;
0034:import java.awt.event.ItemEvent;
0035:import java.awt.event.ItemListener;
0036:import java.beans.PropertyChangeEvent;
0037:import java.beans.PropertyChangeListener;
0038:import java.io.InputStream;
0039:import java.io.InputStreamReader;
0040:import java.io.IOException;
0041:import java.io.Reader;
0042:import java.io.StringWriter;
0043:import java.util.ArrayList;
0044:import java.util.Arrays;
0045:import java.util.Collections;
0046:import java.util.HashMap;
0047:import java.util.Iterator;
0048:import java.util.Locale;
0049:import javax.swing.AbstractListModel;
0050:import javax.swing.BorderFactory;
0051:import javax.swing.Box;
0052:import javax.swing.ComboBoxModel;
0053:import javax.swing.DefaultComboBoxModel;
0054:import javax.swing.JButton;
0055:import javax.swing.JCheckBox;
0056:import javax.swing.JComboBox;
0057:import javax.swing.JComponent;
0058:import javax.swing.JLabel;
0059:import javax.swing.JList;
0060:import javax.swing.JOptionPane;
0061:import javax.swing.JPanel;
0062:import javax.swing.JScrollPane;
0063:import javax.swing.JTextField;
0064:import javax.swing.ListModel;
0065:import javax.swing.ListSelectionModel;
0066:import javax.swing.SwingConstants;
0067:import javax.swing.SwingUtilities;
0068:import javax.swing.event.ListSelectionEvent;
0069:import javax.swing.event.ListSelectionListener;
0070:import javax.swing.border.TitledBorder;
0071:import javax.swing.text.BadLocationException;
0072:import javax.swing.text.Document;
0073:import org.skunk.assert.Assertion;
0074:import org.skunk.config.Configurator;
0075:import org.skunk.config.ConfigStore;
0076:import org.skunk.dav.client.DAVFile;
0077:import org.skunk.dav.client.gui.editor.ConfigurableEditor;
0078:import org.skunk.dav.client.gui.editor.SimpleTextEditor;
0079:import org.skunk.swing.ColorChoiceButton;
0080:import org.skunk.swing.text.EntryDocument;
0081:import org.skunk.swing.text.PositiveIntegerEntryFilter;
0082:import org.skunk.swing.text.TextEditorPane;
0083:import org.skunk.swing.text.syntax.FileMode;
0084:import org.skunk.swing.text.syntax.SyntaxDocument;
0085:import org.skunk.swing.text.syntax.SyntaxEditorKit;
0086:import org.skunk.swing.text.syntax.SyntaxStyle;
0087:import org.skunk.trace.Debug;
0088:
0089:/**
0090: * customizes the editor's appearance and behavior.
0091: *
0092: * @author Jacob Smullyan ($Author: smulloni $) <smulloni@krinst.org>
0093: * @version $Revision: 1.7 $
0094: */
0095:public class TextEditorCustomizer extends PreferencesCustomizer
0096:{
0097: private static HashMap previewHash;
0098:
0099: private JButton removeExtensionButton;
0100: private JPanel customizer;
0101: private PreviewPane previewPane;
0102: private ColorChoiceButton globalBackgroundButton,
0103: globalForegroundButton,
0104: globalCaretColorButton,
0105: styleColorButton;
0106: private JCheckBox highlightModeCheckBox,
0107: boldCheckBox,
0108: italicCheckBox;
0109: private JComboBox fontDropdown,
0110: styleDropdown;
0111: private StyleComboBoxModel styleModel;
0112: private FileModeExtensionListModel extModel;
0113: private JList extensionsList,
0114: fileModeList;
0115: private JTextField fontSizeField,
0116: tabSizeField;
0117: private Color globalForeground,
0118: lastForeground,
0119: globalBackground,
0120: lastBackground,
0121: globalCaretColor,
0122: lastCaretColor;
0123: private Font defaultFont,
0124: lastFont;
0125: private int tabSize,
0126: lastTabSize;
0127: private String lastStyleConfigData;
0128:
0129: private SyntaxStyle.SyntaxStyleSet configSet;
0130: private FileMode.ModeMapContainer modeSet;
0131:
0132: /* private String lineSeparator; */ //for future release
0133:
0134: private static final int USE_DEFAULT=0;
0135: private static final int USE_REVERT=1;
0136: private static final int USE_CONFIG=2;
0137:
0138: static
0139: {
0140: previewHash=new HashMap();
0141: }
0142:
0143: private static String slurp(String resourceName) throws IOException
0144: {
0145: InputStream in=TextEditorCustomizer.class.getResourceAsStream(resourceName);
0146: if (in ==null) throw new IOException("resourceName not found");
0147: Reader r=new InputStreamReader(in);
0148: StringWriter sw=new StringWriter();
0149: int charsRead;
0150: int offset=0;
0151: char[] buffer=new char[1<<12];
0152: while ((charsRead=r.read(buffer, offset, buffer.length))>0)
0153: {
0154: sw.write(buffer, offset, charsRead);
0155: }
0156: sw.flush();
0157: r.close();
0158: sw.close();
0159: return sw.toString();
0160: }
0161:
0162: private static String getPreviewText(String mode)
0163: {
0164: if (previewHash.containsKey(mode))
0165: return (String) previewHash.get(mode);
0166: else
0167: {
0168: try
0169: {
0170: String s=slurp(mode+".example");
0171: previewHash.put(mode, s);
0172: return s;
0173: }
0174: catch (IOException oyVeh)
0175: {
0176: return ResourceManager.getMessage(ResourceManager.TEXT_EDITOR_CUSTOMIZER_IO_EXCEPTION,
0177: new Object[] {mode, oyVeh.getMessage()});
0178: }
0179: }
0180: }
0181:
0182: /**
0183: * constructor
0184: * @param title
0185: * @param configurator
0186: */
0187: public TextEditorCustomizer(String title, Configurator configurator)
0188: {
0189: super (title, configurator);
0190: initConfig();
0191: initComponents();
0192: }
0193:
0194: private Object getConfiguredValue(Class propertyClass, String propertyName, boolean useRevert)
0195: {
0196: ConfigStore store=(useRevert)
0197: ? getConfigurator().getReversionStore()
0198: : getConfigurator().getStore();
0199: return store.getConfigValue(propertyClass, propertyName);
0200: }
0201:
0202: private Color getConfiguredGlobalBackground(int mode)
0203: {
0204: if (mode!=USE_DEFAULT)
0205: {
0206: Object val=getConfiguredValue(SimpleTextEditor.class,
0207: SimpleTextEditor.BACKGROUND_PROPERTY,
0208: (mode==USE_REVERT));
0209: if (mode==USE_REVERT && val==null)
0210: {
0211: globalBackground=lastBackground;
0212: return globalBackground;
0213: }
0214: lastBackground=globalBackground;
0215: this .globalBackground=(val!=null && val instanceof Color)
0216: ? (Color) val
0217: : SyntaxStyle.DEFAULT_BACKGROUND;
0218: }
0219: else
0220: {
0221: this .globalBackground=SyntaxStyle.DEFAULT_BACKGROUND;
0222: lastBackground=globalBackground;
0223: }
0224: if (lastBackground==null) lastBackground=globalBackground;
0225: return globalBackground;
0226: }
0227:
0228: private Color getConfiguredGlobalForeground(int mode)
0229: {
0230: if (mode!=USE_DEFAULT)
0231: {
0232: Object val=getConfiguredValue(SimpleTextEditor.class,
0233: SimpleTextEditor.FOREGROUND_PROPERTY,
0234: mode==USE_REVERT);
0235: if (mode==USE_REVERT && val==null)
0236: {
0237: globalForeground=lastForeground;
0238: return globalForeground;
0239: }
0240: lastForeground=globalForeground;
0241: this .globalForeground=(val!=null && val instanceof Color)
0242: ? (Color) val
0243: : SyntaxStyle.DEFAULT_FOREGROUND;
0244: }
0245: else
0246: {
0247: this .globalForeground=SyntaxStyle.DEFAULT_FOREGROUND;
0248: lastForeground=globalForeground;
0249: }
0250: if (lastForeground==null) lastForeground=globalForeground;
0251: return globalForeground;
0252: }
0253:
0254: private Color getConfiguredCaretColor(int mode)
0255: {
0256: if (mode!=USE_DEFAULT)
0257: {
0258: Object val=getConfiguredValue(SimpleTextEditor.class,
0259: SimpleTextEditor.CARET_COLOR_PROPERTY,
0260: mode==USE_REVERT);
0261: if (mode==USE_REVERT && val==null)
0262: {
0263: globalCaretColor=lastCaretColor;
0264: return globalCaretColor;
0265: }
0266: lastCaretColor=globalCaretColor;
0267: this .globalCaretColor=(val!=null && val instanceof Color)
0268: ? (Color) val
0269: : SimpleTextEditor.DEFAULT_CARET_COLOR;
0270: }
0271: else
0272: {
0273: this .globalCaretColor=SimpleTextEditor.DEFAULT_CARET_COLOR;
0274: lastCaretColor=globalCaretColor;
0275: }
0276: if (lastCaretColor==null) lastCaretColor=globalCaretColor;
0277: return globalCaretColor;
0278: }
0279:
0280: private Font getConfiguredFont(int mode)
0281: {
0282: if (mode!=USE_DEFAULT)
0283: {
0284: Object val=getConfiguredValue(SimpleTextEditor.class,
0285: SimpleTextEditor.FONT_PROPERTY,
0286: mode==USE_REVERT);
0287: if (mode==USE_REVERT && val==null)
0288: {
0289: defaultFont=lastFont;
0290: return defaultFont;
0291: }
0292: lastFont=defaultFont;
0293: boolean gotAFont=val!=null && (val instanceof Font);
0294: defaultFont=(gotAFont) ? (Font) val : SyntaxStyle.DEFAULT_FONT;
0295:
0296: }
0297: else
0298: {
0299: defaultFont=SyntaxStyle.DEFAULT_FONT;
0300: lastFont=defaultFont;
0301: }
0302: if (lastFont==null) lastFont=defaultFont;
0303: return defaultFont;
0304: }
0305:
0306: private int getConfiguredTabSize(int mode)
0307: {
0308: if (mode!=USE_DEFAULT)
0309: {
0310: Object val=getConfiguredValue(SimpleTextEditor.class,
0311: SimpleTextEditor.TAB_SIZE_PROPERTY,
0312: mode==USE_REVERT);
0313: if (mode==USE_REVERT && val==null)
0314: {
0315: tabSize=lastTabSize;
0316: return tabSize;
0317: }
0318: lastTabSize=tabSize;
0319: this .tabSize=(val!=null && val instanceof Integer)
0320: ? ((Integer)val).intValue()
0321: : SimpleTextEditor.DEFAULT_TAB_SIZE;
0322: }
0323: else
0324: {
0325: this .tabSize=SimpleTextEditor.DEFAULT_TAB_SIZE;
0326: lastTabSize=tabSize;
0327: }
0328: if (lastTabSize<=0) lastTabSize=tabSize;
0329: return this .tabSize;
0330: }
0331:
0332: private SyntaxStyle.SyntaxStyleSet getConfiguredStyleSet(int mode)
0333: {
0334: if (this .configSet==null)
0335: this .configSet=new SyntaxStyle.SyntaxStyleSet();
0336: switch (mode)
0337: {
0338: case USE_CONFIG:
0339: lastStyleConfigData=configSet.getConfigData();
0340: getConfigurator().configure(configSet);
0341: break;
0342: case USE_REVERT:
0343: Object val=getConfiguredValue(SyntaxStyle.SyntaxStyleSet.class,
0344: SyntaxStyle.SyntaxStyleSet.CONFIG_DATA_PROPERTY,
0345: true);
0346: if (val!=null)
0347: {
0348: if (Assertion.ASSERT)
0349: Assertion.assert((val instanceof String),
0350: "config data is a string");
0351: configSet.setConfigData((String) val);
0352: }
0353: else
0354: {
0355: configSet.setConfigData(lastStyleConfigData);
0356: }
0357: break;
0358: case USE_DEFAULT:
0359: default:
0360: SyntaxStyle.initDefaultStyles(configSet);
0361: }
0362: return this .configSet;
0363: }
0364:
0365: private FileMode.ModeMapContainer getConfiguredModeSet(int mode)
0366: {
0367: if (modeSet==null)
0368: modeSet=new FileMode.ModeMapContainer();
0369: switch (mode)
0370: {
0371: case USE_CONFIG:
0372: getConfigurator().configure(modeSet);
0373: break;
0374: case USE_REVERT:
0375: /*
0376: I'm not checking for a null value in revert here, because
0377: I'm not currently updating the editor display on the basis of the
0378: these values. Should I do so, I would have to use the same
0379: kludge here as I am doing elsewhere. JS
0380: */
0381: getConfigurator().revert(modeSet);
0382: break;
0383: case USE_DEFAULT:
0384: default:
0385: FileMode.initDefaultModes(modeSet);
0386: }
0387: if (Debug.DEBUG) Debug.trace(this , Debug.DP5, "modeSet: "+modeSet.getModeMap());
0388: return this .modeSet;
0389: }
0390:
0391: private void addEditorTargets()
0392: {
0393: AppContext context=ExplorerApp.getAppContext();
0394: if (context!=null)
0395: {
0396: for (Iterator it1=context.views(); it1.hasNext();)
0397: {
0398: View v=(View) it1.next();
0399: for (Iterator it2=v.getDockedBuffers();it2.hasNext();)
0400: {
0401: Object buffer=it2.next();
0402: if (buffer instanceof SimpleTextEditor)
0403: {
0404: if (Debug.DEBUG) Debug.trace(this , Debug.DP4, "text editor found");
0405: addConfigTarget(buffer);
0406: }
0407: }
0408: }
0409: }
0410: }
0411:
0412: private void initConfig()
0413: {
0414: addEditorTargets();
0415: addConfigTarget(FileMode.getModeMapContainer());
0416: addConfigTarget(SyntaxStyle.getDefaultStyleSet());
0417: //this initialization deals with the case where there are no saved preferences
0418: getConfiguredStyleSet(USE_DEFAULT);
0419: getConfiguredModeSet(USE_DEFAULT);
0420:
0421: getConfiguredGlobalBackground(USE_CONFIG);
0422: getConfiguredGlobalForeground(USE_CONFIG);
0423: getConfiguredCaretColor(USE_CONFIG);
0424: getConfiguredFont(USE_CONFIG);
0425: getConfiguredStyleSet(USE_CONFIG);
0426: getConfiguredTabSize(USE_CONFIG);
0427: getConfiguredModeSet(USE_CONFIG);
0428: }
0429:
0430: private void _setConfigValues()
0431: {
0432: setConfigValue(SimpleTextEditor.class,
0433: SimpleTextEditor.FOREGROUND_PROPERTY,
0434: globalForeground);
0435: setConfigValue(SimpleTextEditor.class,
0436: SimpleTextEditor.BACKGROUND_PROPERTY,
0437: globalBackground);
0438: setConfigValue(SimpleTextEditor.class,
0439: SimpleTextEditor.CARET_COLOR_PROPERTY,
0440: globalCaretColor);
0441: setConfigValue(SimpleTextEditor.class,
0442: SimpleTextEditor.FONT_PROPERTY,
0443: defaultFont);
0444: setConfigValue(SyntaxStyle.SyntaxStyleSet.class,
0445: SyntaxStyle.SyntaxStyleSet.DEFAULT_FONT_PROPERTY,
0446: defaultFont);
0447: setConfigValue(SimpleTextEditor.class,
0448: SimpleTextEditor.TAB_SIZE_PROPERTY,
0449: new Integer(tabSize));
0450: setConfigValue(FileMode.ModeMapContainer.class,
0451: FileMode.ModeMapContainer.CONFIG_DATA_PROPERTY,
0452: modeSet.getConfigData());
0453: setConfigValue(SyntaxStyle.SyntaxStyleSet.class,
0454: SyntaxStyle.SyntaxStyleSet.CONFIG_DATA_PROPERTY,
0455: configSet.getConfigData());
0456: }
0457:
0458: /**
0459: * workaround for a weird bug on IBM JDK1.2 for Linux -- calling getFamily may
0460: * yield a name entirely in lowercase,
0461: * but list of all family names are capitalized.
0462: */
0463: private String getFontName(Font f)
0464: {
0465: String fName=f.getFamily(Locale.getDefault());
0466:
0467: if (!Character.isUpperCase(fName.charAt(0)))
0468: {
0469: StringBuffer sb=new StringBuffer();
0470: sb.append(Character.toUpperCase(fName.charAt(0)));
0471: sb.append(fName.substring(1));
0472: fName=sb.toString();
0473: }
0474: return fName;
0475: }
0476:
0477: public void ok()
0478: {
0479: _setConfigValues();
0480: addEditorTargets();
0481: super .ok();
0482: lastBackground=globalBackground;
0483: lastForeground=globalForeground;
0484: lastFont=defaultFont;
0485: lastCaretColor=globalCaretColor;
0486: lastTabSize=tabSize;
0487: }
0488:
0489: public void tryOn()
0490: {
0491: _setConfigValues();
0492: addEditorTargets();
0493: super .tryOn();
0494: }
0495:
0496: public void revert()
0497: {
0498: synchConfig(USE_REVERT);
0499: synchGlobalControls();
0500: _setConfigValues();
0501: addEditorTargets();
0502: super .revert();
0503: //getConfigurator().tryOff(SimpleTextEditor.class);
0504: synchFileModes();
0505: synchStyles();
0506: synchPreview();
0507: }
0508:
0509: public void revertToDefault()
0510: {
0511: synchConfig(USE_DEFAULT);
0512: synchGlobalControls();
0513: _setConfigValues();
0514: addEditorTargets();
0515: super .revertToDefault();
0516: synchFileModes();
0517: synchStyles();
0518: synchPreview();
0519: }
0520:
0521: private void synchFileModes()
0522: {
0523: ((FileModeListModel)fileModeList.getModel()).refresh();
0524: FileMode mode=modeSet.getMode((String)fileModeList.getSelectedValue());
0525: ((SyntaxDocument)previewPane.getDocument()).setFileMode(mode);
0526: extModel.setFileMode(mode);
0527: if (extModel.getSize()>0)
0528: {
0529: extensionsList.setSelectedIndex(0);
0530: removeExtensionButton.setEnabled(true);
0531: }
0532: else removeExtensionButton.setEnabled(false);
0533: highlightModeCheckBox.setSelected(mode.getShouldHighlight());
0534: highlightModeCheckBox.setEnabled(mode.getCanHighlight());
0535: }
0536:
0537: private void synchStyles()
0538: {
0539: Object item=styleDropdown.getSelectedItem();
0540: styleModel.refresh();
0541: styleDropdown.setSelectedItem(item);
0542: SyntaxStyle ss=configSet.getStyle((String) item);
0543: styleColorButton.setColor(ss.getForegroundColor());
0544: boldCheckBox.setSelected(ss.isBold());
0545: italicCheckBox.setSelected(ss.isItalic());
0546: }
0547:
0548: private void synchPreview()
0549: {
0550: previewPane.setBackground(globalBackground);
0551: previewPane.setForeground(globalForeground);
0552: previewPane.setCaretColor(globalCaretColor);
0553: previewPane.setFont(defaultFont);
0554: previewPane.setTabSize(tabSize);
0555: previewPane.repaint();
0556: }
0557:
0558: private void synchGlobalControls()
0559: {
0560: globalBackgroundButton.setBackground(globalBackground);
0561: globalForegroundButton.setBackground(globalForeground);
0562: globalCaretColorButton.setBackground(globalCaretColor);
0563: fontDropdown.setSelectedItem(getFontName(defaultFont));
0564: fontSizeField.setText(Integer.toString(defaultFont.getSize()));
0565: tabSizeField.setText(Integer.toString(tabSize));
0566: }
0567:
0568: private void synchConfig(int mode)
0569: {
0570: getConfiguredGlobalBackground(mode);
0571: getConfiguredGlobalForeground(mode);
0572: getConfiguredCaretColor(mode);
0573: getConfiguredTabSize(mode);
0574: getConfiguredFont(mode);
0575: getConfiguredStyleSet(mode);
0576: getConfiguredModeSet(mode);
0577: }
0578:
0579: private GridBagConstraints initGBC()
0580: {
0581: GridBagConstraints gbc=new GridBagConstraints();
0582: gbc.gridx=0;
0583: gbc.gridy=0;
0584: gbc.gridwidth=1;
0585: gbc.gridheight=1;
0586: gbc.insets=new Insets(2, 2, 2, 2);
0587: gbc.fill=GridBagConstraints.NONE;
0588: gbc.ipadx=1;
0589: gbc.ipady=1;
0590: gbc.weightx=0.33;
0591: gbc.weighty=0.0;
0592: gbc.anchor=GridBagConstraints.WEST;
0593: return gbc;
0594: }
0595:
0596: private JPanel initGlobal()
0597: {
0598: String globalPropertiesStr=ResourceManager.getMessage(ResourceManager.GLOBAL_PROPERTIES);
0599: JLabel globalBackgroundLbl=new JLabel(ResourceManager.getMessage(ResourceManager.GLOBAL_BACKGROUND));
0600: JLabel globalForegroundLbl=new JLabel(ResourceManager.getMessage(ResourceManager.GLOBAL_FOREGROUND));
0601: JLabel globalCaretColorLbl=new JLabel(ResourceManager.getMessage(ResourceManager.GLOBAL_CARET_COLOR));
0602: JLabel fontNameLbl=new JLabel(ResourceManager.getMessage(ResourceManager.FONT_NAME));
0603: JLabel fontSizeLbl=new JLabel(ResourceManager.getMessage(ResourceManager.FONT_SIZE));
0604: JLabel tabSizeLbl=new JLabel(ResourceManager.getMessage(ResourceManager.TAB_SIZE));
0605: /*
0606: //not yet used
0607: JLabel lineSeparatorLbl=new JLabel(ResourceManager.getMessage(ResourceManager.LINE_SEPARATOR));
0608: String[] separatorOptions=new String[]
0609: {
0610: ResourceManager.getMessage(ResourceManager.LF_LINE_SEPARATOR),
0611: ResourceManager.getMessage(ResourceManager.CRLF_LINE_SEPARATOR),
0612: ResourceManager.getMessage(ResourceManager.CR_LINE_SEPARATOR)
0613: };
0614: */
0615: globalForegroundButton=new ColorChoiceButton();
0616: globalForegroundButton.setColor(globalForeground);
0617: globalForegroundButton.addPropertyChangeListener(new PropertyChangeListener()
0618: {
0619: public void propertyChange(PropertyChangeEvent cheese)
0620: {
0621: if (cheese.getPropertyName().equals(ColorChoiceButton.COLOR_PROPERTY))
0622: {
0623: Color c=globalForegroundButton.getColor();
0624: if (c.equals(TextEditorCustomizer.this .globalForeground))
0625: return;
0626: TextEditorCustomizer.this .globalForeground=c;
0627: TextEditorCustomizer.this .previewPane.setForeground(globalForeground);
0628: TextEditorCustomizer.this .setDirty(true);
0629: }
0630: }
0631: });
0632:
0633: globalBackgroundButton=new ColorChoiceButton();
0634: globalBackgroundButton.setColor(globalBackground);
0635: globalBackgroundButton.addPropertyChangeListener(new PropertyChangeListener()
0636: {
0637: public void propertyChange(PropertyChangeEvent cheese)
0638: {
0639: if (cheese.getPropertyName().equals(ColorChoiceButton.COLOR_PROPERTY))
0640: {
0641: Color c=globalBackgroundButton.getColor();
0642: if (TextEditorCustomizer.this .globalBackground.equals(c)) return;
0643: TextEditorCustomizer.this .globalBackground=c;
0644: TextEditorCustomizer.this .previewPane.setBackground(globalBackground);
0645: TextEditorCustomizer.this .setDirty(true);
0646: }
0647: }
0648: });
0649: globalCaretColorButton=new ColorChoiceButton();
0650: globalCaretColorButton.setColor(globalCaretColor);
0651: globalCaretColorButton.addPropertyChangeListener(new PropertyChangeListener()
0652: {
0653: public void propertyChange(PropertyChangeEvent cheese)
0654: {
0655: if (cheese.getPropertyName().equals(ColorChoiceButton.COLOR_PROPERTY))
0656: {
0657: Color c=globalCaretColorButton.getColor();
0658: if (TextEditorCustomizer.this .globalCaretColor.equals(c)) return;
0659: TextEditorCustomizer.this .globalCaretColor=c;
0660: TextEditorCustomizer.this .previewPane.setCaretColor(globalCaretColor);
0661: TextEditorCustomizer.this .setDirty(true);
0662: }
0663: }
0664: });
0665: String[] fontNames=GraphicsEnvironment.getLocalGraphicsEnvironment()
0666: .getAvailableFontFamilyNames(Locale.getDefault());
0667: Arrays.sort(fontNames);
0668: fontDropdown=new JComboBox(fontNames);
0669: /*
0670: * on IBM JDK1.3 for Linux, a blank item is returned, for some reason.
0671: * Maybe it the font of our dreams, but I don't want it.
0672: */
0673: fontDropdown.removeItem("");
0674: fontDropdown.setSelectedItem(getFontName(defaultFont));
0675:
0676: fontDropdown.addItemListener(new ItemListener()
0677: {
0678: public void itemStateChanged(ItemEvent ie)
0679: {
0680: if (ie.getStateChange()==ItemEvent.SELECTED)
0681: {
0682: Object o=ie.getItem();
0683: String fontName=(String) o;
0684: int fontSize=Integer.parseInt(fontSizeField.getText());
0685: TextEditorCustomizer.this .defaultFont=new Font(fontName,
0686: Font.PLAIN,
0687: fontSize);
0688: if (TextEditorCustomizer.this .configSet.getDefaultFont().equals(defaultFont))
0689: return;
0690: TextEditorCustomizer.this .configSet.setDefaultFont(defaultFont);
0691: TextEditorCustomizer.this .previewPane.setFont(defaultFont);
0692: setDirty(true);
0693: }
0694: }
0695: });
0696: fontSizeField=new JTextField(3);
0697: fontSizeField.setDocument(new EntryDocument(new PositiveIntegerEntryFilter(1, 72)));
0698: fontSizeField.setText(Integer.toString(defaultFont.getSize()));
0699: tabSizeField=new JTextField(2);
0700: tabSizeField.setDocument(new EntryDocument(new PositiveIntegerEntryFilter(1, 12)));
0701: tabSizeField.setText(Integer.toString(tabSize));
0702: //listener for both tabSize and fontSize
0703: ActionListener tabAndFontSizeListener=new ActionListener()
0704: {
0705: public void actionPerformed(ActionEvent ae)
0706: {
0707: try
0708: {
0709: Integer tabInt=new Integer(tabSizeField.getText());
0710: tabSize=tabInt.intValue();
0711: previewPane.setTabSize(tabSize);
0712: int fontSize=Integer.parseInt(fontSizeField.getText());
0713: defaultFont=new Font(getFontName(defaultFont), Font.PLAIN, fontSize);
0714: previewPane.setFont(defaultFont);
0715: configSet.setDefaultFont(defaultFont);
0716: setDirty(true);
0717: }
0718: catch (NumberFormatException nafta)
0719: {
0720: //nothing
0721: }
0722: }
0723: };
0724:
0725: fontSizeField.addActionListener(tabAndFontSizeListener);
0726: tabSizeField.addActionListener(tabAndFontSizeListener);
0727:
0728: GridBagConstraints gbc=initGBC();
0729: JPanel tmp=new JPanel(new GridBagLayout());
0730:
0731: tmp.add(globalBackgroundLbl, gbc);
0732: gbc.gridx++;
0733: tmp.add(globalBackgroundButton, gbc);
0734: gbc.gridx++;
0735:
0736: tmp.add(globalForegroundLbl, gbc);
0737: gbc.gridx++;
0738: tmp.add(globalForegroundButton, gbc);
0739: gbc.gridx++;
0740:
0741: tmp.add(globalCaretColorLbl, gbc);
0742: gbc.gridx++;
0743: tmp.add(globalCaretColorButton, gbc);
0744: gbc.gridx=0;
0745: gbc.gridy++;
0746:
0747: tmp.add(fontNameLbl, gbc);
0748: gbc.gridx++;
0749: tmp.add(fontDropdown, gbc);
0750: gbc.gridx++;
0751:
0752: tmp.add(fontSizeLbl, gbc);
0753: gbc.gridx++;
0754: tmp.add(fontSizeField, gbc);
0755:
0756: gbc.gridx++;
0757: tmp.add(tabSizeLbl, gbc);
0758: gbc.gridx++;
0759: tmp.add(tabSizeField, gbc);
0760:
0761: tmp.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
0762: globalPropertiesStr,
0763: TitledBorder.LEFT,
0764: TitledBorder.TOP));
0765: return tmp;
0766: }
0767:
0768: private JPanel initFileModes()
0769: {
0770: String fileModePropertiesStr=ResourceManager.getMessage(ResourceManager.FILE_MODE_PROPERTIES);
0771: JLabel fileModesLbl=new JLabel(ResourceManager.getMessage(ResourceManager.FILE_MODES));
0772: JLabel extensionsLbl=new JLabel(ResourceManager.getMessage(ResourceManager.EXTENSIONS));
0773:
0774: final String newExtensionDialogTitle=ResourceManager.getMessage(ResourceManager.NEW_EXTENSION_DIALOG_TITLE);
0775: fileModeList=new JList(new FileModeListModel(modeSet));
0776: fileModeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
0777: extModel=new FileModeExtensionListModel();
0778: extensionsList=new JList(extModel);
0779:
0780: highlightModeCheckBox=new JCheckBox(ResourceManager.getMessage(ResourceManager.HIGHLIGHT_THIS_MODE));
0781: highlightModeCheckBox.addActionListener(new ActionListener()
0782: {
0783: public void actionPerformed(ActionEvent ae)
0784: {
0785: FileMode mode=modeSet.getMode((String)fileModeList.getSelectedValue());
0786: mode.setShouldHighlight(highlightModeCheckBox.isSelected());
0787: SyntaxDocument sdoc=(SyntaxDocument)previewPane.getDocument();
0788: sdoc.setFileMode(mode);
0789: sdoc.retokenizeAll();
0790: TextEditorCustomizer.this .previewPane.repaint();
0791: TextEditorCustomizer.this .setDirty(true);
0792: }
0793: });
0794: removeExtensionButton=new JButton(ResourceManager.getMessage(ResourceManager.REMOVE_EXTENSION));
0795: fileModeList.addListSelectionListener(new ListSelectionListener()
0796: {
0797: public void valueChanged(ListSelectionEvent lassie)
0798: {
0799: final FileMode mode=modeSet.getMode((String)fileModeList.getSelectedValue());
0800: extModel.setFileMode(mode);
0801: if (extModel.getSize()>0)
0802: {
0803: extensionsList.setSelectedIndex(0);
0804: removeExtensionButton.setEnabled(true);
0805: }
0806: else removeExtensionButton.setEnabled(false);
0807: highlightModeCheckBox.setSelected(mode.getCanHighlight() && mode.getShouldHighlight());
0808: highlightModeCheckBox.setEnabled(mode.getCanHighlight());
0809: final SyntaxDocument sdoc=(SyntaxDocument)previewPane.getDocument();
0810: sdoc.setFileMode(mode);
0811: SwingUtilities.invokeLater(new Runnable()
0812: {
0813: public void run()
0814: {
0815: previewPane.setText(getPreviewText(mode.getName()));
0816: sdoc.retokenizeAll();
0817: previewPane.repaint();
0818: }
0819: });
0820: }
0821: });
0822: fileModeList.setSelectedValue("plain", true);
0823: final JButton addExtensionButton=new JButton(ResourceManager.getMessage(ResourceManager.ADD_EXTENSION));
0824: addExtensionButton.addActionListener(new ActionListener()
0825: {
0826: public void actionPerformed(ActionEvent ae)
0827: {
0828: FileMode mode=modeSet.getMode((String)fileModeList.getSelectedValue());
0829: String message=ResourceManager.getMessage(ResourceManager.NEW_EXTENSION_DIALOG_PROMPT,
0830: new Object[] { mode.getName() });
0831: String newExt=JOptionPane.showInputDialog(TextEditorCustomizer.this .getCustomizer(),
0832: message,
0833: newExtensionDialogTitle,
0834: JOptionPane.QUESTION_MESSAGE);
0835: if (newExt!=null)
0836: {
0837: mode.addExtension(newExt);
0838: extModel.setFileMode(mode);
0839: if (extModel.getSize()>0)
0840: {
0841: extensionsList.setSelectedIndex(0);
0842: removeExtensionButton.setEnabled(true);
0843: }
0844: else removeExtensionButton.setEnabled(false);
0845: TextEditorCustomizer.this .setDirty(true);
0846: }
0847: }
0848: });
0849:
0850: removeExtensionButton.addActionListener(new ActionListener()
0851: {
0852: public void actionPerformed(ActionEvent ae)
0853: {
0854: FileMode mode=modeSet.getMode((String)fileModeList.getSelectedValue());
0855: Object o=extensionsList.getSelectedValue();
0856: if (o!=null)
0857: {
0858: mode.removeExtension((String)o);
0859: extModel.setFileMode(mode);
0860: if (extModel.getSize()>0)
0861: {
0862: extensionsList.setSelectedIndex(0);
0863: removeExtensionButton.setEnabled(true);
0864: }
0865: else removeExtensionButton.setEnabled(false);
0866: TextEditorCustomizer.this .setDirty(true);
0867: }
0868: }
0869: });
0870:
0871: //layout file modes sub-panel
0872: JPanel tmp=new JPanel(new GridBagLayout());
0873: GridBagConstraints gbc=initGBC();
0874: gbc.fill=GridBagConstraints.VERTICAL;
0875: JScrollPane scroll=new JScrollPane(fileModeList);
0876: scroll.setPreferredSize(new Dimension(48, 70));
0877: Box tmpBox=Box.createVerticalBox();
0878: tmpBox.add(fileModesLbl);
0879: tmpBox.add(scroll);
0880: tmp.add(tmpBox, gbc);
0881: gbc.gridx++;
0882: scroll=new JScrollPane(extensionsList);
0883: scroll.setPreferredSize(new Dimension(48, 70));
0884: tmpBox=Box.createVerticalBox();
0885: tmpBox.add(extensionsLbl);
0886: tmpBox.add(scroll);
0887: tmp.add(tmpBox, gbc);
0888: gbc.gridx++;
0889: tmpBox=Box.createVerticalBox();
0890: tmpBox.add(Box.createVerticalGlue());
0891: tmpBox.add(addExtensionButton);
0892: tmpBox.add(removeExtensionButton);
0893: tmp.add(tmpBox, gbc);
0894: gbc.gridx++;
0895: tmp.add(highlightModeCheckBox, gbc);
0896:
0897: tmp.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
0898: fileModePropertiesStr,
0899: TitledBorder.LEFT,
0900: TitledBorder.TOP));
0901: return tmp;
0902: }
0903:
0904: private JPanel initStyles()
0905: {
0906: String stylePropertiesStr=ResourceManager.getMessage(ResourceManager.STYLE_PROPERTIES);
0907: boldCheckBox=new JCheckBox(ResourceManager.getMessage(ResourceManager.BOLD));
0908: boldCheckBox.setHorizontalTextPosition(SwingConstants.LEFT);
0909: italicCheckBox=new JCheckBox(ResourceManager.getMessage(ResourceManager.ITALIC));
0910: italicCheckBox.setHorizontalTextPosition(SwingConstants.LEFT);
0911: JLabel colorLbl=new JLabel(ResourceManager.getMessage(ResourceManager.COLOR));
0912: styleModel=new StyleComboBoxModel();
0913: styleDropdown=new JComboBox(styleModel);
0914: styleColorButton=new ColorChoiceButton();
0915: styleColorButton.addPropertyChangeListener(new PropertyChangeListener()
0916: {
0917: public void propertyChange(PropertyChangeEvent cheese)
0918: {
0919: if (cheese.getPropertyName().equals(ColorChoiceButton.COLOR_PROPERTY))
0920: {
0921: Color styleColor=styleColorButton.getColor();
0922: SyntaxStyle ss=configSet.getStyle((String)styleDropdown.getSelectedItem());
0923: if (ss.getForegroundColor().equals(styleColor))
0924: return;
0925: ss.setForegroundColor(styleColor);
0926: previewPane.repaint();
0927: TextEditorCustomizer.this .setDirty(true);
0928: }
0929: }
0930: });
0931: styleDropdown.addItemListener(new ItemListener()
0932: {
0933: public void itemStateChanged(ItemEvent ie)
0934: {
0935: if (ie.getStateChange()==ItemEvent.SELECTED)
0936: {
0937: Object o=ie.getItem();
0938: if (Assertion.ASSERT)
0939: Assertion.assert((o instanceof String), "selected item is a string");
0940: SyntaxStyle ss=configSet.getStyle((String) o);
0941: styleColorButton.setColor(ss.getForegroundColor());
0942: boldCheckBox.setSelected(ss.isBold());
0943: italicCheckBox.setSelected(ss.isItalic());
0944: }
0945: }
0946: });
0947: styleDropdown.setSelectedIndex(0);
0948:
0949: boldCheckBox.addActionListener(new ActionListener()
0950: {
0951: public void actionPerformed(ActionEvent ae)
0952: {
0953: SyntaxStyle ss=configSet.getStyle((String)styleDropdown.getSelectedItem());
0954: ss.setBold(boldCheckBox.isSelected());
0955: previewPane.repaint();
0956: TextEditorCustomizer.this .setDirty(true);
0957: }
0958: });
0959: italicCheckBox.addActionListener(new ActionListener()
0960: {
0961: public void actionPerformed(ActionEvent ae)
0962: {
0963: SyntaxStyle ss=configSet.getStyle((String)styleDropdown.getSelectedItem());
0964: ss.setItalic(italicCheckBox.isSelected());
0965: previewPane.repaint();
0966: TextEditorCustomizer.this .setDirty(true);
0967: }
0968: });
0969: GridBagConstraints gbc=initGBC();
0970: JPanel tmp=new JPanel(new GridBagLayout());
0971:
0972: tmp.add(styleDropdown, gbc);
0973: gbc.gridx++;
0974: tmp.add(boldCheckBox, gbc);
0975: gbc.gridx++;
0976: tmp.add(italicCheckBox, gbc);
0977: gbc.gridx++;
0978: tmp.add(colorLbl, gbc);
0979: gbc.gridx++;
0980: tmp.add(styleColorButton, gbc);
0981:
0982: tmp.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
0983: stylePropertiesStr,
0984: TitledBorder.LEFT,
0985: TitledBorder.TOP));
0986: return tmp;
0987: }
0988:
0989: private JScrollPane initPreview()
0990: {
0991: String previewStr=ResourceManager.getMessage(ResourceManager.PREVIEW);
0992: previewPane.setBackground(globalBackground);
0993: previewPane.setForeground(globalForeground);
0994: previewPane.setCaretColor(globalCaretColor);
0995: previewPane.setFont(defaultFont);
0996: previewPane.setBorder(BorderFactory.createEtchedBorder());
0997: //margin isn't configurable, for now
0998: previewPane.setMargin(new Insets(8, 8, 8, 8));
0999: previewPane.setTabSize(tabSize);
1000: previewPane.setText(getPreviewText("plain"));
1001: JScrollPane scroller =new JScrollPane(previewPane);
1002: scroller.setPreferredSize(new Dimension(600, 280));
1003: scroller.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
1004: previewStr,
1005: TitledBorder.LEFT,
1006: TitledBorder.TOP));
1007: return scroller;
1008: }
1009:
1010: private void initComponents()
1011: {
1012: customizer=new JPanel(new GridBagLayout());
1013: previewPane=new PreviewPane();
1014: previewPane.setEditorKit(new SyntaxEditorKit(configSet));
1015: GridBagConstraints gbc=initGBC();
1016: gbc.fill=GridBagConstraints.HORIZONTAL;
1017: customizer.add(initGlobal(), gbc);
1018: gbc.gridy=1;
1019: customizer.add(initFileModes(), gbc);
1020: gbc.gridy=2;
1021: customizer.add(initStyles(), gbc);
1022: gbc.gridy=3;
1023: customizer.add(initPreview(), gbc);
1024:
1025: }
1026:
1027: public JComponent getCustomizer()
1028: {
1029: return customizer;
1030: }
1031:
1032: private class FileModeListModel extends AbstractListModel
1033: {
1034: private ArrayList modeList;
1035: private FileMode.ModeMapContainer modeSet;
1036:
1037: FileModeListModel(FileMode.ModeMapContainer modeSet)
1038: {
1039: super ();
1040: this .modeSet=modeSet;
1041: modeList=new ArrayList();
1042: refresh();
1043: }
1044:
1045: public void refresh()
1046: {
1047: modeList.clear();
1048: for (Iterator it=modeSet.modeNames();it.hasNext();)
1049: modeList.add(it.next());
1050: Collections.sort(modeList);
1051: }
1052:
1053: public Object getElementAt(int index)
1054: {
1055: return modeList.get(index);
1056: }
1057:
1058: public int getSize()
1059: {
1060: return modeList.size();
1061: }
1062: }
1063:
1064: private class FileModeExtensionListModel extends AbstractListModel
1065: {
1066: private String[] extensions;
1067:
1068: FileModeExtensionListModel()
1069: {
1070: super ();
1071: }
1072:
1073: void setFileMode(FileMode mode)
1074: {
1075: if (mode!=null)
1076: {
1077: this .extensions=mode.getExtensions();
1078: fireContentsChanged(this , 0, extensions.length);
1079: }
1080: else
1081: {
1082: this .extensions=null;
1083: fireContentsChanged(this , 0, 0);
1084: }
1085:
1086: }
1087:
1088: public int getSize()
1089: {
1090: if (extensions==null)
1091: return 0;
1092: else return extensions.length;
1093: }
1094:
1095: public Object getElementAt(int index)
1096: {
1097: return extensions[index];
1098: }
1099: }
1100:
1101: private class StyleComboBoxModel extends DefaultComboBoxModel
1102: {
1103: ArrayList styleList;
1104:
1105: StyleComboBoxModel()
1106: {
1107: super ();
1108: styleList=new ArrayList();
1109: refresh();
1110: }
1111:
1112: public void refresh()
1113: {
1114: styleList.clear();
1115: for (Iterator it=configSet.styles();it.hasNext();)
1116: {
1117: styleList.add(((SyntaxStyle)it.next()).getName());
1118: }
1119: Collections.sort(styleList);
1120: }
1121:
1122: public int getSize()
1123: {
1124: return styleList.size();
1125: }
1126:
1127: public Object getElementAt(int index)
1128: {
1129: return styleList.get(index);
1130: }
1131: }
1132:
1133: public static class PreviewPane extends TextEditorPane
1134: implements ConfigurableEditor
1135: {
1136: int tabSize=DEFAULT_TAB_SIZE;
1137:
1138: PreviewPane()
1139: {
1140: super ();
1141: }
1142:
1143: public int getTabSize()
1144: {
1145: return tabSize;
1146: }
1147:
1148: public void setTabSize(int tabSize)
1149: {
1150: this .tabSize=tabSize;
1151: getDocument().putProperty("tabSize", new Integer(tabSize));
1152: }
1153: }
1154:}
1155:
1156:/* $Log: TextEditorCustomizer.java,v $
1157:/* Revision 1.7 2001/02/20 18:04:26 smulloni
1158:/* fixed bug in TextEditorCustomizer that prevented file extensions from being
1159:/* removed from file modes.
1160:/*
1161:/* Revision 1.6 2001/02/16 19:57:36 smulloni
1162:/* fixed problem with reverting customizations to the syntax style set.
1163:/*
1164:/* Revision 1.5 2001/02/16 18:15:10 smulloni
1165:/* many fixes to TextEditorCustomizer. FileMode and SyntaxStyle now have a
1166:/* configData property (they will probably be made into sibling classes).
1167:/*
1168:/* Revision 1.4 2001/02/08 23:48:50 smulloni
1169:/* now load default styles from a config file. Styles have been renamed to be
1170:/* more general (comment3 instead of docComment) so future modes won't need to
1171:/* invent more styles.
1172:/*
1173:/* Revision 1.3 2001/02/06 22:13:40 smulloni
1174:/* first more-or-less working version of syntax highlighting, with customization.
1175:/*
1176:/* Revision 1.2 2001/02/06 00:11:18 smulloni
1177:/* struggle, perhaps futile, with the TextEditorCustomizer and other implicated
1178:/* classes
1179:/*
1180: /* Revision 1.1 2001/02/02 23:30:33 smulloni
1181: /* adding customization features to the text editor.
1182: /* */
|