0001: /*
0002: * Editor.java
0003: *
0004: * Created on August 4, 2000, 9:06 AM
0005: */
0006: package org.netbeans.editor.example;
0007:
0008: import java.util.*;
0009:
0010: import java.net.URL;
0011: import java.io.*;
0012: import java.awt.Component;
0013: import java.awt.Dimension;
0014: import java.awt.MenuItem;
0015: import java.awt.event.*;
0016: import java.util.ArrayList;
0017: import java.util.Collection;
0018: import java.util.Iterator;
0019:
0020: import javax.swing.*;
0021: import javax.swing.text.Document;
0022: import javax.swing.text.EditorKit;
0023: import javax.swing.text.JTextComponent;
0024: import javax.swing.event.DocumentListener;
0025: import javax.swing.event.DocumentEvent;
0026: import javax.swing.undo.UndoManager;
0027: import javax.swing.filechooser.FileFilter;
0028: import javax.swing.filechooser.FileView;
0029: import org.netbeans.editor.*;
0030: import org.netbeans.editor.ext.*;
0031:
0032: /**
0033: *
0034: * @author Petr Nejedly
0035: * @version 0.2
0036: */
0037: public class Editor extends javax.swing.JFrame {
0038:
0039: private static final File distributionDirectory;
0040:
0041: static {
0042: URL url = Editor.class.getProtectionDomain().getCodeSource()
0043: .getLocation();
0044: String protocol = url.getProtocol();
0045: File file = new File(url.getFile());
0046: if (!file.isDirectory())
0047: file = file.getParentFile();
0048: distributionDirectory = file;
0049: }
0050:
0051: /** Document property holding String name of associated file */
0052: private static final String FILE = "file"; // NOI18N
0053: /** Document property holding Boolean if document was created or opened */
0054: private static final String CREATED = "created"; // NOI18N
0055: /** Document property holding Boolean modified information */
0056: private static final String MODIFIED = "modified"; // NOI18N
0057:
0058: private ResourceBundle settings = ResourceBundle
0059: .getBundle("settings"); // NOI18N
0060:
0061: private JFileChooser fileChooser;
0062:
0063: private boolean createBackups;
0064: private boolean safeSave;
0065:
0066: private int fileCounter = -1;
0067: Map com2text = new HashMap();
0068:
0069: private Impl impl = new Impl("org.netbeans.editor.Bundle"); // NOI18N
0070:
0071: private class Impl extends FileView implements WindowListener,
0072: ActionListener, LocaleSupport.Localizer {
0073:
0074: private ResourceBundle bundle;
0075:
0076: public Impl(String bundleName) {
0077: bundle = ResourceBundle.getBundle(bundleName);
0078: }
0079:
0080: // FileView implementation
0081: public String getName(File f) {
0082: return null;
0083: }
0084:
0085: public String getDescription(File f) {
0086: return null;
0087: }
0088:
0089: public String getTypeDescription(File f) {
0090: return null;
0091: }
0092:
0093: public Boolean isTraversable(File f) {
0094: return null;
0095: }
0096:
0097: public Icon getIcon(File f) {
0098: if (f.isDirectory())
0099: return null;
0100: KitInfo ki = KitInfo.getKitInfoForFile(f);
0101: return ki == null ? null : ki.getIcon();
0102: }
0103:
0104: // Localizer
0105: public String getString(String key) {
0106: return bundle.getString(key);
0107: }
0108:
0109: // Mostly no-op WindowListener for close
0110: public void windowActivated(WindowEvent evt) {
0111: }
0112:
0113: public void windowClosed(WindowEvent evt) {
0114: }
0115:
0116: public void windowDeactivated(WindowEvent evt) {
0117: }
0118:
0119: public void windowDeiconified(WindowEvent evt) {
0120: }
0121:
0122: public void windowIconified(WindowEvent evt) {
0123: }
0124:
0125: public void windowOpened(WindowEvent evt) {
0126: }
0127:
0128: public void windowClosing(java.awt.event.WindowEvent evt) {
0129: doExit();
0130: }
0131:
0132: // ActionListener for menu items
0133: public void actionPerformed(java.awt.event.ActionEvent evt) {
0134: Object src = evt.getSource();
0135:
0136: if (!handleOpenRecent(src)) {
0137: if (src == openItem) {
0138: fileChooser.setMultiSelectionEnabled(true);
0139: int returnVal = fileChooser
0140: .showOpenDialog(Editor.this );
0141: if (returnVal == JFileChooser.APPROVE_OPTION) {
0142: File[] files = fileChooser.getSelectedFiles();
0143: for (int i = 0; i < files.length; i++)
0144: openFile(files[i], i == 0);
0145: }
0146: fileChooser.setMultiSelectionEnabled(false);
0147: } else if (src == closeItem) {
0148: Component editor = tabPane.getSelectedComponent();
0149: if (checkClose(editor)) {
0150: doCloseEditor(editor);
0151: }
0152: } else if (src == saveItem) {
0153: saveFile(tabPane.getSelectedComponent());
0154: } else if (src == saveAsItem) {
0155: saveAs(tabPane.getSelectedComponent());
0156: } else if (src == saveAllItem) {
0157: int index = tabPane.getSelectedIndex();
0158: for (int i = 0; i < tabPane.getComponentCount(); i++) {
0159: saveFile(tabPane.getComponentAt(i));
0160: }
0161: tabPane.setSelectedIndex(index);
0162: } else if (src == exitItem) {
0163: doExit();
0164: } else if (src instanceof JMenuItem) {
0165: Object ki = ((JMenuItem) src)
0166: .getClientProperty("kitInfo"); // NOI18N
0167:
0168: if (ki instanceof KitInfo) {
0169: createNewFile((KitInfo) ki);
0170: }
0171: }
0172: }
0173: }
0174: }
0175:
0176: public Editor() {
0177: super ("NetBeans Editor"); // NOI18N
0178: LocaleSupport.addLocalizer(impl);
0179:
0180: // Feed our kits with their default Settings
0181: Settings.addInitializer(new BaseSettingsInitializer(),
0182: Settings.CORE_LEVEL);
0183: Settings.addInitializer(new ExtSettingsInitializer(),
0184: Settings.CORE_LEVEL);
0185: Settings.reset();
0186:
0187: // Create visual hierarchy
0188: initComponents();
0189: openItem.addActionListener(impl);
0190: closeItem.addActionListener(impl);
0191: saveItem.addActionListener(impl);
0192: saveAsItem.addActionListener(impl);
0193: saveAllItem.addActionListener(impl);
0194: exitItem.addActionListener(impl);
0195: addWindowListener(impl);
0196:
0197: // Prepare the editor kits and such things
0198: readSettings();
0199:
0200: // Do the actual layout
0201: setLocation(150, 150);
0202: pack();
0203:
0204: fileToMenu = new HashMap();
0205: menuToFile = new HashMap();
0206: recentFiles = new Vector();
0207: maxRecent = 4;
0208:
0209: createBackups = false;
0210: safeSave = true;
0211: }
0212:
0213: public Dimension getPreferredSize() {
0214: Dimension size = new Dimension(640, 480);
0215: return size;
0216: }
0217:
0218: /** This method is called from within the constructor to
0219: * initialize the form.
0220: * WARNING: Do NOT modify this code. The content of this method is
0221: * always regenerated by the Form Editor.
0222: */
0223: private void initComponents() {//GEN-BEGIN:initComponents
0224: tabPane = new javax.swing.JTabbedPane();
0225: menuBar = new javax.swing.JMenuBar();
0226: fileMenu = new javax.swing.JMenu();
0227: newMenu = new javax.swing.JMenu();
0228: openItem = new javax.swing.JMenuItem();
0229: closeItem = new javax.swing.JMenuItem();
0230: sep1 = new javax.swing.JSeparator();
0231: saveItem = new javax.swing.JMenuItem();
0232: saveAsItem = new javax.swing.JMenuItem();
0233: saveAllItem = new javax.swing.JMenuItem();
0234: sep2 = new javax.swing.JSeparator();
0235: exitItem = new javax.swing.JMenuItem();
0236:
0237: getContentPane().setLayout(new java.awt.GridLayout(1, 1));
0238:
0239: setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
0240: getContentPane().add(tabPane);
0241:
0242: fileMenu.setMnemonic(KeyEvent.VK_F);
0243: fileMenu.setText("File"); // NOI18N
0244: newMenu.setMnemonic(KeyEvent.VK_N);
0245: newMenu.setText("New..."); // NOI18N
0246: fileMenu.add(newMenu);
0247: openItem.setMnemonic(KeyEvent.VK_O);
0248: openItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
0249: java.awt.event.KeyEvent.VK_O,
0250: java.awt.event.InputEvent.CTRL_MASK));
0251: openItem.setText("Open File..."); // NOI18N
0252: fileMenu.add(openItem);
0253: closeItem.setMnemonic(KeyEvent.VK_C);
0254: closeItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
0255: java.awt.event.KeyEvent.VK_F4,
0256: java.awt.event.InputEvent.CTRL_MASK));
0257: closeItem.setText("Close"); // NOI18N
0258: fileMenu.add(closeItem);
0259: fileMenu.add(sep1);
0260: saveItem.setMnemonic(KeyEvent.VK_S);
0261: saveItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
0262: java.awt.event.KeyEvent.VK_S,
0263: java.awt.event.InputEvent.CTRL_MASK));
0264: saveItem.setText("Save"); // NOI18N
0265: fileMenu.add(saveItem);
0266: saveAsItem.setMnemonic(KeyEvent.VK_A);
0267: saveAsItem.setText("Save As..."); // NOI18N
0268: fileMenu.add(saveAsItem);
0269: saveAllItem.setMnemonic(KeyEvent.VK_L);
0270: saveAllItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
0271: java.awt.event.KeyEvent.VK_A,
0272: java.awt.event.InputEvent.CTRL_MASK));
0273: saveAllItem.setText("Save All"); // NOI18N
0274: fileMenu.add(saveAllItem);
0275: fileMenu.add(sep2);
0276: exitItem.setMnemonic(KeyEvent.VK_E);
0277: exitItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(
0278: java.awt.event.KeyEvent.VK_X,
0279: java.awt.event.InputEvent.CTRL_MASK));
0280: exitItem.setText("Exit"); // NOI18N
0281: fileMenu.add(exitItem);
0282: menuBar.add(fileMenu);
0283: setJMenuBar(menuBar);
0284:
0285: }//GEN-END:initComponents
0286:
0287: private boolean saveFile(Component comp, File file,
0288: boolean checkOverwrite) {
0289: if (comp == null)
0290: return false;
0291: tabPane.setSelectedComponent(comp);
0292: JTextComponent edit = (JTextComponent) com2text.get(comp);
0293: Document doc = edit.getDocument();
0294:
0295: if (checkOverwrite && file.exists()) {
0296: tabPane.setSelectedComponent(comp);
0297: int choice = JOptionPane.showOptionDialog(this ,
0298: "File " + file.getName()
0299: + " already exists, overwrite?", // NOI18N
0300: "File exists", // NOI18N
0301: JOptionPane.YES_NO_CANCEL_OPTION,
0302: JOptionPane.QUESTION_MESSAGE, null, // don't use a custom Icon
0303: null, // use standard button titles
0304: null // no default selection
0305: );
0306: if (choice != 0)
0307: return false;
0308: }
0309:
0310: File safeSaveFile = new File(file.getAbsolutePath() + "~~"); // NOI18N
0311: File backupFile = new File(file.getAbsolutePath() + "~"); // NOI18N
0312:
0313: if (safeSave || createBackups) {
0314: file.renameTo(safeSaveFile);
0315: }
0316:
0317: FileWriter output = null;
0318:
0319: try {
0320: output = new FileWriter(file);
0321: edit.write(output);
0322:
0323: if (createBackups) {
0324: safeSaveFile.renameTo(backupFile);
0325: } else {
0326: if (safeSave) {
0327: safeSaveFile.delete();
0328: }
0329: }
0330: } catch (IOException exc) {
0331: JOptionPane.showMessageDialog(this , "Can't write to file '"
0332: + // NOI18N
0333: file.getName() + "'.", "Error",
0334: JOptionPane.ERROR_MESSAGE); // NOI18N
0335:
0336: if (safeSave)
0337: safeSaveFile.renameTo(file);
0338:
0339: return false;
0340: } finally {
0341: if (output != null) {
0342: try {
0343: output.close();
0344: } catch (IOException e) {
0345: e.printStackTrace(System.err);
0346: }
0347: }
0348: }
0349:
0350: doc.putProperty(MODIFIED, Boolean.FALSE);
0351: doc.putProperty(CREATED, Boolean.FALSE);
0352: doc.putProperty(FILE, file);
0353: doc.addDocumentListener(new MarkingDocumentListener(comp));
0354:
0355: int index = tabPane.indexOfComponent(comp);
0356: tabPane.setTitleAt(index, file.getName());
0357:
0358: return true;
0359: }
0360:
0361: private boolean saveFile(Component comp) {
0362: if (comp == null)
0363: return false;
0364: JTextComponent edit = (JTextComponent) com2text.get(comp);
0365: Document doc = edit.getDocument();
0366: File file = (File) doc.getProperty(FILE);
0367: boolean created = ((Boolean) doc.getProperty(CREATED))
0368: .booleanValue();
0369:
0370: return saveFile(comp, file, created);
0371: }
0372:
0373: private boolean saveAs(Component comp) {
0374: if (comp == null)
0375: return false;
0376: JTextComponent edit = (JTextComponent) com2text.get(comp);
0377: File file = (File) edit.getDocument().getProperty(FILE);
0378:
0379: fileChooser.setCurrentDirectory(file.getParentFile());
0380: fileChooser.setSelectedFile(file);
0381: KitInfo fileInfo = KitInfo.getKitInfoOrDefault(file);
0382:
0383: if (fileInfo != null)
0384: fileChooser.setFileFilter(fileInfo);
0385:
0386: // show the dialog, test the result
0387: if (fileChooser.showSaveDialog(this ) == JFileChooser.APPROVE_OPTION)
0388: return saveFile(comp, fileChooser.getSelectedFile(), true);
0389: else
0390: return false; // Cancel was pressed - not saved
0391: }
0392:
0393: private void openFile(File file, boolean focus) {
0394: KitInfo info = KitInfo.getKitInfoOrDefault(file);
0395:
0396: final JEditorPane pane = new JEditorPane(info.getType(), "");
0397: try {
0398: pane.read(new FileInputStream(file), file
0399: .getCanonicalPath());
0400: } catch (IOException exc) {
0401: JOptionPane.showMessageDialog(this ,
0402: "Can't read from file '" + // NOI18N
0403: file.getName() + "'.", "Error",
0404: JOptionPane.ERROR_MESSAGE); // NOI18N
0405: return;
0406: }
0407: addEditorPane(pane, info.getIcon(), file, false, focus);
0408:
0409: removeFromRecent(file.getAbsolutePath());
0410: }
0411:
0412: private void doExit() {
0413: boolean exit = true;
0414: int components = tabPane.getComponentCount();
0415:
0416: for (int cntr = 0; cntr < components; cntr++) {
0417: Component editor = tabPane.getComponentAt(cntr);
0418:
0419: if (!checkClose(editor)) {
0420: exit = false;
0421: return;
0422: }
0423: }
0424:
0425: if (!exit) {
0426: System.err.println("keeping");
0427: return;
0428: }
0429:
0430: writeUserConfiguration();
0431:
0432: while (tabPane.getComponentCount() > 0) {
0433: Component editor = tabPane.getComponentAt(0);
0434:
0435: if ((editor != null) && (com2text.get(editor) != null))
0436: doCloseEditor(editor);
0437: }
0438:
0439: if (exit)
0440: System.exit(0);
0441: }
0442:
0443: private void doCloseEditor(Component editor) {
0444: JTextComponent editorPane = (JTextComponent) com2text
0445: .get(editor);
0446: if (editorPane != null) {
0447: File file = (File) editorPane.getDocument().getProperty(
0448: FILE);
0449:
0450: addToRecent(file.getAbsolutePath());
0451: }
0452:
0453: tabPane.remove(editor);
0454: com2text.remove(editor);
0455: }
0456:
0457: private boolean checkClose(Component comp) {
0458: if (comp == null)
0459: return false;
0460: JTextComponent edit = (JTextComponent) com2text.get(comp);
0461: Document doc = edit.getDocument();
0462:
0463: Object mod = doc.getProperty(MODIFIED);
0464: if (mod == null || !((Boolean) mod).booleanValue())
0465: return true;
0466:
0467: tabPane.setSelectedComponent(comp);
0468: File file = (File) doc.getProperty(FILE);
0469:
0470: for (;;) {
0471: int choice = JOptionPane.showOptionDialog(this ,
0472: "File " + file.getName()
0473: + " was modified, save it?", // NOI18N
0474: "File modified", // NOI18N
0475: JOptionPane.YES_NO_CANCEL_OPTION,
0476: JOptionPane.QUESTION_MESSAGE, null, // don't use a custom Icon
0477: new String[] { "Save", "Save As...", "Discard",
0478: "Cancel" }, // use standard button titles // NOI18N
0479: "Cancel" //default selection // NOI18N
0480: );
0481:
0482: switch (choice) {
0483: case JOptionPane.CLOSED_OPTION:
0484: case 4:
0485: return false; // Cancel or Esc pressed
0486: case 1:
0487: if (!saveAs(comp))
0488: continue; // Ask for fileName, then save
0489: return true;
0490: case 0:
0491: if (!saveFile(comp))
0492: continue; // else fall through
0493: case 2:
0494: return true; // Discard changes, close window
0495: }
0496: return false;
0497: }
0498: }
0499:
0500: private void addEditorPane(JEditorPane pane, Icon icon, File file,
0501: boolean created, boolean focus) {
0502: final JComponent c = (pane.getUI() instanceof BaseTextUI) ? Utilities
0503: .getEditorUI(pane).getExtComponent()
0504: : new JScrollPane(pane);
0505: Document doc = pane.getDocument();
0506:
0507: doc.addDocumentListener(new MarkingDocumentListener(c));
0508: doc.putProperty(FILE, file);
0509: doc
0510: .putProperty(CREATED, created ? Boolean.TRUE
0511: : Boolean.FALSE);
0512:
0513: UndoManager um = new UndoManager();
0514: doc.addUndoableEditListener(um);
0515: doc.putProperty(BaseDocument.UNDO_MANAGER_PROP, um);
0516:
0517: com2text.put(c, pane);
0518: tabPane.addTab(file.getName(), icon, c, file.getAbsolutePath());
0519: if (focus) {
0520: tabPane.setSelectedComponent(c);
0521: pane.requestFocus();
0522: }
0523: }
0524:
0525: private void createNewFile(KitInfo info) {
0526: final String fileName = ((++fileCounter == 0) ? "unnamed" : // NOI18N
0527: ("unnamed" + fileCounter)) + info.getDefaultExtension(); // NOI18N
0528: final File file = new File(fileName).getAbsoluteFile();
0529:
0530: final JEditorPane pane = new JEditorPane(info.getType(), "");
0531: URL template = info.getTemplate();
0532: if (template != null) {
0533: try {
0534: pane.read(template.openStream(), file
0535: .getCanonicalPath());
0536: } catch (IOException e) {
0537: JOptionPane.showMessageDialog(this ,
0538: "Can't read template", "Error",
0539: JOptionPane.ERROR_MESSAGE); // NOI18N
0540: }
0541: }
0542: addEditorPane(pane, info.getIcon(), file, true, true);
0543: }
0544:
0545: public static File getDistributionDirectory() {
0546: return distributionDirectory;
0547: }
0548:
0549: /**
0550: * @param args the command line arguments
0551: */
0552: public static void main(String args[]) {
0553: if (!getDistributionDirectory().canRead()) {
0554: System.err
0555: .println("Fatal error while startup - can read from distribution directory.");
0556: System.exit(0);
0557: }
0558:
0559: Editor editor = new Editor();
0560:
0561: editor.show();
0562:
0563: editor.readUserConfiguration();
0564:
0565: for (int i = 0; i < args.length; i++) {
0566: String fileName = args[i];
0567: editor.openFile(new File(fileName), i == 0);
0568: }
0569: }
0570:
0571: private Map fileToMenu;
0572: private Map menuToFile;
0573: private Vector recentFiles;
0574: private int maxRecent;
0575: private JSeparator recentSeparator;
0576: private int separatorIndex;
0577:
0578: private String[] getOpenedFiles() {
0579: ArrayList opened = new ArrayList();
0580:
0581: int components = tabPane.getComponentCount();
0582:
0583: for (int cntr = 0; cntr < components; cntr++) {
0584: Component editorComponent = tabPane.getComponentAt(cntr);
0585:
0586: JTextComponent editor = (JTextComponent) com2text
0587: .get(editorComponent);
0588:
0589: if (editor == null) {
0590: continue;
0591: }
0592:
0593: Document doc = editor.getDocument();
0594: File file = (File) doc.getProperty(FILE);
0595:
0596: if (file != null) {
0597: opened.add(file.getAbsolutePath());
0598: }
0599: }
0600:
0601: return (String[]) opened.toArray(new String[opened.size()]);
0602: }
0603:
0604: private int findInRecent(String fileToFind) {
0605: for (int cntr = 0; cntr < recentFiles.size(); cntr++) {
0606: String file = (String) recentFiles.get(cntr);
0607:
0608: if (fileToFind.equals(file))
0609: return cntr;
0610: }
0611:
0612: return -1;
0613: }
0614:
0615: private boolean handleOpenRecent(Object source) {
0616: String fileName = (String) menuToFile.get(source);
0617:
0618: if (fileName == null)
0619: return false;
0620:
0621: openFile(new File(fileName), true);
0622:
0623: return true;
0624: }
0625:
0626: private String generateMenuItemName(int index, String file) {
0627: return "" + index + ". " + file; // NOI18N
0628: }
0629:
0630: private void addToRecent(String fileToAdd) {
0631: //Remove possible previous occurence:
0632: removeFromRecent(fileToAdd);
0633:
0634: if (recentFiles.size() >= maxRecent) {
0635: while (recentFiles.size() >= maxRecent) {
0636: removeFromRecent(recentFiles.size() - 1);
0637: }
0638: }
0639:
0640: recentFiles.add(0, fileToAdd);
0641:
0642: JMenuItem newItem = new JMenuItem(generateMenuItemName(1,
0643: fileToAdd));
0644:
0645: if (recentFiles.size() == 1) {
0646: recentSeparator = new JSeparator();
0647: fileMenu.add(recentSeparator);
0648: separatorIndex = fileMenu.getMenuComponentCount();
0649: }
0650:
0651: newItem.addActionListener(impl);
0652:
0653: fileMenu.insert(newItem, separatorIndex);
0654: fileToMenu.put(fileToAdd, newItem);
0655: menuToFile.put(newItem, fileToAdd);
0656:
0657: correctItemNumbers();
0658: }
0659:
0660: private void correctItemNumbers() {
0661: for (int cntr = 0; cntr < recentFiles.size(); cntr++) {
0662: JMenuItem item = (JMenuItem) fileToMenu.get(recentFiles
0663: .get(cntr));
0664:
0665: item.setText(generateMenuItemName(cntr + 1,
0666: (String) recentFiles.get(cntr)));
0667: }
0668: }
0669:
0670: private void removeFromRecent(String fileToRemove) {
0671: int position = findInRecent(fileToRemove);
0672:
0673: if (position != (-1))
0674: removeFromRecent(position);
0675: }
0676:
0677: private void removeFromRecent(int indexToRemove) {
0678: String file = (String) recentFiles.get(indexToRemove);
0679:
0680: recentFiles.remove(indexToRemove);
0681:
0682: JMenuItem fileItem = (JMenuItem) fileToMenu.get(file);
0683:
0684: fileMenu.remove(fileItem);
0685:
0686: fileToMenu.remove(file);
0687: menuToFile.remove(fileItem);
0688:
0689: correctItemNumbers();
0690:
0691: if (recentFiles.size() == 0) {
0692: fileMenu.remove(recentSeparator);
0693: recentSeparator = null;
0694: separatorIndex = -1;
0695: }
0696: }
0697:
0698: private String[] readStrings(ResourceBundle bundle, String prefix) {
0699: int count = 0;
0700: boolean finish = false;
0701: ArrayList result = new ArrayList();
0702:
0703: while (!finish) {
0704: try {
0705: String current = bundle.getString(prefix + "_" + count);
0706:
0707: result.add(current);
0708: count++;
0709: } catch (MissingResourceException e) {
0710: finish = true;
0711: }
0712: }
0713:
0714: return (String[]) result.toArray(new String[result.size()]);
0715: }
0716:
0717: private void readUserConfiguration(ResourceBundle bundle) {
0718: String[] openedFiles = readStrings(bundle, "Open-File"); // NOI18N
0719: String[] recentFiles = readStrings(bundle, "Recent-File"); // NOI18N
0720: String recentFilesMaxCount = bundle
0721: .getString("Max-Recent-Files");
0722: String safeSaveString = bundle.getString("Safe-Save");
0723: String createBackupsString = bundle.getString("Create-Backups");
0724:
0725: this .maxRecent = Integer.parseInt(recentFilesMaxCount);
0726: this .safeSave = Boolean.valueOf(safeSaveString).booleanValue();
0727: this .createBackups = Boolean.valueOf(createBackupsString)
0728: .booleanValue();
0729:
0730: for (int cntr = recentFiles.length; cntr > 0; cntr--) {
0731: addToRecent(recentFiles[cntr - 1]);
0732: }
0733:
0734: for (int cntr = 0; cntr < openedFiles.length; cntr++) {
0735: openFile(new File(openedFiles[cntr]), false);
0736: }
0737: }
0738:
0739: private void writeUserConfiguration(PrintWriter output) {
0740: output.println("Max-Recent-Files=" + maxRecent); // NOI18N
0741: output.println("Safe-Save=" + safeSave); // NOI18N
0742: output.println("Create-Backups=" + createBackups); // NOI18N
0743:
0744: for (int cntr = 0; cntr < recentFiles.size(); cntr++) {
0745: output.println("Recent-File_" + cntr + "="
0746: + recentFiles.get(cntr)); // NOI18N
0747: }
0748: String[] openFiles = getOpenedFiles();
0749:
0750: for (int cntr = 0; cntr < openFiles.length; cntr++) {
0751: output.println("Open-File_" + cntr + "=" + openFiles[cntr]); // NOI18N
0752: }
0753: }
0754:
0755: private File getConfigurationFileName() {
0756: File homedir = new File(System.getProperty("user.home"))
0757: .getAbsoluteFile();
0758: File configurationFile = new File(homedir, ".nb-editor"); // NOI18N
0759:
0760: return configurationFile;
0761: }
0762:
0763: private void writeUserConfiguration() {
0764: File configurationFile = getConfigurationFileName();
0765: File configurationFileBackup = new File(configurationFile
0766: .getAbsolutePath()
0767: + "~"); // NOI18N
0768: boolean backup = false;
0769:
0770: if (configurationFile.exists()) {
0771: backup = true;
0772: configurationFile.renameTo(configurationFileBackup);
0773: }
0774:
0775: PrintWriter output = null;
0776: try {
0777: output = new PrintWriter(new FileWriter(configurationFile));
0778:
0779: writeUserConfiguration(output);
0780:
0781: if (backup) {
0782: if (!output.checkError()) {
0783: configurationFileBackup.delete();
0784: } else {
0785: //Put back to original configuration:
0786: configurationFileBackup.renameTo(configurationFile);
0787: }
0788: }
0789: } catch (IOException e) {
0790: e.printStackTrace();
0791: } finally {
0792: if (output != null) {
0793: output.close();
0794: }
0795: }
0796: }
0797:
0798: private void readUserConfiguration() {
0799: File configurationFileName = getConfigurationFileName();
0800: InputStream in = null;
0801: try {
0802: in = new FileInputStream(configurationFileName);
0803: readUserConfiguration(new PropertyResourceBundle(in));
0804: } catch (FileNotFoundException e) {
0805: //The file containing user-defined configuration not found.
0806: //This is nothing really important.
0807: try {
0808: System.err.println("User configuration not found in \""
0809: + configurationFileName.getCanonicalPath()
0810: + "\".");
0811: } catch (IOException f) {
0812: }
0813: } catch (IOException e) {
0814: e.printStackTrace();
0815: } finally {
0816: if (in != null) {
0817: try {
0818: in.close();
0819: } catch (IOException e) {
0820: e.printStackTrace();
0821: }
0822: }
0823: }
0824:
0825: }
0826:
0827: // Variables declaration - do not modify//GEN-BEGIN:variables
0828: private javax.swing.JSeparator sep2;
0829: private javax.swing.JSeparator sep1;
0830: private javax.swing.JMenu newMenu;
0831: private javax.swing.JMenuItem saveAllItem;
0832: private javax.swing.JMenuItem closeItem;
0833: private javax.swing.JMenuBar menuBar;
0834: private javax.swing.JMenuItem exitItem;
0835: private javax.swing.JTabbedPane tabPane;
0836: private javax.swing.JMenuItem saveAsItem;
0837: private javax.swing.JMenu fileMenu;
0838: private javax.swing.JMenuItem openItem;
0839: private javax.swing.JMenuItem saveItem;
0840:
0841: // End of variables declaration//GEN-END:variables
0842:
0843: private void readSettings() throws MissingResourceException {
0844: File currentPath = new File(System.getProperty("user.dir"))
0845: .getAbsoluteFile();
0846: fileChooser = new JFileChooser(currentPath);
0847:
0848: fileChooser.setFileView(impl);
0849:
0850: String kits = settings.getString("InstalledEditors");
0851: String defaultKit = settings.getString("DefaultEditor");
0852:
0853: StringTokenizer st = new StringTokenizer(kits, ","); // NOI18N
0854: while (st.hasMoreTokens()) {
0855: String kitName = st.nextToken();
0856: // At the first, we have to read ALL info about kit
0857: String contentType = settings.getString(kitName
0858: + "_ContentType");
0859: String extList = settings.getString(kitName
0860: + "_ExtensionList");
0861: String menuTitle = settings.getString(kitName
0862: + "_NewMenuTitle");
0863: char menuMnemonic = settings.getString(
0864: kitName + "_NewMenuMnemonic").charAt(0);
0865: String templateURL = settings.getString(kitName
0866: + "_Template");
0867: String iconName = settings.getString(kitName + "_Icon");
0868: String filterTitle = settings.getString(kitName
0869: + "_FileFilterTitle");
0870: String kit = settings.getString(kitName + "_KitClass");
0871:
0872: // At the second, we surely need an instance of kitClass
0873: Class kitClass;
0874: try {
0875: kitClass = Class.forName(kit);
0876: } catch (ClassNotFoundException exc) { // we really need it
0877: throw new MissingResourceException("Missing class",
0878: kit, "KitClass"); // NOI18N
0879: }
0880:
0881: // At the third, it is nice to have icon although we could live without one
0882: Icon icon = null;
0883: ClassLoader loader = kitClass.getClassLoader();
0884: if (loader == null)
0885: loader = ClassLoader.getSystemClassLoader();
0886: URL resource = loader.getResource(iconName);
0887: if (resource == null)
0888: resource = ClassLoader.getSystemResource(iconName);
0889: if (resource != null)
0890: icon = new ImageIcon(resource);
0891:
0892: // At the fourth, try to get URL for template
0893: URL template = loader.getResource(templateURL);
0894: if (resource == null)
0895: template = ClassLoader.getSystemResource(templateURL);
0896:
0897: // Finally, convert the list of extensions to, ehm, List :-)
0898: List l = new ArrayList(5);
0899: StringTokenizer extST = new StringTokenizer(extList, ","); // NOI18N
0900: while (extST.hasMoreTokens())
0901: l.add(extST.nextToken());
0902:
0903: // Actually create the KitInfo from provided informations
0904: KitInfo ki = new KitInfo(contentType, l, template, icon,
0905: filterTitle, kitClass, loader, defaultKit
0906: .equals(kitName));
0907:
0908: // Make the MenuItem for it
0909: JMenuItem item = new JMenuItem(menuTitle, icon);
0910: item.setMnemonic(menuMnemonic);
0911: item.putClientProperty("kitInfo", ki); // NOI18N
0912: item.addActionListener(impl);
0913: newMenu.add(item);
0914:
0915: // Register a FileFilter for given type of file
0916: fileChooser.addChoosableFileFilter(ki);
0917: }
0918:
0919: // Finally, add fileFilter that would recognize files of all kits
0920:
0921: fileChooser.addChoosableFileFilter(new FileFilter() {
0922: public String getDescription() {
0923: return "All recognized files"; // NOI18N
0924: }
0925:
0926: public boolean accept(File f) {
0927: return f.isDirectory()
0928: || KitInfo.getKitInfoForFile(f) != null;
0929: }
0930: });
0931:
0932: if (KitInfo.getDefault() == null)
0933: throw new MissingResourceException(
0934: "Missing default kit definition", defaultKit,
0935: "DefaultEditor"); // NOI18N
0936: }
0937:
0938: private static final class KitInfo extends FileFilter {
0939:
0940: private static List kits = new ArrayList();
0941: private static KitInfo defaultKitInfo;
0942:
0943: public static List getKitList() {
0944: return new ArrayList(kits);
0945: }
0946:
0947: public static KitInfo getDefault() {
0948: return defaultKitInfo;
0949: }
0950:
0951: public static KitInfo getKitInfoOrDefault(File f) {
0952: KitInfo ki = getKitInfoForFile(f);
0953: return ki == null ? defaultKitInfo : ki;
0954: }
0955:
0956: public static KitInfo getKitInfoForFile(File f) {
0957: for (int i = 0; i < kits.size(); i++) {
0958: if (((KitInfo) kits.get(i)).accept(f))
0959: return (KitInfo) kits.get(i);
0960: }
0961: return null;
0962: }
0963:
0964: private String type;
0965: private String[] extensions;
0966: private URL template;
0967: private Icon icon;
0968: private Class kitClass;
0969: private String description;
0970:
0971: public KitInfo(String type, List exts, URL template, Icon icon,
0972: String description, Class kitClass, ClassLoader loader,
0973: boolean isDefault) {
0974: // Fill in the structure
0975: this .type = type;
0976: this .extensions = (String[]) exts.toArray(new String[0]);
0977: this .template = template;
0978: this .icon = icon;
0979: this .description = description;
0980: this .kitClass = kitClass;
0981:
0982: // Register us
0983: JEditorPane.registerEditorKitForContentType(type, kitClass
0984: .getName(), loader);
0985: kits.add(this );
0986: if (isDefault)
0987: defaultKitInfo = this ;
0988: }
0989:
0990: public String getType() {
0991: return type;
0992: }
0993:
0994: public String getDefaultExtension() {
0995: return extensions[0];
0996: }
0997:
0998: public URL getTemplate() {
0999: return template;
1000: }
1001:
1002: public Icon getIcon() {
1003: return icon;
1004: }
1005:
1006: public Class getKitClass() {
1007: return kitClass;
1008: }
1009:
1010: public String getDescription() {
1011: return description;
1012: }
1013:
1014: public boolean accept(File f) {
1015: if (f.isDirectory())
1016: return true;
1017: String fileName = f.getName();
1018: for (int i = 0; i < extensions.length; i++) {
1019: if (fileName.endsWith(extensions[i]))
1020: return true;
1021: }
1022: return false;
1023: }
1024: }
1025:
1026: /** Listener listening for document changes on opened documents. There is
1027: * initially one instance per opened document, but this listener is
1028: * one-fire only - as soon as it gets fired, markes changes and removes
1029: * itself from document. On save, new Listener is hooked again.
1030: */
1031: private class MarkingDocumentListener implements DocumentListener {
1032: private Component comp;
1033:
1034: public MarkingDocumentListener(Component comp) {
1035: this .comp = comp;
1036: }
1037:
1038: private void markChanged(DocumentEvent evt) {
1039: Document doc = evt.getDocument();
1040: doc.putProperty(MODIFIED, Boolean.TRUE);
1041:
1042: File file = (File) doc.getProperty(FILE);
1043: int index = tabPane.indexOfComponent(comp);
1044:
1045: tabPane.setTitleAt(index, file.getName() + '*');
1046:
1047: doc.removeDocumentListener(this );
1048: }
1049:
1050: public void changedUpdate(DocumentEvent e) {
1051: }
1052:
1053: public void insertUpdate(DocumentEvent evt) {
1054: markChanged(evt);
1055: }
1056:
1057: public void removeUpdate(DocumentEvent evt) {
1058: markChanged(evt);
1059: }
1060: }
1061: }
|