Package jreepad

Source Code of jreepad.JreepadView

/*
           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.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Vector;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreePath;
import javax.swing.text.DefaultEditorKit;

import jreepad.editor.ArticleView;
import jreepad.editor.ContentChangeListener;
import jreepad.editor.HtmlViewer;
import jreepad.editor.PlainTextEditor;
import jreepad.editor.TableViewer;
import jreepad.editor.TextileViewer;
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;
import jreepad.editor.EditPopupHandler;
import jreepad.editor.TextTransferHandler;
import javax.swing.text.JTextComponent;
import java.util.ResourceBundle;

public class JreepadView
    extends Box {

  private static JreepadPrefs prefs;
  private JreepadNode root;
  private JreepadNode currentNode;
  private JreepadTreeModel treeModel;
  private TreeView tree;
  private JScrollPane treeView;
  private JScrollPane articlePane;

  // editorPane is supposed to represent the pane currently displayed/edited - so it's the one
  //    to refer to when you're doing GUI-related stuff
  // It will be equal to one of the content-type-specific panes. Need to set the content of BOTH of these...
//  private JEditorPane editorPane;
  private PlainTextEditor editorPanePlainText;
  private HtmlViewer editorPaneHtml;
  private TextileViewer editorPaneTextile;
  private TableViewer editorPaneCsv;

  private EditPopupHandler editPopupHandler = new EditPopupHandler();
  private TextTransferHandler textTransferHandler = new TextTransferHandler();

  private ArticleView currentArticleView;


  // Undo features
//  protected UndoManager undoMgr;

  private JSplitPane splitPane;

  private JreepadSearcher searcher;

  // Things concerned with the "undo" function
//OLD ATTEMPT private JreepadNode oldRootForUndo, oldCurrentNodeForUndo;
//OLD ATTEMPT private TreePath[] oldExpandedPaths;
//OLD ATTEMPT private TreePath oldSelectedPath;

  public JreepadView()
  {
    this(new JreepadTreeModel());
  }

  public JreepadView(JreepadTreeModel treeModel)
  {
    super(BoxLayout.X_AXIS);
    treeView = new JScrollPane();
    splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
    splitPane.setResizeWeight(0.5);
    if(getPrefs().dividerLocation > 0)
    {
      splitPane.setDividerLocation(getPrefs().dividerLocation);
    }
    splitPane.addPropertyChangeListener("lastDividerLocation", new java.beans.PropertyChangeListener()
           {
             public void propertyChange(java.beans.PropertyChangeEvent evt)
             {
             // System.out.println(evt.getPropertyName());
             getPrefs().dividerLocation = splitPane.getDividerLocation();
             // System.out.println("New divider location = " + getPrefs().dividerLocation);
             }
           }
           );

    this.treeModel = treeModel;
    root = (JreepadNode)treeModel.getRoot();

    treeModel.addTreeModelListener(new JreepadTreeModelListener());

    tree = new TreeView(treeModel);

    searcher = new JreepadSearcher(root);

//    undoMgr = new UndoManager();


    //Listen for when the selection changes.
    tree.addTreeSelectionListener(new TreeSelectionListener()
                   {
                     public void valueChanged(TreeSelectionEvent e)
                     {
                        JreepadNode node = (JreepadNode)
                           tree.getLastSelectedPathComponent();
                        if (node == null) return;

// UNDO DEVELOPMENT:
//                        System.out.println("TreeSelectionListener:valueChanged");
//                        undoMgr.discardAllEdits();

                        setCurrentNode(node);
                      }
                   });


    tree.addKeyListener(new KeyAdapter(){public void keyPressed(KeyEvent kee) {
     int key = kee.getKeyCode();
     switch(key)
     {
       case KeyEvent.VK_ENTER:
         addNodeBelow();
         break;
       case KeyEvent.VK_F2:
         editNodeTitleAction();
         break;
     }
     // System.out.println("Tree detected a keypress: " + kee.getKeyText(kee.getKeyCode()) + " (key code "+ kee.getKeyCode()+")");
     }});

    treeView.setViewportView(tree);

    initEditPopupHandler();
    editorPanePlainText = new PlainTextEditor(root.getArticle());
    initTextComponent((JTextComponent)editorPanePlainText.getComponent());
    editorPaneHtml = new HtmlViewer(root.getArticle());
    initTextComponent((JTextComponent)editorPaneHtml.getComponent());
    editorPaneTextile = new TextileViewer(root.getArticle());
    initTextComponent((JTextComponent)editorPaneTextile.getComponent());
    editorPaneCsv = new TableViewer(root.getArticle());
    currentArticleView = editorPanePlainText;

    editorPanePlainText.setContentChangeListener(new ContentChangeListener() {
      public void contentChanged()
      {
            JreepadView.this.treeModel.setContentSaved(false);
      }
    });

    articlePane = new JScrollPane(editorPanePlainText.getComponent(), JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

    /* XXX Is this really needed?
    articleView.addComponentListener(new ComponentListener()
              {
                public void componentResized(ComponentEvent e)
                {
                  editorPanePlainText.setMaximumSize(new Dimension(articleView.getViewport().getWidth(), Integer.MAX_VALUE));
                  editorPanePlainText.setSize(articleView.getViewport().getViewSize());
                  editorPaneHtml.setMaximumSize(new Dimension(articleView.getViewport().getWidth(), Integer.MAX_VALUE));
                  editorPaneHtml.setSize(articleView.getViewport().getViewSize());
                }
                public void componentMoved(ComponentEvent e){}
                public void componentHidden(ComponentEvent e){}
                public void componentShown(ComponentEvent e){}
              }
              );
    articleView.getViewport().addChangeListener(new ChangeListener()
              {
                public void stateChanged(ChangeEvent e)
                {
                  editorPanePlainText.setPreferredSize(articleView.getViewport().getExtentSize());
                  editorPanePlainText.setMaximumSize(new Dimension(articleView.getViewport().getWidth(), Integer.MAX_VALUE));
                  editorPanePlainText.setSize(articleView.getViewport().getViewSize());
                  editorPaneHtml.setPreferredSize(articleView.getViewport().getExtentSize());
                  editorPaneHtml.setMaximumSize(new Dimension(articleView.getViewport().getWidth(), Integer.MAX_VALUE));
                  editorPaneHtml.setSize(articleView.getViewport().getViewSize());
                }
              }
              );
    */

    setCurrentNode(root);

    setViewBoth();
    tree.setSelectionRow(0);
  }

  private void initEditPopupHandler() {
    ResourceBundle lang = ResourceBundle.getBundle(
      "jreepad.lang.JreepadStrings");
    editPopupHandler.addActionItem(new DefaultEditorKit.CopyAction(),
                                   lang.getString("MENUITEM_COPY"),
                                   EditPopupHandler.ITEM_COPY);
    editPopupHandler.addActionItem(new DefaultEditorKit.CutAction(),
                                   lang.getString("MENUITEM_CUT"),
                                   EditPopupHandler.ITEM_CUT);
    editPopupHandler.addActionItem(new DefaultEditorKit.PasteAction(),
                                   lang.getString("MENUITEM_PASTE"),
                                   EditPopupHandler.ITEM_PASTE);
  }

  private void initTextComponent(JTextComponent textComp) {
    textComp.addMouseListener(editPopupHandler);
    textComp.setTransferHandler(textTransferHandler);
    textComp.setDragEnabled(true);
  }

  public static final int CHANGE_ARTICLE_FONT = 1;
  public static final int CHANGE_TREE_FONT = 2;

  public void changeFont(int direction,
                         int comptype) {
    if (comptype == CHANGE_ARTICLE_FONT && currentArticleView != null) {
      currentArticleView.updateFont(direction);
    }
    if (comptype == CHANGE_TREE_FONT && tree != null) {
      FontHelper.updateFont(tree, direction);
    }
  }

  public void setViewMode(int mode) {
//      System.out.println("-------------------------------------------------------------");
//      System.out.println("editorPane size: " + editorPane.getSize());
//      System.out.println("articleView size: " + articleView.getSize());
//      System.out.println("articleView viewport size: " + articleView.getViewport().getSize());
//      System.out.println();

    switch(mode)
    {
      case JreepadPrefs.VIEW_BOTH:
        setViewBoth();
        break;
      case JreepadPrefs.VIEW_TREE:
        setViewTreeOnly();
        break;
      case JreepadPrefs.VIEW_ARTICLE:
        setViewArticleOnly();
        break;
      default:
        System.err.println("Invalid argument to JreepadView.setViewMode()!");
        return;
    }
      setSize(getSize());
      currentArticleView.getComponent().setPreferredSize(articlePane.getViewport().getExtentSize());
      currentArticleView.getComponent().setSize(articlePane.getViewport().getExtentSize());
      validate();
      repaint();
//      System.out.println("editorPane size: " + editorPane.getSize());
//      System.out.println("articleView size: " + articleView.getSize());
//      System.out.println("articleView viewport size: " + articleView.getViewport().getSize());
//      System.out.println();
//      System.out.println();
  }

  private void setViewBoth()
  {
    ensureCorrectArticleRenderMode();
    splitPane.setLeftComponent(treeView);
    splitPane.setRightComponent(articlePane);
    this.add(splitPane);
//      editorPane.setSize(articleView.getSize());
//      editorPane.setSize(articleView.getViewport().getViewSize());
    getPrefs().viewWhich = JreepadPrefs.VIEW_BOTH;
  }
  private void setViewTreeOnly()
  {   this.remove(splitPane);
      this.remove(articlePane);
      this.add(treeView);
      treeView.setSize(getSize());
    getPrefs().viewWhich = JreepadPrefs.VIEW_TREE;
  }
  private void setViewArticleOnly()
  {
     this.remove(splitPane);
     this.remove(treeView);
     ensureCorrectArticleRenderMode();
     this.add(articlePane);
     articlePane.setSize(getSize());
    getPrefs().viewWhich = JreepadPrefs.VIEW_ARTICLE;
  }

  private void setCurrentNode(JreepadNode n)
  {
    //    This should stop the caret jumping to the end of the text when we press Save.
    if (currentNode == n)
      return;

    ArticleView oldView = currentArticleView;
    oldView.lockEdits(); // Deactivate the caret-listener, effectively - ALSO DEACTIVATES UNDO-STORAGE

    currentNode = n;
    ensureCorrectArticleRenderMode();

    oldView.unlockEdits(); // Reactivate the caret listener - ALSO REACTIVATES UNDO-STORAGE
  }

  public JTree getTree()
  {
    return tree;
  }

  public JreepadNode getCurrentNode()
  {
    return currentNode;
  }

  public String getTreepadNodeUrl()
  {
    StringBuffer ret = new StringBuffer("\"node:/");
    Object[] p = tree.getLeadSelectionPath().getPath();
    for(int i=0; i<p.length; i++)
      ret.append("/" + ((JreepadNode)p[i]).getTitle());
    return ret.toString() + "\"";
  }

  public void indentCurrentNode()
  {
    if(currentNode.equals(root))
    {
      notForRootNode();
      return;
    }

    TreePath parentPath = tree.getSelectionPath().getParentPath();
    int pos = currentNode.getIndex();
    if(pos<1) return;

    //DEL storeForUndo();

    JreepadNode newParent = ((JreepadNode)currentNode.getParent().getChildAt(pos-1));

    if(currentNode.indent())
    {
      treeModel.reload(currentNode.getParent().getParent());
      parentPath = parentPath.pathByAddingChild(newParent);
      TreePath myPath = parentPath.pathByAddingChild(currentNode);
      // Now use scrollPathToVisible() or scrollRowToVisible() to make sure it's visible
      tree.scrollPathToVisible(myPath);
      tree.setSelectionPath(myPath);
    }
  }

  public void outdentCurrentNode()
  {
    if(currentNode.equals(root))
    {
      notForRootNode();
      return;
    }

    TreePath parentPath = tree.getSelectionPath().getParentPath();
    if(parentPath==null) return;
    TreePath parentParentPath = parentPath.getParentPath();
    if(parentParentPath==null) return;

    //DEL storeForUndo();

    if(currentNode.outdent())
    {
      TreePath myPath = parentParentPath.pathByAddingChild(currentNode);
      treeModel.reload(currentNode.getParent());
      // Now use scrollPathToVisible() or scrollRowToVisible() to make sure it's visible
      tree.scrollPathToVisible(myPath);
      tree.setSelectionPath(myPath);
    }
  }

  public void moveCurrentNodeUp()
  {
    TreePath nodePath = tree.getSelectionPath();

    if(currentNode.equals(root))
    {
      notForRootNode();
      return;
    }

    //DEL storeForUndo();
    currentNode.moveUp();
    treeModel.reload(currentNode.getParent());
    tree.setSelectionPath(nodePath);
  }

  public void moveCurrentNodeDown()
  {
    TreePath nodePath = tree.getSelectionPath();

    if(currentNode.equals(root))
    {
      notForRootNode();
      return;
    }

    //DEL storeForUndo();
    currentNode.moveDown();
    treeModel.reload(currentNode.getParent());
    tree.setSelectionPath(nodePath);
  }

  private void notForRootNode()
  {
    // FIXME: If there are no child nodes, assume the user needs some advice about adding nodes
    if(root.isLeaf())
      JOptionPane.showMessageDialog(this,
       JreepadViewer.lang.getString("MSG_ONLY_ON_CHILDNODES"), JreepadViewer.lang.getString("TITLE_ONLY_ON_CHILDNODES") ,
         JOptionPane.INFORMATION_MESSAGE);
    else
      return;
//      JOptionPane.showMessageDialog(this,
//       "The root node is currently selected - you can only perform this operation on child nodes.", "Root node is selected" ,
//         JOptionPane.INFORMATION_MESSAGE);
  }

  public void insertDate()
  {
    if(currentNode.getArticle().getArticleMode() != JreepadArticle.ARTICLEMODE_ORDINARY)
      return; // May want to fix this later - allow other modes to have the date inserted...

    //DEL storeForUndo();
    String theDate = JreepadArticle.getCurrentDate();
    editorPanePlainText.insertText(theDate);
  }

  public JreepadNode addNodeAbove()
  {
    int index = currentNode.getIndex();
    if(index==-1)
    {
      notForRootNode();
      return null;
    }

    if(tree.getSelectionPath()==null)
      return null;
    //DEL storeForUndo();
    TreePath parentPath = tree.getSelectionPath().getParentPath();
    JreepadNode parent = currentNode.getParentNode();
    JreepadNode ret = parent.addChild(index);
    treeModel.nodesWereInserted(parent, new int[]{index});
    TreePath newPath = (parentPath.pathByAddingChild(ret));
    if(newPath!=null)
      tree.startEditingAtPath(newPath);
    return ret;
  }

  public JreepadNode addNodeBelow()
  {
    int index = currentNode.getIndex();
    if(index==-1)
    {
      notForRootNode();
      return null;
    }

    if(tree.getSelectionPath()==null)
      return null;
    //DEL storeForUndo();
    TreePath parentPath = tree.getSelectionPath().getParentPath();
    JreepadNode parent = currentNode.getParentNode();
    JreepadNode ret = parent.addChild(index+1);
    treeModel.nodesWereInserted(parent, new int[]{index+1});
    tree.startEditingAtPath(parentPath.pathByAddingChild(ret));
    return ret;
  }

  public JreepadNode addNode()
  {
    //DEL storeForUndo();
    JreepadNode ret = currentNode.addChild();
    TreePath nodePath = tree.getSelectionPath();
    treeModel.nodesWereInserted(currentNode, new int[]{currentNode.getIndex(ret)});

//    tree.setSelectionPath(nodePath.pathByAddingChild(ret));
    tree.scrollPathToVisible(nodePath.pathByAddingChild(ret));
    tree.startEditingAtPath(nodePath.pathByAddingChild(ret));
    return ret;
  }

  public JreepadNode removeNode()
  {
    JreepadNode parent = (JreepadNode)currentNode.getParent();
    TreePath parentPath = tree.getSelectionPath().getParentPath();
    if(parent != null)
    {
      //DEL storeForUndo();
      int index = parent.getIndex(currentNode);
      JreepadNode ret = parent.removeChild(index);

      tree.setSelectionPath(parentPath);
      treeModel.nodesWereRemoved(parent, new int[]{index}, new Object[]{ret});

      repaint();
      return ret;
    }
    else
      return null;
  }

  public void sortChildren()
  {
    //DEL storeForUndo();
    currentNode.sortChildren();
    treeModel.reload(currentNode);
    // System.out.println(currentNode.toFullString());
  }

  public void sortChildrenRecursive()
  {
    //DEL storeForUndo();
    currentNode.sortChildrenRecursive();
    treeModel.reload(currentNode);
    // System.out.println(currentNode.toFullString());
  }

  public void returnFocusToTree()
  {
    tree.requestFocus();
  }

  public void expandAllCurrentNode()
  {
    tree.expandAll(currentNode, tree.getLeadSelectionPath());
  }

  public void collapseAllCurrentNode()
  {
    tree.collapseAll(currentNode, tree.getLeadSelectionPath());
  }

  public TreePath[] getAllExpandedPaths()
  {
      return tree.getAllExpandedPaths();
  }

  // THIS FUNCTION SEEMS TO HAVE NO EFFECT, ON MY MACHINE AT LEAST! WHAT'S GOING ON?
  public void expandPaths(TreePath[] paths)
  {
      tree.expandPaths(paths);
  }


  // Functions and inner class for searching nodes
  public boolean performSearch(String inNodes, String inArticles, int searchWhat // 0=selected, 1=all
                , boolean orNotAnd, boolean caseSensitive, int maxResults)
  {
    switch(searchWhat)
    {
      case 0: // search selected node
        searcher.performSearch(inNodes, inArticles, tree.getSelectionPath(), orNotAnd, caseSensitive, maxResults);
        break;
      default: // case 1==search whole tree
        searcher.performSearch(inNodes, inArticles, new TreePath(root), orNotAnd, caseSensitive, maxResults);
        break;
    }
  return true;
  }

  public JreepadSearcher.JreepadSearchResult[] getSearchResults()
  {
    return searcher.getSearchResults();
  }

  public void addChildrenFromTextFiles(File[] inFiles) throws IOException
  {
    //DEL storeForUndo();
  for(int i=0; i<inFiles.length; i++)
      getCurrentNode().addChildFromTextFile(new InputStreamReader(new FileInputStream(inFiles[i]), getPrefs().getEncoding())
                         , inFiles[i].getName());
    treeModel.reload(currentNode);
    tree.expandPath(tree.getSelectionPath());
  }

  public void addChild(JreepadNode newKid)
  {
    //DEL storeForUndo();
  getCurrentNode().add(newKid);
    treeModel.reload(currentNode);
    tree.expandPath(tree.getSelectionPath());
  }

  public void addChildrenFromListTextFile(InputStreamReader inFile) throws IOException
  {
    //DEL storeForUndo();

    BufferedReader bReader = new BufferedReader(inFile);

    String curLine;
    while((curLine = bReader.readLine())!=null)
      if(curLine.trim().length() > 0)
        getCurrentNode().add(new JreepadNode(curLine.trim(), ""));

    treeModel.reload(currentNode);
    tree.expandPath(tree.getSelectionPath());
  }

  public static JreepadPrefs getPrefs()
  {
    return prefs;
  }
  public static void setPrefs(JreepadPrefs thesePrefs)
  {
    prefs = thesePrefs;
    prefs.save();
  }

  // Stuff concerned with linking
  public void webSearchTextSelectedInArticle()
  {
    // JComponent treeOrArticle;
    String url = currentArticleView.getSelectedText();

    if(url==null || url.length()==0)
      url = currentNode.getTitle();

    if((url == null) && (currentNode.getArticle().getArticleMode()==JreepadArticle.ARTICLEMODE_ORDINARY))
      url = editorPanePlainText.selectWordUnderCursor();

    if(url==null || !(url.length()>0))
      url = currentNode.getTitle();

    webSearchText(url);
  }

  public void webSearchText(String text)
  {
    openURL("http://" + getPrefs().webSearchPrefix + text + getPrefs().webSearchPostfix);
  }

  public void openURLSelectedInArticle()
  {
    String url = currentArticleView.getSelectedText();
    if((url == null) && (currentNode.getArticle().getArticleMode()==JreepadArticle.ARTICLEMODE_ORDINARY))
      url = editorPanePlainText.selectWordUnderCursor();
    openURL(url);
  }

  public static boolean isPureWord(String in)
  {
    char[] c = in.toCharArray();
    for(int i=0; i<c.length; i++)
      if(c[i]==':' || c[i]=='/' || c[i]=='[' || c[i]==']')
        return false;
    return true;
  }

  public static boolean isWikiWord(String in)
  {
    if(in.length()>4 && in.startsWith("[[") && in.endsWith("]]"))
      return true;

    char[] c = in.toCharArray();
    int uppers = 0;
    boolean currentlyUpper = false;
    for(int i=0; i<c.length; i++)
      if(!Character.isLetter(c[i]))
        return false;
      else if(i==0 && !Character.isUpperCase(c[i]))
        return false;
      else
        if(currentlyUpper && Character.isLowerCase(c[i]))
        {
          currentlyUpper = false;
          uppers++;
        }
        else if(!currentlyUpper && Character.isUpperCase(c[i]))
        {
          currentlyUpper = true;
        }
    return uppers>1;
  }

  public void openURL(String url)
  {
    if(url==null || url=="")
      return;
    url = url.trim();

    // Wiki-like links
    if(isWikiWord(url))
    {
      followWikiLink(url, prefs.wikiBehaviourActive);
      return;
    }
//    if(url.length()>4 && url.startsWith("[[") && url.endsWith("]]"))
//    {
//      followWikiLink(url.substring(2, url.length()-2));
//      return;
//    }
    if(isPureWord(url))
    {
      if(prefs.defaultSearchMode == 0)
        webSearchText(url);
      else
        followWikiLink(url, false);
      return;
    }

    // Strip quotes off
    if(url.length()>2 && url.startsWith("\"") && url.endsWith("\""))
      url = url.substring(1, url.length()-1);

    // Treepad node:// links
    if(url.startsWith("node://"))
    {
      if(!followTreepadInternalLink(url))
      JOptionPane.showMessageDialog(this,
              JreepadViewer.lang.getString("MSG_NODE_NOT_FOUND"),
              JreepadViewer.lang.getString("TITLE_NODE_NOT_FOUND"),
              JOptionPane.ERROR_MESSAGE);
      return;
    }

    // It's probably a web-link, so let's do something to it and then try and launch it

/*

//  NOTE:
//  I haven't been able to get this file:// method to work, on Windows 2000 or on Mac OSX.
//  So I'm disactivating it for now.

    // Firstly we use Kami's method for attempting to open file:// links
    if(url.startsWith("file://"))
    {
      url =  getPrefs().openLocation.getParentFile().getPath() + System.getProperty("file.separator")+  url.substring(7);
      try
      {
        BrowserLauncher.openURL(url.toString());
      }
      catch(IOException err)
      {
        JOptionPane.showMessageDialog(this, "I/O error while opening URL:\n"+url+"\n\nThe \"BrowserLauncher\" used to open a URL is an open-source Java library \nseparate from Jreepad itself - i.e. a separate Sourceforge project. \nIt may be a good idea to submit a bug report to\nhttp://sourceforge.net/projects/browserlauncher\n\nIf you do, please remember to supply information about the operating system\nyou are using - which type, and which version.", "Error" , JOptionPane.ERROR_MESSAGE);
      }
    }
    else
    {
*/
    char[] curl = url.toCharArray();
    StringBuffer surl = new StringBuffer();
    for(int i=0; i<curl.length; i++)
      if(curl[i]==' ')
      surl.append("%20");
      else
      surl.append(curl[i]);
        try
        {
          new BrowserLauncher(null).openURLinBrowser(surl.toString());
        }
        catch (BrowserLaunchingInitializingException e)
        {
          displayBrowserLauncherException(e, surl.toString());
        }
        catch (BrowserLaunchingExecutionException e)
        {
          displayBrowserLauncherException(e, surl.toString());
        }
        catch (UnsupportedOperatingSystemException e)
        {
          displayBrowserLauncherException(e, surl.toString());
        }
//    }
  }

  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.", "Error",
      JOptionPane.ERROR_MESSAGE);
  }

  public boolean followTreepadInternalLink(String url)
  {
      url = url.substring(7);
      // Split it at slashes, and then add each one to the new TreePath object as we go
      Vector pathNames = new Vector();
      StringBuffer buf = new StringBuffer();
      char[] curl = url.toCharArray();
      for(int i=0; i<curl.length; i++)
        if(curl[i]=='/')
        {
          pathNames.add(buf.toString());
          buf = new StringBuffer();
        }
        else
          buf.append(curl[i]);
      if(buf.length()>0)
        pathNames.add(buf.toString());

//      System.out.println(pathNames);

      // OK, so we've got the names into an array. Now how do we actually follow the path?
      if(pathNames.size()<1 || !((String)pathNames.get(0)).equals(root.getTitle()))
        return false;
      TreePath goTo = new TreePath(root);
      JreepadNode nextNode = root;
      for(int i=1; i<pathNames.size(); i++)
      {
        nextNode = nextNode.getChildByTitle((String)pathNames.get(i));
        if(nextNode == null)
          return false;
        goTo = goTo.pathByAddingChild(nextNode);
      }
      tree.setSelectionPath(goTo);
    tree.scrollPathToVisible(goTo);
    return true;
  }
  // End of: stuff concerned with linking

  // Searching (for wikilike action)
  public void followWikiLink(String text, boolean noNeedToConfirm)
  {
    if(text.length()>4 && text.startsWith("[[") && text.endsWith("]]"))
      text = text.substring(2, text.length()-2);

    TreePath tp = findNearestNodeTitled(text);
    if(tp == null)
    {
    if(noNeedToConfirm || JOptionPane.showConfirmDialog(this, JreepadViewer.lang.getString("TITLE_NODE_NOT_FOUND_PROMPT_CREATE"), JreepadViewer.lang.getString("MSG_NODE_NOT_FOUND") , JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE)
               == JOptionPane.YES_OPTION)
    {
        JreepadNode newNode;
        TreePath newPath;
      newNode = new JreepadNode(text, "");
      addChild(newNode);
      TreePath leadPath = tree.getLeadSelectionPath();
      if(leadPath != null)
        newPath = leadPath.pathByAddingChild(newNode);
      else
        newPath = new TreePath(newNode);

      // Now we need to select it... how do we do that?
      tree.setSelectionPath(newPath);
      tree.scrollPathToVisible(newPath);
    }
    }
    else
      tree.setSelectionPath(tp);
  }

  public TreePath findNearestNodeTitled(String text)
  {
    TreePath curPath = tree.getLeadSelectionPath();
    TreePath tp;
    while(curPath != null && curPath.getPathCount()>0)
    {
      tp = findChildTitled(text, curPath);
      if(tp!=null)
        return tp;
      // Else try again but using the parent...
      curPath = curPath.getParentPath();
    }
    return null;
  }

  public TreePath findChildTitled(String text)
  {
    return findChildTitled(text, tree.getLeadSelectionPath());
  }

  public TreePath findChildTitled(String text, TreePath pathToNode)
  {
    JreepadNode myNode = (JreepadNode)pathToNode.getLastPathComponent();
    JreepadNode myChild;
    TreePath childPath;
    for(int i=0; i<myNode.getChildCount(); i++)
    {
      myChild = (JreepadNode)myNode.getChildAt(i);
      childPath = pathToNode.pathByAddingChild(myChild);
      if(myChild.getTitle().equals(text))
        return childPath;
      else
      { // Ask the child to search its descendents
        childPath = findChildTitled(text, childPath);
        if(childPath!=null)
          return childPath;
      }
    }
    return null;

  }
  // End of: Searching (for wikilike action)

//  public void setTreeFont(Font f)
//  {
//    ((DefaultTreeCellRenderer)tree.getCellRenderer()).setFont(f);
//  }
//  public void setArticleFont(Font f)
//  {
//    editorPane.setFont(f);
//  }

  public void wrapContentToCharWidth(int charWidth)
  {
    //DEL storeForUndo();
    currentNode.getArticle().wrapContentToCharWidth(charWidth);
    currentArticleView.reloadArticle();
  }

  public void stripAllTags()
  {
    //DEL storeForUndo();
    currentNode.getArticle().stripAllTags();
    currentArticleView.reloadArticle();
  }

  public void setArticleMode(int newMode)
  {
  ArticleView oldView = currentArticleView;
    oldView.lockEdits(); // Disables store-for-undo

    currentNode.getArticle().setArticleMode(newMode);
    ensureCorrectArticleRenderMode();
    currentArticleView.getComponent().repaint();

    oldView.unlockEdits(); // Re-enables store-for-undo
  }

  public void ensureCorrectArticleRenderMode()
  {
    switch(currentNode.getArticle().getArticleMode())
    {
      case JreepadArticle.ARTICLEMODE_ORDINARY:
        currentArticleView = editorPanePlainText;
        break;
      case JreepadArticle.ARTICLEMODE_HTML:
        currentArticleView = editorPaneHtml;
        break;
      case JreepadArticle.ARTICLEMODE_TEXTILEHTML:
        currentArticleView = editorPaneTextile;
        break;
      case JreepadArticle.ARTICLEMODE_CSV:
        currentArticleView = editorPaneCsv;
        break;
      default:
        System.err.println("getEditorPaneComponent() says: JreepadNode.getArticleMode() returned an unrecognised value");
        currentArticleView = null;
    }
    currentArticleView.setArticle(currentNode.getArticle());
    articlePane.setViewportView(currentArticleView.getComponent());
  }

  public void editNodeTitleAction()
  {
    if(getPrefs().viewWhich == JreepadPrefs.VIEW_ARTICLE)
    {
      setViewMode(JreepadPrefs.VIEW_BOTH);
    }
   
    tree.startEditingAtPath(tree.getSelectionPath());
  }

  class JreepadTreeModelListener implements TreeModelListener
  {
    public void treeNodesChanged(TreeModelEvent e)
    {
      treeModel.setContentSaved(false);
      tree.repaint();
    }

    public void treeNodesInserted(TreeModelEvent e)
    {
      treeModel.setContentSaved(false);
      tree.expandPath(e.getTreePath());
      tree.scrollPathToVisible(e.getTreePath());
      tree.repaint();
    }

    public void treeNodesRemoved(TreeModelEvent e)
    {
      treeModel.setContentSaved(false);
      tree.repaint();
    }

    public void treeStructureChanged(TreeModelEvent e)
    {
      treeModel.setContentSaved(false);
      tree.repaint();
    }
  } // End of: class JreepadTreeModelListener
}
TOP

Related Classes of jreepad.JreepadView

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.