PageRenderTime 43ms CodeModel.GetById 14ms app.highlight 23ms RepoModel.GetById 2ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre5/org/gjt/sp/jedit/textarea/Gutter.java

#
Java | 880 lines | 539 code | 110 blank | 231 comment | 85 complexity | 0cdc119c4fa4bfb9b242a16f9654b81a MD5 | raw file
  1/*
  2 * Gutter.java
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 1999, 2000 mike dillon
  7 * Portions copyright (C) 2001, 2002 Slava Pestov
  8 *
  9 * This program is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU General Public License
 11 * as published by the Free Software Foundation; either version 2
 12 * of the License, or any later version.
 13 *
 14 * This program is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17 * GNU General Public License for more details.
 18 *
 19 * You should have received a copy of the GNU General Public License
 20 * along with this program; if not, write to the Free Software
 21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 22 */
 23
 24package org.gjt.sp.jedit.textarea;
 25
 26//{{{ Imports
 27import java.awt.*;
 28import java.awt.event.*;
 29import java.util.ArrayList;
 30import javax.swing.*;
 31import javax.swing.border.*;
 32import javax.swing.event.*;
 33import org.gjt.sp.jedit.*;
 34import org.gjt.sp.util.Log;
 35//}}}
 36
 37/**
 38 * The gutter is the component that displays folding triangles and line
 39 * numbers to the left of the text area. The only methods in this class
 40 * that should be called by plugins are those for adding and removing
 41 * text area extensions.
 42 *
 43 * @see #addExtension(TextAreaExtension)
 44 * @see #addExtension(int,TextAreaExtension)
 45 * @see #removeExtension(TextAreaExtension)
 46 * @see TextAreaExtension
 47 * @see JEditTextArea
 48 *
 49 * @author Mike Dillon and Slava Pestov
 50 * @version $Id: Gutter.java 4004 2002-02-01 07:40:23Z spestov $
 51 */
 52public class Gutter extends JComponent implements SwingConstants
 53{
 54	//{{{ Layers
 55	/**
 56	 * The lowest possible layer.
 57	 * @see #addExtension(int,TextAreaExtension)
 58	 * @since jEdit 4.0pre4
 59	 */
 60	public static final int LOWEST_LAYER = Integer.MIN_VALUE;
 61
 62	/**
 63	 * Default extension layer. This is above the wrap guide but below the
 64	 * bracket highlight.
 65	 * @since jEdit 4.0pre4
 66	 */
 67	public static final int DEFAULT_LAYER = 0;
 68
 69	/**
 70	 * Highest possible layer.
 71	 * @since jEdit 4.0pre4
 72	 */
 73	public static final int HIGHEST_LAYER = Integer.MAX_VALUE;
 74	//}}}
 75
 76	//{{{ Gutter constructor
 77	public Gutter(View view, JEditTextArea textArea)
 78	{
 79		this.view = view;
 80		this.textArea = textArea;
 81
 82		extensionMgr = new ExtensionManager();
 83
 84		MouseHandler ml = new MouseHandler();
 85		addMouseListener(ml);
 86		addMouseMotionListener(ml);
 87
 88		addExtension(new MarkerHighlight());
 89	} //}}}
 90
 91	//{{{ paintComponent() method
 92	public void paintComponent(Graphics _gfx)
 93	{
 94		Graphics2D gfx = (Graphics2D)_gfx;
 95
 96		// fill the background
 97		Rectangle clip = gfx.getClipBounds();
 98		gfx.setColor(getBackground());
 99		gfx.fillRect(clip.x, clip.y, clip.width, clip.height);
100
101		// if buffer is loading, don't paint anything
102		if (!textArea.getBuffer().isLoaded())
103			return;
104
105		// paint highlights and line numbers
106		int lineHeight = textArea.getPainter().getFontMetrics()
107			.getHeight();
108
109		int firstLine = clip.y / lineHeight;
110		int lastLine = (clip.y + clip.height - 1) / lineHeight;
111
112		FontMetrics pfm = textArea.getPainter().getFontMetrics();
113		Color fg = getForeground();
114
115		int baseline = (int)((this.baseline + lineHeight
116			- pfm.getDescent()) / 2.0);
117
118		boolean highlightCurrentLine = currentLineHighlightEnabled
119			&& textArea.selection.size() == 0;
120
121		int y = (clip.y - clip.y % lineHeight);
122
123		Buffer buffer = textArea.getBuffer();
124		textArea.chunkCache.updateChunksUpTo(lastLine);
125
126		for (int line = firstLine; line <= lastLine;
127			line++, y += lineHeight)
128		{
129			ChunkCache.LineInfo info = textArea.chunkCache.getLineInfo(line);
130			if(!info.chunksValid)
131				System.err.println("gutter paint: not valid");
132			int physicalLine = info.physicalLine;
133
134			//{{{ Paint text area extensions
135			if(physicalLine != -1)
136			{
137				int start = textArea.getScreenLineStartOffset(line);
138				int end = textArea.getScreenLineEndOffset(line);
139
140				extensionMgr.paintValidLine(gfx,line,physicalLine,start,end,y);
141			}
142			else
143				extensionMgr.paintInvalidLine(gfx,line,y);
144			//}}}
145
146			// Skip lines beyond EOF
147			if(physicalLine == -1)
148				return;
149
150			//{{{ Paint fold triangles
151			if(info.firstSubregion
152				&& physicalLine != buffer.getLineCount() - 1
153				&& buffer.isFoldStart(physicalLine))
154			{
155				int _y = y + lineHeight / 2;
156				gfx.setColor(foldColor);
157				if(textArea.getFoldVisibilityManager()
158					.isLineVisible(physicalLine + 1))
159				{
160					gfx.drawLine(1,_y - 3,10,_y - 3);
161					gfx.drawLine(2,_y - 2,9,_y - 2);
162					gfx.drawLine(3,_y - 1,8,_y - 1);
163					gfx.drawLine(4,_y,7,_y);
164					gfx.drawLine(5,_y + 1,6,_y + 1);
165				}
166				else
167				{
168					gfx.drawLine(4,_y - 5,4,_y + 4);
169					gfx.drawLine(5,_y - 4,5,_y + 3);
170					gfx.drawLine(6,_y - 3,6,_y + 2);
171					gfx.drawLine(7,_y - 2,7,_y + 1);
172					gfx.drawLine(8,_y - 1,8,_y);
173				}
174			} //}}}
175			//{{{ Paint bracket scope
176			else if(bracketHighlight)
177			{
178				if(textArea.isBracketHighlightVisible())
179				{
180					int bracketLine = textArea.getBracketLine();
181					int caretLine = textArea.getCaretLine();
182					if(caretLine != bracketLine)
183					{
184						if(caretLine > bracketLine)
185						{
186							int tmp = caretLine;
187							caretLine = bracketLine;
188							bracketLine = tmp;
189						}
190
191						gfx.setColor(bracketHighlightColor);
192						if(physicalLine == caretLine)
193						{
194							gfx.fillRect(5,
195								y
196								+ lineHeight / 2,
197								5,
198								2);
199							gfx.fillRect(5,
200								y
201								+ lineHeight / 2,
202								2,
203								lineHeight - lineHeight / 2);
204						}
205						else if(physicalLine == bracketLine)
206						{
207							gfx.fillRect(5,
208								y,
209								2,
210								lineHeight / 2);
211							gfx.fillRect(5,
212								y + lineHeight / 2,
213								5,
214								2);
215						}
216						else if(physicalLine > caretLine
217							&& physicalLine < bracketLine)
218						{
219							gfx.fillRect(5,
220								y,
221								2,
222								lineHeight);
223						}
224					}
225				}
226			} //}}}
227
228			//{{{ Paint line numbers
229			if(info.firstSubregion && expanded)
230			{
231				String number = Integer.toString(physicalLine + 1);
232
233				int offset;
234				switch (alignment)
235				{
236				case RIGHT:
237					offset = gutterSize.width - collapsedSize.width
238						- (fm.stringWidth(number) + 1);
239					break;
240				case CENTER:
241					offset = ((gutterSize.width - collapsedSize.width)
242						- fm.stringWidth(number)) / 2;
243					break;
244				case LEFT: default:
245					offset = 0;
246					break;
247				}
248
249				if (physicalLine == textArea.getCaretLine() && highlightCurrentLine)
250				{
251					gfx.setColor(currentLineHighlight);
252				}
253				else if (interval > 1 && (line
254					+ textArea.getFirstLine() + 1)
255					% interval == 0)
256					gfx.setColor(intervalHighlight);
257				else
258					gfx.setColor(fg);
259
260				gfx.drawString(number, FOLD_MARKER_SIZE + offset,
261					baseline + y);
262			} //}}}
263		}
264	} //}}}
265
266	//{{{ addCustomHighlight() method
267	/**
268	 * @deprecated Write a <code>TextAreaExtension</code> instead.
269	 */
270	public void addCustomHighlight(TextAreaHighlight highlight)
271	{
272		Log.log(Log.WARNING,this,"Old highlighter API not supported: "
273			+ highlight);
274	} //}}}
275
276	//{{{ removeCustomHighlight() method
277	/**
278	 * @deprecated Write a <code>TextAreaExtension</code> instead.
279	 */
280	public void removeCustomHighlight(TextAreaHighlight highlight)
281	{
282		Log.log(Log.WARNING,this,"Old highlighter API not supported: "
283			+ highlight);
284	} //}}}
285
286	//{{{ addExtension() method
287	/**
288	 * Adds a text area extension, which can perform custom painting and
289	 * tool tip handling.
290	 * @param extension The extension
291	 * @since jEdit 4.0pre4
292	 */
293	public void addExtension(TextAreaExtension extension)
294	{
295		extensionMgr.addExtension(DEFAULT_LAYER,extension);
296		repaint();
297	} //}}}
298
299	//{{{ addExtension() method
300	/**
301	 * Adds a text area extension, which can perform custom painting and
302	 * tool tip handling.
303	 * @param layer The layer to add the extension to. Note that more than
304	 * extension can share the same layer.
305	 * @param extension The extension
306	 * @since jEdit 4.0pre4
307	 */
308	public void addExtension(int layer, TextAreaExtension extension)
309	{
310		extensionMgr.addExtension(layer,extension);
311		repaint();
312	} //}}}
313
314	//{{{ removeExtension() method
315	/**
316	 * Removes a text area extension. It will no longer be asked to
317	 * perform custom painting and tool tip handling.
318	 * @param extension The extension
319	 * @since jEdit 4.0pre4
320	 */
321	public void removeExtension(TextAreaExtension extension)
322	{
323		extensionMgr.removeExtension(extension);
324		repaint();
325	} //}}}
326
327	//{{{ getToolTipText() method
328	/**
329	 * Returns the tool tip to display at the specified location.
330	 * @param evt The mouse event
331	 */
332	public String getToolTipText(MouseEvent evt)
333	{
334		if(!textArea.getBuffer().isLoaded())
335			return null;
336
337		return extensionMgr.getToolTipText(evt.getX(),evt.getY());
338	} //}}}
339
340	//{{{ setBorder() method
341	/**
342	 * Convenience method for setting a default matte border on the right
343	 * with the specified border width and color
344	 * @param width The border width (in pixels)
345	 * @param color1 The focused border color
346	 * @param color2 The unfocused border color
347	 * @param color3 The gutter/text area gap color
348	 */
349	public void setBorder(int width, Color color1, Color color2, Color color3)
350	{
351		this.borderWidth = width;
352
353		focusBorder = new CompoundBorder(new MatteBorder(0,0,0,width,color3),
354			new MatteBorder(0,0,0,width,color1));
355		noFocusBorder = new CompoundBorder(new MatteBorder(0,0,0,width,color3),
356			new MatteBorder(0,0,0,width,color2));
357		updateBorder();
358	} //}}}
359
360	//{{{ updateBorder() method
361	/**
362	 * Sets the border differently if the text area has focus or not.
363	 */
364	public void updateBorder()
365	{
366		// because we are called from the text area's focus handler,
367		// we do an invokeLater() so that the view's focus handler
368		// has a chance to execute and set the edit pane properly
369		SwingUtilities.invokeLater(new Runnable()
370		{
371			public void run()
372			{
373				if(view.getEditPane() == null)
374					return;
375
376				if(view.getEditPane().getTextArea() == textArea)
377					setBorder(focusBorder);
378				else
379					setBorder(noFocusBorder);
380			}
381		});
382	} //}}}
383
384	//{{{ setBorder() method
385	/*
386	 * JComponent.setBorder(Border) is overridden here to cache the left
387	 * inset of the border (if any) to avoid having to fetch it during every
388	 * repaint.
389	 */
390	public void setBorder(Border border)
391	{
392		super.setBorder(border);
393
394		if (border == null)
395		{
396			collapsedSize.width = 0;
397			collapsedSize.height = 0;
398		}
399		else
400		{
401			Insets insets = border.getBorderInsets(this);
402			collapsedSize.width = FOLD_MARKER_SIZE + insets.right;
403			collapsedSize.height = gutterSize.height
404				= insets.top + insets.bottom;
405			gutterSize.width = FOLD_MARKER_SIZE + insets.right
406				+ fm.stringWidth("12345");
407		}
408
409		revalidate();
410	} //}}}
411
412	//{{{ setFont() method
413	/*
414	 * JComponent.setFont(Font) is overridden here to cache the baseline for
415	 * the font. This avoids having to get the font metrics during every
416	 * repaint.
417	 */
418	public void setFont(Font font)
419	{
420		super.setFont(font);
421
422		fm = getFontMetrics(font);
423
424		baseline = fm.getAscent();
425
426		Border border = getBorder();
427		if(border != null)
428		{
429			gutterSize.width = FOLD_MARKER_SIZE
430				+ border.getBorderInsets(this).right
431				+ fm.stringWidth("12345");
432			revalidate();
433		}
434	} //}}}
435
436	//{{{ Getters and setters
437
438	//{{{ getHighlightedForeground() method
439	/**
440	 * Get the foreground color for highlighted line numbers
441	 * @return The highlight color
442	 */
443	public Color getHighlightedForeground()
444	{
445		return intervalHighlight;
446	} //}}}
447
448	//{{{ setHighlightedForeground() method
449	public void setHighlightedForeground(Color highlight)
450	{
451		intervalHighlight = highlight;
452	} //}}}
453
454	//{{{ getCurrentLineForeground() method
455	public Color getCurrentLineForeground()
456 	{
457		return currentLineHighlight;
458	} //}}}
459
460	//{{{ setCurrentLineForeground() method
461	public void setCurrentLineForeground(Color highlight)
462	{
463		currentLineHighlight = highlight;
464 	} //}}}
465
466	//{{{ getFoldColor() method
467	public Color getFoldColor()
468 	{
469		return foldColor;
470	} //}}}
471
472	//{{{ setFoldColor() method
473	public void setFoldColor(Color foldColor)
474	{
475		this.foldColor = foldColor;
476 	} //}}}
477
478	//{{{ getPreferredSize() method
479	/*
480	 * Component.getPreferredSize() is overridden here to support the
481	 * collapsing behavior.
482	 */
483	public Dimension getPreferredSize()
484	{
485		if (expanded)
486			return gutterSize;
487		else
488			return collapsedSize;
489	} //}}}
490
491	//{{{ getMinimumSize() method
492	public Dimension getMinimumSize()
493	{
494		return getPreferredSize();
495	} //}}}
496
497	//{{{ getLineNumberAlignment() method
498	/**
499	 * Identifies whether the horizontal alignment of the line numbers.
500	 * @return Gutter.RIGHT, Gutter.CENTER, Gutter.LEFT
501	 */
502	public int getLineNumberAlignment()
503	{
504		return alignment;
505	} //}}}
506
507	//{{{ setLineNumberAlignment() method
508	/**
509	 * Sets the horizontal alignment of the line numbers.
510	 * @param alignment Gutter.RIGHT, Gutter.CENTER, Gutter.LEFT
511	 */
512	public void setLineNumberAlignment(int alignment)
513	{
514		if (this.alignment == alignment) return;
515
516		this.alignment = alignment;
517
518		repaint();
519	} //}}}
520
521	//{{{ isExpanded() method
522	/**
523	 * Identifies whether the gutter is collapsed or expanded.
524	 * @return true if the gutter is expanded, false if it is collapsed
525	 */
526	public boolean isExpanded()
527	{
528		return expanded;
529	} //}}}
530
531	//{{{ setExpanded() method
532	/**
533	 * Sets whether the gutter is collapsed or expanded and force the text
534	 * area to update its layout if there is a change.
535	 * @param collapsed true if the gutter is expanded,
536	 *                   false if it is collapsed
537	 */
538	public void setExpanded(boolean expanded)
539	{
540		if (this.expanded == expanded) return;
541
542		this.expanded = expanded;
543
544		textArea.revalidate();
545	} //}}}
546
547	//{{{ toggleExpanded() method
548	/**
549	 * Toggles whether the gutter is collapsed or expanded.
550	 */
551	public void toggleExpanded()
552	{
553		setExpanded(!expanded);
554	} //}}}
555
556	//{{{ getHighlightInterval() method
557	/**
558	 * Sets the number of lines between highlighted line numbers.
559	 * @return The number of lines between highlighted line numbers or
560	 *          zero if highlighting is disabled
561	 */
562	public int getHighlightInterval()
563	{
564		return interval;
565	} //}}}
566
567	//{{{ setHighlightInterval() method
568	/**
569	 * Sets the number of lines between highlighted line numbers. Any value
570	 * less than or equal to one will result in highlighting being disabled.
571	 * @param interval The number of lines between highlighted line numbers
572	 */
573	public void setHighlightInterval(int interval)
574	{
575		if (interval <= 1) interval = 0;
576		this.interval = interval;
577		repaint();
578	} //}}}
579
580	//{{{ isCurrentLineHighlightEnabled() method
581	public boolean isCurrentLineHighlightEnabled()
582	{
583		return currentLineHighlightEnabled;
584	} //}}}
585
586	//{{{ setCurrentLineHighlightEnabled() method
587	public void setCurrentLineHighlightEnabled(boolean enabled)
588	{
589		if (currentLineHighlightEnabled == enabled) return;
590
591		currentLineHighlightEnabled = enabled;
592
593		repaint();
594	} //}}}
595
596	//{{{ getBracketHighlightColor() method
597	/**
598	 * Returns the bracket highlight color.
599	 */
600	public final Color getBracketHighlightColor()
601	{
602		return bracketHighlightColor;
603	} //}}}
604
605	//{{{ setBracketHighlightColor() method
606	/**
607	 * Sets the bracket highlight color.
608	 * @param bracketHighlightColor The bracket highlight color
609	 * @since jEdit 4.0pre1
610	 */
611	public final void setBracketHighlightColor(Color bracketHighlightColor)
612	{
613		this.bracketHighlightColor = bracketHighlightColor;
614		repaint();
615	} //}}}
616
617	//{{{ isBracketHighlightEnabled() method
618	/**
619	 * Returns true if bracket highlighting is enabled, false otherwise.
620	 * When bracket highlighting is enabled, the bracket matching the
621	 * one before the caret (if any) is highlighted.
622	 * @since jEdit 4.0pre1
623	 */
624	public final boolean isBracketHighlightEnabled()
625	{
626		return bracketHighlight;
627	} //}}}
628
629	//{{{ setBracketHighlightEnabled() method
630	/**
631	 * Enables or disables bracket highlighting.
632	 * When bracket highlighting is enabled, the bracket matching the
633	 * one before the caret (if any) is highlighted.
634	 * @param bracketHighlight True if bracket highlighting should be
635	 * enabled, false otherwise
636	 * @since jEdit 4.0pre1
637	 */
638	public final void setBracketHighlightEnabled(boolean bracketHighlight)
639	{
640		this.bracketHighlight = bracketHighlight;
641		repaint();
642	} //}}}
643
644	//{{{ getMarkerHighlightColor() method
645	public Color getMarkerHighlightColor()
646	{
647		return markerHighlightColor;
648	} //}}}
649
650	//{{{ setMarkerHighlightColor() method
651	public void setMarkerHighlightColor(Color markerHighlightColor)
652	{
653		this.markerHighlightColor = markerHighlightColor;
654	} //}}}
655
656	//{{{ isMarkerHighlightEnabled() method
657	public boolean isMarkerHighlightEnabled()
658	{
659		return markerHighlight;
660	} //}}}
661
662	//{{{ isMarkerHighlightEnabled()
663	public void setMarkerHighlightEnabled(boolean markerHighlight)
664	{
665		this.markerHighlight = markerHighlight;
666	} //}}}
667
668	//}}}
669
670	//{{{ Private members
671	private static final int FOLD_MARKER_SIZE = 12;
672
673	private View view;
674	private JEditTextArea textArea;
675
676	private ExtensionManager extensionMgr;
677
678	private int baseline;
679
680	private Dimension gutterSize = new Dimension(0,0);
681	private Dimension collapsedSize = new Dimension(0,0);
682
683	private Color intervalHighlight;
684	private Color currentLineHighlight;
685	private Color foldColor;
686
687	private FontMetrics fm;
688
689	private int alignment;
690
691	private int interval;
692	private boolean currentLineHighlightEnabled;
693	private boolean expanded;
694
695	private boolean bracketHighlight;
696	private Color bracketHighlightColor;
697
698	private boolean markerHighlight;
699	private Color markerHighlightColor;
700
701	private int borderWidth;
702	private Border focusBorder, noFocusBorder;
703	//}}}
704
705	//{{{ MouseHandler class
706	class MouseHandler extends MouseInputAdapter
707	{
708		boolean drag;
709		int toolTipInitialDelay, toolTipReshowDelay;
710
711		//{{{ mouseEntered() method
712		public void mouseEntered(MouseEvent e)
713		{
714			ToolTipManager ttm = ToolTipManager.sharedInstance();
715			toolTipInitialDelay = ttm.getInitialDelay();
716			toolTipReshowDelay = ttm.getReshowDelay();
717			ttm.setInitialDelay(0);
718			ttm.setReshowDelay(0);
719		} //}}}
720
721		//{{{ mouseExited() method
722		public void mouseExited(MouseEvent evt)
723		{
724			ToolTipManager ttm = ToolTipManager.sharedInstance();
725			ttm.setInitialDelay(toolTipInitialDelay);
726			ttm.setReshowDelay(toolTipReshowDelay);
727		} //}}}
728
729		//{{{ mousePressed() method
730		public void mousePressed(MouseEvent e)
731		{
732			if(GUIUtilities.isPopupTrigger(e)
733				|| e.getX() >= getWidth() - borderWidth * 2)
734			{
735				e.translatePoint(-getWidth(),0);
736				textArea.mouseHandler.mousePressed(e);
737				drag = true;
738			}
739			else
740			{
741				Buffer buffer = textArea.getBuffer();
742
743				int screenLine = e.getY() / textArea.getPainter()
744					.getFontMetrics().getHeight();
745				textArea.chunkCache.updateChunksUpTo(screenLine);
746
747				int line = textArea.chunkCache.getLineInfo(screenLine)
748					.physicalLine;
749
750				if(line == -1)
751					return;
752
753				FoldVisibilityManager foldVisibilityManager
754					= textArea.getFoldVisibilityManager();
755
756				//{{{ Clicking on fold triangle does various things
757				if(buffer.isFoldStart(line))
758				{
759					if(e.isControlDown())
760					{
761						foldVisibilityManager
762							.expandFold(line,true);
763						textArea.selectFold(line);
764					}
765					else if(foldVisibilityManager
766						.isLineVisible(line + 1))
767					{
768						foldVisibilityManager
769							.collapseFold(line);
770					}
771					else
772					{
773						foldVisibilityManager
774							.expandFold(line,
775							e.isShiftDown());
776					}
777				} //}}}
778				//{{{ Clicking in bracket scope locates matching bracket
779				else if(bracketHighlight)
780				{
781					if(textArea.isBracketHighlightVisible())
782					{
783						int bracketLine = textArea.getBracketLine();
784						int caretLine = textArea.getCaretLine();
785						if(caretLine != bracketLine)
786						{
787							if(caretLine > bracketLine)
788							{
789								int tmp = caretLine;
790								caretLine = bracketLine;
791								bracketLine = tmp;
792							}
793
794							if(line >= caretLine
795								&& line <= bracketLine)
796							{
797								if(e.isControlDown())
798									textArea.selectToMatchingBracket();
799								else
800									textArea.goToMatchingBracket();
801							}
802						}
803					}
804				} //}}}
805			}
806		} //}}}
807
808		//{{{ mouseDragged() method
809		public void mouseDragged(MouseEvent e)
810		{
811			if(drag /* && e.getX() >= getWidth() - borderWidth * 2 */)
812			{
813				e.translatePoint(-getWidth(),0);
814				textArea.mouseHandler.mouseDragged(e);
815			}
816		} //}}}
817
818		//{{{ mouseReleased() method
819		public void mouseReleased(MouseEvent e)
820		{
821			if(drag && e.getX() >= getWidth() - borderWidth * 2)
822			{
823				e.translatePoint(-getWidth(),0);
824				textArea.mouseHandler.mouseReleased(e);
825			}
826
827			drag = false;
828		} //}}}
829	} //}}}
830
831	//{{{ MarkerHighlight class
832	class MarkerHighlight extends TextAreaExtension
833	{
834		//{{{ paintValidLine() method
835		public void paintValidLine(Graphics2D gfx, int screenLine,
836			int physicalLine, int start, int end, int y)
837		{
838			if(isMarkerHighlightEnabled())
839			{
840				Buffer buffer = textArea.getBuffer();
841				if(buffer.getMarkerInRange(start,end) != null)
842				{
843					gfx.setColor(getMarkerHighlightColor());
844					FontMetrics fm = textArea.getPainter().getFontMetrics();
845					gfx.fillRect(0,y,textArea.getGutter()
846						.getWidth(),fm.getHeight());
847				}
848			}
849		} //}}}
850
851		//{{{ getToolTipText() method
852		public String getToolTipText(int x, int y)
853		{
854			if(isMarkerHighlightEnabled())
855			{
856				int start = textArea.xyToOffset(0,y);
857				if(start == -1)
858					return null;
859
860				int end = textArea.getScreenLineEndOffset(
861					textArea.getScreenLineOfOffset(start));
862
863				Marker marker = textArea.getBuffer().getMarkerInRange(start,end);
864				if(marker != null)
865				{
866					char shortcut = marker.getShortcut();
867					if(shortcut == '\0')
868						return jEdit.getProperty("view.gutter.marker.no-name");
869					else
870					{
871						String[] args = { String.valueOf(shortcut) };
872						return jEdit.getProperty("view.gutter.marker",args);
873					}
874				}
875			}
876
877			return null;
878		} //}}}
879	} //}}}
880}