    001    /*
    002    * SourceTree.java
    003    * :folding=explicit:collapseFolds=1:
    004    *
    005    * Copyright (C) 2005 by Martin Raspe
    006    * (hertzhaft@biblhertz.it)
    007    *
    008    * This program is free software; you can redistribute it and/or
    009    * modify it under the terms of the GNU General Public License
    010    * as published by the Free Software Foundation; either version 2
    011    * of the License, or any later version.
    012    *
    013    * This program is distributed in the hope that it will be useful,
    014    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    015    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    016    * GNU General Public License for more details.
    017    *
    018    * You should have received a copy of the GNU General Public License
    019    * along with this program; if not, write to the Free Software
    020    * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    021    */
    022    package sidekick.enhanced;
    023
    024    //{{{ Imports
    025    import java.awt.Color;
    026    import java.awt.Component;
    027    import java.awt.FontMetrics;
    028    import java.awt.Graphics;
    029    import java.awt.event.KeyAdapter;
    030    import java.awt.event.KeyEvent;
    031    import java.awt.event.MouseAdapter;
    032    import java.awt.event.MouseEvent;
    033    import java.awt.event.MouseMotionListener;
    034    import java.util.HashMap;
    035
    036    import javax.swing.JLabel;
    037    import javax.swing.JPopupMenu;
    038    import javax.swing.JTree;
    039    import javax.swing.ToolTipManager;
    040    import javax.swing.tree.DefaultMutableTreeNode;
    041    import javax.swing.tree.DefaultTreeCellRenderer;
    042    import javax.swing.tree.TreePath;
    043
    044    import org.gjt.sp.jedit.EBMessage;
    045    import org.gjt.sp.jedit.GUIUtilities;
    046    import org.gjt.sp.jedit.Mode;
    047    import org.gjt.sp.jedit.View;
    048    import org.gjt.sp.jedit.jEdit;
    049    import org.gjt.sp.jedit.gui.DockableWindowFactory;
    050    import org.gjt.sp.jedit.gui.KeyEventTranslator;
    051    import org.gjt.sp.jedit.msg.BufferUpdate;
    052
    053    import sidekick.Asset;
    054    import sidekick.IAsset;
    055    import sidekick.SideKickTree;
    056
    057    //}}}
    058
    059    /**
    060     * @author     Martin Raspe
    061     * @created    Oct 15, 2005
    062     * @modified   $Id: SourceTree.java,v 1.9 2006/06/13 21:46:53 daleanson Exp $
    063     * @version    $Revision: 1.9 $
    064
    065     * The Structure Browser dockable. Extends the SideKick structure browser,
    066     * adding a popup menu for marker setting and enhanced keyboard handling
    067     * It replaces the SideKickTree dockable if desired.
    068     */
    069    public class SourceTree extends SideKickTree {
    070
    071        //{{{ private vars
    072        private static boolean _hasMarker;
    073        private static boolean _showMarkers = true;
    074        private static Color _markerColor = jEdit.getColorProperty( "view.gutter.markerColor" );
    075
    076        private Asset _asset;
    077
    078        private HashMap _actionShortcuts = new HashMap();
    079        //}}}
    080
    081        public JPopupMenu popup;
    082
    083        public SourceTree( View view, boolean docked ) {
    084            //{{{ SourceTree constructor
    085            super( view, docked );
    086            tree.setCellRenderer( new Renderer() );
    087            if (jEdit.getBooleanProperty("options.sidekick.showToolTips"))
    088                ToolTipManager.sharedInstance().registerComponent( tree );
    089            tree.addKeyListener( new KeyHandler() );
    090            MouseHandler mh = new MouseHandler();
    091            tree.addMouseListener( mh );
    092            if ( docked )
    093                tree.addMouseMotionListener( mh );
    094            update();
    095        } //}}}
    096
    097        protected void createPopup() {
    098            //{{{ create the tree Popup menu from the "sidekick-tree.{mode}.menu" property
    099            // if not present, use the default menu (see above)
    100                    Mode mode = view.getBuffer().getMode();
    101            String modename = (mode == null)
    102                ? ""
    103                : "." + mode.getName();
    104            String menu = "sidekick-tree" + modename + ".menu";
    105            if (jEdit.getProperty(menu) == null)
    106                menu = "sidekick-tree.menu";
    107            popup = GUIUtilities.loadPopupMenu(menu);
    108            } //}}}
    109
    110        protected void update() {
    111            //{{{ create a new popup menu if mode changes
    112            super.update();
    113            createPopup();
    114            } //}}}
    115
    116        private boolean hasMarker( int start, int end ) {
    117            //{{{ getMarker method
    118            return ( view.getBuffer().getMarkerInRange( start, end ) != null );
    119        } //}}}
    120
    121        public static void toggleMarkersFlag() {
    122            //{{{ method toggleMarkersFlag
    123            _showMarkers = ! _showMarkers;
    124        } //}}}
    125
    126        public static boolean isRegisteredDockable( String name ) {
    127            //{{{ method isRegisteredDockable
    128            // see if the dockable "name" is registered
    129            String[] dockables = DockableWindowFactory.getInstance()
    130                    .getRegisteredDockableWindows();
    131            boolean _found = false;
    132            for ( int i = 0; i < dockables.length; i++ ) {
    133                if ( dockables[ i ].equals( name ) ) {
    134                    _found = true;
    135                    break;
    136                }
    137            }
    138            return _found;
    139        } //}}}
    140
    141        public static boolean isMarkersFlagSet() {
    142            //{{{ method isMarkersFlagSet
    143            // should marked routines be shown in structure tree?
    144            return _showMarkers;
    145        } //}}}
    146
    147        public void handleMessage( EBMessage msg ) {
    148            //{{{ handleMessage() method
    149            // react to marker changes immediately
    150            super.handleMessage( msg );
    151            if ( msg instanceof BufferUpdate ) {
    152                BufferUpdate upd = ( BufferUpdate ) msg;
    153                if ( upd.getWhat() == BufferUpdate.MARKERS_CHANGED )
    154                    update();
    155            }
    156        } //}}}
    157
    158        public void handleKey( KeyEvent evt ) {
    159            //{{{ handleKey() method
    160            int _code = evt.getKeyCode();
    161            KeyEventTranslator.Key _key = KeyEventTranslator.translateKeyEvent( evt );
    162            // let the view handle marker actions
    163            // is there an easier way to assign a jEdit shortcut to a tree?
    164            if ( _actionShortcuts.containsKey( _key ) )
    165                view.getInputHandler().handleKey( _key );
    166            else if ( _code == KeyEvent.VK_ESCAPE || _code == KeyEvent.VK_CANCEL )
    167                view.getTextArea().requestFocus();
    168        } //}}}
    169
    170        public void handleMouse( MouseEvent evt ) {
    171            //{{{ handleMouse() method
    172            if ( GUIUtilities.isPopupTrigger( evt ) ) {
    173                GUIUtilities.showPopupMenu( popup, this, evt.getX(), evt.getY() );
    174                view.getTextArea().requestFocus();
    175            }
    176        } //}}}
    177
    178        protected class KeyHandler extends KeyAdapter {
    179            //{{{ KeyHandler class
    180            public void keyPressed( KeyEvent evt ) {
    181                handleKey( evt );
    182            }
    183        } //}}}
    184
    185        protected class MouseHandler extends MouseAdapter implements MouseMotionListener {
    186            //{{{ MouseHandler class
    187            public void mousePressed( MouseEvent evt ) {
    188                handleMouse( evt );
    189            }
    190            public void mouseDragged( MouseEvent evt ) {
    191                // no-op, required for interface
    192            }
    193            public void mouseMoved( MouseEvent evt ) {
    194                TreePath path = tree.getPathForLocation(
    195                            evt.getX(), evt.getY() );
    196                if ( path == null )
    197                    view.getStatus().setMessage( null );
    198                else {
    199                    Object value = ( ( DefaultMutableTreeNode ) path
    200                            .getLastPathComponent() ).getUserObject();
    201
    202                    if ( value instanceof IAsset ) {
    203                            IAsset as = (IAsset)value;
    204                        view.getStatus().setMessage(as.getShortString());
    205                        setStatus(as.getLongString() == null ? as.getShortString() : as.getLongString());
    206                    }
    207                }
    208            }
    209        } //}}}
    210
    211        protected class Renderer extends DefaultTreeCellRenderer {
    212            //{{{ Renderer class
    213            // based on sidekick/SideKickTree.java
    214            public Component getTreeCellRendererComponent(
    215                //{{{ +getTreeCellRendererComponent() : Component
    216                JTree tree, Object value,
    217                boolean sel, boolean expanded, boolean leaf,
    218                int row, boolean hasFocus
    219            ) {
    220                JLabel comp = ( JLabel ) super.getTreeCellRendererComponent(
    221                            tree, value, sel, expanded, leaf, row, hasFocus );
    222                DefaultMutableTreeNode node = ( DefaultMutableTreeNode ) value;
    223                Object nodeValue = node.getUserObject();
    224                _hasMarker = false;
    225                if ( node.getParent() == null ) {
    226                    setIcon( org.gjt.sp.jedit.browser.FileCellRenderer.fileIcon );
    227                }
    228                if ( nodeValue instanceof Asset ) {
    229                    _asset = ( Asset ) node.getUserObject();
    230                    setIcon( _asset.getIcon() );
    231                    setText( _asset.getShortString() );
    232                    _hasMarker = hasMarker(
    233                                _asset.start.getOffset(),
    234                                _asset.end.getOffset() );
    235                    setToolTipText( _asset.getLongString() );
    236                }
    237                else
    238                    setIcon( null );
    239                return this;
    240            } //}}}
    241
    242            public void paintComponent( Graphics g ) {
    243                //{{{ +paintComponent(Graphics) : void
    244                // inspired from ProjectViewer plugin
    245                // underlines the asset if it contains a marker
    246                if ( isMarkersFlagSet() && _hasMarker ) {
    247                    FontMetrics fm = getFontMetrics( getFont() );
    248                    int x, y;
    249                    y = getHeight() - 3;
    250                    x = ( getIcon() == null )
    251                        ? 0
    252                        : getIcon().getIconWidth() + getIconTextGap();
    253                    g.setColor( _markerColor );
    254                    g.fillRect( x, y, fm.stringWidth( getText() ), 3 );
    255                }
    256                //  setBackground(_markerColor); // does not work here
    257                super.paintComponent( g );
    258            } //}}}
    259        } //}}}
    260
    261    }
    262