PageRenderTime 260ms CodeModel.GetById 209ms app.highlight 41ms RepoModel.GetById 1ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/EditPane.java

#
Java | 680 lines | 453 code | 73 blank | 154 comment | 114 complexity | 0110387449a2320acda24798891ca630 MD5 | raw file
  1/*
  2 * EditPane.java - Text area and buffer switcher
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 2000, 2004 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 org.gjt.sp.jedit;
 24
 25//{{{ Imports
 26import javax.swing.*;
 27import java.awt.event.*;
 28import java.awt.*;
 29import java.lang.reflect.Method;
 30import org.gjt.sp.jedit.gui.*;
 31import org.gjt.sp.jedit.io.VFSManager;
 32import org.gjt.sp.jedit.msg.*;
 33import org.gjt.sp.jedit.options.GlobalOptions;
 34import org.gjt.sp.jedit.syntax.SyntaxStyle;
 35import org.gjt.sp.jedit.textarea.*;
 36import org.gjt.sp.util.Log;
 37//}}}
 38
 39/**
 40 * A panel containing a text area.<p>
 41 *
 42 * In a BeanShell script, you can obtain the current edit pane from the
 43 * <code>editPane</code> variable.<p>
 44 *
 45 * This class does not have a public constructor.
 46 * Edit panes can be created and destroyed using methods in the
 47 * {@link View} class.<p>
 48 *
 49 * Each edit pane can edit one buffer at a time.
 50 *
 51 * @see View#splitHorizontally()
 52 * @see View#splitVertically()
 53 * @see View#unsplitCurrent()
 54 * @see View#unsplit()
 55 * @see View#getEditPane()
 56 * @see View#getEditPanes()
 57 *
 58 * @author Slava Pestov
 59 * @version $Id: EditPane.java 4959 2004-01-25 01:38:30Z spestov $
 60 */
 61public class EditPane extends JPanel implements EBComponent
 62{
 63	//{{{ getView() method
 64	/**
 65	 * Returns the view containing this edit pane.
 66	 * @since jEdit 2.5pre2
 67	 */
 68	public View getView()
 69	{
 70		return view;
 71	} //}}}
 72
 73	//{{{ getBuffer() method
 74	/**
 75	 * Returns the current buffer.
 76	 * @since jEdit 2.5pre2
 77	 */
 78	public Buffer getBuffer()
 79	{
 80		return buffer;
 81	} //}}}
 82
 83	//{{{ setBuffer() method
 84	/**
 85	 * Sets the current buffer.
 86	 * @param buffer The buffer to edit.
 87	 * @since jEdit 2.5pre2
 88	 */
 89	public void setBuffer(final Buffer buffer)
 90	{
 91		if(buffer == null)
 92			throw new NullPointerException();
 93
 94		if(this.buffer == buffer)
 95			return;
 96
 97		//if(buffer.insideCompoundEdit())
 98		//	buffer.endCompoundEdit();
 99
100		recentBuffer = this.buffer;
101		if(recentBuffer != null)
102			saveCaretInfo();
103		this.buffer = buffer;
104
105		textArea.setBuffer(buffer);
106
107		if(!init)
108		{
109			view.updateTitle();
110
111			if(bufferSwitcher != null)
112			{
113				if(bufferSwitcher.getSelectedItem() != buffer)
114					bufferSwitcher.setSelectedItem(buffer);
115			}
116
117			EditBus.send(new EditPaneUpdate(this,EditPaneUpdate
118				.BUFFER_CHANGED));
119		}
120
121		SwingUtilities.invokeLater(new Runnable()
122		{
123			public void run()
124			{
125				// only do this if we are the current edit pane
126				if(view.getEditPane() == EditPane.this
127					&& (bufferSwitcher == null
128					|| !bufferSwitcher.isPopupVisible()))
129				{
130					textArea.requestFocus();
131				}
132			}
133		});
134
135		// Only do this after all I/O requests are complete
136		Runnable runnable = new Runnable()
137		{
138			public void run()
139			{
140				// avoid a race condition
141				// see bug #834338
142				if(buffer == getBuffer())
143					loadCaretInfo();
144			}
145		};
146
147		if(buffer.isPerformingIO())
148			VFSManager.runInAWTThread(runnable);
149		else
150			runnable.run();
151	} //}}}
152
153	//{{{ prevBuffer() method
154	/**
155	 * Selects the previous buffer.
156	 * @since jEdit 2.7pre2
157	 */
158	public void prevBuffer()
159	{
160		Buffer buffer = this.buffer.getPrev();
161		if(buffer == null)
162			setBuffer(jEdit.getLastBuffer());
163		else
164			setBuffer(buffer);
165	} //}}}
166
167	//{{{ nextBuffer() method
168	/**
169	 * Selects the next buffer.
170	 * @since jEdit 2.7pre2
171	 */
172	public void nextBuffer()
173	{
174		Buffer buffer = this.buffer.getNext();
175		if(buffer == null)
176			setBuffer(jEdit.getFirstBuffer());
177		else
178			setBuffer(buffer);
179	} //}}}
180
181	//{{{ recentBuffer() method
182	/**
183	 * Selects the most recently edited buffer.
184	 * @since jEdit 2.7pre2
185	 */
186	public void recentBuffer()
187	{
188		if(recentBuffer != null)
189			setBuffer(recentBuffer);
190		else
191			getToolkit().beep();
192	} //}}}
193
194	//{{{ focusOnTextArea() method
195	/**
196	 * Sets the focus onto the text area.
197	 * @since jEdit 2.5pre2
198	 */
199	public void focusOnTextArea()
200	{
201		SwingUtilities.invokeLater(new Runnable()
202		{
203			public void run()
204			{
205				textArea.requestFocus();
206			}
207		});
208	} //}}}
209
210	//{{{ getTextArea() method
211	/**
212	 * Returns the view's text area.
213	 * @since jEdit 2.5pre2
214	 */
215	public JEditTextArea getTextArea()
216	{
217		return textArea;
218	} //}}}
219
220	//{{{ getBufferSwitcher() method
221	/**
222	 * Returns the buffer switcher combo box instance.
223	 * @since jEdit 4.1pre8
224	 */
225	public BufferSwitcher getBufferSwitcher()
226	{
227		return bufferSwitcher;
228	} //}}}
229
230	//{{{ showBufferSwitcher() method
231	/**
232	 * Shows the buffer switcher combo box.
233	 * @since jEdit 4.1pre8
234	 */
235	public void showBufferSwitcher()
236	{
237		if(bufferSwitcher == null)
238			getToolkit().beep();
239		else
240		{
241			bufferSwitcher.requestFocus();
242			bufferSwitcher.showPopup();
243		}
244	} //}}}
245
246	//{{{ saveCaretInfo() method
247	/**
248	 * Saves the caret information to the current buffer.
249	 * @since jEdit 2.5pre2
250	 */
251	public void saveCaretInfo()
252	{
253		buffer.setIntegerProperty(Buffer.CARET,
254			textArea.getCaretPosition());
255
256		/*Selection[] selection = textArea.getSelection();
257		if(selection != null)
258			buffer.setProperty(Buffer.SELECTION,selection);*/
259
260		buffer.setIntegerProperty(Buffer.SCROLL_VERT,
261			textArea.getFirstPhysicalLine());
262		buffer.setIntegerProperty(Buffer.SCROLL_HORIZ,
263			textArea.getHorizontalOffset());
264	} //}}}
265
266	//{{{ loadCaretInfo() method
267	/**
268	 * Loads the caret information from the current buffer.
269	 * @since jEdit 2.5pre2
270	 */
271	public void loadCaretInfo()
272	{
273		Integer caret = (Integer)buffer.getProperty(Buffer.CARET);
274		//Selection[] selection = (Selection[])buffer.getProperty(Buffer.SELECTION);
275
276		Integer firstLine = (Integer)buffer.getProperty(Buffer.SCROLL_VERT);
277		Integer horizontalOffset = (Integer)buffer.getProperty(Buffer.SCROLL_HORIZ);
278
279		if(caret != null)
280		{
281			textArea.setCaretPosition(Math.min(caret.intValue(),
282				buffer.getLength()));
283		}
284
285		/*if(selection != null)
286			textArea.setSelection(selection);*/
287
288		if(firstLine != null)
289			textArea.setFirstPhysicalLine(firstLine.intValue());
290
291		if(horizontalOffset != null)
292			textArea.setHorizontalOffset(horizontalOffset.intValue());
293
294		/* Silly bug workaround #8694. If you look at the above code,
295		 * note that we restore the saved caret position first, then
296		 * scroll to the saved location. However, the caret changing
297		 * can itself result in scrolling to a different location than
298		 * what was saved; and since moveCaretPosition() calls
299		 * updateBracketHighlight(), the bracket highlight's out of
300		 * bounds calculation will rely on a different set of physical
301		 * first/last lines than what we will end up with eventually.
302		 * Instead of confusing the user with status messages that
303		 * appear at random when switching buffers, we simply hide the
304		 * message altogether. */
305		view.getStatus().setMessage(null);
306	} //}}}
307
308	//{{{ handleMessage() method
309	public void handleMessage(EBMessage msg)
310	{
311		if(msg instanceof PropertiesChanged)
312		{
313			propertiesChanged();
314			loadBufferSwitcher();
315		}
316		else if(msg instanceof BufferUpdate)
317			handleBufferUpdate((BufferUpdate)msg);
318	} //}}}
319
320	//{{{ getMinimumSize() method
321	/**
322	 * Returns 0,0 for split pane compatibility.
323	 */
324	public final Dimension getMinimumSize()
325	{
326		return new Dimension(0,0);
327	} //}}}
328
329	//{{{ toString() method
330	public String toString()
331	{
332		return getClass().getName() + "["
333			+ (view.getEditPane() == this
334			? "active" : "inactive")
335			+ "]";
336	} //}}}
337
338	//{{{ Package-private members
339
340	//{{{ EditPane constructor
341	EditPane(View view, Buffer buffer)
342	{
343		super(new BorderLayout());
344
345		init = true;
346
347		this.view = view;
348
349		EditBus.addToBus(this);
350
351		textArea = new JEditTextArea(view);
352
353		add(BorderLayout.CENTER,textArea);
354
355		propertiesChanged();
356
357		if(buffer == null)
358			setBuffer(jEdit.getFirstBuffer());
359		else
360			setBuffer(buffer);
361
362		loadBufferSwitcher();
363
364		init = false;
365	} //}}}
366
367	//{{{ close() method
368	void close()
369	{
370		saveCaretInfo();
371		EditBus.send(new EditPaneUpdate(this,EditPaneUpdate.DESTROYED));
372		EditBus.removeFromBus(this);
373		textArea.dispose();
374	} //}}}
375
376	//}}}
377
378	//{{{ Private members
379
380	private static Method initBufferSwitcher;
381
382	static
383	{
384		if(OperatingSystem.hasJava14())
385		{
386			try
387			{
388				initBufferSwitcher = Java14.class
389					.getMethod("initBufferSwitcher",
390					new Class[] { EditPane.class,
391					BufferSwitcher.class });
392			}
393			catch(Exception e)
394			{
395				Log.log(Log.ERROR,EditPane.class,e);
396			}
397		}
398	}
399
400	//{{{ Instance variables
401	private boolean init;
402	private View view;
403	private Buffer buffer;
404	private Buffer recentBuffer;
405	private BufferSwitcher bufferSwitcher;
406	private JEditTextArea textArea;
407	//}}}
408
409	//{{{ propertiesChanged() method
410	private void propertiesChanged()
411	{
412		TextAreaPainter painter = textArea.getPainter();
413
414		painter.setFont(jEdit.getFontProperty("view.font"));
415		painter.setStructureHighlightEnabled(jEdit.getBooleanProperty(
416			"view.structureHighlight"));
417		painter.setStructureHighlightColor(
418			jEdit.getColorProperty("view.structureHighlightColor"));
419		painter.setEOLMarkersPainted(jEdit.getBooleanProperty(
420			"view.eolMarkers"));
421		painter.setEOLMarkerColor(
422			jEdit.getColorProperty("view.eolMarkerColor"));
423		painter.setWrapGuidePainted(jEdit.getBooleanProperty(
424			"view.wrapGuide"));
425		painter.setWrapGuideColor(
426			jEdit.getColorProperty("view.wrapGuideColor"));
427		painter.setCaretColor(
428			jEdit.getColorProperty("view.caretColor"));
429		painter.setSelectionColor(
430			jEdit.getColorProperty("view.selectionColor"));
431		painter.setMultipleSelectionColor(
432			jEdit.getColorProperty("view.multipleSelectionColor"));
433		painter.setBackground(
434			jEdit.getColorProperty("view.bgColor"));
435		painter.setForeground(
436			jEdit.getColorProperty("view.fgColor"));
437		painter.setBlockCaretEnabled(jEdit.getBooleanProperty(
438			"view.blockCaret"));
439		painter.setLineHighlightEnabled(jEdit.getBooleanProperty(
440			"view.lineHighlight"));
441		painter.setLineHighlightColor(
442			jEdit.getColorProperty("view.lineHighlightColor"));
443		painter.setAntiAliasEnabled(jEdit.getBooleanProperty(
444			"view.antiAlias"));
445		painter.setFractionalFontMetricsEnabled(jEdit.getBooleanProperty(
446			"view.fracFontMetrics"));
447
448		String defaultFont = jEdit.getProperty("view.font");
449		int defaultFontSize = jEdit.getIntegerProperty("view.fontsize",12);
450		painter.setStyles(GUIUtilities.loadStyles(defaultFont,defaultFontSize));
451
452		SyntaxStyle[] foldLineStyle = new SyntaxStyle[4];
453		for(int i = 0; i <= 3; i++)
454		{
455			foldLineStyle[i] = GUIUtilities.parseStyle(
456				jEdit.getProperty("view.style.foldLine." + i),
457				defaultFont,defaultFontSize);
458		}
459		painter.setFoldLineStyle(foldLineStyle);
460		Gutter gutter = textArea.getGutter();
461		gutter.setExpanded(jEdit.getBooleanProperty(
462			"view.gutter.lineNumbers"));
463		int interval = jEdit.getIntegerProperty(
464			"view.gutter.highlightInterval",5);
465		gutter.setHighlightInterval(interval);
466		gutter.setCurrentLineHighlightEnabled(jEdit.getBooleanProperty(
467			"view.gutter.highlightCurrentLine"));
468		gutter.setStructureHighlightEnabled(jEdit.getBooleanProperty(
469			"view.gutter.structureHighlight"));
470		gutter.setStructureHighlightColor(
471			jEdit.getColorProperty("view.gutter.structureHighlightColor"));
472		gutter.setBackground(
473			jEdit.getColorProperty("view.gutter.bgColor"));
474		gutter.setForeground(
475			jEdit.getColorProperty("view.gutter.fgColor"));
476		gutter.setHighlightedForeground(
477			jEdit.getColorProperty("view.gutter.highlightColor"));
478		gutter.setFoldColor(
479			jEdit.getColorProperty("view.gutter.foldColor"));
480		gutter.setMarkerHighlightColor(
481			jEdit.getColorProperty("view.gutter.markerColor"));
482		gutter.setMarkerHighlightEnabled(jEdit.getBooleanProperty(
483			"view.gutter.markerHighlight"));
484		gutter.setCurrentLineForeground(
485			jEdit.getColorProperty("view.gutter.currentLineColor"));
486		String alignment = jEdit.getProperty(
487			"view.gutter.numberAlignment");
488		if ("right".equals(alignment))
489		{
490			gutter.setLineNumberAlignment(Gutter.RIGHT);
491		}
492		else if ("center".equals(alignment))
493		{
494			gutter.setLineNumberAlignment(Gutter.CENTER);
495		}
496		else // left == default case
497		{
498			gutter.setLineNumberAlignment(Gutter.LEFT);
499		}
500
501		gutter.setFont(jEdit.getFontProperty("view.gutter.font"));
502
503		int width = jEdit.getIntegerProperty(
504			"view.gutter.borderWidth",3);
505		gutter.setBorder(width,
506			jEdit.getColorProperty("view.gutter.focusBorderColor"),
507			jEdit.getColorProperty("view.gutter.noFocusBorderColor"),
508			textArea.getPainter().getBackground());
509
510		textArea.setCaretBlinkEnabled(jEdit.getBooleanProperty(
511			"view.caretBlink"));
512
513		textArea.setElectricScroll(jEdit.getIntegerProperty(
514			"view.electricBorders",0));
515
516		// Set up the right-click popup menu
517		JPopupMenu popup = GUIUtilities.loadPopupMenu("view.context");
518		JMenuItem customize = new JMenuItem(jEdit.getProperty(
519			"view.context.customize"));
520		customize.addActionListener(new ActionListener()
521		{
522			public void actionPerformed(ActionEvent evt)
523			{
524				new GlobalOptions(view,"context");
525			}
526		});
527		popup.addSeparator();
528		popup.add(customize);
529		textArea.setRightClickPopup(popup);
530
531		// use old property name for backwards compatibility
532		textArea.setQuickCopyEnabled(jEdit.getBooleanProperty(
533			"view.middleMousePaste"));
534
535		textArea.setDragEnabled(jEdit.getBooleanProperty(
536			"view.dragAndDrop"));
537
538		textArea.propertiesChanged();
539	} //}}}
540
541	//{{{ loadBufferSwitcher() method
542	private void loadBufferSwitcher()
543	{
544		if(jEdit.getBooleanProperty("view.showBufferSwitcher"))
545		{
546			if(bufferSwitcher == null)
547			{
548				bufferSwitcher = new BufferSwitcher(this);
549				if(initBufferSwitcher != null)
550				{
551					try
552					{
553						initBufferSwitcher.invoke(
554							null,new Object[] {
555								EditPane.this,
556								bufferSwitcher
557							});
558					}
559					catch(Exception e)
560					{
561						Log.log(Log.ERROR,this,e);
562					}
563				}
564				add(BorderLayout.NORTH,bufferSwitcher);
565				bufferSwitcher.updateBufferList();
566				revalidate();
567			}
568		}
569		else if(bufferSwitcher != null)
570		{
571			remove(bufferSwitcher);
572			revalidate();
573			bufferSwitcher = null;
574		}
575	} //}}}
576
577	//{{{ handleBufferUpdate() method
578	private void handleBufferUpdate(BufferUpdate msg)
579	{
580		Buffer _buffer = msg.getBuffer();
581		if(msg.getWhat() == BufferUpdate.CREATED)
582		{
583			if(bufferSwitcher != null)
584				bufferSwitcher.updateBufferList();
585
586			/* When closing the last buffer, the BufferUpdate.CLOSED
587			 * handler doesn't call setBuffer(), because null buffers
588			 * are not supported. Instead, it waits for the subsequent
589			 * 'Untitled' file creation. */
590			if(buffer.isClosed())
591			{
592				setBuffer(jEdit.getFirstBuffer());
593				// since recentBuffer will be set to the one that
594				// was closed
595				recentBuffer = null;
596			}
597		}
598		else if(msg.getWhat() == BufferUpdate.CLOSED)
599		{
600			if(bufferSwitcher != null)
601				bufferSwitcher.updateBufferList();
602
603			if(_buffer == buffer)
604			{
605				Buffer newBuffer = (recentBuffer != null ?
606					recentBuffer : _buffer.getPrev());
607				if(newBuffer != null && !newBuffer.isClosed())
608					setBuffer(newBuffer);
609				else if(jEdit.getBufferCount() != 0)
610					setBuffer(jEdit.getFirstBuffer());
611
612				recentBuffer = null;
613			}
614			else if(_buffer == recentBuffer)
615				recentBuffer = null;
616		}
617		else if(msg.getWhat() == BufferUpdate.LOAD_STARTED)
618		{
619			if(_buffer == buffer)
620			{
621				textArea.setCaretPosition(0);
622				textArea.getPainter().repaint();
623			}
624		}
625		else if(msg.getWhat() == BufferUpdate.LOADED)
626		{
627			if(_buffer == buffer)
628			{
629				textArea.repaint();
630				if(bufferSwitcher != null)
631					bufferSwitcher.updateBufferList();
632
633				if(view.getEditPane() == this)
634				{
635					StatusBar status = view.getStatus();
636					status.updateCaretStatus();
637					status.updateBufferStatus();
638					status.updateMiscStatus();
639				}
640
641				loadCaretInfo();
642			}
643
644		}
645		else if(msg.getWhat() == BufferUpdate.DIRTY_CHANGED)
646		{
647			if(_buffer == buffer)
648			{
649				if(bufferSwitcher != null)
650				{
651					if(buffer.isDirty())
652						bufferSwitcher.repaint();
653					else
654						bufferSwitcher.updateBufferList();
655				}
656			}
657		}
658		else if(msg.getWhat() == BufferUpdate.MARKERS_CHANGED)
659		{
660			if(_buffer == buffer)
661				textArea.getGutter().repaint();
662		}
663		else if(msg.getWhat() == BufferUpdate.PROPERTIES_CHANGED)
664		{
665			if(_buffer == buffer)
666			{
667				textArea.propertiesChanged();
668				if(view.getEditPane() == this)
669					view.getStatus().updateBufferStatus();
670			}
671		}
672		else if(msg.getWhat() == BufferUpdate.SAVED)
673		{
674			if(_buffer == buffer)
675				textArea.propertiesChanged();
676		}
677	} //}}}
678
679	//}}}
680}