PageRenderTime 129ms CodeModel.GetById 96ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/gui/StatusBar.java

#
Java | 492 lines | 349 code | 55 blank | 88 comment | 55 complexity | 03b2bc4578fdf5f4e46c4f2bebb6e252 MD5 | raw file
  1/*
  2 * StatusBar.java - The status bar displayed at the bottom of views
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 2001, 2004 Slava Pestov
  7 * Portions copyright (C) 2001 Mike Dillon
  8 * Portions copyright (C) 2008 Matthieu Casanova
  9 *
 10 * This program is free software; you can redistribute it and/or
 11 * modify it under the terms of the GNU General Public License
 12 * as published by the Free Software Foundation; either version 2
 13 * of the License, or any later version.
 14 *
 15 * This program is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18 * GNU General Public License for more details.
 19 *
 20 * You should have received a copy of the GNU General Public License
 21 * along with this program; if not, write to the Free Software
 22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 23 */
 24
 25package org.gjt.sp.jedit.gui;
 26
 27//{{{ Imports
 28import javax.swing.border.*;
 29import javax.swing.text.Segment;
 30import javax.swing.*;
 31import java.awt.event.*;
 32import java.awt.*;
 33import java.util.StringTokenizer;
 34import org.gjt.sp.jedit.io.*;
 35import org.gjt.sp.jedit.textarea.*;
 36import org.gjt.sp.jedit.*;
 37import org.gjt.sp.jedit.gui.statusbar.StatusWidgetFactory;
 38import org.gjt.sp.jedit.gui.statusbar.Widget;
 39import org.gjt.sp.jedit.gui.statusbar.ToolTipLabel;
 40import org.gjt.sp.util.*;
 41//}}}
 42
 43/**
 44 * The status bar used to display various information to the user.<p>
 45 *
 46 * Currently, it is used for the following:
 47 * <ul>
 48 * <li>Displaying caret position information
 49 * <li>Displaying {@link InputHandler#readNextChar(String,String)} prompts
 50 * <li>Displaying {@link #setMessage(String)} messages
 51 * <li>Displaying I/O progress
 52 * <li>Displaying various editor settings
 53 * <li>Displaying memory status
 54 * </ul>
 55 *
 56 * @version $Id: StatusBar.java 17443 2010-03-09 19:53:40Z kpouer $
 57 * @author Slava Pestov
 58 * @since jEdit 3.2pre2
 59 */
 60public class StatusBar extends JPanel implements WorkThreadProgressListener
 61{
 62	//{{{ StatusBar constructor
 63	public StatusBar(View view)
 64	{
 65		super(new BorderLayout());
 66		setName("StatusBar");
 67		setBorder(new CompoundBorder(new EmptyBorder(4,0,0,
 68			(OperatingSystem.isMacOS() ? 18 : 0)),
 69			UIManager.getBorder("TextField.border")));
 70
 71		this.view = view;
 72
 73		panel = new JPanel(new BorderLayout());
 74		box = new Box(BoxLayout.X_AXIS);
 75		panel.add(BorderLayout.EAST,box);
 76		add(BorderLayout.CENTER,panel);
 77
 78		MouseHandler mouseHandler = new MouseHandler();
 79
 80		caretStatus = new ToolTipLabel();
 81		caretStatus.setName("caretStatus");
 82		caretStatus.setToolTipText(jEdit.getProperty("view.status.caret-tooltip"));
 83		caretStatus.addMouseListener(mouseHandler);
 84
 85		message = new JLabel(" ");
 86		setMessageComponent(message);
 87
 88		modeWidget = _getWidget("mode");
 89		foldWidget = _getWidget("fold");
 90		encodingWidget = _getWidget("encoding");
 91		wrapWidget = _getWidget("wrap");
 92		multiSelectWidget = _getWidget("multiSelect");
 93		rectSelectWidget = _getWidget("rectSelect");
 94		overwriteWidget = _getWidget("overwrite");
 95		lineSepWidget = _getWidget("lineSep");
 96	} //}}}
 97
 98	//{{{ propertiesChanged() method
 99	public void propertiesChanged()
100	{
101		Color fg = jEdit.getColorProperty("view.status.foreground");
102		Color bg = jEdit.getColorProperty("view.status.background");
103
104		showCaretStatus = jEdit.getBooleanProperty("view.status.show-caret-status");
105
106		panel.setBackground(bg);
107		panel.setForeground(fg);
108		caretStatus.setBackground(bg);
109		caretStatus.setForeground(fg);
110		message.setBackground(bg);
111		message.setForeground(fg);
112
113		// retarded GTK look and feel!
114		Font font = new JLabel().getFont();
115		//UIManager.getFont("Label.font");
116		FontMetrics fm = getFontMetrics(font);
117
118		if (showCaretStatus)
119		{
120			panel.add(BorderLayout.WEST,caretStatus);
121
122			caretStatus.setFont(font);
123
124			Dimension dim = new Dimension(fm.stringWidth(caretTestStr),
125					fm.getHeight());
126			caretStatus.setPreferredSize(dim);
127			updateCaretStatus();
128		}
129		else
130			panel.remove(caretStatus);
131
132		String statusBar = jEdit.getProperty("view.status");
133		if (!StandardUtilities.objectsEqual(currentBar, statusBar))
134		{
135			box.removeAll();
136			StringTokenizer tokenizer = new StringTokenizer(statusBar);
137			while (tokenizer.hasMoreTokens())
138			{
139				String token = tokenizer.nextToken();
140				if (Character.isLetter(token.charAt(0)))
141				{
142					Widget widget = getWidget(token);
143					if (widget == null)
144					{
145						JLabel label = new JLabel(token);
146						label.setBackground(bg);
147						label.setForeground(fg);
148						box.add(label);
149						continue;
150					}
151					Component c = widget.getComponent();
152					c.setBackground(bg);
153					c.setForeground(fg);
154					box.add(c);
155					widget.update();
156					widget.propertiesChanged();
157				}
158				else
159				{
160					JLabel label = new JLabel(token);
161					label.setBackground(bg);
162					label.setForeground(fg);
163					box.add(label);
164				}
165			}
166			currentBar = statusBar;
167		}
168		updateBufferStatus();
169		updateMiscStatus();
170	} //}}}
171
172	//{{{ addNotify() method
173	@Override
174	public void addNotify()
175	{
176		super.addNotify();
177		VFSManager.getIOThreadPool().addProgressListener(this);
178	} //}}}
179
180	//{{{ removeNotify() method
181	@Override
182	public void removeNotify()
183	{
184		super.removeNotify();
185		VFSManager.getIOThreadPool().removeProgressListener(this);
186	} //}}}
187
188	//{{{ WorkThreadListener implementation
189
190	//{{{ statusUpdate() method
191	public void statusUpdate(final WorkThreadPool threadPool, int threadIndex)
192	{
193		SwingUtilities.invokeLater(new Runnable()
194		{
195			public void run()
196			{
197				// don't obscure existing message
198				if(message != null && !"".equals(message.getText().trim())
199					&& !currentMessageIsIO)
200					return;
201
202				int requestCount = threadPool.getRequestCount();
203				if(requestCount == 0)
204				{
205					setMessageAndClear(jEdit.getProperty(
206						"view.status.io.done"));
207					currentMessageIsIO = true;
208				}
209				else if(requestCount == 1)
210				{
211					setMessage(jEdit.getProperty(
212						"view.status.io-1"));
213					currentMessageIsIO = true;
214				}
215				else
216				{
217					Object[] args = {requestCount};
218					setMessage(jEdit.getProperty(
219						"view.status.io",args));
220					currentMessageIsIO = true;
221				}
222			}
223		});
224	} //}}}
225
226	//{{{ progressUpdate() method
227	public void progressUpdate(WorkThreadPool threadPool, int threadIndex)
228	{
229	} //}}}
230
231	//}}}
232
233	//{{{ getMessage() method
234	/**
235	 * Returns the current message.
236	 *
237	 * @return the current message
238	 * @since jEdit 4.4pre1
239	 */
240	public String getMessage()
241	{
242		return message.getText();
243	} //}}}
244
245	//{{{ setMessageAndClear() method
246	/**
247	 * Show a message for a short period of time.
248	 * @param message The message
249	 * @since jEdit 3.2pre5
250	 */
251	public void setMessageAndClear(String message)
252	{
253		setMessage(message);
254
255		tempTimer = new Timer(0,new ActionListener()
256		{
257			public void actionPerformed(ActionEvent evt)
258			{
259				// so if view is closed in the meantime...
260				if(isShowing())
261					setMessage(null);
262			}
263		});
264
265		tempTimer.setInitialDelay(10000);
266		tempTimer.setRepeats(false);
267		tempTimer.start();
268	} //}}}
269
270	//{{{ setMessage() method
271	/**
272	 * Displays a status message.
273	 * @param message the message to display, it can be null
274	 */
275	public void setMessage(String message)
276	{
277		if(tempTimer != null)
278		{
279			tempTimer.stop();
280			tempTimer = null;
281		}
282
283		setMessageComponent(this.message);
284
285		if(message == null)
286		{
287			if(view.getMacroRecorder() != null)
288				this.message.setText(jEdit.getProperty("view.status.recording"));
289			else
290				this.message.setText(" ");
291		}
292		else
293			this.message.setText(message);
294	} //}}}
295
296	//{{{ setMessageComponent() method
297	public void setMessageComponent(Component comp)
298	{
299		currentMessageIsIO = false;
300
301		if (comp == null || messageComp == comp)
302		{
303			return;
304		}
305
306		messageComp = comp;
307		panel.add(BorderLayout.CENTER, messageComp);
308	} //}}}
309
310	//{{{ updateCaretStatus() method
311	public void updateCaretStatus()
312	{
313		if (showCaretStatus)
314		{
315			Buffer buffer = view.getBuffer();
316
317			if(!buffer.isLoaded() ||
318				/* can happen when switching buffers sometimes */
319				buffer != view.getTextArea().getBuffer())
320			{
321				caretStatus.setText(" ");
322				return;
323			}
324
325			JEditTextArea textArea = view.getTextArea();
326
327			int caretPosition = textArea.getCaretPosition();
328			int currLine = textArea.getCaretLine();
329
330			// there must be a better way of fixing this...
331			// the problem is that this method can sometimes
332			// be called as a result of a text area scroll
333			// event, in which case the caret position has
334			// not been updated yet.
335			if(currLine >= buffer.getLineCount())
336				return; // hopefully another caret update will come?
337
338			int start = textArea.getLineStartOffset(currLine);
339			int dot = caretPosition - start;
340
341			if(dot < 0)
342				return;
343
344			int bufferLength = buffer.getLength();
345
346			buffer.getText(start,dot,seg);
347			int virtualPosition = StandardUtilities.getVirtualWidth(seg,
348				buffer.getTabSize());
349			// for GC
350			seg.array = null;
351			seg.count = 0;
352
353			if (jEdit.getBooleanProperty("view.status.show-caret-linenumber", true))
354			{
355				buf.append(currLine + 1);
356				buf.append(',');
357			}
358			if (jEdit.getBooleanProperty("view.status.show-caret-dot", true))
359			{
360				buf.append(dot + 1);
361			}
362			if (jEdit.getBooleanProperty("view.status.show-caret-virtual", true) &&
363				virtualPosition != dot)
364			{
365				buf.append('-');
366				buf.append(virtualPosition + 1);
367			}
368			if (buf.length() > 0)
369			{
370				buf.append(' ');
371			}
372			if (jEdit.getBooleanProperty("view.status.show-caret-offset", true) &&
373				jEdit.getBooleanProperty("view.status.show-caret-bufferlength", true))
374			{
375				buf.append('(');
376				buf.append(caretPosition);
377				buf.append('/');
378				buf.append(bufferLength);
379				buf.append(')');
380			}
381			else if (jEdit.getBooleanProperty("view.status.show-caret-offset", true))
382			{
383				buf.append('(');
384				buf.append(caretPosition);
385				buf.append(')');
386			}
387			else if (jEdit.getBooleanProperty("view.status.show-caret-bufferlength", true))
388			{
389				buf.append('(');
390				buf.append(bufferLength);
391				buf.append(')');
392			}
393
394			caretStatus.setText(buf.toString());
395			buf.setLength(0);
396		}
397	} //}}}
398
399	//{{{ updateBufferStatus() method
400	public void updateBufferStatus()
401	{
402		wrapWidget.update();
403		lineSepWidget.update();
404		modeWidget.update();
405		foldWidget.update();
406		encodingWidget.update();
407	} //}}}
408
409	//{{{ updateMiscStatus() method
410	public void updateMiscStatus()
411	{
412		multiSelectWidget.update();
413		rectSelectWidget.update();
414		overwriteWidget.update();
415	} //}}}
416
417	//{{{ Private members
418	private String currentBar;
419	private final View view;
420	private final JPanel panel;
421	private final Box box;
422	private final ToolTipLabel caretStatus;
423	private Component messageComp;
424	private final JLabel message;
425	private final Widget modeWidget;
426	private final Widget foldWidget;
427	private final Widget encodingWidget;
428	private final Widget wrapWidget;
429	private final Widget multiSelectWidget;
430	private final Widget rectSelectWidget;
431	private final Widget overwriteWidget;
432	private final Widget lineSepWidget;
433	/* package-private for speed */ StringBuilder buf = new StringBuilder();
434	private Timer tempTimer;
435	private boolean currentMessageIsIO;
436
437	private final Segment seg = new Segment();
438
439	private boolean showCaretStatus;
440	//}}}
441
442	static final String caretTestStr = "9999,999-999 (99999999/99999999)";
443
444	//{{{ getWidget() method
445	private Widget getWidget(String name)
446	{
447		if ("mode".equals(name))
448			return modeWidget;
449		if ("fold".equals(name))
450			return foldWidget;
451		if ("encoding".equals(name))
452			return encodingWidget;
453		if ("wrap".equals(name))
454			return wrapWidget;
455		if ("multiSelect".equals(name))
456			return multiSelectWidget;
457		if ("rectSelect".equals(name))
458			return rectSelectWidget;
459		if ("overwrite".equals(name))
460			return overwriteWidget;
461		if ("lineSep".equals(name))
462			return lineSepWidget;
463
464		return _getWidget(name);
465	} //}}}
466
467	//{{{ _getWidget() method
468	private Widget _getWidget(String name)
469	{
470		StatusWidgetFactory widgetFactory =
471		(StatusWidgetFactory) ServiceManager.getService("org.gjt.sp.jedit.gui.statusbar.StatusWidget", name);
472		if (widgetFactory == null)
473		{
474			return null;
475		}
476		return widgetFactory.getWidget(view);
477	} //}}}
478
479	//{{{ MouseHandler class
480	private class MouseHandler extends MouseAdapter
481	{
482		@Override
483		public void mouseClicked(MouseEvent evt)
484		{
485			Object source = evt.getSource();
486			if(source == caretStatus && evt.getClickCount() == 2)
487			{
488				view.getTextArea().showGoToLineDialog();
489			}
490		}
491	} //}}}
492}