PageRenderTime 16ms CodeModel.GetById 1ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/SideKick/sidekick/enhanced/SourceTree.java

#
Java | 329 lines | 237 code | 30 blank | 62 comment | 40 complexity | 8e60d4d4752aff64282310457f34036e MD5 | raw file
  1/*
  2* SourceTree.java
  3* :folding=explicit:collapseFolds=1:
  4*
  5* Copyright (C) 2005 by Martin Raspe
  6* (hertzhaft@biblhertz.it)
  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*/
 22package sidekick.enhanced;
 23
 24//{{{ Imports
 25import java.awt.Color;
 26import java.awt.FontMetrics;
 27import java.awt.Graphics;
 28import java.awt.event.KeyAdapter;
 29import java.awt.event.KeyEvent;
 30import java.awt.event.MouseAdapter;
 31import java.awt.event.MouseEvent;
 32import java.awt.event.MouseMotionListener;
 33import java.util.HashMap;
 34import java.util.StringTokenizer;
 35
 36import javax.swing.JPopupMenu;
 37import javax.swing.JTree;
 38import javax.swing.ToolTipManager;
 39import javax.swing.tree.DefaultMutableTreeNode;
 40import javax.swing.tree.TreeCellRenderer;
 41import javax.swing.tree.TreeNode;
 42import javax.swing.tree.TreePath;
 43
 44import marker.MarkerSetsPlugin;
 45
 46import org.gjt.sp.jedit.EditPlugin;
 47import org.gjt.sp.jedit.GUIUtilities;
 48import org.gjt.sp.jedit.Mode;
 49import org.gjt.sp.jedit.View;
 50import org.gjt.sp.jedit.jEdit;
 51import org.gjt.sp.jedit.EditBus.EBHandler;
 52import org.gjt.sp.jedit.gui.DockableWindowFactory;
 53import org.gjt.sp.jedit.gui.KeyEventTranslator;
 54import org.gjt.sp.jedit.msg.BufferUpdate;
 55import org.gjt.sp.util.EnhancedTreeCellRenderer;
 56
 57import sidekick.IAsset;
 58import sidekick.SideKickPlugin;
 59import sidekick.SideKickTree;
 60//}}}
 61
 62/**
 63 * @author     Martin Raspe
 64 * @created    Oct 15, 2005
 65 * @modified   $Id: SourceTree.java 20420 2011-11-25 08:01:11Z kpouer $
 66 * @version    $Revision: 20420 $
 67 
 68 * The Structure Browser dockable. Extends the SideKick structure browser,
 69 * adding a popup menu for marker setting and enhanced keyboard handling 
 70 * It replaces the SideKickTree dockable if desired.
 71 */
 72public class SourceTree extends SideKickTree {
 73
 74    //{{{ private vars
 75    private static boolean _hasMarker;
 76    private static boolean _showMarkers = true;
 77    private static Color _markerColor = jEdit.getColorProperty( "view.gutter.markerColor" );
 78
 79    private HashMap _actionShortcuts = new HashMap();
 80    //}}}
 81
 82    public JPopupMenu popup;
 83
 84    public SourceTree( View view, boolean docked ) {
 85        //{{{ SourceTree constructor
 86        super( view, docked );
 87        tree.setCellRenderer( new Renderer() );
 88        tree.addKeyListener( new KeyHandler() );
 89        MouseHandler mh = new MouseHandler();
 90        tree.addMouseListener( mh );
 91        if ( docked )
 92            tree.addMouseMotionListener( mh );
 93        update();
 94    } //}}}
 95
 96    protected void createPopup() {
 97        //{{{ create the tree Popup menu from the "sidekick-tree.{mode}.menu" property
 98        // if not present, use the default menu (see above)
 99		Mode mode = view.getBuffer().getMode();
100        String modename = (mode == null)
101            ? ""
102            : "." + mode.getName();
103        String menu = "sidekick-tree" + modename + ".menu";
104        if (jEdit.getProperty(menu) == null)
105            menu = "sidekick-tree.menu";
106        popup = GUIUtilities.loadPopupMenu(menu);
107        } //}}}
108
109    protected void update() {
110        //{{{ create a new popup menu if mode changes
111        super.update();
112        createPopup();
113        } //}}}
114
115    private boolean hasMarker(int start, int end) {
116        //{{{ getMarker method
117    	EditPlugin markerSets = SideKickPlugin.getMarkerSetsPlugin();
118    	if (markerSets != null) {
119    		if (((MarkerSetsPlugin) markerSets).hasMarker(view.getBuffer(), start, end))
120    			return true;
121    	}
122        return (view.getBuffer().getMarkerInRange(start, end) != null);
123    } //}}}
124
125    public static void toggleMarkersFlag() {
126        //{{{ method toggleMarkersFlag
127        _showMarkers = ! _showMarkers;
128    } //}}}
129
130    public static boolean isRegisteredDockable( String name ) {
131        //{{{ method isRegisteredDockable
132        // see if the dockable "name" is registered
133        String[] dockables = DockableWindowFactory.getInstance()
134                .getRegisteredDockableWindows();
135        boolean _found = false;
136        for ( int i = 0; i < dockables.length; i++ ) {
137            if ( dockables[ i ].equals( name ) ) {
138                _found = true;
139                break;
140            }
141        }
142        return _found;
143    } //}}}
144
145    public static boolean isMarkersFlagSet() {
146        //{{{ method isMarkersFlagSet
147        // should marked routines be shown in structure tree?
148        return _showMarkers;
149    } //}}}
150
151    @EBHandler
152    public void handleBufferUpdate( BufferUpdate upd ) {
153        //{{{ handleBufferUpdate() method
154        // react to marker changes immediately
155        if ( upd.getWhat() == BufferUpdate.MARKERS_CHANGED )
156            update();
157    } //}}}
158
159    public void handleKey( KeyEvent evt ) {
160        //{{{ handleKey() method
161        int _code = evt.getKeyCode();
162        KeyEventTranslator.Key _key = KeyEventTranslator.translateKeyEvent( evt );
163        // let the view handle marker actions
164        // is there an easier way to assign a jEdit shortcut to a tree?
165        if ( _actionShortcuts.containsKey( _key ) )
166            view.getInputHandler().handleKey( _key);
167        else if (( _code == KeyEvent.VK_ESCAPE || _code == KeyEvent.VK_CANCEL ) &&
168                 !evt.isConsumed())
169        {
170            view.getTextArea().requestFocus();
171        }
172    } //}}}
173
174    public void handleMouse( MouseEvent evt ) {
175        //{{{ handleMouse() method
176        if ( GUIUtilities.isPopupTrigger( evt ) ) {
177            GUIUtilities.showPopupMenu( popup, this, evt.getX(), evt.getY() );
178            view.getTextArea().requestFocus();
179        }
180    } //}}}
181
182    @Override
183    protected void propertiesChanged() {
184    	super.propertiesChanged();
185    	Color c = jEdit.getColorProperty("view.gutter.markerColor");
186    	if (! _markerColor.equals(c)) {
187    		_markerColor = c;
188    		repaint();
189    	}
190        if (jEdit.getBooleanProperty("sidekick.showToolTips"))
191            ToolTipManager.sharedInstance().registerComponent( tree );
192        else
193        	ToolTipManager.sharedInstance().unregisterComponent( tree );
194    }
195
196	protected class KeyHandler extends KeyAdapter {
197        //{{{ KeyHandler class
198        public void keyPressed( KeyEvent evt ) {
199            handleKey( evt );
200        }
201    } //}}}
202
203    protected class MouseHandler extends MouseAdapter implements MouseMotionListener {
204        //{{{ MouseHandler class
205        public void mousePressed( MouseEvent evt ) {
206            handleMouse( evt );
207        }
208        public void mouseDragged( MouseEvent evt ) {
209            // no-op, required for interface
210        }
211        public void mouseMoved( MouseEvent evt ) {
212            TreePath path = tree.getPathForLocation(
213                        evt.getX(), evt.getY() );
214            if ( path == null )
215                view.getStatus().setMessage( null );
216            else {
217                Object value = ( ( DefaultMutableTreeNode ) path
218                        .getLastPathComponent() ).getUserObject();
219
220                if ( value instanceof IAsset ) {
221                	IAsset as = (IAsset)value;
222                    view.getStatus().setMessage(as.getShortString());
223                    setStatus(as.getLongString() == null ? as.getShortString() : as.getLongString());
224                }
225            }
226        }
227    } //}}}
228
229    protected class Renderer extends EnhancedTreeCellRenderer {
230        //{{{ Renderer class
231        // based on sidekick/SideKickTree.java
232    	@Override
233        protected void configureTreeCellRendererComponent(
234            //{{{ +getTreeCellRendererComponent() : Component
235            JTree tree, Object value,
236            boolean sel, boolean expanded, boolean leaf,
237            int row, boolean hasFocus
238        ) {
239            DefaultMutableTreeNode node = ( DefaultMutableTreeNode ) value;
240            Object nodeValue = node.getUserObject();
241            _hasMarker = false;
242            if ( node.getParent() == null ) {
243                setIcon( org.gjt.sp.jedit.browser.FileCellRenderer.fileIcon );
244            }
245            if ( nodeValue instanceof IAsset ) {
246                IAsset _asset = ( IAsset ) node.getUserObject();
247                setIcon( _asset.getIcon() );
248                setText( _asset.getShortString() );
249                _hasMarker = hasMarker(
250                            _asset.getStart().getOffset(),
251                            _asset.getEnd().getOffset() );
252                setToolTipText( getToolTipText(node, _asset) );
253            }
254            else
255                setIcon( null );
256        } //}}}
257
258        private void wrap(StringBuffer sb, String indent, String s) {
259        	StringTokenizer st = new StringTokenizer(s, " \t\n", false);
260        	StringBuilder line = new StringBuilder();
261        	while (st.hasMoreTokens())
262        	{
263        		String t = st.nextToken();
264        		if (line.length() + t.length() >= 80)
265        		{
266        			sb.append(line + "<br>" + indent);
267        			line.setLength(0);
268        		}
269    			line.append(t + " ");
270        	}
271    		sb.append(line);
272        }
273       
274        private String getToolTipText(DefaultMutableTreeNode node, IAsset asset) {
275            //{{{ -getToolTipText(DefaultMutableTreeNode, IAsset): String
276        	StringBuffer sb = new StringBuffer("<html><body>");
277        	sb.append(asset.getLongString());
278        	sb.append("<br><br>");
279        	StringBuffer indent = new StringBuffer();
280        	for (TreeNode n: node.getPath()) {
281        		DefaultMutableTreeNode tn = (DefaultMutableTreeNode) n;
282        		Object o = tn.getUserObject();
283        		boolean last = (n == node);
284        		if (last)
285        			sb.append("<b>");
286        		String s;
287        		if (o instanceof IAsset)
288        			s = ((IAsset) o).getShortString();
289        		else
290        			s = o.toString();
291        		wrap(sb, indent.toString(), s);
292        		if (last)
293        			sb.append("</b>");
294        		if (! last) {
295            		sb.append("<br>");
296        			indent.append("&nbsp;&nbsp;");
297       				sb.append(indent.toString());
298        		}
299        	}
300        	sb.append("</body></html>");
301        	return sb.toString();
302        } //}}}
303        
304        public void paintComponent( Graphics g ) {
305            //{{{ +paintComponent(Graphics) : void
306            // inspired from ProjectViewer plugin
307            // underlines the asset if it contains a marker
308            if ( isMarkersFlagSet() && _hasMarker ) {
309                FontMetrics fm = getFontMetrics( getFont() );
310                int x, y;
311                y = getHeight() - 3;
312                x = ( getIcon() == null )
313                    ? 0
314                    : getIcon().getIconWidth() + getIconTextGap();
315                g.setColor( _markerColor );
316                g.fillRect( x, y, fm.stringWidth( getText() ), 3 );
317            }
318            //  setBackground(_markerColor); // does not work here
319            super.paintComponent( g );
320        } //}}}
321
322		@Override
323		protected TreeCellRenderer newInstance() {
324			return new Renderer();
325		}
326    } //}}}
327
328}
329