/* Jreepad - personal information manager. Copyright (C) 2004 Dan Stowell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The full license can be read online here: http://www.gnu.org/copyleft/gpl.html */ package jreepad; import java.awt.Color; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Event; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.lang.reflect.Method; import java.net.URL; import java.util.ListIterator; import java.util.ResourceBundle; import java.util.Vector; import javax.swing.AbstractAction; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SpinnerNumberModel; import javax.swing.UIManager; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import javax.swing.undo.UndoManager; import jreepad.io.AutoDetectReader; import jreepad.io.EncryptedWriter; import jreepad.io.HtmlWriter; import jreepad.io.JreepadReader; import jreepad.io.JreepadWriter; import jreepad.io.TreepadWriter; import jreepad.io.XmlWriter; import jreepad.ui.PasswordDialog; import jreepad.ui.SaveFileChooser; import edu.stanford.ejalbert.BrowserLauncher; import edu.stanford.ejalbert.exception.BrowserLaunchingExecutionException; import edu.stanford.ejalbert.exception.BrowserLaunchingInitializingException; import edu.stanford.ejalbert.exception.UnsupportedOperatingSystemException; import jreepad.ui.FontHelper; public class JreepadViewer extends JFrame { // implements ApplicationListener // Jreepad version, to appear in "about" box etc public static String version = "1.6 rc1"; private static Vector theApps = new Vector(1,1); private Box toolBar, toolBarIconic; private JreepadView theJreepad; private JreepadTreeModel document; private Container content; // DEPRECATED private File prefsFile = new File(System.getProperty("user.home"), ".jreepref"); protected static ResourceBundle lang = ResourceBundle.getBundle("jreepad.lang.JreepadStrings"); // private static final String[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(null); // private static final String[] fontSizes = new String[] {"8","9","10","11","12","13","14","16","18","20","24","30","36"}; private JFileChooser fileChooser; private String windowTitle; protected Clipboard systemClipboard; private JButton addAboveButton; private JButton addBelowButton; private JButton addButton; private JButton removeButton; private JButton upButton; private JButton downButton; private JButton indentButton; private JButton outdentButton; private JComboBox viewSelector, viewSelectorIconic; private JButton newIconButton; private JButton openIconButton; private JButton addAboveIconButton; private JButton addBelowIconButton; private JButton addIconButton; private JButton removeIconButton; private JButton upIconButton; private JButton downIconButton; private JButton indentIconButton; private JButton outdentIconButton; private Thread autoSaveThread; private JDialog autoSaveDialog; private JCheckBox autoSaveCheckBox; private JSpinner autoSavePeriodSpinner; // private DSpinner autoSavePeriodSpinner; private JButton autoSaveOkButton; private JButton autoSaveCancelButton; private JDialog prefsDialog; private SearchDialog searchDialog; private JDialog nodeUrlDisplayDialog; private JTextField nodeUrlDisplayField; private JButton nodeUrlDisplayOkButton; private JMenu openRecentMenu; private JMenuItem undoMenuItem; private JMenuItem redoMenuItem; private JMenuItem webSearchMenuItem; private JMenuItem characterWrapArticleMenuItem; private JCheckBoxMenuItem viewToolbarIconsMenuItem; private JCheckBoxMenuItem viewToolbarTextMenuItem; private JCheckBoxMenuItem viewToolbarOffMenuItem; private ColouredStrip funkyGreenStrip; // private boolean htmlExportOkChecker = false; // Just used to check whether OK or Cancel has been pressed in a certain dialogue box // Check whether we are on Mac OS X. This is crucial to loading and using the OSXAdapter class. public static boolean MAC_OS_X = (System.getProperty("os.name").toLowerCase().startsWith("mac os x")); // Ask AWT which menu modifier we should be using. final static int MENU_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); /* Note - The application code registered with Apple is: JREE� (Hex) 4A524545 In Apple's Java methods they require an integer, so presumably we use 0x4A524545 */ public static final int appleAppCode = 0x4A524545; public JreepadViewer() { this(""); } public JreepadViewer(String fileNameToLoad) { this(fileNameToLoad, null); } public JreepadViewer(String fileNameToLoad, String prefFilename) { // THIS DOESN'T SEEM TO HAVE ANY EFFECT, ON MAC OSX - I'd be interested to know if it does its job on other OSs // Apparently it does work on Windows. So I'll leave it in place! ClassLoader loader = this.getClass().getClassLoader(); // Used for loading icon java.net.URL iconUrl = loader.getResource("images/jreepadlogo-01-iconsize.gif"); if(iconUrl != null){ setIconImage(new ImageIcon(iconUrl).getImage()); }else{ System.out.println("Icon image failed to load: images/jreepadlogo-01-iconsize.gif"); } Toolkit theToolkit = getToolkit(); Dimension wndSize = theToolkit.getScreenSize(); systemClipboard = theToolkit.getSystemClipboard(); // New method of loading prefs - using java's own API rather handling a file setPrefs(new JreepadPrefs(wndSize)); if(!getPrefs().seenLicense) { showLicense(); getPrefs().seenLicense = true; } /* // Check if a preferences file exists - and if so, load it if(prefFilename!=null) prefsFile = new File(prefFilename); try { if(prefsFile.exists() && prefsFile.isFile()) { ObjectInputStream prefsLoader = new ObjectInputStream(new FileInputStream(prefsFile)); setPrefs((JreepadPrefs)prefsLoader.readObject()); prefsLoader.close(); } else { showLicense(); // A crude way of showing the license on first visit setPrefs(new JreepadPrefs(wndSize)); } } catch(Exception err) { setPrefs(new JreepadPrefs(wndSize)); } */ fileChooser = new JFileChooser(); fileChooser.addChoosableFileFilter(SaveFileChooser.JREEPAD_FILE_FILTER); fileChooser.addChoosableFileFilter(SaveFileChooser.JREEPAD_ENCRYPTED_FILE_FILTER); fileChooser.addChoosableFileFilter(SaveFileChooser.TREEPAD_FILE_FILTER); content = getContentPane(); document = new JreepadTreeModel(); theJreepad = new JreepadView(document); establishMenus(); establishToolbar(); searchDialog = new SearchDialog(this, theJreepad); prefsDialog = new PrefsDialog(this); establishAutosaveDialogue(); establishNodeUrlDisplayDialogue(); // Establish the autosave thread autoSaveThread = new Thread("Autosave thread") { public void run() { while(getPrefs().autoSave) { try { // Sleep for a bit... sleep(60000L * getPrefs().autoSavePeriod); yield(); // ...then if the saveLocation != null, trigger saveAction() if(getPrefs().autoSave && document.getSaveLocation() != null) new SaveAction().actionPerformed(null); else updateWindowTitle(); } catch(InterruptedException e){} } } }; autoSaveThread.setPriority(Thread.MIN_PRIORITY); if(getPrefs().autoSave) autoSaveThread.start(); // Finished establishing the autosave thread content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS)); content.add(funkyGreenStrip = new ColouredStrip(new Color(0.09f, 0.4f, 0.12f), wndSize.width, 10) ); funkyGreenStrip.setVisible(getPrefs().showGreenStrip); content.add(toolBar); content.add(toolBarIconic); setToolbarMode(getPrefs().toolbarMode); content.add(theJreepad); // Load the file - if it has been specified, and if it can be found, and if it's a valid HJT file File firstTimeFile = null; if(fileNameToLoad != "") firstTimeFile = new File(fileNameToLoad); else if(getPrefs().loadLastFileOnOpen && getPrefs().getMostRecentFile() != null) firstTimeFile = getPrefs().getMostRecentFile(); if(firstTimeFile != null && firstTimeFile.isFile()) openFile(firstTimeFile); // Set close operation setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e){ quitAction(); }}); setTitleBasedOnFilename(""); // Finally, make the window visible and well-sized setBounds(getPrefs().windowLeft,getPrefs().windowTop, getPrefs().windowWidth, getPrefs().windowHeight); searchDialog.setBounds(getPrefs().windowWidth/2,getPrefs().windowHeight/6, (int)(getPrefs().windowWidth*0.7f),(int)(getPrefs().windowHeight*0.9f)); autoSaveDialog.setBounds((int)(wndSize.width*0.5f),getPrefs().windowHeight/2, getPrefs().windowWidth/2, getPrefs().windowHeight/4); prefsDialog.setBounds(getPrefs().windowWidth/2,getPrefs().windowHeight/3, getPrefs().windowWidth, getPrefs().windowHeight); nodeUrlDisplayDialog.setBounds((int)(wndSize.width*0.1f),(int)(getPrefs().windowHeight*0.7f), (int)(getPrefs().windowWidth*1.3f), getPrefs().windowHeight/3); // pack() actually deprecates some of the functionality of the setBounds() calls just above // - but hopefully gives a better mixture of sizes set programmatically and by the OS searchDialog.pack(); autoSaveDialog.pack(); prefsDialog.pack(); nodeUrlDisplayDialog.pack(); theApps.add(this); macOSXRegistration(); setVisible(true); // If loading the last-saved file, expand the nodes we last had open if(document.getSaveLocation() != null) theJreepad.expandPaths(getPrefs().treePathCollection.paths); theJreepad.returnFocusToTree(); } // Used by the constructor private void establishMenus() { // Create the menu bar JMenuBar menuBar = new JMenuBar(); // Add menus menuBar.add(createFileMenu()); menuBar.add(createEditMenu()); menuBar.add(createActionsMenu()); menuBar.add(createViewMenu()); menuBar.add(createOptionsMenu()); menuBar.add(createHelpMenu()); setJMenuBar(menuBar); } /** * Creates the File menu. */ private JMenu createFileMenu() { JMenu fileMenu = new JMenu(lang.getString("MENU_FILE")); //"File"); fileMenu.setMnemonic(KeyEvent.VK_F); JMenuItem newMenuItem = new JMenuItem(lang.getString("MENUITEM_NEW")); //"New"); newMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { newAction();}}); fileMenu.add(newMenuItem); JMenuItem openMenuItem = new JMenuItem(lang.getString("MENUITEM_OPEN")); //"Open"); openMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {openAction();}}); fileMenu.add(openMenuItem); openRecentMenu = new JMenu(lang.getString("MENUITEM_OPENRECENT")); //"Open recent"); updateOpenRecentMenu(); fileMenu.add(openRecentMenu); fileMenu.add(new SaveAction()); // Save fileMenu.add(new SaveAction(true)); // Save As JMenuItem backupToMenuItem = new JMenuItem(lang.getString("MENUITEM_BACKUPTO")); //"Backup to..."); backupToMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {backupToAction();}}); fileMenu.add(backupToMenuItem); fileMenu.add(new JSeparator()); JMenuItem printSubtreeMenuItem = new JMenuItem(lang.getString("MENUITEM_PRINTSUBTREE")); //"Print subtree"); printSubtreeMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {subtreeToBrowserForPrintAction();}}); fileMenu.add(printSubtreeMenuItem); JMenuItem printArticleMenuItem = new JMenuItem(lang.getString("MENUITEM_PRINTARTICLE")); //"Print article"); printArticleMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {articleToBrowserForPrintAction();}}); fileMenu.add(printArticleMenuItem); fileMenu.add(new JSeparator()); JMenu importMenu = new JMenu(lang.getString("MENUITEM_IMPORT")); //"Import..."); fileMenu.add(importMenu); JMenuItem importHjtMenuItem = new JMenuItem(lang.getString("MENUITEM_IMPORT_HJT")); //"...Treepad file as subtree"); importHjtMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {importAction(FILE_FORMAT_HJT);}}); importMenu.add(importHjtMenuItem); JMenuItem importTextMenuItem = new JMenuItem(lang.getString("MENUITEM_IMPORT_TEXTFILES")); //"...text file(s) as child node(s)"); importTextMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {importAction(FILE_FORMAT_TEXT);}}); importMenu.add(importTextMenuItem); JMenuItem importTextAsListMenuItem = new JMenuItem(lang.getString("MENUITEM_IMPORT_TEXTLIST")); //"...text list file, one-child-per-line"); importTextAsListMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {importAction(FILE_FORMAT_TEXTASLIST);}}); importMenu.add(importTextAsListMenuItem); fileMenu.add(createExportMenu()); fileMenu.add(new JSeparator()); if(!MAC_OS_X) { JMenuItem quitMenuItem = new JMenuItem(lang.getString("MENUITEM_QUIT")); //"Quit"); quitMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { quitAction(); }}); fileMenu.add(quitMenuItem); quitMenuItem.setMnemonic('Q'); quitMenuItem.setAccelerator(KeyStroke.getKeyStroke('Q', MENU_MASK)); } newMenuItem.setMnemonic('N'); newMenuItem.setAccelerator(KeyStroke.getKeyStroke('N', MENU_MASK)); openMenuItem.setMnemonic('O'); openMenuItem.setAccelerator(KeyStroke.getKeyStroke('O', MENU_MASK)); openRecentMenu.setMnemonic('R'); printSubtreeMenuItem.setMnemonic('P'); printSubtreeMenuItem.setAccelerator(KeyStroke.getKeyStroke('P', MENU_MASK)); printArticleMenuItem.setAccelerator(KeyStroke.getKeyStroke('P', MENU_MASK | java.awt.Event.SHIFT_MASK)); backupToMenuItem.setMnemonic('B'); importMenu.setMnemonic('I'); importHjtMenuItem.setMnemonic('f'); importTextMenuItem.setMnemonic('t'); importTextAsListMenuItem.setMnemonic('l'); return fileMenu; } /** * Creates the Export submenu. */ private JMenu createExportMenu() { JMenu exportMenu = new JMenu(lang.getString("MENUITEM_EXPORT")); //"Export selected..."); JMenuItem exportHjtMenuItem = new JMenuItem(lang.getString("MENUITEM_EXPORT_HJT")); //"...subtree to Treepad HJT file"); exportHjtMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {exportAction(FILE_FORMAT_HJT);}}); exportMenu.add(exportHjtMenuItem); JMenuItem exportHtmlMenuItem = new JMenuItem(lang.getString("MENUITEM_EXPORT_HTML")); //"...subtree to HTML"); exportHtmlMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {exportAction(FILE_FORMAT_HTML);}}); exportMenu.add(exportHtmlMenuItem); JMenuItem exportSimpleXmlMenuItem = new JMenuItem(lang.getString("MENUITEM_EXPORT_XML")); //"...subtree to XML"); exportSimpleXmlMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {exportAction(FILE_FORMAT_XML);}}); exportMenu.add(exportSimpleXmlMenuItem); JMenuItem exportListMenuItem = new JMenuItem(lang.getString("MENUITEM_EXPORT_TEXTLIST")); //"...subtree to text list (node titles only)"); exportListMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {exportAction(FILE_FORMAT_TEXTASLIST);}}); exportMenu.add(exportListMenuItem); exportMenu.add(new JSeparator()); JMenuItem exportTextMenuItem = new JMenuItem(lang.getString("MENUITEM_EXPORT_ARTICLE")); //"...article to text file"); exportTextMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {exportAction(FILE_FORMAT_TEXT);}}); exportMenu.add(exportTextMenuItem); JMenuItem exportSubtreeTextMenuItem = new JMenuItem(lang.getString("MENUITEM_EXPORT_ARTICLES")); //"...subtree articles to text file"); exportSubtreeTextMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {exportAction(FILE_FORMAT_ARTICLESTOTEXT);}}); exportMenu.add(exportSubtreeTextMenuItem); exportMenu.setMnemonic('E'); exportHjtMenuItem.setMnemonic('f'); exportHtmlMenuItem.setMnemonic('h'); exportSimpleXmlMenuItem.setMnemonic('x'); exportTextMenuItem.setMnemonic('t'); return exportMenu; } /** * Creates the Edit menu. */ private JMenu createEditMenu() { JMenu editMenu = new JMenu(lang.getString("MENU_EDIT")); //"Edit"); editMenu.setMnemonic(KeyEvent.VK_E); undoMenuItem = new JMenuItem(lang.getString("MENUITEM_UNDO")); //"Undo"); undoMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { undoAction(); updateUndoRedoMenuState();}}); editMenu.add(undoMenuItem); redoMenuItem = new JMenuItem(lang.getString("MENUITEM_REDO")); //"Redo"); redoMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { redoAction(); updateUndoRedoMenuState();}}); editMenu.add(redoMenuItem); editMenu.add(new JSeparator()); JMenuItem addAboveMenuItem = new JMenuItem(lang.getString("MENUITEM_ADDABOVE")); //"Add sibling above"); addAboveMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.addNodeAbove(); updateWindowTitle();}}); editMenu.add(addAboveMenuItem); JMenuItem addBelowMenuItem = new JMenuItem(lang.getString("MENUITEM_ADDBELOW")); //"Add sibling below"); addBelowMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.addNodeBelow(); updateWindowTitle();}}); editMenu.add(addBelowMenuItem); JMenuItem addChildMenuItem = new JMenuItem(lang.getString("MENUITEM_ADDCHILD")); //"Add child"); addChildMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.addNode(); updateWindowTitle(); }}); editMenu.add(addChildMenuItem); editMenu.add(new JSeparator()); JMenuItem newFromClipboardMenuItem = new JMenuItem(lang.getString("MENUITEM_NEWFROMCLIPBOARD")); //"New node from clipboard"); newFromClipboardMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { systemClipboardToNewNode(); }}); editMenu.add(newFromClipboardMenuItem); editMenu.add(new JSeparator()); JMenuItem editNodeTitleMenuItem = new JMenuItem(lang.getString("MENUITEM_EDITNODETITLE")); //"Edit node title"); editNodeTitleMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.editNodeTitleAction(); }}); editMenu.add(editNodeTitleMenuItem); editMenu.add(new JSeparator()); JMenuItem deleteMenuItem = new JMenuItem(lang.getString("MENUITEM_DELETENODE")); //"Delete node"); deleteMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { deleteNodeAction(); }}); editMenu.add(deleteMenuItem); editMenu.add(new JSeparator()); JMenuItem upMenuItem = new JMenuItem(lang.getString("MENUITEM_MOVEUP")); //"Move node up"); upMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.moveCurrentNodeUp(); theJreepad.returnFocusToTree(); updateWindowTitle(); }}); editMenu.add(upMenuItem); JMenuItem downMenuItem = new JMenuItem(lang.getString("MENUITEM_MOVEDOWN")); //"Move node down"); downMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.moveCurrentNodeDown(); theJreepad.returnFocusToTree(); updateWindowTitle(); }}); editMenu.add(downMenuItem); editMenu.add(new JSeparator()); JMenuItem indentMenuItem = new JMenuItem(lang.getString("MENUITEM_MOVEIN")); //"Indent node (demote)"); indentMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.indentCurrentNode(); theJreepad.returnFocusToTree(); updateWindowTitle(); }}); editMenu.add(indentMenuItem); JMenuItem outdentMenuItem = new JMenuItem(lang.getString("MENUITEM_MOVEOUT")); //"Outdent node (promote)"); outdentMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.outdentCurrentNode(); theJreepad.returnFocusToTree(); updateWindowTitle(); }}); editMenu.add(outdentMenuItem); editMenu.add(new JSeparator()); JMenuItem expandAllMenuItem = new JMenuItem(lang.getString("MENUITEM_EXPAND")); //"Expand subtree"); expandAllMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.expandAllCurrentNode(); }}); editMenu.add(expandAllMenuItem); JMenuItem collapseAllMenuItem = new JMenuItem(lang.getString("MENUITEM_COLLAPSE")); //"Collapse subtree"); collapseAllMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.collapseAllCurrentNode(); }}); editMenu.add(collapseAllMenuItem); undoMenuItem.setMnemonic('u'); undoMenuItem.setAccelerator(KeyStroke.getKeyStroke('Z', MENU_MASK)); redoMenuItem.setMnemonic('r'); redoMenuItem.setAccelerator(KeyStroke.getKeyStroke('Z', MENU_MASK | java.awt.event.InputEvent.SHIFT_MASK)); addAboveMenuItem.setMnemonic('a'); addAboveMenuItem.setAccelerator(KeyStroke.getKeyStroke('T', MENU_MASK)); addBelowMenuItem.setMnemonic('b'); addBelowMenuItem.setAccelerator(KeyStroke.getKeyStroke('B', MENU_MASK)); addChildMenuItem.setMnemonic('c'); addChildMenuItem.setAccelerator(KeyStroke.getKeyStroke('D', MENU_MASK)); newFromClipboardMenuItem.setAccelerator(KeyStroke.getKeyStroke('M', MENU_MASK)); editNodeTitleMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0)); upMenuItem.setMnemonic('u'); upMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP, MENU_MASK | java.awt.Event.ALT_MASK)); downMenuItem.setMnemonic('d'); downMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, MENU_MASK | java.awt.Event.ALT_MASK)); indentMenuItem.setMnemonic('i'); indentMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, MENU_MASK | java.awt.Event.ALT_MASK)); outdentMenuItem.setMnemonic('o'); outdentMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, MENU_MASK | java.awt.Event.ALT_MASK)); expandAllMenuItem.setMnemonic('x'); expandAllMenuItem.setAccelerator(KeyStroke.getKeyStroke('=', MENU_MASK)); collapseAllMenuItem.setMnemonic('l'); collapseAllMenuItem.setAccelerator(KeyStroke.getKeyStroke('-', MENU_MASK)); deleteMenuItem.setMnemonic('k'); deleteMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, MENU_MASK)); undoMenuItem.setMnemonic('u'); undoMenuItem.setAccelerator(KeyStroke.getKeyStroke('Z', MENU_MASK)); redoMenuItem.setMnemonic('r'); redoMenuItem.setAccelerator(KeyStroke.getKeyStroke('Z', MENU_MASK | java.awt.event.InputEvent.SHIFT_MASK)); addAboveMenuItem.setMnemonic('a'); addAboveMenuItem.setAccelerator(KeyStroke.getKeyStroke('T', MENU_MASK)); addBelowMenuItem.setMnemonic('b'); addBelowMenuItem.setAccelerator(KeyStroke.getKeyStroke('B', MENU_MASK)); addChildMenuItem.setMnemonic('c'); addChildMenuItem.setAccelerator(KeyStroke.getKeyStroke('D', MENU_MASK)); newFromClipboardMenuItem.setAccelerator(KeyStroke.getKeyStroke('M', MENU_MASK)); upMenuItem.setMnemonic('u'); upMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP, MENU_MASK | java.awt.Event.ALT_MASK)); downMenuItem.setMnemonic('d'); downMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, MENU_MASK | java.awt.Event.ALT_MASK)); indentMenuItem.setMnemonic('i'); indentMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, MENU_MASK | java.awt.Event.ALT_MASK)); outdentMenuItem.setMnemonic('o'); outdentMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, MENU_MASK | java.awt.Event.ALT_MASK)); expandAllMenuItem.setMnemonic('x'); expandAllMenuItem.setAccelerator(KeyStroke.getKeyStroke('=', MENU_MASK)); collapseAllMenuItem.setMnemonic('l'); collapseAllMenuItem.setAccelerator(KeyStroke.getKeyStroke('-', MENU_MASK)); deleteMenuItem.setMnemonic('k'); deleteMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, MENU_MASK)); return editMenu; } /** * Creates the Actions menu. */ private JMenu createActionsMenu() { JMenu actionsMenu = new JMenu(lang.getString("MENU_ACTIONS")); // "Actions"); actionsMenu.setMnemonic(KeyEvent.VK_T); JMenuItem searchMenuItem = new JMenuItem(lang.getString("MENUITEM_SEARCH")); //"Search"); searchMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { searchDialog.open(); }}); actionsMenu.add(searchMenuItem); JMenuItem launchUrlMenuItem = new JMenuItem(lang.getString("MENUITEM_FOLLOWLINK")); //"Follow highlighted link"); launchUrlMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.openURLSelectedInArticle(); }}); actionsMenu.add(launchUrlMenuItem); webSearchMenuItem = new JMenuItem(getPrefs().webSearchName); webSearchMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.webSearchTextSelectedInArticle(); }}); actionsMenu.add(webSearchMenuItem); actionsMenu.add(new JSeparator()); characterWrapArticleMenuItem = new JMenuItem(lang.getString("MENUITEM_HARDWRAP1") + " " + getPrefs().characterWrapWidth + " " + lang.getString("MENUITEM_HARDWRAP2")); //); characterWrapArticleMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { wrapContentToCharWidth(); }}); actionsMenu.add(characterWrapArticleMenuItem); JMenuItem stripTagsMenuItem = new JMenuItem(lang.getString("MENUITEM_STRIPTAGS")); //"Strip <tags> from article"); stripTagsMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { stripAllTags(); }}); actionsMenu.add(stripTagsMenuItem); JMenuItem insertDateMenuItem = new JMenuItem(lang.getString("MENUITEM_INSERTDATE")); //"Insert date"); insertDateMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { insertDate(); }}); actionsMenu.add(insertDateMenuItem); actionsMenu.add(new JSeparator()); JMenuItem sortMenuItem = new JMenuItem(lang.getString("MENUITEM_SORTONELEVEL")); //"Sort children (one level)"); sortMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.sortChildren(); updateWindowTitle(); }}); actionsMenu.add(sortMenuItem); JMenuItem sortRecursiveMenuItem = new JMenuItem(lang.getString("MENUITEM_SORTALLLEVELS")); //"Sort children (all levels)"); sortRecursiveMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.sortChildrenRecursive(); updateWindowTitle(); }}); actionsMenu.add(sortRecursiveMenuItem); searchMenuItem.setMnemonic('s'); searchMenuItem.setAccelerator(KeyStroke.getKeyStroke('F', MENU_MASK)); webSearchMenuItem.setMnemonic('g'); webSearchMenuItem.setAccelerator(KeyStroke.getKeyStroke('G', MENU_MASK)); characterWrapArticleMenuItem.setAccelerator(KeyStroke.getKeyStroke('R', MENU_MASK)); characterWrapArticleMenuItem.setMnemonic('r'); launchUrlMenuItem.setAccelerator(KeyStroke.getKeyStroke('L', MENU_MASK)); launchUrlMenuItem.setMnemonic('l'); stripTagsMenuItem.setAccelerator(KeyStroke.getKeyStroke('T', MENU_MASK)); stripTagsMenuItem.setMnemonic('t'); insertDateMenuItem.setAccelerator(KeyStroke.getKeyStroke('E', MENU_MASK)); insertDateMenuItem.setMnemonic('e'); return actionsMenu; } /** * Creates the View menu. */ private JMenu createViewMenu() { JMenu viewMenu = new JMenu(lang.getString("MENU_VIEW")); //"View"); viewMenu.setMnemonic('V'); JMenuItem viewBothMenuItem = new JMenuItem(lang.getString("MENUITEM_VIEWBOTH")); //"Both tree and article"); viewBothMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { setViewMode(JreepadPrefs.VIEW_BOTH); }}); viewMenu.add(viewBothMenuItem); JMenuItem viewTreeMenuItem = new JMenuItem(lang.getString("MENUITEM_VIEWTREE")); //"Tree"); viewTreeMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { setViewMode(JreepadPrefs.VIEW_TREE); }}); viewMenu.add(viewTreeMenuItem); JMenuItem viewArticleMenuItem = new JMenuItem(lang.getString("MENUITEM_VIEWARTICLE")); //"Article"); viewArticleMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { setViewMode(JreepadPrefs.VIEW_ARTICLE); }}); viewMenu.add(viewArticleMenuItem); viewMenu.add(new JSeparator()); JMenu viewToolbarMenu = new JMenu(lang.getString("MENUITEM_TOOLBAR")); //"Toolbar"); viewMenu.add(viewToolbarMenu); viewToolbarIconsMenuItem = new JCheckBoxMenuItem(lang.getString("MENUITEM_TOOLBAR_ICONS")); //"Icons", true); viewToolbarIconsMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { setToolbarMode(JreepadPrefs.TOOLBAR_ICON); }}); viewToolbarMenu.add(viewToolbarIconsMenuItem); viewToolbarTextMenuItem = new JCheckBoxMenuItem(lang.getString("MENUITEM_TOOLBAR_TEXT")); //"Text", true); viewToolbarTextMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { setToolbarMode(JreepadPrefs.TOOLBAR_TEXT); }}); viewToolbarMenu.add(viewToolbarTextMenuItem); viewToolbarOffMenuItem = new JCheckBoxMenuItem(lang.getString("MENUITEM_TOOLBAR_OFF")); //"Off", true); viewToolbarOffMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { setToolbarMode(JreepadPrefs.TOOLBAR_OFF); }}); viewToolbarMenu.add(viewToolbarOffMenuItem); viewMenu.add(new JSeparator()); JMenuItem articleViewModeMenuItem = new JMenu(lang.getString("MENUITEM_ARTICLEFORMAT")); //"View this article as..."); JMenuItem articleViewModeTextMenuItem = new JMenuItem(lang.getString("MENUITEM_ARTICLEFORMAT_TEXT")); //"Text"); articleViewModeTextMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.setArticleMode(JreepadArticle.ARTICLEMODE_ORDINARY); updateUndoRedoMenuState(); }}); articleViewModeMenuItem.add(articleViewModeTextMenuItem); JMenuItem articleViewModeHtmlMenuItem = new JMenuItem(lang.getString("MENUITEM_ARTICLEFORMAT_HTML")); //"HTML"); articleViewModeHtmlMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.setArticleMode(JreepadArticle.ARTICLEMODE_HTML); updateUndoRedoMenuState(); }}); articleViewModeMenuItem.add(articleViewModeHtmlMenuItem); JMenuItem articleViewModeCsvMenuItem = new JMenuItem(lang.getString("MENUITEM_ARTICLEFORMAT_CSV")); //"Table (comma-separated data)"); articleViewModeCsvMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.setArticleMode(JreepadArticle.ARTICLEMODE_CSV); updateUndoRedoMenuState(); }}); articleViewModeMenuItem.add(articleViewModeCsvMenuItem); JMenuItem articleViewModeTextileMenuItem = new JMenuItem(lang.getString("MENUITEM_ARTICLEFORMAT_TEXTILE")); articleViewModeTextileMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { theJreepad.setArticleMode(JreepadArticle.ARTICLEMODE_TEXTILEHTML); updateUndoRedoMenuState(); }}); articleViewModeMenuItem.add(articleViewModeTextileMenuItem); viewMenu.add(articleViewModeMenuItem); viewMenu.add(new JSeparator()); JMenuItem thisNodesUrlMenuItem = new JMenuItem(lang.getString("MENUITEM_NODEADDRESS")); //"\"node://\" address for current node"); thisNodesUrlMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { getTreepadNodeUrl(); }}); viewMenu.add(thisNodesUrlMenuItem); thisNodesUrlMenuItem.setMnemonic('n'); viewBothMenuItem.setMnemonic('b'); viewTreeMenuItem.setMnemonic('t'); viewArticleMenuItem.setMnemonic('a'); viewBothMenuItem.setAccelerator(KeyStroke.getKeyStroke('1', MENU_MASK)); viewTreeMenuItem.setAccelerator(KeyStroke.getKeyStroke('2', MENU_MASK)); viewArticleMenuItem.setAccelerator(KeyStroke.getKeyStroke('3', MENU_MASK)); viewToolbarIconsMenuItem.setAccelerator(KeyStroke.getKeyStroke('4', MENU_MASK)); viewToolbarTextMenuItem.setAccelerator(KeyStroke.getKeyStroke('5', MENU_MASK)); viewToolbarOffMenuItem.setAccelerator(KeyStroke.getKeyStroke('6', MENU_MASK)); articleViewModeTextMenuItem.setAccelerator(KeyStroke.getKeyStroke('7', MENU_MASK)); articleViewModeHtmlMenuItem.setAccelerator(KeyStroke.getKeyStroke('8', MENU_MASK)); articleViewModeCsvMenuItem.setAccelerator(KeyStroke.getKeyStroke('9', MENU_MASK)); articleViewModeTextileMenuItem.setAccelerator(KeyStroke.getKeyStroke('0', MENU_MASK)); viewToolbarMenu.setMnemonic('o'); viewMenu.add(new JSeparator()); // section to adjust fonts JMenu articleFontMenu = new JMenu(lang.getString("MENUITEM_FONT_ARTICLE")); viewMenu.add(articleFontMenu); JMenuItem increaseFontMenuItem = new JMenuItem(lang.getString( "MENUITEM_FONT_INCREASE")); increaseFontMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theJreepad.changeFont(FontHelper.FONT_DIR_UP, JreepadView.CHANGE_ARTICLE_FONT); } }); JMenuItem decreaseFontMenuItem = new JMenuItem(lang.getString( "MENUITEM_FONT_DECREASE")); decreaseFontMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theJreepad.changeFont(FontHelper.FONT_DIR_DOWN, JreepadView.CHANGE_ARTICLE_FONT); } }); articleFontMenu.add(increaseFontMenuItem); articleFontMenu.add(decreaseFontMenuItem); JMenu treeFontMenu = new JMenu(lang.getString("MENUITEM_FONT_TREE")); viewMenu.add(treeFontMenu); JMenuItem increaseTreeFontMenuItem = new JMenuItem(lang.getString( "MENUITEM_FONT_INCREASE")); increaseTreeFontMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theJreepad.changeFont(FontHelper.FONT_DIR_UP, JreepadView.CHANGE_TREE_FONT); } }); JMenuItem decreaseTreeFontMenuItem = new JMenuItem(lang.getString( "MENUITEM_FONT_DECREASE")); decreaseTreeFontMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { theJreepad.changeFont(FontHelper.FONT_DIR_DOWN, JreepadView.CHANGE_TREE_FONT); } }); treeFontMenu.add(increaseTreeFontMenuItem); treeFontMenu.add(decreaseTreeFontMenuItem); return viewMenu; } /** * Creates the Options menu. */ private JMenu createOptionsMenu() { JMenu optionsMenu = new JMenu(lang.getString("MENU_OPTIONS")); //"Options"); optionsMenu.setMnemonic('O'); JMenuItem autoSaveMenuItem = new JMenuItem(lang.getString("MENUITEM_AUTOSAVE_PREFS")); //"Autosave..."); autoSaveMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { showAutoSaveDialog(); }}); optionsMenu.add(autoSaveMenuItem); JMenuItem prefsMenuItem = new JMenuItem(lang.getString("MENUITEM_PREFS")); //"Preferences"); prefsMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { // updateFontsInPrefsBox(); showPrefsDialog(); }}); optionsMenu.add(prefsMenuItem); autoSaveMenuItem.setMnemonic('a'); prefsMenuItem.setMnemonic('p'); return optionsMenu; } private JMenu createHelpMenu() { JMenu helpMenu = new JMenu(lang.getString("MENU_HELP")); //"Help"); helpMenu.setMnemonic('H'); JMenuItem keyboardHelpMenuItem = new JMenuItem(lang.getString("MENUITEM_KEYBOARDSHORTCUTS")); //"Keyboard shortcuts"); keyboardHelpMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { keyboardHelp(); }}); helpMenu.add(keyboardHelpMenuItem); JMenuItem linksHelpMenuItem = new JMenuItem(lang.getString("MENUITEM_LINKSHELP")); //"Help with links"); linksHelpMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { linksHelp(); }}); helpMenu.add(linksHelpMenuItem); JMenuItem dragDropHelpMenuItem = new JMenuItem(lang.getString("MENUITEM_DRAGDROPHELP")); //"Help with drag-and-drop"); dragDropHelpMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { dragDropHelp(); }}); helpMenu.add(dragDropHelpMenuItem); helpMenu.add(new JSeparator()); if(!MAC_OS_X) { JMenuItem aboutMenuItem = new JMenuItem(lang.getString("MENUITEM_ABOUT")); //"About Jreepad"); aboutMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { aboutAction(); }}); aboutMenuItem.setMnemonic('a'); helpMenu.add(aboutMenuItem); } JMenuItem licenseMenuItem = new JMenuItem(lang.getString("MENUITEM_LICENSE")); //"License"); licenseMenuItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { showLicense(); }}); helpMenu.add(licenseMenuItem); keyboardHelpMenuItem.setMnemonic('k'); dragDropHelpMenuItem.setMnemonic('d'); linksHelpMenuItem.setMnemonic('l'); licenseMenuItem.setMnemonic('i'); return helpMenu; } // Used by the constructor public void establishToolbar() { // Add the toolbar buttons toolBar = Box.createHorizontalBox(); toolBarIconic = Box.createHorizontalBox(); // addAboveButton = new JButton(lang.getString("TOOLBAR_ADDABOVE")); addBelowButton = new JButton(lang.getString("TOOLBAR_ADDBELOW")); addButton = new JButton(lang.getString("TOOLBAR_ADDCHILD")); removeButton = new JButton(lang.getString("TOOLBAR_DELETE")); // upButton = new JButton(lang.getString("TOOLBAR_UP")); downButton = new JButton(lang.getString("TOOLBAR_DOWN")); indentButton = new JButton(lang.getString("TOOLBAR_IN")); outdentButton = new JButton(lang.getString("TOOLBAR_OUT")); // // Now the mnemonics... addAboveButton.setMnemonic('a'); addBelowButton.setMnemonic('b'); addButton.setMnemonic('c'); upButton.setMnemonic('u'); downButton.setMnemonic('d'); indentButton.setMnemonic('i'); outdentButton.setMnemonic('o'); removeButton.setMnemonic('k'); // viewSelector = new JComboBox(new String[]{lang.getString("TOOLBAR_VIEWBOTH"),lang.getString("TOOLBAR_VIEWTREE"),lang.getString("TOOLBAR_VIEWARTICLE")}); viewSelector.setEditable(false); viewSelector.setSelectedIndex(0); viewSelector.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ switch(viewSelector.getSelectedIndex()) { case 1: setViewMode(JreepadPrefs.VIEW_TREE); break; case 2: setViewMode(JreepadPrefs.VIEW_ARTICLE); break; default: setViewMode(JreepadPrefs.VIEW_BOTH); break; } } }); viewSelectorIconic = new JComboBox(new String[]{lang.getString("TOOLBAR_VIEWBOTH"),lang.getString("TOOLBAR_VIEWTREE"),lang.getString("TOOLBAR_VIEWARTICLE")}); viewSelectorIconic.setEditable(false); viewSelectorIconic.setSelectedIndex(0); viewSelectorIconic.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ switch(viewSelectorIconic.getSelectedIndex()) { case 1: setViewMode(JreepadPrefs.VIEW_TREE); break; case 2: setViewMode(JreepadPrefs.VIEW_ARTICLE); break; default: setViewMode(JreepadPrefs.VIEW_BOTH); break; } } }); // Add the actions to the toolbar buttons upButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.moveCurrentNodeUp(); repaint(); theJreepad.returnFocusToTree(); updateWindowTitle();} }); downButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.moveCurrentNodeDown(); repaint(); theJreepad.returnFocusToTree(); updateWindowTitle();} }); indentButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.indentCurrentNode(); repaint(); theJreepad.returnFocusToTree(); updateWindowTitle();} }); outdentButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.outdentCurrentNode(); repaint(); theJreepad.returnFocusToTree(); updateWindowTitle(); } }); addAboveButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.addNodeAbove(); repaint(); updateWindowTitle();} }); addBelowButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.addNodeBelow(); repaint(); updateWindowTitle();} }); addButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.addNode(); repaint(); updateWindowTitle();} }); removeButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ deleteNodeAction(); } }); // Now establish the iconic buttons (code contributed by Coen Schalkwijk) // New file newIconButton = new JButton(); newIconButton.setToolTipText(lang.getString("TOOLBAR_NEW")); newIconButton.setBorderPainted(false); newIconButton.setIcon(this.getIcon("New16.gif")); // Open existing openIconButton = new JButton(); openIconButton.setToolTipText(lang.getString("TOOLBAR_OPEN")); openIconButton.setBorderPainted(false); openIconButton.setIcon(this.getIcon("Open16.gif")); // Save current JButton saveIconButton = new JButton(new SaveAction()); saveIconButton.setBorderPainted(false); saveIconButton.setText(null); // Ignore action text // Insert node before addAboveIconButton = new JButton(lang.getString("TOOLBAR_ADDABOVE")); // addAboveIconButton = new JButton(); // addAboveIconButton.setToolTipText(lang.getString("TOOLBAR_")); // addAboveIconButton.setBorderPainted(false); // addAboveIconButton.setMnemonic('a'); // addAboveIconButton.setIcon(this.getIcon("InsertBefore16.gif")); // Insert node after addBelowIconButton = new JButton(lang.getString("TOOLBAR_ADDBELOW")); // addBelowIconButton = new JButton(); addBelowIconButton.setMnemonic('b'); // addBelowIconButton.setToolTipText("Add below"); // addBelowIconButton.setBorderPainted(false); // addBelowIconButton.setIcon(this.getIcon("InsertAfter16.gif")); // Add child node addIconButton = new JButton(); addIconButton.setMnemonic('c'); addIconButton.setToolTipText(lang.getString("TOOLBAR_ADDCHILD")); addIconButton.setBorderPainted(false); addIconButton.setIcon(this.getIcon("Add16.gif")); // Remove node removeIconButton = new JButton(); removeIconButton.setMnemonic('k'); removeIconButton.setToolTipText(lang.getString("TOOLBAR_DELETE")); removeIconButton.setBorderPainted(false); removeIconButton.setIcon(this.getIcon("Remove16.gif")); // Move node up upIconButton = new JButton(); upIconButton.setMnemonic('u'); upIconButton.setToolTipText(lang.getString("TOOLBAR_UP")); upIconButton.setBorderPainted(false); upIconButton.setIcon(this.getIcon("Up16.gif")); // Move node down downIconButton = new JButton(); downIconButton.setMnemonic('d'); downIconButton.setToolTipText(lang.getString("TOOLBAR_DOWN")); downIconButton.setBorderPainted(false); downIconButton.setIcon(this.getIcon("Down16.gif")); // Move node from current outdentIconButton = new JButton(); outdentIconButton.setMnemonic('i'); outdentIconButton.setToolTipText(lang.getString("TOOLBAR_IN")); outdentIconButton.setBorderPainted(false); outdentIconButton.setIcon(this.getIcon("Back16.gif")); // Move node to previous indentIconButton = new JButton(); indentIconButton.setMnemonic('o'); indentIconButton.setToolTipText(lang.getString("TOOLBAR_OUT")); indentIconButton.setBorderPainted(false); indentIconButton.setIcon(this.getIcon("Forward16.gif")); // Add the actions to the toolbar buttons newIconButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ newAction(); } }); openIconButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ openAction(); } }); upIconButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.moveCurrentNodeUp(); repaint(); theJreepad.returnFocusToTree(); updateWindowTitle();} }); downIconButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.moveCurrentNodeDown(); repaint(); theJreepad.returnFocusToTree(); updateWindowTitle();} }); indentIconButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.indentCurrentNode(); repaint(); theJreepad.returnFocusToTree(); updateWindowTitle();} }); outdentIconButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.outdentCurrentNode(); repaint(); theJreepad.returnFocusToTree(); updateWindowTitle(); } }); addAboveIconButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.addNodeAbove(); repaint(); /* theJreepad.returnFocusToTree(); */ updateWindowTitle();} }); addBelowIconButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.addNodeBelow(); repaint(); /* theJreepad.returnFocusToTree(); */ updateWindowTitle();} }); addIconButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ theJreepad.addNode(); repaint(); /* theJreepad.returnFocusToTree(); */ updateWindowTitle();} }); removeIconButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ deleteNodeAction(); } }); // Finished establishing the iconic buttons // Add all the buttons to their respective toolbar toolBar.add(addAboveButton); toolBar.add(addBelowButton); toolBar.add(addButton); toolBar.add(removeButton); toolBar.add(upButton); toolBar.add(downButton); toolBar.add(indentButton); toolBar.add(outdentButton); toolBar.add(viewSelector); toolBar.add(Box.createGlue()); toolBarIconic.add(newIconButton); toolBarIconic.add(openIconButton); toolBarIconic.add(saveIconButton); // if(!MAC_OS_X) // The separators look RUBBISH on OSX // toolBarIconic.add(new JSeparator(JSeparator.VERTICAL)); // toolBarIconic.add(Box.createHorizontalStrut(16)); toolBarIconic.add(addAboveIconButton); toolBarIconic.add(addBelowIconButton); toolBarIconic.add(addIconButton); toolBarIconic.add(removeIconButton); // if(!MAC_OS_X) // The separators look RUBBISH on OSX // toolBarIconic.add(new JSeparator(JSeparator.VERTICAL)); // toolBarIconic.add(Box.createHorizontalStrut(16)); toolBarIconic.add(upIconButton); toolBarIconic.add(downIconButton); toolBarIconic.add(outdentIconButton); toolBarIconic.add(indentIconButton); // if(!MAC_OS_X) // The separators look RUBBISH on OSX // toolBarIconic.add(new JSeparator(JSeparator.VERTICAL)); // toolBarIconic.add(Box.createHorizontalStrut(16)); toolBarIconic.add(viewSelectorIconic); toolBarIconic.add(Box.createGlue()); } private ClassLoader loader = this.getClass().getClassLoader(); private final Icon getIcon(String name){ try{ // TODO create single funct for all img loading URL iconUrl = loader.getResource("images/"+name); return new ImageIcon(iconUrl); }catch(Exception e){ System.err.println("Jreepad: Icon image failed to load: images/"+name); // e.printStackTrace();// Ignore, use default icon } return null; } protected void setToolbarMode(int newMode) { switch(newMode) { case JreepadPrefs.TOOLBAR_TEXT: toolBar.setVisible(true); toolBarIconic.setVisible(false); break; case JreepadPrefs.TOOLBAR_ICON: toolBar.setVisible(false); toolBarIconic.setVisible(true); break; case JreepadPrefs.TOOLBAR_OFF: toolBar.setVisible(false); toolBarIconic.setVisible(false); break; default: // Invalid mode passed return; } getPrefs().toolbarMode = newMode; viewToolbarIconsMenuItem.setSelected(newMode==JreepadPrefs.TOOLBAR_ICON); viewToolbarTextMenuItem.setSelected(newMode==JreepadPrefs.TOOLBAR_TEXT); viewToolbarOffMenuItem.setSelected(newMode==JreepadPrefs.TOOLBAR_OFF); repaint(); } public void establishAutosaveDialogue() { Box vBox, hBox; // Establish the autosave dialogue box autoSaveDialog = new JDialog(this, lang.getString("AUTOSAVE"), true); autoSaveDialog.setVisible(false); vBox = Box.createVerticalBox(); vBox.add(Box.createGlue()); hBox = Box.createHorizontalBox(); hBox.add(autoSaveCheckBox = new JCheckBox(lang.getString("AUTOSAVE_EVERY"), getPrefs().autoSave)); //DSpinner version: hBox.add(autoSavePeriodSpinner = new DSpinner(1, 1000, getPrefs().autoSavePeriod)); hBox.add(autoSavePeriodSpinner = new JSpinner(new SpinnerNumberModel(getPrefs().autoSavePeriod, 1, 1000, 1))); hBox.add(new JLabel(lang.getString("AUTOSAVE_MINUTES"))); vBox.add(hBox); vBox.add(Box.createGlue()); hBox = Box.createHorizontalBox(); hBox.add(autoSaveOkButton = new JButton(lang.getString("OK"))); hBox.add(autoSaveCancelButton = new JButton(lang.getString("CANCEL"))); autoSaveOkButton.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){ getPrefs().autoSavePeriod = ((Integer)(autoSavePeriodSpinner.getValue())).intValue(); // getPrefs().autoSavePeriod = autoSavePeriodSpinner.getValue(); getPrefs().autoSave = autoSaveCheckBox.isSelected(); autoSaveDialog.setVisible(false); if(getPrefs().autoSave && !(autoSaveThread.isAlive())) { autoSaveWarningMessage(); autoSaveThread.start(); } updateWindowTitle(); }}); autoSaveCancelButton.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){autoSaveDialog.setVisible(false);}}); vBox.add(Box.createGlue()); vBox.add(hBox); autoSaveDialog.getContentPane().add(vBox); // Finished establishing the autosave dialogue box } public void autoSaveWarningMessage() { JOptionPane.showMessageDialog(this, lang.getString("AUTOSAVE_ACTIVE_LONG"), lang.getString("AUTOSAVE_ACTIVE") , JOptionPane.INFORMATION_MESSAGE); } public void establishNodeUrlDisplayDialogue() { Box vBox; // Establish the nodeUrlDisplay dialogue box nodeUrlDisplayDialog = new JDialog(this, "Node URL", true); nodeUrlDisplayDialog.setVisible(false); vBox = Box.createVerticalBox(); vBox.add(new JLabel(lang.getString("MSG_NODEURL1"))); vBox.add(nodeUrlDisplayField = new JTextField("node://its/a/secret")); vBox.add(new JLabel(lang.getString("MSG_NODEURL2"))); vBox.add(nodeUrlDisplayOkButton = new JButton(lang.getString("OK"))); nodeUrlDisplayOkButton.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){ nodeUrlDisplayDialog.setVisible(false); }}); nodeUrlDisplayDialog.getContentPane().add(vBox); // Finished: Establish the nodeUrlDisplay dialogue box } public static void main(String[] args) { // System.err.println("" + args.length + " input arguments provided."); // for(int i=0; i<args.length; i++){ // System.err.println(args[i]); // } try { UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) {} String launchFilename="", launchPrefsFilename=null; int ARGMODE_FILE = 0; int ARGMODE_PREF = 1; int argMode = ARGMODE_FILE; for(int i=0; i<args.length; i++) { if(args[i].startsWith("-h") || args[i].startsWith("--h")) { System.out.println("Jreepad command-line arguments:"); System.out.println(" -p [prefsfile] Load/save preferences from named location instead of default"); System.out.println(" [filename] Jreepad/treepad file to load on startup"); System.out.println(" "); System.out.println("For example:"); System.out.println(" java -jar Jreepad.jar -p /Users/jo/Library/jreeprefs.dat /Users/jo/Documents/mynotes.hjt"); System.exit(1); } else if(args[i].equals("-p")) argMode = ARGMODE_PREF; else if(argMode == ARGMODE_PREF && launchPrefsFilename==null) { launchPrefsFilename=args[i]; argMode = ARGMODE_FILE; } else if(argMode == ARGMODE_FILE && launchFilename.equals("")) { launchFilename=args[i]; } } // System.err.println("Launching using prefs file \"" + launchPrefsFilename + "\" and loadfile \"" + launchFilename + "\"\n"); new JreepadViewer(launchFilename, launchPrefsFilename); /* The old way of handling the arguments if(args.length==0) new JreepadViewer(); else if(args.length==1) new JreepadViewer(args[0]); else System.err.println("Only one (optional) argument can be passed - the name of the HJT file to load."); */ } /** * Ask the user whether to save the current file if it is unsaved. * @param prompt message to display * @return true if the user clicked "Yes" and the save was successful or the user clicked "No" or the file didn't need to be saved; * false if the user clicked "Cancel" or the save failed */ private boolean askAndSave(String prompt) { if (document.isContentSaved()) return true; int answer = JOptionPane.showConfirmDialog(this, prompt, "Save?" , JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if(answer == JOptionPane.CANCEL_OPTION) return false; if(answer == JOptionPane.YES_OPTION) { SaveAction saveAction = new SaveAction(); saveAction.actionPerformed(null); if (!saveAction.isSuccessful()) return false; } return true; } private void newAction() { if (!askAndSave(lang.getString("PROMPT_SAVE_BEFORE_NEW"))) return; content.remove(theJreepad); document = new JreepadTreeModel(); theJreepad = new JreepadView(document); content.add(theJreepad); searchDialog.setJreepad(theJreepad); setTitleBasedOnFilename(""); validate(); repaint(); document.setContentSaved(true); updateUndoRedoMenuState(); // theJreepad.clearUndoCache(); } private void openAction() { if (!askAndSave(lang.getString("PROMPT_SAVE_BEFORE_OPEN"))) return; fileChooser.setCurrentDirectory(getPrefs().openLocation); if(fileChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) return; setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); openFile(fileChooser.getSelectedFile()); setCursor(Cursor.getDefaultCursor()); updateUndoRedoMenuState(); } // End of: openAction() public boolean openFile(File file) { getPrefs().openLocation = file; // Remember the open directory try { InputStream in = new FileInputStream(file); JreepadReader reader = new AutoDetectReader(getPrefs().getEncoding(), getPrefs().autoDetectHtmlArticles); document = reader.read(in); document.setSaveLocation(file); } catch(IOException e) { JOptionPane.showMessageDialog(this, e, lang.getString("MSG_LOAD_FILE_FAILED") , JOptionPane.ERROR_MESSAGE); return false; } content.remove(theJreepad); theJreepad = new JreepadView(document); content.add(theJreepad); searchDialog.setJreepad(theJreepad); getPrefs().exportLocation = getPrefs().importLocation = file; setTitleBasedOnFilename(file.getName()); validate(); repaint(); return true; } private class SaveAction extends AbstractAction { private boolean askForFilename; private boolean successful = false; public SaveAction() { this(false); } public SaveAction(boolean askForFilename) { super(askForFilename ? lang.getString("MENUITEM_SAVEAS") : lang.getString("MENUITEM_SAVE"), getIcon("Save16.gif")); this.askForFilename = askForFilename; if (askForFilename) { putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_A)); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke('A', MENU_MASK)); } else { putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_S)); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke('S', MENU_MASK)); putValue(SHORT_DESCRIPTION, lang.getString("TOOLBAR_SAVE")); } } public void actionPerformed(ActionEvent e) { int fileType = getPrefs().mainFileType; if (document.getSaveLocation() != null) fileType = document.getFileType(); File saveLocation = document.getSaveLocation(); if(askForFilename || saveLocation==null || (saveLocation.isFile() && !saveLocation.canWrite())) { // Ask for filename SaveFileChooser fileChooser = new SaveFileChooser(getPrefs().mainFileType); fileChooser.setCurrentDirectory(getPrefs().openLocation); fileChooser.setSelectedFile(new File(document.getRootNode().getTitle() + (fileType==JreepadPrefs.FILETYPE_XML?".jree":".hjt"))); if(fileChooser.showSaveDialog(JreepadViewer.this) != JFileChooser.APPROVE_OPTION) { successful = false; return; // No file chosen } saveLocation = fileChooser.getSelectedFile(); fileType = fileChooser.getFileType(); } getPrefs().openLocation = saveLocation; // Remember the file's directory // Save the file try { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); // Select default application encoding or document encoding String encoding; if (askForFilename || document.getEncoding() == null) encoding = getPrefs().getEncoding(); else encoding = document.getEncoding(); // Write to either HJT or XML JreepadWriter writer; if(fileType == JreepadPrefs.FILETYPE_XML) writer = new XmlWriter(); else if (fileType == JreepadPrefs.FILETYPE_XML_ENCRYPTED) { String password = document.getPassword(); if (password == null || askForFilename) password = PasswordDialog.showPasswordDialog(true); if (password == null) { successful = false; // "Cancel" was pressed return; } EncryptedWriter encryptedWriter = new EncryptedWriter(new XmlWriter()); encryptedWriter.setPassword(password); writer = encryptedWriter; document.setPassword(password); } else writer = new TreepadWriter(encoding); OutputStream fos = new FileOutputStream(saveLocation); writer.write(fos, document); fos.close(); if(MAC_OS_X){ com.apple.eio.FileManager.setFileTypeAndCreator(saveLocation.toString(), appleAppCode, appleAppCode); } // When calling "Save As..." remember the _new_ file settings document.setSaveLocation(saveLocation); document.setFileType(fileType); document.setEncoding(encoding); updateWindowTitle(); addToOpenRecentMenu(saveLocation); savePreferencesFile(); setCursor(Cursor.getDefaultCursor()); successful = true; } catch(IOException err) { setCursor(Cursor.getDefaultCursor()); JOptionPane.showMessageDialog(JreepadViewer.this, err, lang.getString("TITLE_FILE_ERROR") , JOptionPane.ERROR_MESSAGE); successful = false; } } public boolean isSuccessful() { return successful; } } private boolean backupToAction() { try { fileChooser.setCurrentDirectory(getPrefs().backupLocation); if(fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION && checkOverwrite(fileChooser.getSelectedFile())) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); getPrefs().backupLocation = fileChooser.getSelectedFile(); // Write to either HJT JreepadWriter writer = new TreepadWriter(getPrefs().getEncoding()); OutputStream fos = new FileOutputStream(getPrefs().backupLocation); writer.write(fos, document); fos.close(); setCursor(Cursor.getDefaultCursor()); return true; } else return false; } catch(IOException err) { setCursor(Cursor.getDefaultCursor()); JOptionPane.showMessageDialog(this, err, lang.getString("TITLE_FILE_ERROR") , JOptionPane.ERROR_MESSAGE); } return false; } // End of: backupToAction() private void setTitleBasedOnFilename(String filename) { if(filename=="") windowTitle = "Jreepad (Java Treepad Editor)"; else windowTitle = filename + " - Jreepad"; updateWindowTitle(); } private void updateWindowTitle() { setTitle(windowTitle + (document.isContentSaved()?"":"*") + (getPrefs().autoSave?" ["+lang.getString("AUTOSAVE_ACTIVE")+"]":"")); } private static final int FILE_FORMAT_HJT=1; private static final int FILE_FORMAT_HTML=2; private static final int FILE_FORMAT_XML=3; private static final int FILE_FORMAT_TEXT=4; private static final int FILE_FORMAT_TEXTASLIST=5; private static final int FILE_FORMAT_ARTICLESTOTEXT=6; private void importAction(int importFormat) { boolean multipleFiles; try { multipleFiles = (importFormat == FILE_FORMAT_TEXT); if(multipleFiles) fileChooser.setMultiSelectionEnabled(true); fileChooser.setCurrentDirectory(getPrefs().importLocation); fileChooser.setSelectedFile(new File(theJreepad.getCurrentNode().getTitle())); if(fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); getPrefs().importLocation = fileChooser.getSelectedFile(); switch(importFormat) { case FILE_FORMAT_HJT: InputStream in = new FileInputStream(getPrefs().importLocation); JreepadReader reader = new AutoDetectReader(getPrefs().getEncoding(), getPrefs().autoDetectHtmlArticles); theJreepad.addChild(reader.read(in).getRootNode()); break; case FILE_FORMAT_TEXT: theJreepad.addChildrenFromTextFiles(fileChooser.getSelectedFiles()); break; case FILE_FORMAT_TEXTASLIST: theJreepad.addChildrenFromListTextFile(new InputStreamReader(new FileInputStream(getPrefs().importLocation), getPrefs().getEncoding())); break; default: setCursor(Cursor.getDefaultCursor()); JOptionPane.showMessageDialog(this, "Unknown which format to import - coding error! Oops!",lang.getString("TITLE_MISC_ERROR") , JOptionPane.ERROR_MESSAGE); return; } updateWindowTitle(); } fileChooser.setMultiSelectionEnabled(false); setCursor(Cursor.getDefaultCursor()); } catch(IOException err) { setCursor(Cursor.getDefaultCursor()); JOptionPane.showMessageDialog(this, err, lang.getString("TITLE_MISC_ERROR") , JOptionPane.ERROR_MESSAGE); } } // End of: importAction() private void exportAction(int exportFormat) { try { fileChooser.setCurrentDirectory(getPrefs().exportLocation); String suggestFilename = theJreepad.getCurrentNode().getTitle(); switch(exportFormat) { case FILE_FORMAT_HJT: suggestFilename += ".hjt"; break; case FILE_FORMAT_HTML: suggestFilename += ".html"; break; case FILE_FORMAT_XML: suggestFilename += ".xml"; break; case FILE_FORMAT_TEXT: case FILE_FORMAT_TEXTASLIST: case FILE_FORMAT_ARTICLESTOTEXT: suggestFilename += ".txt"; break; } fileChooser.setSelectedFile(new File(suggestFilename)); if(fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION && checkOverwrite(fileChooser.getSelectedFile())) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); getPrefs().exportLocation = fileChooser.getSelectedFile(); String output = null; JreepadWriter writer = null; switch(exportFormat) { case FILE_FORMAT_HTML: writer = new HtmlWriter(getPrefs().getEncoding(), getPrefs().htmlExportArticleType, getPrefs().htmlExportUrlsToLinks, getPrefs().htmlExportAnchorLinkType); break; case FILE_FORMAT_XML: writer= new XmlWriter(); break; case FILE_FORMAT_HJT: writer= new TreepadWriter(getPrefs().getEncoding()); break; case FILE_FORMAT_TEXT: output = theJreepad.getCurrentNode().getContent(); break; case FILE_FORMAT_TEXTASLIST: output = theJreepad.getCurrentNode().exportTitlesAsList(); break; case FILE_FORMAT_ARTICLESTOTEXT: int answer = JOptionPane.showConfirmDialog(this, lang.getString("PROMPT_INCLUDE_TITLES"), lang.getString("TITLE_INCLUDE_TITLES") , JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); boolean titlesToo = (answer == JOptionPane.YES_OPTION); output = theJreepad.getCurrentNode().exportArticlesToText(titlesToo); break; default: setCursor(Cursor.getDefaultCursor()); JOptionPane.showMessageDialog(this, "Unknown which format to export - coding error! Oops!",lang.getString("TITLE_MISC_ERROR") , JOptionPane.ERROR_MESSAGE); return; } OutputStream fos = new FileOutputStream(getPrefs().exportLocation); if (writer != null) { writer.write(fos, new JreepadTreeModel(theJreepad.getCurrentNode())); fos.close(); } else // assume (output != null) { OutputStreamWriter osw = new OutputStreamWriter(fos, getPrefs().getEncoding()); osw.write(output); osw.close(); } setCursor(Cursor.getDefaultCursor()); } } catch(IOException err) { setCursor(Cursor.getDefaultCursor()); JOptionPane.showMessageDialog(this, err, lang.getString("TITLE_FILE_ERROR") , JOptionPane.ERROR_MESSAGE); } } // End of: exportAction() private void subtreeToBrowserForPrintAction() { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); HtmlWriter writer = new HtmlWriter( getPrefs().getEncoding(), getPrefs().htmlExportArticleType, getPrefs().htmlExportUrlsToLinks, getPrefs().htmlExportAnchorLinkType, true); String output = writer.write(theJreepad.getCurrentNode()); toBrowserForPrintAction(output); setCursor(Cursor.getDefaultCursor()); } // End of: subtreeToBrowserForPrintAction() private void articleToBrowserForPrintAction() { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); String output = theJreepad.getCurrentNode().getArticle().exportAsHtml( getPrefs().htmlExportArticleType, getPrefs().htmlExportUrlsToLinks, getPrefs().htmlExportAnchorLinkType, true); toBrowserForPrintAction(output); setCursor(Cursor.getDefaultCursor()); } // End of: articleToBrowserForPrintAction() private void toBrowserForPrintAction(String output) { String surl = ""; try { File systemTempFile = File.createTempFile("TMPjree", ".html"); FileOutputStream fO = new FileOutputStream(systemTempFile); DataOutputStream dO = new DataOutputStream(fO); dO.writeBytes(output); dO.close(); fO.close(); setCursor(Cursor.getDefaultCursor()); // Now launch the file in a browser... surl = systemTempFile.toURL().toString(); new BrowserLauncher(null).openURLinBrowser(surl); } catch (BrowserLaunchingInitializingException e) { displayBrowserLauncherException(e, surl); } catch (BrowserLaunchingExecutionException e) { displayBrowserLauncherException(e, surl); } catch (UnsupportedOperatingSystemException e) { displayBrowserLauncherException(e, surl); } catch (IOException err) { JOptionPane.showMessageDialog(this, err, lang.getString("TITLE_FILE_ERROR"), JOptionPane.ERROR_MESSAGE); } } private void displayBrowserLauncherException(Exception e, String url) { JOptionPane.showMessageDialog(this, "Error while opening URL:\n" + url + "\n" + e.getMessage() + "\n\n" + "The \"BrowserLauncher\" used to open a URL is an open-source Java library \n" + "separate from Jreepad itself - i.e. a separate Sourceforge project. \n" + "It may be a good idea to submit a bug report to\n" + "http://browserlaunch2.sourceforge.net/\n\n" + "If you do, please remember to supply information about the operating system\n" + "you are using - which type, and which version.", lang.getString("TITLE_MISC_ERROR"), JOptionPane.ERROR_MESSAGE); } public void quitAction() { // We need to check about warning-if-unsaved! // For a multiple-Jreepad interface, we would need to use: // for(int i=0; i<theApps.length(); i++) // { // currApp = getApp(i); // if(currApp.warnAboutUnsaved()) // { // if (!askAndSave(lang.getString("PROMPT_SAVE_BEFORE_QUIT"))) return; // Save preferences - including window position and size, and open/closed state of the current tree's nodes getPrefs().treePathCollection = new TreePathCollection(theJreepad.getAllExpandedPaths()); getPrefs().windowLeft = getX(); getPrefs().windowTop = getY(); getPrefs().windowWidth = getWidth(); getPrefs().windowHeight = getHeight(); savePreferencesFile(); System.exit(0); } private void savePreferencesFile() { getPrefs().save(); /* try { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(prefsFile)); out.writeObject(getPrefs()); out.close(); } catch(IOException err) { } */ } private void setViewMode(int mode) { theJreepad.setViewMode(mode); // Update the dropdown menu if(mode==JreepadPrefs.VIEW_ARTICLE){ viewSelector.setSelectedIndex(2); }else if(mode==JreepadPrefs.VIEW_TREE){ viewSelector.setSelectedIndex(1); }else{ viewSelector.setSelectedIndex(0); } // Update the preferences object getPrefs().viewWhich = mode; // Update the undo menus updateUndoRedoMenuState(); } private static JreepadPrefs getPrefs() { return JreepadView.getPrefs(); } private static void setPrefs(JreepadPrefs thesePrefs) { JreepadView.setPrefs(thesePrefs); } private void setViewToolbar(boolean boo) { toolBar.setVisible(boo); } private void undoAction() { /* if(theJreepad.canWeUndo()) theJreepad.undoAction(); else JOptionPane.showMessageDialog(this, lang.getString("MSG_NOTHING_TO_UNDO"), "No change" , JOptionPane.INFORMATION_MESSAGE); */ UndoManager undoMgr = theJreepad.getCurrentNode().getArticle().getUndoMgr(); String undoStyle = undoMgr.getUndoPresentationName(); try{ // This "while" should roll multiple adds or deletes into one. //System.out.println(undoStyle); //System.out.println(undoMgr.getUndoPresentationName()); while(undoStyle.equals(undoMgr.getUndoPresentationName())) undoMgr.undo(); }catch(CannotUndoException ex){ //JOptionPane.showMessageDialog(this, lang.getString("MSG_NOTHING_TO_UNDO"), "No change" , JOptionPane.INFORMATION_MESSAGE); } updateWindowTitle(); updateUndoRedoMenuState(); } private void redoAction(){ UndoManager undoMgr = theJreepad.getCurrentNode().getArticle().getUndoMgr(); String redoStyle = undoMgr.getRedoPresentationName(); try{ while(redoStyle.equals(undoMgr.getRedoPresentationName())) undoMgr.redo(); }catch(CannotRedoException ex){ //JOptionPane.showMessageDialog(this, lang.getString("MSG_NOTHING_TO_UNDO"), "No change" , JOptionPane.INFORMATION_MESSAGE); } updateWindowTitle(); updateUndoRedoMenuState(); } public void updateUndoRedoMenuState(){ undoMenuItem.setEnabled(isArticleUndoPossible()); redoMenuItem.setEnabled(isArticleRedoPossible()); } public boolean isArticleUndoPossible(){ if(getPrefs().viewWhich == JreepadPrefs.VIEW_TREE) return false; if(theJreepad.getCurrentNode().getArticle().getArticleMode() != JreepadArticle.ARTICLEMODE_ORDINARY) return false; // Deactivated: since this class can't tell if text has been typed or not... // if(!theJreepad.getCurrentNode().undoMgr.canUndo()) // return false; return true; } public boolean isArticleRedoPossible(){ if(getPrefs().viewWhich == JreepadPrefs.VIEW_TREE) return false; if(theJreepad.getCurrentNode().getArticle().getArticleMode() != JreepadArticle.ARTICLEMODE_ORDINARY) return false; if(!theJreepad.getCurrentNode().getArticle().getUndoMgr().canRedo()) return false; return true; } private void aboutAction() { JOptionPane.showMessageDialog(this, "Jreepad v " + version + "\n\n" + lang.getString("HELP_ABOUT") + "\n" + "\nJreepad \u00A9 2004-2007 Dan Stowell" + "\n" + "\nhttp://jreepad.sourceforge.net" , "About Jreepad", JOptionPane.INFORMATION_MESSAGE); } private void showAutoSaveDialog() { // The autosave simply launches a background thread which periodically triggers saveAction if saveLocation != null autoSaveCheckBox.setSelected(getPrefs().autoSave); autoSavePeriodSpinner.getModel().setValue(new Integer(getPrefs().autoSavePeriod)); // autoSavePeriodSpinner.setValue(getPrefs().autoSavePeriod); autoSaveDialog.setVisible(true); autoSaveDialog.toFront(); } private void showPrefsDialog() { prefsDialog.setVisible(true); prefsDialog.toFront(); // Apply preferences that immediately affect the GUI funkyGreenStrip.setVisible(getPrefs().showGreenStrip); webSearchMenuItem.setText(getPrefs().webSearchName); characterWrapArticleMenuItem.setText(JreepadViewer.lang.getString("MENUITEM_HARDWRAP1") + getPrefs().characterWrapWidth + JreepadViewer.lang.getString("MENUITEM_HARDWRAP2")); } private void deleteNodeAction() { if(JOptionPane.showConfirmDialog(this, lang.getString("PROMPT_CONFIRM_DELETE")+":\n"+theJreepad.getCurrentNode().getTitle(), lang.getString("TITLE_CONFIRM_DELETE"), JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) return; theJreepad.removeNode(); theJreepad.returnFocusToTree(); updateWindowTitle(); } private void getTreepadNodeUrl() { // String ret = theJreepad.getTreepadNodeUrl(); nodeUrlDisplayField.setText(theJreepad.getTreepadNodeUrl()); nodeUrlDisplayDialog.setVisible(true); } private boolean checkOverwrite(File theFile) { // If file doesn't already exist then fine if(theFile == null || !theFile.exists()) return true; // Else we need to confirm return (JOptionPane.showConfirmDialog(this, lang.getString("PROMPT_CONFIRM_OVERWRITE1")+" "+theFile.getName()+" "+lang.getString("PROMPT_CONFIRM_OVERWRITE2"), lang.getString("TITLE_CONFIRM_OVERWRITE"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION); } public void showLicense() { JOptionPane.showMessageDialog(this, lang.getString("HELP_LICENSE") + "\n\n http://www.gnu.org/copyleft/gpl.html\n" + "\n" , lang.getString("MENUITEM_LICENSE"), JOptionPane.INFORMATION_MESSAGE); } public void wrapContentToCharWidth() { theJreepad.wrapContentToCharWidth(getPrefs().characterWrapWidth); } public void stripAllTags() { if(JOptionPane.showConfirmDialog(this, lang.getString("PROMPT_CONFIRM_STRIPTAGS"), lang.getString("TITLE_CONFIRM_STRIPTAGS"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) theJreepad.stripAllTags(); } private void addToOpenRecentMenu(File f) { // Remove the file from the list if it's already in there... ListIterator iter = getPrefs().openRecentList.listIterator(); File tempFile; while(iter.hasNext()) { tempFile = (File)iter.next(); if(tempFile == null || tempFile.equals(f)) iter.remove(); } getPrefs().openRecentList.insertElementAt(f, 0); updateOpenRecentMenu(); } private File[] openRecentTempFileList; private void updateOpenRecentMenu() { if(getPrefs().openRecentList.size() > getPrefs().openRecentListLength) getPrefs().openRecentList.setSize(getPrefs().openRecentListLength); try { // openRecentTempFileList = (File[])getPrefs().openRecentList.toArray(); openRecentTempFileList = new File[getPrefs().openRecentList.size()]; for(int i=0; i<getPrefs().openRecentList.size(); i++) { openRecentTempFileList[i] = (File)getPrefs().openRecentList.get(i); } } catch(ClassCastException e) { System.err.println(e); openRecentTempFileList = new File[0]; } openRecentMenu.setEnabled(getPrefs().openRecentList.size()>1); openRecentMenu.removeAll(); JMenuItem tempMenuItem; File tempFile; char theChar; for(int i=1; i<openRecentTempFileList.length; i++) { tempFile = openRecentTempFileList[i]; tempMenuItem = new JMenuItem(tempFile.getParentFile().getName() + "/" + tempFile.getName()); if(i<10) { theChar = ("" + i).charAt(0); tempMenuItem.setText("("+theChar+") "+tempMenuItem.getText()); tempMenuItem.setMnemonic(theChar); } // ADD THE ACTIONLISTENER HERE tempMenuItem.addActionListener(new FileOpeningActionListener(tempFile)); openRecentMenu.add(tempMenuItem); } } private void insertDate() { theJreepad.insertDate(); } private class FileOpeningActionListener implements ActionListener { File f; FileOpeningActionListener(File f) {this.f = f;} public void actionPerformed(ActionEvent e) {openFile(f);} } // End of: private class FileOpeningActionListener extends ActionListener // private void updateFontsInPrefsBox() // { // String treeFontName = getPrefs().treeFont.getFamily(); // String articleFontName = getPrefs().articleFont.getFamily(); // String treeFontSize = "" + getPrefs().treeFont.getSize(); // String articleFontSize = "" + getPrefs().articleFont.getSize(); // int i; // for(i=0; i<fonts.length; i++) // { // if(treeFontName.equals(fonts[i])) // treeFontFamilySelector.setSelectedIndex(i); // if(articleFontName.equals(fonts[i])) // { // articleFontFamilySelector.setSelectedIndex(i); // break; // } // } // for(i=0; i<fontSizes.length; i++) // { // if(treeFontSize.equals(fontSizes[i])) // treeFontSizeSelector.setSelectedIndex(i); // if(articleFontSize.equals(fontSizes[i])) // { // articleFontSizeSelector.setSelectedIndex(i); // break; // } // } // } // private void setFontsFromPrefsBox() // { // getPrefs().treeFont = new Font((String)treeFontFamilySelector.getSelectedItem(), Font.PLAIN, // getPrefs().treeFont.getSize() ); // getPrefs().articleFont = new Font((String)articleFontFamilySelector.getSelectedItem(), Font.PLAIN, // (Integer.valueOf((String)articleFontSizeSelector.getSelectedItem())).intValue() ); // theJreepad.setTreeFont(getPrefs().treeFont); // theJreepad.setArticleFont(getPrefs().articleFont); // } // Generic registration with the Mac OS X application menu. Checks the platform, then attempts // to register with the Apple EAWT. // This method calls OSXAdapter.registerMacOSXApplication() and OSXAdapter.enablePrefs(). // See OSXAdapter.java for the signatures of these methods. public void macOSXRegistration() { if (MAC_OS_X) { try { Class osxAdapter = Class.forName("jreepad.OSXAdapter"); Class[] defArgs = {JreepadViewer.class}; Method registerMethod = osxAdapter.getDeclaredMethod("registerMacOSXApplication", defArgs); if (registerMethod != null) { Object[] args = { this }; registerMethod.invoke(osxAdapter, args); } /* // This is slightly gross. to reflectively access methods with boolean args, // use "boolean.class", then pass a Boolean object in as the arg, which apparently // gets converted for you by the reflection system. defArgs[0] = boolean.class; Method prefsEnableMethod = osxAdapter.getDeclaredMethod("enablePrefs", defArgs); if (prefsEnableMethod != null) { Object args[] = {Boolean.TRUE}; prefsEnableMethod.invoke(osxAdapter, args); } */ } catch (NoClassDefFoundError e) { // This will be thrown first if the OSXAdapter is loaded on a system without the EAWT // because OSXAdapter extends ApplicationAdapter in its def System.err.println("This version of Mac OS X does not support the Apple EAWT. Application Menu handling has been disabled (" + e + ")"); } catch (ClassNotFoundException e) { // This shouldn't be reached; if there's a problem with the OSXAdapter we should get the // above NoClassDefFoundError first. System.err.println("This version of Mac OS X does not support the Apple EAWT. Application Menu handling has been disabled (" + e + ")"); } catch (Exception e) { System.err.println("Exception while loading the OSXAdapter:"); e.printStackTrace(); } } } // General info dialog. The OSXAdapter calls this method when "About OSXAdapter" // is selected from the application menu. public void about() { aboutAction(); } // General preferences dialog. The OSXAdapter calls this method when "Preferences..." // is selected from the application menu. public void preferences() { // prefs.setSize(320, 240); // prefs.setLocation((int)this.getLocation().getX() + 22, (int)this.getLocation().getY() + 22); // prefs.setResizable(false); // prefs.setVisible(true); } // General info dialog. The OSXAdapter calls this method when "Quit OSXAdapter" // is selected from the application menu, Cmd-Q is pressed, or "Quit" is selected from the Dock. public void quit() { quitAction(); } protected void systemClipboardToNewNode() { Transferable cont = systemClipboard.getContents(this); /* DataFlavor[] flavs = cont.getTransferDataFlavors(); System.out.println("Data flavors supported by contents:\n"); for(int i=0; i<flavs.length; i++) System.out.println(" " + flavs[i].getHumanPresentableName() + "\n" + flavs[i].getMimeType() + "\n"); */ if(cont == null) { JOptionPane.showMessageDialog(this, lang.getString("MSG_CLIPBOARD_EMPTY"), lang.getString("TITLE_CLIPBOARD_EMPTY") , JOptionPane.ERROR_MESSAGE); return; } try { // Reader readIt = DataFlavor.getTextPlainUnicodeFlavor().getReaderForText(cont); Reader readIt = DataFlavor.stringFlavor.getReaderForText(cont); char[] theStuff = new char[64]; int numRead; StringBuffer theStuffBuf = new StringBuffer(); while((numRead = readIt.read(theStuff)) != -1) { theStuffBuf.append(theStuff, 0, numRead); } String contStr = theStuffBuf.toString(); String titStr; int newlinePos = contStr.indexOf("\n"); if(newlinePos == -1) { titStr = contStr; contStr = ""; } else titStr = contStr.substring(0, newlinePos-1); theJreepad.addChild(new JreepadNode(titStr, contStr)); } catch(Exception err) { JOptionPane.showMessageDialog(this, lang.getString("MSG_CLIPBOARD_TEXTERROR"), lang.getString("TITLE_CLIPBOARD_ERROR") , JOptionPane.ERROR_MESSAGE); return; } } public void keyboardHelp() { String menuText; if(MAC_OS_X) menuText = "Apple"; else switch(MENU_MASK) { case Event.ALT_MASK: menuText = "Alt"; break; case Event.META_MASK: menuText = "Meta"; break; case Event.CTRL_MASK: default: menuText = "Ctrl"; break; } JOptionPane.showMessageDialog(this, "\nNAVIGATING AROUND THE TREE:" + "\nUse the arrow (cursor) keys to navigate around the tree." + "\nUp/down will move you up/down the visible nodes." + "\nLeft/right will expand/collapse nodes." + "\n" + "\nADDING/DELETING NODES:" + "\n["+menuText+"+T] Add sibling node above current node" + "\n["+menuText+"+B] Add sibling node below current node" + "\n["+menuText+"+D] Add child node to current node" + "\n["+menuText+"+K] Delete current node" + "\n" + "\nMOVING NODES:" + "\n["+menuText+"+up arrow] Move node up" + "\n["+menuText+"+down arrow] Move node down" + "\n["+menuText+"+right arrow] Indent node" + "\n["+menuText+"+left arrow] Outdent node" + "\n" + "\nCOPYING AND PASTING:" + "\n["+menuText+"+X] Cut selected text" + "\n["+menuText+"+C] Copy selected text" + "\n["+menuText+"+V] Paste selected text" + "\n - The copy/paste functions are included automatically" + "\n by the Mac OSX runtime. I can't guarantee they exist" + "\n for you if you're using a different operating system!" + /* "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n[] " + "\n" + */ "" , lang.getString("HELP_KEYBOARD_TITLE"), JOptionPane.INFORMATION_MESSAGE); } public void linksHelp() { JOptionPane.showMessageDialog(this, lang.getString("HELP_LINKS") /* "\nSelect any piece of text in an article," + "\nthen choose \"Actions > Follow link in article\"." + "\n" + "\nTYPES OF LINK:" + "\n" + "\n\"Normal\" link - We've tested these types of link:" + "\n Web: e.g. http://jreepad.sourceforge.net" + "\n Email: e.g. mailto:billg@microsoft.com" + "\n FTP: e.g. ftp://ftp.compaq.com/pub/" + "\n File: (can't get these to work, on OSX at least)" + "\n" + "\nWiki link - If the selected text is a WikiWord (i.e. if " + "\n it LooksLikeThis with no spaces and some capital " + "\n letters somewhere in the middle) OR begins " + "\n with \"[[\" and ends with \"]]\" then " + "\n Jreepad will search for a node of the same " + "\n title, and jump directly to it. If one " + "\n isn't found then it'll create one " + "\n for you. Try it!" + "\n" + "\nTreepad link - Treepad Lite uses links which begin " + "\n with \"node://\", and specify the exact path" + "\n to a different node within the same file."+ "\n e.g. \"node://TreePad manual/Using Treepad\"" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n[] " + "\n" + "" */ , lang.getString("HELP_LINKS_TITLE"), JOptionPane.INFORMATION_MESSAGE); } public void dragDropHelp() { JOptionPane.showMessageDialog(this, lang.getString("HELP_DRAGDROP") /* "\nDRAG-AND-DROP:" + "\n" + "\nOne of the easiest ways to manage the structure" + "\nof your Treepad file is to drag the nodes around" + "\nusing the mouse." + "\n" + "\nClick on a node's title, and, keeping the mouse" + "\nbutton held down, move the mouse to where you" + "\nwant the node to be moved to. Then release the" + "\nmouse button, and the node will be moved to its" + "\nnew position in the tree." + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n[] " + "\n" + "" */ , lang.getString("HELP_DRAGDROP_TITLE"), JOptionPane.INFORMATION_MESSAGE); } /* // Replacement for the "JSpinner" which is not available in Java 1.3 or 1.2 static class DSpinner extends Box { private int min, max, val; private JTextField textField; private JButton upBut, downBut; private ActionListener al; DSpinner(int min, int max, int myVal) { super(BoxLayout.X_AXIS); this.min=this.val=min; this.max=max; this.add(Box.createGlue()); this.add(textField = new JTextField(val)); this.add(downBut = new JButton("-")); this.add(upBut = new JButton("+")); this.add(Box.createGlue()); downBut.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { setValue(val-1); if(al!=null) al.actionPerformed(null); }}); upBut.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) { setValue(val+1); if(al!=null) al.actionPerformed(null); }}); setValue(myVal); } int getValue() { try { val = Integer.parseInt(textField.getText()); } catch(NumberFormatException e) { } return val; } void setValue(int newVal) { if(newVal>=min && newVal<=max) val=newVal; textField.setText("" + val); } void addActionListener(ActionListener al) { this.al = al; textField.addActionListener(al); } void addCaretListener(CaretListener cl) { textField.addCaretListener(cl); } } // End of class DSpinner */ static class ColouredStrip extends JPanel { Color col; ColouredStrip(Color col, int maxWidth, int maxHeight) { super(false); setMaximumSize(new Dimension(maxWidth, maxHeight)); setBackground(col); // this.col = col; } // public void paint(Graphics gggg) // { // Graphics2D g = (Graphics2D)gggg; // g.setPaint(col); // g.fillRect(0,0,getWidth(),getHeight()); // } } /* // Methods required by Apple's "ApplicationListener" interface public void handleOpenFile(ApplicationEvent ae) { System.err.println("Jreepad.handleOpenFile() - ApplicationEvent is " + ae); openHjtFile(new java.io.File(ae.getFilename())); ae.setHandled(true); } public void handleOpenApplication(ApplicationEvent ae) { System.err.println("Jreepad.handleOpenApplication() - ApplicationEvent is " + ae); } public void handleReOpenApplication(ApplicationEvent ae) { System.err.println("Jreepad.handleReOpenApplication() - ApplicationEvent is " + ae); } public void handlePrintFile(ApplicationEvent ae) { System.err.println("Jreepad.handlePrintFile() - ApplicationEvent is " + ae); ae.setHandled(true); toBrowserForPrintAction(); } public void handleAbout(ApplicationEvent ae) { ae.setHandled(true); about(); } public void handlePreferences(ApplicationEvent ae) { preferences(); ae.setHandled(true); } public void handleQuit(ApplicationEvent ae) { // // You MUST setHandled(false) if you want to delay or cancel the quit. // This is important for cross-platform development -- have a universal quit // routine that chooses whether or not to quit, so the functionality is identical // on all platforms. This example simply cancels the AppleEvent-based quit and // defers to that universal method. // ae.setHandled(false); quit(); } */ }