PageRenderTime 260ms CodeModel.GetById 164ms app.highlight 84ms RepoModel.GetById 1ms app.codeStats 1ms

/bundles/plugins-trunk/SideKick/sidekick/SideKickTree.java

#
Java | 1484 lines | 1229 code | 129 blank | 126 comment | 221 complexity | c6702f1f2202778b943ec4d559c63f12 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * SideKickTree.java
   3 * :tabSize=8:indentSize=8:noTabs=false:
   4 * :folding=explicit:collapseFolds=1:
   5 *
   6 * Copyright (C) 2000, 2003 Slava Pestov
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License
  10 * as published by the Free Software Foundation; either version 2
  11 * of the License, or any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21*/
  22
  23package sidekick;
  24
  25// {{{ Imports
  26import java.awt.BorderLayout;
  27import java.awt.Dimension;
  28import java.awt.Insets;
  29import java.awt.Rectangle;
  30import java.awt.event.ActionEvent;
  31import java.awt.event.ActionListener;
  32import java.awt.event.KeyAdapter;
  33import java.awt.event.KeyEvent;
  34import java.awt.event.MouseEvent;
  35import java.awt.event.MouseMotionAdapter;
  36import java.util.Arrays;
  37import java.util.Enumeration;
  38import java.util.Stack;
  39import java.util.HashSet;
  40
  41import javax.swing.Box;
  42import javax.swing.DefaultComboBoxModel;
  43import javax.swing.Icon;
  44import javax.swing.JCheckBoxMenuItem;
  45import javax.swing.JComboBox;
  46import javax.swing.JTextArea;
  47import javax.swing.JTextField;
  48import javax.swing.JMenuItem;
  49import javax.swing.JPanel;
  50import javax.swing.JPopupMenu;
  51import javax.swing.JScrollPane;
  52import javax.swing.JSplitPane;
  53import javax.swing.SwingUtilities;
  54import javax.swing.JToolBar;
  55import javax.swing.JTree;
  56import javax.swing.Timer;
  57import javax.swing.JLabel;
  58import javax.swing.event.CaretEvent;
  59import javax.swing.event.CaretListener;
  60import javax.swing.tree.DefaultMutableTreeNode;
  61import javax.swing.tree.DefaultTreeModel;
  62import javax.swing.tree.TreeCellRenderer;
  63import javax.swing.tree.TreeModel;
  64import javax.swing.tree.TreeNode;
  65import javax.swing.tree.TreePath;
  66import javax.swing.tree.TreeSelectionModel;
  67
  68import org.gjt.sp.jedit.Buffer;
  69import org.gjt.sp.jedit.EditBus;
  70import org.gjt.sp.jedit.EditPane;
  71import org.gjt.sp.jedit.GUIUtilities;
  72import org.gjt.sp.jedit.Mode;
  73import org.gjt.sp.jedit.OperatingSystem;
  74import org.gjt.sp.jedit.ServiceManager;
  75import org.gjt.sp.jedit.View;
  76import org.gjt.sp.jedit.jEdit;
  77import org.gjt.sp.jedit.EditBus.EBHandler;
  78import org.gjt.sp.jedit.gui.DefaultFocusComponent;
  79import org.gjt.sp.jedit.gui.RolloverButton;
  80import org.gjt.sp.jedit.msg.EditPaneUpdate;
  81import org.gjt.sp.jedit.msg.PositionChanging;
  82import org.gjt.sp.jedit.msg.PropertiesChanged;
  83import org.gjt.sp.jedit.textarea.JEditTextArea;
  84import org.gjt.sp.jedit.textarea.Selection;
  85import org.gjt.sp.jedit.textarea.TextArea;
  86import org.gjt.sp.util.EnhancedTreeCellRenderer;
  87import org.gjt.sp.util.Log;
  88import org.gjt.sp.util.StandardUtilities;
  89import org.gjt.sp.util.StringList;
  90// }}}
  91
  92/**
  93 * The Structure Browser dockable.  One instance is created for each View.
  94 */
  95public class SideKickTree extends JPanel implements DefaultFocusComponent
  96{
  97
  98        // {{{ Instance variables
  99        private RolloverButton parseBtn;
 100        
 101        private Icon parseIcon;
 102        private Icon stopIcon;
 103
 104        private JComboBox parserCombo;
 105        protected JTree tree;
 106        // protected JEditorPane status;
 107        protected JTextArea status;
 108        private JPanel topPanel;
 109        private JSplitPane splitter;
 110        private boolean statusShowing = false;
 111        private Buffer lastParsedBuffer = null;
 112        private JToolBar filterBox;
 113        protected JPopupMenu configMenu;
 114        protected JCheckBoxMenuItem onChange;
 115        protected JCheckBoxMenuItem followCaret;
 116        protected JCheckBoxMenuItem onSave;
 117
 118        protected View view;
 119        private Timer caretTimer;
 120
 121        protected SideKickParsedData data;
 122
 123        private int autoExpandTree = 0;
 124        private JPanel toolBox;
 125        private JPanel parserPanel = null;
 126
 127        private JTextField searchField;
 128        // }}}
 129
 130        // {{{ SideKickTree constructor
 131        public SideKickTree(View view, boolean docked)
 132        {
 133                super(new BorderLayout());
 134
 135                this.view = view;
 136
 137                topPanel = new JPanel(new BorderLayout());
 138
 139                // create toolbar with parse button
 140                JToolBar buttonBox = new JToolBar();
 141                buttonBox.setFloatable(false);
 142                filterBox = new JToolBar();
 143                filterBox.setLayout(new BorderLayout());
 144                filterBox.setFloatable(false);
 145
 146                parseIcon = GUIUtilities.loadIcon("Parse.png");
 147		stopIcon = GUIUtilities.loadIcon(jEdit.getProperty("hypersearch-results.stop.icon"));                
 148                parseBtn = new RolloverButton(parseIcon);
 149                
 150                parseBtn.setToolTipText(jEdit.getProperty("sidekick-tree.parse"));
 151                parseBtn.setMargin(new Insets(0,0,0,0));
 152                parseBtn.setRequestFocusEnabled(false);
 153                parseBtn.setEnabled(true);
 154                ActionListener ah = new ActionHandler();
 155                parseBtn.addActionListener(ah);
 156                
 157                RolloverButton propsBtn = new RolloverButton(GUIUtilities.loadIcon("ButtonProperties.png"));
 158                propsBtn.setToolTipText(jEdit.getProperty("sidekick-tree.mode-options"));
 159                propsBtn.addActionListener(new SideKickProperties());
 160
 161                configMenu = new JPopupMenu("Parse");
 162                followCaret = new JCheckBoxMenuItem("Follow Caret");
 163
 164                configMenu.add(followCaret);
 165                // configMenu = new PopupMenu("Parse on...");
 166                JMenuItem item = new JMenuItem("Parse on...");
 167                item.setEnabled(false);
 168                configMenu.add(item);
 169
 170                onChange = new JCheckBoxMenuItem("Buffer change");
 171                onChange.setState(SideKick.isParseOnChange());
 172                onSave = new JCheckBoxMenuItem("Buffer save");
 173                onSave.setState(SideKick.isParseOnSave());
 174                configMenu.add(onChange);
 175                configMenu.add(onSave);
 176                parseBtn.setComponentPopupMenu(configMenu);
 177                onChange.addActionListener(ah);
 178                onSave.addActionListener(ah);
 179                followCaret.addActionListener(ah);
 180                JLabel search = new JLabel(jEdit.getProperty("sidekick-tree.filter.label") + " ");
 181                searchField = new JTextField();
 182                searchField.setToolTipText(jEdit.getProperty("sidekick-tree.filter.tooltip"));
 183                RolloverButton clearSearchBtn = new RolloverButton(GUIUtilities.loadIcon("22x22/actions/edit-clear.png"));
 184                clearSearchBtn.addActionListener(new ActionListener()
 185                {
 186                        public void actionPerformed(ActionEvent ae)
 187                        {
 188                                searchField.setText("");
 189                                updateFilter();
 190                        }
 191                }
 192               );
 193                clearSearchBtn.setToolTipText(jEdit.getProperty("sidekick-tree.clear-filter.tooltip"));
 194
 195                buttonBox.add(parseBtn);
 196                buttonBox.add(propsBtn);
 197                filterBox.add(search, BorderLayout.WEST);
 198                filterBox.add(searchField, BorderLayout.CENTER);
 199                filterBox.add(clearSearchBtn, BorderLayout.EAST);
 200
 201                buttonBox.add(Box.createGlue());
 202
 203                parserCombo = new JComboBox();
 204                reloadParserCombo();
 205                parserCombo.setToolTipText(jEdit.getProperty("sidekick-tree.parsercombo.tooltip"));
 206
 207                buttonBox.add(parserCombo);
 208                parserCombo.addActionListener(ah);
 209                parserCombo.addActionListener(new ActionListener()
 210                {
 211                        public void actionPerformed(ActionEvent ae)
 212                        {
 213                                searchField.setText("");
 214                                updateFilter();
 215                        }
 216                }
 217               );
 218
 219                toolBox = new JPanel(new BorderLayout());
 220                toolBox.add(BorderLayout.NORTH, buttonBox);
 221                toolBox.add(BorderLayout.SOUTH, filterBox);
 222
 223                topPanel.add(BorderLayout.NORTH, toolBox);
 224
 225                // create a faux model that will do until a real one arrives
 226                TreeModel emptyModel = new DefaultTreeModel(new DefaultMutableTreeNode(null));
 227                emptyModel = new FilteredTreeModel((DefaultTreeModel) emptyModel, true);
 228                tree = buildTree(emptyModel);
 229                tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
 230                KeyHandler kh = new KeyHandler();
 231                tree.addKeyListener(kh);
 232                if (docked)
 233                {
 234                        tree.addMouseMotionListener(new MouseHandler());
 235                }
 236                searchField.addKeyListener(kh);
 237
 238                // looks bad with the OS X L&F, apparently...
 239                if (!OperatingSystem.isMacOSLF())
 240                {
 241                        tree.putClientProperty("JTree.lineStyle", "Angled");
 242                }
 243
 244                tree.setVisibleRowCount(10);
 245                tree.setCellRenderer(new Renderer());
 246
 247                topPanel.add(BorderLayout.CENTER, new JScrollPane(tree));
 248
 249                status = new JTextArea();
 250                // status.setContentType("text/html");
 251                status.setEditable(false);
 252                status.setBackground(jEdit.getColorProperty("view.bgColor"));
 253                status.setForeground(jEdit.getColorProperty("view.fgColor"));
 254                status.setFont(view.getEditPane().getTextArea().getPainter().getFont());
 255                JScrollPane status_scroller = new JScrollPane(status);
 256
 257                splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, topPanel, status_scroller);
 258
 259                status_scroller.setMinimumSize(new Dimension(0, 30));
 260                splitter.setOneTouchExpandable(true);
 261                splitter.setResizeWeight(1.0f);
 262                int location = splitter.getSize().height - splitter.getInsets().bottom - splitter.getDividerSize() - status_scroller.getMinimumSize().height;
 263                location = jEdit.getIntegerProperty("sidekick.splitter.location", location);
 264
 265                splitter.setDividerLocation(location);
 266
 267                // add(splitter);
 268
 269                propertiesChanged();
 270
 271                CaretHandler caretListener = new CaretHandler();
 272
 273                EditPane[] editPanes = view.getEditPanes();
 274                for (int i = 0; i < editPanes.length; i++)
 275                {
 276                        JEditTextArea textArea = editPanes[i].getTextArea();
 277                        textArea.putClientProperty(CaretHandler.class, caretListener);
 278                        textArea.addCaretListener(caretListener);
 279                }
 280
 281                update();
 282        }        // }}}
 283
 284        public void showStopButton(final boolean show)
 285        {
 286                SwingUtilities.invokeLater (new Runnable()
 287                {
 288                        public void run()
 289                        {
 290                        	if (show && parseIcon.equals(parseBtn.getIcon()))
 291                        	{
 292                        		parseBtn.setToolTipText(jEdit.getProperty("sidekick-tree.stop-parsing"));
 293                        		parseBtn.setIcon(stopIcon);
 294                        		
 295                        	}
 296                        	else 
 297                        	{
 298                        		parseBtn.setToolTipText(jEdit.getProperty("sidekick-tree.parse"));
 299                        		parseBtn.setIcon(parseIcon);
 300                        	}
 301                        }
 302                }
 303               );
 304        }
 305
 306        // {{{ focusOnDefaultComponent() method
 307        public void focusOnDefaultComponent()
 308        {
 309                tree.requestFocusInWindow();
 310        }        // }}}
 311
 312        // {{{ addNotify() method
 313        public void addNotify()
 314        {
 315                super.addNotify();
 316                EditBus.addToBus(this);
 317        }        // }}}
 318
 319        // {{{ removeNotify() method
 320        public void removeNotify()
 321        {
 322                super.removeNotify();
 323                EditBus.removeFromBus(this);
 324        }        // }}}
 325
 326        // {{{ selectPath() method
 327        protected void selectPath(TreePath path)
 328        {
 329                tree.setSelectionPath(path);
 330                Rectangle r = tree.getPathBounds(path);
 331                if (r != null)
 332                {
 333                        r.width = 1;
 334                        tree.scrollRectToVisible(r);
 335                }
 336        }        // }}}
 337
 338        // {{{ handleEditPaneUpdate() method
 339        @EBHandler
 340        public void handleEditPaneUpdate(EditPaneUpdate epu)
 341        {
 342                EditPane editPane = epu.getEditPane();
 343                if (epu.getWhat() == EditPaneUpdate.CREATED)
 344                {
 345					CaretHandler listener = new CaretHandler();
 346					JEditTextArea textArea = editPane.getTextArea();
 347					textArea.putClientProperty(CaretHandler.class, listener);
 348					textArea.addCaretListener(listener);
 349                }
 350        }        // }}}
 351
 352        // {{{ handlePropertiesChanged method
 353        @EBHandler
 354        public void handlePropertiesChanged(PropertiesChanged msg)
 355        {
 356                propertiesChanged();
 357        }        // }}}
 358
 359        // {{{ handleSideKickUpdate() method
 360        @EBHandler
 361        public void handleSideKickUpdate(SideKickUpdate msg)
 362        {
 363                if (msg.getView() == view)
 364                {
 365                        update();
 366                }
 367        }        // }}}
 368
 369        // {{{ setStatus() method
 370        public void setStatus(String msg)
 371        {
 372                status.setText(msg);
 373        }        // }}}
 374
 375        // {{{ addData method
 376        protected void addData(Object obj, Stack<String> keys)
 377        {
 378                if (obj instanceof DefaultMutableTreeNode)
 379                {
 380                        DefaultMutableTreeNode node = (DefaultMutableTreeNode) obj;
 381                        String cur_key = "";
 382                        FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
 383                        try
 384                        {
 385                                Asset a = (Asset) node.getUserObject();
 386                                if (a != null)
 387                                {
 388                                        cur_key = a.getName();
 389                                }
 390                        }
 391                        catch (ClassCastException ex)
 392                        {
 393                                if (node.toString() != null)
 394                                {
 395                                        cur_key = node.toString();
 396                                }
 397                        }
 398                        keys.push(cur_key);
 399                        if (model.isLeaf(node))
 400                        {
 401                                for (String key : keys)
 402                                {
 403                                        model.addSearchKey(node, key);
 404                                }
 405                        }
 406
 407                        Enumeration<DefaultMutableTreeNode> e;
 408                        for (e = node.children(); e.hasMoreElements();)
 409                        {
 410                                addData(e.nextElement(), keys);
 411                        }
 412
 413                        keys.pop();
 414                }
 415                else
 416                {
 417                        Log.log(Log.DEBUG, this, "addData called on a node that isn't a treenode!!!!!!!!!");                        // how exciting!
 418                }
 419        }        // }}}
 420
 421        // {{{ updateSearchData() method
 422        protected void updateSearchData()
 423        {
 424                DefaultMutableTreeNode root;
 425                FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
 426                root = (DefaultMutableTreeNode) model.getRoot();
 427                addData(root, new Stack<String>());
 428        }        // }}}
 429
 430        // {{{ update() method
 431        protected void update()
 432        {
 433                onChange.setState(SideKick.isParseOnChange());
 434                onSave.setState(SideKick.isParseOnSave());
 435                Buffer parsedBuffer = view.getBuffer();
 436                SideKickParser parser = SideKickPlugin.getParserForBuffer(parsedBuffer);
 437                if (parser != null)
 438                {
 439                        Object item = parserCombo.getSelectedItem();
 440                        if (item != parser.getName())
 441                        {
 442                                parserCombo.setSelectedItem(parser.getName());
 443                        }
 444                }
 445
 446                data = SideKickParsedData.getParsedData(view);
 447                if (parser == null || data == null)
 448                {
 449                        DefaultMutableTreeNode root = new DefaultMutableTreeNode(parsedBuffer.getName());
 450                        root.insert(new DefaultMutableTreeNode(jEdit.getProperty("sidekick-tree.not-parsed")),0);
 451                        tree.setModel(new FilteredTreeModel(new DefaultTreeModel(root), true));
 452                        lastParsedBuffer = null;
 453                }
 454                else
 455                {
 456                        tree.setModel(new FilteredTreeModel(data.tree, true));
 457                        lastParsedBuffer = parsedBuffer;
 458                        if (SideKick.isFollowCaret())
 459                        {
 460                                expandTreeAt(view.getTextArea().getCaretPosition());
 461                        }
 462                }
 463                updateSearchData();
 464
 465                if (data != null && data.expansionModel != null)
 466                {
 467                        // collapse all rows, then expand per the expansion model
 468                        for (int i = tree.getRowCount() - 1; i >= 0; i--)
 469                        {
 470                                tree.collapseRow(i);
 471                        }
 472                        for (Integer row : data.expansionModel)
 473                        {
 474                                tree.expandRow(row);
 475                        }
 476                }
 477                else
 478                {
 479                        if (autoExpandTree == -1)
 480                        {
 481                                expandAll(true);
 482                        }
 483                        else if (autoExpandTree == 0)
 484                        {
 485                                expandAll(false);
 486                        }
 487                        else if (autoExpandTree > 0)
 488                        {
 489                                tree.expandRow(0);
 490                                for (int i = 1; i < autoExpandTree; i++)
 491                                {
 492                                        for (int j = tree.getRowCount() - 1; j > 0; j--)
 493                                        {
 494                                                tree.expandRow(j);
 495                                        }
 496
 497                                }
 498                        }
 499                }
 500
 501                if (searchField.getText().length() != 0)
 502                {
 503                        updateFilter();
 504                }
 505
 506        }        // }}}
 507
 508        // {{{ expandAll() methods
 509        /**
 510         * Expand or collapse all nodes in the tree.
 511         * @param expand if true, expand all nodes, if false, collapse all nodes
 512         */
 513        public void expandAll(boolean expand)
 514        {
 515                TreeNode root = (TreeNode) tree.getModel().getRoot();
 516                expandAll(new TreePath(root), expand);
 517        }
 518
 519        // recursive method to traverse children
 520        private void expandAll(final TreePath parent, final boolean expand)
 521        {
 522                SwingUtilities.invokeLater(new Runnable()
 523                {
 524                        public void run()
 525                        {
 526                                TreeNode node = (TreeNode) parent.getLastPathComponent();
 527                                if (node.getChildCount() >= 0)
 528                                {
 529                                        for (Enumeration e = node.children(); e.hasMoreElements();)
 530                                        {
 531                                                TreeNode n = (TreeNode) e.nextElement();
 532                                                TreePath path = parent.pathByAddingChild(n);
 533                                                expandAll(path, expand);
 534                                        }
 535                                }
 536
 537                                // expansion or collapse must be done from the bottom up
 538                                if (expand)
 539                                {
 540                                        tree.expandPath(parent);
 541                                }
 542                                else
 543                                {
 544                                        tree.collapsePath(parent);
 545                                }
 546                        }
 547                } );
 548        }        // }}}
 549
 550        // {{{ buildTree() method
 551        protected JTree buildTree(TreeModel model)
 552        {
 553                return new CustomTree(model);
 554        }        // }}}
 555
 556        // {{{ buildActionListener() method
 557        /**
 558         * Creates an action listener for the parse button.
 559         */
 560        protected ActionListener buildActionListener()
 561        {
 562                return new ActionHandler();
 563        }        // }}}
 564
 565        // {{{ propertiesChanged() method
 566        protected void propertiesChanged()
 567        {
 568                followCaret.setSelected(SideKick.isFollowCaret());
 569                Mode m = view.getBuffer().getMode();
 570                String mode = m != null ? m.getName() : null;
 571                autoExpandTree = AbstractModeOptionPane.getIntegerProperty(mode, SideKick.AUTO_EXPAND_DEPTH, 1);
 572                // autoExpandTree = ModeOptions.getAutoExpandTreeDepth();
 573
 574                if (AbstractModeOptionPane.getBooleanProperty(mode, SideKick.SHOW_STATUS))
 575                {
 576                        if (!statusShowing)
 577                        {
 578                                remove(topPanel);
 579                                splitter.setTopComponent(topPanel);
 580                                add(splitter);
 581                        }
 582                        statusShowing = true;
 583                }
 584                else
 585                {
 586                        remove(splitter);
 587                        splitter.remove(topPanel);
 588                        add(topPanel);
 589                        statusShowing = false;
 590                }
 591
 592                // show or hide the filter box
 593                final boolean showFilter = jEdit.getBooleanProperty(SideKick.SHOW_FILTER, true);
 594                if (showFilter != filterBox.isVisible())
 595                {
 596                        SwingUtilities.invokeLater(new Runnable()
 597                        {
 598                                public void run()
 599                                {
 600                                        filterBox.setVisible(showFilter);
 601                                        searchField.setEnabled(showFilter);
 602                                }
 603                        } );
 604                }
 605        }        // }}}
 606
 607        // {{{ parserList() method
 608        /** @return a list of parsers, sorted, with special choices
 609         * on top */
 610        public static StringList parserList()
 611        {
 612                String[] serviceNames = ServiceManager.getServiceNames(SideKickParser.SERVICE);
 613                Arrays.sort(serviceNames, new StandardUtilities.StringCompare<String>(true));
 614                StringList sl = new StringList();
 615                sl.add(SideKickPlugin.NONE);
 616                sl.add(SideKickPlugin.DEFAULT);
 617                sl.addAll(serviceNames);
 618                return sl;
 619        }        // }}}
 620
 621        // {{{ reloadParserCombo() method
 622        void reloadParserCombo()
 623        {
 624                parserCombo.setModel(new DefaultComboBoxModel(parserList().toArray()));
 625                SideKickParser currentParser = SideKickPlugin.getParserForBuffer(view.getBuffer());
 626                if (currentParser != null)
 627                {
 628                        String name = currentParser.getName();
 629                        if (name == null)
 630                        {
 631                        	name = SideKickPlugin.DEFAULT;	
 632                        }
 633                        parserCombo.setSelectedItem(name);
 634                }
 635                else
 636                {
 637                        String pp = view.getBuffer().getStringProperty(SideKickPlugin.PARSER_PROPERTY);
 638                        if (pp == SideKickPlugin.NONE)
 639                        {
 640                                parserCombo.setSelectedItem(SideKickPlugin.NONE);
 641                        }
 642                        else
 643                        {
 644                                parserCombo.setSelectedItem(SideKickPlugin.DEFAULT);
 645                        }
 646                }
 647        }        // }}}
 648
 649        // {{{ addParserPanel() method
 650        void addParserPanel(SideKickParser parser)
 651        {
 652                JPanel newParserPanel = parser.getPanel();
 653                boolean returnFocusToSearchField = searchField.hasFocus();
 654                if (newParserPanel != parserPanel)
 655                {
 656                        if (parserPanel != null)
 657                        {
 658                                toolBox.remove(parserPanel);
 659                                parserPanel = null;
 660                        }
 661                        if (newParserPanel != null)
 662                        {
 663                                toolBox.add(BorderLayout.WEST, newParserPanel);
 664                                parserPanel = newParserPanel;
 665                        }
 666                }
 667                if (returnFocusToSearchField)
 668                {
 669                        focusOnDefaultComponent();
 670                }
 671        }        // }}}
 672
 673        // {{{ removeParserPanel() method
 674        void removeParserPanel()
 675        {
 676                if (parserPanel != null)
 677                {
 678                        toolBox.remove(parserPanel);
 679                        parserPanel = null;
 680                }
 681        }        // }}}
 682
 683        // {{{ expandTreeWithDelay() method
 684        /**
 685         * Expands the tree after a delay.
 686         * The delay timer is restarted each time this method is called.
 687         */
 688        protected void expandTreeWithDelay()
 689        {
 690                if (caretTimer != null)
 691                {
 692                        caretTimer.stop();
 693                }
 694                else
 695                {
 696                        caretTimer = new Timer(0, new ActionListener()
 697                        {
 698                                public void actionPerformed(ActionEvent evt)
 699                                {
 700                                        // If the filter is *not* persistent, then clear
 701                                        // it when the tree is expanded for the current
 702                                        // caret position.
 703                                        if (!jEdit.getBooleanProperty("sidekick.persistentFilter"))
 704                                        {
 705                                                if (searchField.getText().length() > 0)		// NOPMD
 706                                                {
 707                                                        searchField.setText("");
 708                                                        updateFilter(false);
 709                                                }
 710                                        }
 711                                        TextArea textArea = view.getTextArea();
 712                                        int caret = textArea.getCaretPosition();
 713                                        Selection s = textArea.getSelectionAtOffset(caret);
 714                                        expandTreeAt(s == null ? caret : s.getStart());
 715                                }
 716                        } );
 717                        caretTimer.setInitialDelay(500);
 718                        caretTimer.setRepeats(false);
 719                }
 720                caretTimer.start();
 721        }        // }}}
 722
 723        // {{{ expandTreeAt() method
 724        protected void expandTreeAt(int dot)
 725        {
 726                if (data == null)
 727                {
 728                        return;
 729                }
 730
 731                TreePath treePath = data.getTreePathForPosition(dot);
 732                if (treePath != null)
 733                {
 734                        tree.expandPath(treePath);
 735                        tree.setSelectionPath(treePath);
 736                        if (jEdit.getBooleanProperty("sidekick.scrollToVisible"))
 737                        {
 738                                Rectangle r = tree.getPathBounds(treePath);
 739                                if (r != null)
 740                                {
 741                                        r.width = 1;
 742                                        tree.scrollRectToVisible(r);
 743                                }
 744                                else
 745                                {
 746                                        tree.scrollPathToVisible(treePath);
 747                                }
 748                        }
 749                }
 750        }        // }}}
 751
 752        protected void expandCurrentNode()
 753        {
 754                DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
 755                TreePath path = new TreePath(node.getPath());
 756                tree.expandPath(path);
 757        }
 758
 759        protected void collapseCurrentNode()
 760        {
 761                DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
 762                TreePath path = new TreePath(node.getPath());
 763                tree.collapsePath(path);
 764        }
 765
 766        // {{{ Inner classes
 767
 768        // {{{ CustomTree class
 769        /**
 770         * A JTree with added mouse handling.  Other plugins providing similar trees
 771         * can extend CustomTree and override the mouse methods.
 772         */
 773        protected class CustomTree extends JTree
 774        {
 775                protected CustomTree(TreeModel model)
 776                {
 777                        super(model);
 778                }
 779                
 780		public Enumeration<TreePath> getExpandedDescendants(TreePath parent) 
 781		{
 782			return null;
 783		}
 784		
 785                protected void processMouseEvent(MouseEvent evt)
 786                {
 787                        switch (evt.getID() )
 788                        {
 789                                // {{{ MOUSE_PRESSED...
 790                                case MouseEvent.MOUSE_PRESSED:
 791                                        TreePath path = getPathForLocation(evt.getX(), evt.getY());
 792                                        if (path != null)
 793                                        {
 794                                                Object value = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
 795
 796                                                if (value instanceof IAsset)
 797                                                {
 798                                                        IAsset asset = (IAsset) value;
 799
 800                                                        JEditTextArea textArea = view.getTextArea();
 801                                                        EditPane editPane = view.getEditPane();
 802
 803                                                        if (evt.getClickCount() == 2)
 804                                                        {
 805                                                                doubleClicked(view, asset, path);
 806                                                        }
 807                                                        else if (evt.isShiftDown())
 808                                                        {
 809                                                                shiftClick(view, asset, path);
 810                                                        }
 811                                                        else if (evt.isControlDown())
 812                                                        {
 813                                                                controlClick(view, asset, path);
 814                                                        }
 815                                                        else
 816                                                        {
 817                                                                EditBus.send(new PositionChanging(editPane));
 818                                                                textArea.setCaretPosition(asset.getStart().getOffset());
 819                                                        }
 820
 821                                                }
 822                                                if (!jEdit.getBooleanProperty("sidekick.persistentFilter"))
 823                                                {
 824                                                        if (searchField.getText().length() > 0)		// NOPMD
 825                                                        {
 826                                                                searchField.setText("");
 827                                                                updateFilter(false);
 828                                                        }
 829                                                }
 830                                        }
 831                                        super.processMouseEvent(evt);
 832                                        searchField.requestFocusInWindow();
 833                                        if (path != null)
 834                                        {
 835                                                selectPath(path);
 836                                        }
 837                                        break;                                        // }}}
 838                                        // {{{ MOUSE_EXITED...
 839                                case MouseEvent.MOUSE_EXITED:
 840                                        view.getStatus().setMessage(null);
 841                                        super.processMouseEvent(evt);
 842                                        break;                                        // }}}
 843                                default:
 844                                        super.processMouseEvent(evt);
 845                                        break;
 846                        }
 847                }
 848
 849                protected void doubleClicked(View view, IAsset asset, TreePath path)
 850                {
 851                }
 852
 853                protected void shiftClick(View view, IAsset asset, TreePath path)
 854                {
 855                        JEditTextArea textArea = view.getTextArea();
 856                        textArea.setCaretPosition(asset.getEnd().getOffset());
 857                        Selection.Range range = new Selection.Range(asset.getStart().getOffset(), asset.getEnd().getOffset());
 858                        textArea.addToSelection(range);
 859                }
 860
 861                protected void controlClick(View view, IAsset asset, TreePath path)
 862                {
 863                        JEditTextArea textArea = view.getTextArea();
 864                        textArea.getDisplayManager().narrow(textArea.getLineOfOffset(asset.getStart().getOffset()), textArea.getLineOfOffset(asset.getEnd().getOffset()));
 865                }
 866        }        // }}}
 867
 868        // {{{ ActionHandler class
 869        class ActionHandler implements ActionListener
 870        {
 871                /** A counter for counting how deep in recursion we are.
 872                 *  Since a call to reloadParserCombo can cause itemselected events
 873                 *  from the parserCombo,
 874                 */
 875                int level =0;
 876                public void actionPerformed(ActionEvent evt)
 877                {
 878
 879                        // Workaround to avoid infinite recursion as a result of parsercombos
 880                        // updating
 881                        synchronized (this)
 882                        {
 883                                if (evt.getSource() == parseBtn)
 884                                {
 885                                        level = 0;
 886                                }
 887                                level++;
 888                                if (level > 1)
 889                                {
 890                                        level--;
 891                                        return;
 892                                }
 893                        }
 894                        Buffer b = view.getBuffer();
 895                        jEdit.setIntegerProperty("sidekick.splitter.location", splitter.getDividerLocation());
 896                        if (evt.getSource() == onSave)
 897                        {
 898                                SideKick.setParseOnSave(onSave.isSelected());
 899                                propertiesChanged();
 900                        }
 901                        if (evt.getSource() == followCaret)
 902                        {
 903                                boolean v = followCaret.isSelected();
 904                                SideKick.setGlobalFollowCaret(followCaret.isSelected());
 905                                if (v)
 906                                {
 907                                        onChange.setSelected(true);
 908                                }
 909                                propertiesChanged();
 910                        }
 911                        else if (evt.getSource() == onChange)
 912                        {
 913                                boolean v = onChange.isSelected();
 914                                SideKick.setParseOnChange(v);
 915                                if (!v)
 916                                {
 917                                        followCaret.setSelected(false);
 918                                }
 919                                propertiesChanged();
 920                        }
 921                        else if (evt.getSource() == parserCombo)
 922                        {
 923                                Object selectedParser = parserCombo.getSelectedItem();
 924                                // String preferredParser = b.getStringProperty(SideKickPlugin.PARSER_PROPERTY);
 925                                if (selectedParser.toString().equals(SideKickPlugin.NONE))
 926                                {
 927                                        b.setProperty("usermode", Boolean.TRUE);
 928                                        SideKickPlugin.setParserForBuffer(b, selectedParser.toString());
 929                                }
 930                                else if (selectedParser.toString().equals(SideKickPlugin.DEFAULT))
 931                                {
 932                                        b = view.getBuffer();
 933                                        b.setProperty("usermode", Boolean.FALSE);
 934                                        Mode m = b.getMode();
 935                                        if (m == null)
 936                                        {
 937                                                Log.log(Log.ERROR, this, "SideKick: can't determine mode of current buffer:" + b);
 938                                        }
 939                                        else
 940                                        {
 941                                                SideKickParser newParser = SideKickPlugin.getParserForMode(m);
 942                                                if (newParser == null)
 943                                                {
 944                                                        SideKickPlugin.setParserForBuffer(b, SideKickPlugin.NONE);
 945                                                }
 946                                                else
 947                                                {
 948                                                        SideKickPlugin.setParserForBuffer(b, newParser.getName());
 949                                                }
 950                                        }
 951                                }
 952                                else
 953                                {
 954                                        SideKickPlugin.setParserForBuffer(b, selectedParser.toString());
 955                                        b.setProperty("usermode", Boolean.TRUE);
 956                                }
 957                                propertiesChanged();
 958
 959                        }
 960                        else if (evt.getSource() == parseBtn && stopIcon.equals(parseBtn.getIcon()))
 961                        {
 962                                SideKickPlugin.stop(view);
 963                                SwingUtilities.invokeLater(new Runnable()
 964				{
 965					public void run()
 966					{
 967						parseBtn.setIcon(parseIcon);
 968						parseBtn.setToolTipText(jEdit.getProperty("sidekick-tree.parse"));
 969					}
 970				});
 971                        }
 972                        if (evt.getSource() == parseBtn || evt.getSource() == parserCombo)
 973                        {
 974                        	if (evt.getSource() == parseBtn) 
 975                        	{
 976                        		SwingUtilities.invokeLater(new Runnable()
 977						{
 978							public void run()
 979							{
 980								parseBtn.setIcon(stopIcon);
 981								parseBtn.setToolTipText(jEdit.getProperty("sidekick-tree.stop-parsing"));
 982
 983							}
 984						});	
 985                        	}
 986                                level = 0;
 987                                Object usermode = b.getProperty("usermode");
 988                                if (usermode == null || usermode == Boolean.FALSE)
 989                                {
 990                                        SideKickParser sp = SideKickPlugin.getParserForBuffer(b);
 991                                        if (sp == null)
 992                                        {
 993                                                return;
 994                                        }
 995                                        else
 996                                        {
 997                                                reloadParserCombo();
 998                                        }
 999                                }
1000                                SideKickPlugin.parse(view, true);
1001                        }
1002                        level--;
1003                }
1004        }        // }}}
1005
1006        // {{{ CaretHandler class
1007        class CaretHandler implements CaretListener
1008        {
1009                public void caretUpdate(CaretEvent evt)
1010                {
1011                        if (!view.getBuffer().equals(lastParsedBuffer))
1012                        {
1013                                return;
1014                        }
1015                        if (evt.getSource() == view.getTextArea() && SideKick.isFollowCaret())
1016                        {
1017                                expandTreeWithDelay();
1018                        }
1019                }
1020        }        // }}}
1021
1022        protected void find_visible_nodes(HashSet<TreePath> set, DefaultMutableTreeNode node)
1023        {
1024                TreePath path = new TreePath(node.getPath());
1025                if (tree.isVisible(path) && tree.isExpanded(path))
1026                {
1027                        set.add(new TreePath(node.getPath()));
1028                        for (Enumeration e = node.children(); e.hasMoreElements();)
1029                        {
1030                                find_visible_nodes(set, (DefaultMutableTreeNode) e.nextElement());
1031                        }
1032
1033                }
1034        }
1035
1036        protected void filter_visible_nodes(FilteredTreeModel model, HashSet<TreePath> visible, DefaultMutableTreeNode node)
1037        {
1038                if (!jEdit.getBooleanProperty(SideKick.SHOW_FILTER))
1039                {
1040                        return;
1041                }
1042
1043                TreePath path = new TreePath(node.getPath());
1044                if (!visible.contains(path))
1045                {
1046                        return;
1047                }
1048
1049                tree.expandPath(path);
1050                for (Enumeration e = node.children(); e.hasMoreElements();)
1051                {
1052                        filter_visible_nodes(model, visible, (DefaultMutableTreeNode) e.nextElement());
1053                }
1054        }
1055
1056        public void updateFilter(boolean with_delay)
1057        {
1058                if (!jEdit.getBooleanProperty(SideKick.SHOW_FILTER))
1059                {
1060                        return;
1061                }
1062
1063                FilteredTreeModel ftm = (FilteredTreeModel) tree.getModel();
1064
1065                if (searchField.getText().length() == 0)
1066                {
1067                        ftm.clearFilter();
1068                        ftm.reset();
1069                        if (autoExpandTree == -1)
1070                        {
1071                                expandAll(true);
1072                        }
1073                        else if (autoExpandTree == 0)
1074                        {
1075                                expandAll(false);
1076                        }
1077                        else if (autoExpandTree > 0)
1078                        {
1079                                tree.expandRow(0);
1080                                for (int i = 1; i < autoExpandTree; i++)
1081                                {
1082                                        for (int j = tree.getRowCount() - 1; j > 0; j--)
1083                                        {
1084                                                tree.expandRow(j);
1085                                        }
1086
1087                                }
1088                        }
1089
1090                        if (SideKick.isFollowCaret() && with_delay)
1091                        {
1092                                expandTreeWithDelay();
1093                        }
1094                }
1095                else
1096                {
1097                        HashSet<TreePath> visible = new HashSet<TreePath>();
1098                        find_visible_nodes(visible, (DefaultMutableTreeNode) ftm.getRoot());
1099                        ftm.filterByText(searchField.getText());
1100                        DefaultMutableTreeNode root = (DefaultMutableTreeNode) ftm.getRoot();
1101                        if (jEdit.getBooleanProperty(SideKick.FILTER_VISIBLE))
1102                        {
1103                                filter_visible_nodes(ftm, visible, root);
1104                        }
1105                        else
1106                        {
1107                                expandAll(true);
1108                        }
1109                }
1110        }
1111
1112        public void updateFilter()
1113        {
1114                updateFilter(true);
1115        }
1116
1117        public void setSearchFilter(String text)
1118        {
1119                searchField.setText(text);
1120                updateFilter();
1121        }
1122        public String getSearchFilter()
1123        {
1124                return searchField.getText();
1125        }
1126
1127        // {{{ KeyHandler class
1128        class KeyHandler extends KeyAdapter
1129        {
1130
1131                protected void next()
1132                {
1133                        DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
1134                        FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
1135                        if (node == null)
1136                        {
1137                                node = (DefaultMutableTreeNode) model.getRoot();
1138                        }
1139
1140                        // standard tree movement for next:
1141                        // If selected node has children and selected node is expanded,
1142                        // then next is the first child of the selected node, otherwise,
1143                        // next is the next sibling.
1144                        // If selected node is a leaf, then next is next sibling.
1145                        // If next sibling is null, that means selected node is the
1146                        // last child of the parent node, so next is parent.nextSibling
1147                        if (node.getChildCount() > 0)
1148                        {
1149                                DefaultMutableTreeNode firstChild = (DefaultMutableTreeNode) node.getFirstChild();
1150                                TreePath path = new TreePath(firstChild.getPath());
1151                                if (tree.isVisible(path))
1152                                {
1153                                        node = firstChild;
1154                                }
1155                                else
1156                                {
1157                                        node = (DefaultMutableTreeNode) node.getNextSibling();
1158                                }
1159                        }
1160                        else
1161                        {
1162                                // node is a leaf
1163                                DefaultMutableTreeNode next = (DefaultMutableTreeNode) node.getNextSibling();
1164                                if (next == null)
1165                                {
1166                                        // must be last child of parent
1167                                        next = (DefaultMutableTreeNode) ((DefaultMutableTreeNode) node.getParent()).getNextSibling();
1168                                }
1169                                node = next;
1170                        }
1171
1172                        if (node != null)
1173                        {
1174                                TreePath p = new TreePath(node.getPath());
1175                                selectPath(p);
1176                        }
1177                }
1178
1179                protected void nextLeaf()
1180                {
1181                        DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
1182                        FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
1183                        if (node == null)
1184                        {
1185                                node = (DefaultMutableTreeNode) model.getRoot();
1186                        

Large files files are truncated, but you can click here to view the full file