/jEdit/tags/jedit-4-3-pre14/org/gjt/sp/jedit/gui/StatusBar.java

# · Java · 497 lines · 354 code · 59 blank · 84 comment · 53 complexity · f99285bf5692de8d0e2202b7c2c58572 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. package org.gjt.sp.jedit.gui;
  25. //{{{ Imports
  26. import javax.swing.border.*;
  27. import javax.swing.text.Segment;
  28. import javax.swing.*;
  29. import java.awt.event.*;
  30. import java.awt.font.*;
  31. import java.awt.geom.*;
  32. import java.awt.*;
  33. import java.text.*;
  34. import java.util.StringTokenizer;
  35. import org.gjt.sp.jedit.io.*;
  36. import org.gjt.sp.jedit.textarea.*;
  37. import org.gjt.sp.jedit.*;
  38. import org.gjt.sp.jedit.gui.statusbar.StatusWidgetFactory;
  39. import org.gjt.sp.jedit.gui.statusbar.Widget;
  40. import org.gjt.sp.util.*;
  41. //}}}
  42. /**
  43. * The status bar used to display various information to the user.<p>
  44. *
  45. * Currently, it is used for the following:
  46. * <ul>
  47. * <li>Displaying caret position information
  48. * <li>Displaying {@link InputHandler#readNextChar(String,String)} prompts
  49. * <li>Displaying {@link #setMessage(String)} messages
  50. * <li>Displaying I/O progress
  51. * <li>Displaying various editor settings
  52. * <li>Displaying memory status
  53. * </ul>
  54. *
  55. * @version $Id: StatusBar.java 12504 2008-04-22 23:12:43Z ezust $
  56. * @author Slava Pestov
  57. * @since jEdit 3.2pre2
  58. */
  59. public class StatusBar extends JPanel implements WorkThreadProgressListener
  60. {
  61. //{{{ StatusBar constructor
  62. public StatusBar(View view)
  63. {
  64. super(new BorderLayout());
  65. setBorder(new CompoundBorder(new EmptyBorder(4,0,0,
  66. (OperatingSystem.isMacOS() ? 18 : 0)),
  67. UIManager.getBorder("TextField.border")));
  68. this.view = view;
  69. panel = new JPanel(new BorderLayout());
  70. box = new Box(BoxLayout.X_AXIS);
  71. panel.add(BorderLayout.EAST,box);
  72. add(BorderLayout.CENTER,panel);
  73. MouseHandler mouseHandler = new MouseHandler();
  74. caretStatus = new ToolTipLabel();
  75. caretStatus.setToolTipText(jEdit.getProperty("view.status.caret-tooltip"));
  76. caretStatus.addMouseListener(mouseHandler);
  77. message = new JLabel(" ");
  78. setMessageComponent(message);
  79. modeWidget = _getWidget("mode");
  80. foldWidget = _getWidget("fold");
  81. encodingWidget = _getWidget("encoding");
  82. wrapWidget = _getWidget("wrap");
  83. multiSelectWidget = _getWidget("multiSelect");
  84. rectSelectWidget = _getWidget("rectSelect");
  85. overwriteWidget = _getWidget("overwrite");
  86. lineSepWidget = _getWidget("lineSep");
  87. } //}}}
  88. //{{{ propertiesChanged() method
  89. public void propertiesChanged()
  90. {
  91. Color fg = jEdit.getColorProperty("view.status.foreground");
  92. Color bg = jEdit.getColorProperty("view.status.background");
  93. showCaretStatus = jEdit.getBooleanProperty("view.status.show-caret-status");
  94. showEditMode = jEdit.getBooleanProperty("view.status.show-edit-mode");
  95. showFoldMode = jEdit.getBooleanProperty("view.status.show-fold-mode");
  96. showEncoding = jEdit.getBooleanProperty("view.status.show-encoding");
  97. showWrap = jEdit.getBooleanProperty("view.status.show-wrap");
  98. showMultiSelect = jEdit.getBooleanProperty("view.status.show-multi-select");
  99. showRectSelect = jEdit.getBooleanProperty("view.status.show-rect-select");
  100. showOverwrite = jEdit.getBooleanProperty("view.status.show-overwrite");
  101. showLineSeperator = jEdit.getBooleanProperty("view.status.show-line-seperator");
  102. boolean showMemory = jEdit.getBooleanProperty("view.status.show-memory");
  103. boolean showClock = jEdit.getBooleanProperty("view.status.show-clock");
  104. panel.setBackground(bg);
  105. panel.setForeground(fg);
  106. caretStatus.setBackground(bg);
  107. caretStatus.setForeground(fg);
  108. message.setBackground(bg);
  109. message.setForeground(fg);
  110. // retarded GTK look and feel!
  111. Font font = new JLabel().getFont();
  112. //UIManager.getFont("Label.font");
  113. FontMetrics fm = getFontMetrics(font);
  114. Dimension dim;
  115. if (showCaretStatus)
  116. {
  117. panel.add(BorderLayout.WEST,caretStatus);
  118. caretStatus.setFont(font);
  119. dim = new Dimension(fm.stringWidth(caretTestStr),
  120. fm.getHeight());
  121. caretStatus.setPreferredSize(dim);
  122. }
  123. else
  124. panel.remove(caretStatus);
  125. String statusBar = jEdit.getProperty("view.status");
  126. if (!StandardUtilities.objectsEqual(currentBar, statusBar))
  127. {
  128. box.removeAll();
  129. StringTokenizer tokenizer = new StringTokenizer(statusBar);
  130. while (tokenizer.hasMoreTokens())
  131. {
  132. String token = tokenizer.nextToken();
  133. if (Character.isLetter(token.charAt(0)))
  134. {
  135. Widget widget = getWidget(token);
  136. if (widget == null)
  137. {
  138. Log.log(Log.WARNING, this, "Widget " + token + " doesn't exists");
  139. continue;
  140. }
  141. Component c = widget.getComponent();
  142. c.setBackground(bg);
  143. c.setForeground(fg);
  144. box.add(c);
  145. widget.update();
  146. widget.propertiesChanged();
  147. }
  148. else
  149. {
  150. box.add(new JLabel(token));
  151. }
  152. }
  153. currentBar = statusBar;
  154. }
  155. updateBufferStatus();
  156. updateMiscStatus();
  157. } //}}}
  158. //{{{ addNotify() method
  159. @Override
  160. public void addNotify()
  161. {
  162. super.addNotify();
  163. VFSManager.getIOThreadPool().addProgressListener(this);
  164. } //}}}
  165. //{{{ removeNotify() method
  166. @Override
  167. public void removeNotify()
  168. {
  169. super.removeNotify();
  170. VFSManager.getIOThreadPool().removeProgressListener(this);
  171. } //}}}
  172. //{{{ WorkThreadListener implementation
  173. //{{{ statusUpdate() method
  174. public void statusUpdate(final WorkThreadPool threadPool, int threadIndex)
  175. {
  176. SwingUtilities.invokeLater(new Runnable()
  177. {
  178. public void run()
  179. {
  180. // don't obscure existing message
  181. if(message != null && !"".equals(message.getText().trim())
  182. && !currentMessageIsIO)
  183. return;
  184. int requestCount = threadPool.getRequestCount();
  185. if(requestCount == 0)
  186. {
  187. setMessageAndClear(jEdit.getProperty(
  188. "view.status.io.done"));
  189. currentMessageIsIO = true;
  190. }
  191. else if(requestCount == 1)
  192. {
  193. setMessage(jEdit.getProperty(
  194. "view.status.io-1"));
  195. currentMessageIsIO = true;
  196. }
  197. else
  198. {
  199. Object[] args = {Integer.valueOf(requestCount)};
  200. setMessage(jEdit.getProperty(
  201. "view.status.io",args));
  202. currentMessageIsIO = true;
  203. }
  204. }
  205. });
  206. } //}}}
  207. //{{{ progressUpdate() method
  208. public void progressUpdate(WorkThreadPool threadPool, int threadIndex)
  209. {
  210. } //}}}
  211. //}}}
  212. //{{{ setMessageAndClear() method
  213. /**
  214. * Show a message for a short period of time.
  215. * @param message The message
  216. * @since jEdit 3.2pre5
  217. */
  218. public void setMessageAndClear(String message)
  219. {
  220. setMessage(message);
  221. tempTimer = new Timer(0,new ActionListener()
  222. {
  223. public void actionPerformed(ActionEvent evt)
  224. {
  225. // so if view is closed in the meantime...
  226. if(isShowing())
  227. setMessage(null);
  228. }
  229. });
  230. tempTimer.setInitialDelay(10000);
  231. tempTimer.setRepeats(false);
  232. tempTimer.start();
  233. } //}}}
  234. //{{{ setMessage() method
  235. /**
  236. * Displays a status message.
  237. */
  238. public void setMessage(String message)
  239. {
  240. if(tempTimer != null)
  241. {
  242. tempTimer.stop();
  243. tempTimer = null;
  244. }
  245. setMessageComponent(this.message);
  246. if(message == null)
  247. {
  248. if(view.getMacroRecorder() != null)
  249. this.message.setText(jEdit.getProperty("view.status.recording"));
  250. else
  251. this.message.setText(" ");
  252. }
  253. else
  254. this.message.setText(message);
  255. } //}}}
  256. //{{{ setMessageComponent() method
  257. public void setMessageComponent(Component comp)
  258. {
  259. currentMessageIsIO = false;
  260. if (comp == null || messageComp == comp)
  261. {
  262. return;
  263. }
  264. messageComp = comp;
  265. panel.add(BorderLayout.CENTER, messageComp);
  266. } //}}}
  267. //{{{ updateCaretStatus() method
  268. public void updateCaretStatus()
  269. {
  270. //if(!isShowing())
  271. // return;
  272. if (showCaretStatus)
  273. {
  274. Buffer buffer = view.getBuffer();
  275. if(!buffer.isLoaded() ||
  276. /* can happen when switching buffers sometimes */
  277. buffer != view.getTextArea().getBuffer())
  278. {
  279. caretStatus.setText(" ");
  280. return;
  281. }
  282. JEditTextArea textArea = view.getTextArea();
  283. int currLine = textArea.getCaretLine();
  284. // there must be a better way of fixing this...
  285. // the problem is that this method can sometimes
  286. // be called as a result of a text area scroll
  287. // event, in which case the caret position has
  288. // not been updated yet.
  289. if(currLine >= buffer.getLineCount())
  290. return; // hopefully another caret update will come?
  291. int start = textArea.getLineStartOffset(currLine);
  292. int dot = textArea.getCaretPosition() - start;
  293. // see above
  294. if(dot < 0)
  295. return;
  296. buffer.getText(start,dot,seg);
  297. int virtualPosition = StandardUtilities.getVirtualWidth(seg,
  298. buffer.getTabSize());
  299. buf.setLength(0);
  300. buf.append(Integer.toString(currLine + 1));
  301. buf.append(',');
  302. buf.append(Integer.toString(dot + 1));
  303. if (virtualPosition != dot)
  304. {
  305. buf.append('-');
  306. buf.append(Integer.toString(virtualPosition + 1));
  307. }
  308. buf.append(' ');
  309. int firstLine = textArea.getFirstLine();
  310. int visible = textArea.getVisibleLines();
  311. int lineCount = textArea.getDisplayManager().getScrollLineCount();
  312. if (visible >= lineCount)
  313. {
  314. buf.append("All");
  315. }
  316. else if (firstLine == 0)
  317. {
  318. buf.append("Top");
  319. }
  320. else if (firstLine + visible >= lineCount)
  321. {
  322. buf.append("Bot");
  323. }
  324. else
  325. {
  326. float percent = (float)firstLine / (float)lineCount
  327. * 100.0f;
  328. buf.append(Integer.toString((int)percent));
  329. buf.append('%');
  330. }
  331. caretStatus.setText(buf.toString());
  332. }
  333. } //}}}
  334. //{{{ updateBufferStatus() method
  335. public void updateBufferStatus()
  336. {
  337. wrapWidget.update();
  338. lineSepWidget.update();
  339. modeWidget.update();
  340. foldWidget.update();
  341. encodingWidget.update();
  342. } //}}}
  343. //{{{ updateMiscStatus() method
  344. public void updateMiscStatus()
  345. {
  346. multiSelectWidget.update();
  347. rectSelectWidget.update();
  348. overwriteWidget.update();
  349. } //}}}
  350. //{{{ Private members
  351. private String currentBar;
  352. private View view;
  353. private JPanel panel;
  354. private Box box;
  355. private ToolTipLabel caretStatus;
  356. private Component messageComp;
  357. private JLabel message;
  358. private Widget modeWidget;
  359. private Widget foldWidget;
  360. private Widget encodingWidget;
  361. private Widget wrapWidget;
  362. private Widget multiSelectWidget;
  363. private Widget rectSelectWidget;
  364. private Widget overwriteWidget;
  365. private Widget lineSepWidget;
  366. /* package-private for speed */ StringBuilder buf = new StringBuilder();
  367. private Timer tempTimer;
  368. private boolean currentMessageIsIO;
  369. private Segment seg = new Segment();
  370. private boolean showCaretStatus;
  371. private boolean showEditMode;
  372. private boolean showFoldMode;
  373. private boolean showEncoding;
  374. private boolean showWrap;
  375. private boolean showMultiSelect;
  376. private boolean showRectSelect;
  377. private boolean showOverwrite;
  378. private boolean showLineSeperator;
  379. //}}}
  380. static final String caretTestStr = "9999,999-999 99%";
  381. //{{{ getWidget() method
  382. private Widget getWidget(String name)
  383. {
  384. if ("mode".equals(name))
  385. return modeWidget;
  386. if ("fold".equals(name))
  387. return foldWidget;
  388. if ("encoding".equals(name))
  389. return encodingWidget;
  390. if ("wrap".equals(name))
  391. return wrapWidget;
  392. if ("multiSelect".equals(name))
  393. return multiSelectWidget;
  394. if ("rectSelect".equals(name))
  395. return rectSelectWidget;
  396. if ("overwrite".equals(name))
  397. return overwriteWidget;
  398. if ("lineSep".equals(name))
  399. return lineSepWidget;
  400. return _getWidget(name);
  401. } //}}}
  402. //{{{ _getWidget() method
  403. private Widget _getWidget(String name)
  404. {
  405. StatusWidgetFactory widgetFactory =
  406. (StatusWidgetFactory) ServiceManager.getService("org.gjt.sp.jedit.gui.statusbar.StatusWidget", name);
  407. if (widgetFactory == null)
  408. {
  409. Log.log(Log.ERROR, this, "Widget " + name + " doesn't exists");
  410. return null;
  411. }
  412. return widgetFactory.getWidget(view);
  413. } //}}}
  414. //{{{ MouseHandler class
  415. class MouseHandler extends MouseAdapter
  416. {
  417. @Override
  418. public void mouseClicked(MouseEvent evt)
  419. {
  420. Object source = evt.getSource();
  421. if(source == caretStatus)
  422. {
  423. if(evt.getClickCount() == 2)
  424. view.getTextArea().showGoToLineDialog();
  425. }
  426. }
  427. } //}}}
  428. //{{{ ToolTipLabel class
  429. static class ToolTipLabel extends JLabel
  430. {
  431. //{{{ getToolTipLocation() method
  432. @Override
  433. public Point getToolTipLocation(MouseEvent event)
  434. {
  435. return new Point(event.getX(),-20);
  436. } //}}}
  437. } //}}}
  438. }