001: /*
002: * Sun Public License Notice
003: *
004: * The contents of this file are subject to the Sun Public License
005: * Version 1.0 (the "License"). You may not use this file except in
006: * compliance with the License. A copy of the License is available at
007: * http://www.sun.com/
008: *
009: * The Original Code is NetBeans. The Initial Developer of the Original
010: * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
011: * Microsystems, Inc. All Rights Reserved.
012: */
013:
014: package org.netbeans.editor;
015:
016: import java.awt.Dimension;
017: import java.awt.Font;
018: import java.awt.FontMetrics;
019: import java.awt.GridBagConstraints;
020: import java.awt.GridBagLayout;
021: import java.awt.Insets;
022: import java.awt.event.ActionEvent;
023: import java.awt.event.ActionListener;
024: import java.beans.PropertyChangeEvent;
025: import java.beans.PropertyChangeListener;
026: import java.util.ArrayList;
027: import java.util.Iterator;
028: import java.util.List;
029:
030: import javax.swing.BorderFactory;
031: import javax.swing.JLabel;
032: import javax.swing.JPanel;
033: import javax.swing.SwingConstants;
034: import javax.swing.SwingUtilities;
035: import javax.swing.Timer;
036: import javax.swing.border.BevelBorder;
037: import javax.swing.border.Border;
038: import javax.swing.event.ChangeEvent;
039: import javax.swing.event.ChangeListener;
040: import javax.swing.text.Caret;
041: import javax.swing.text.JTextComponent;
042:
043: /**
044: * Status bar support
045: *
046: * @author Miloslav Metelka
047: * @version 1.00
048: */
049:
050: public class StatusBar implements PropertyChangeListener,
051: SettingsChangeListener {
052:
053: public static final String CELL_MAIN = "main"; // NOI18N
054:
055: public static final String CELL_POSITION = "position"; // NOI18N
056:
057: public static final String CELL_TYPING_MODE = "typing-mode"; // NOI18N
058:
059: public static final String INSERT_LOCALE = "status-bar-insert"; // NOI18N
060:
061: public static final String OVERWRITE_LOCALE = "status-bar-overwrite"; // NOI18N
062:
063: private static final String[] POS_MAX_STRINGS = new String[] { "99999:999" }; // NOI18N
064:
065: private static final Insets NULL_INSETS = new Insets(0, 0, 0, 0);
066:
067: static final Border CELL_BORDER = BorderFactory
068: .createCompoundBorder(BorderFactory
069: .createBevelBorder(BevelBorder.LOWERED),
070: BorderFactory.createEmptyBorder(0, 2, 0, 2));
071:
072: protected EditorUI editorUI;
073:
074: /** The status bar panel into which the cells are added. */
075: private JPanel panel;
076:
077: private boolean visible;
078:
079: private Coloring coloring;
080:
081: private Coloring boldColoring;
082:
083: private List cellList = new ArrayList();
084:
085: private Caret caret;
086:
087: private CaretListener caretL;
088:
089: private int caretDelay;
090:
091: private boolean overwriteModeDisplayed;
092:
093: private String insText;
094:
095: private String ovrText;
096:
097: static final long serialVersionUID = -6266183959929157349L;
098:
099: public StatusBar(EditorUI editorUI) {
100: this .editorUI = editorUI;
101:
102: caretDelay = 10;
103: caretL = new CaretListener(caretDelay);
104: insText = LocaleSupport.getString(INSERT_LOCALE);
105: ovrText = LocaleSupport.getString(OVERWRITE_LOCALE);
106:
107: Settings.addSettingsChangeListener(this );
108:
109: synchronized (editorUI.getComponentLock()) {
110: // if component already installed in EditorUI simulate installation
111: JTextComponent component = editorUI.getComponent();
112: if (component != null) {
113: propertyChange(new PropertyChangeEvent(editorUI,
114: EditorUI.COMPONENT_PROPERTY, null, component));
115: }
116:
117: editorUI.addPropertyChangeListener(this );
118: }
119: }
120:
121: public void settingsChange(SettingsChangeEvent evt) {
122: Class kitClass = Utilities.getKitClass(editorUI.getComponent());
123: String settingName = (evt != null) ? evt.getSettingName()
124: : null;
125: if (kitClass != null) {
126: Coloring dc = editorUI.getDefaultColoring();
127: coloring = editorUI
128: .getColoring(SettingsNames.STATUS_BAR_COLORING);
129: boldColoring = editorUI
130: .getColoring(SettingsNames.STATUS_BAR_BOLD_COLORING);
131:
132: // assign coloring
133: if (coloring != null) {
134: coloring = coloring.apply(dc);
135: } else {
136: coloring = dc;
137: }
138:
139: // assign bold coloring
140: if (boldColoring != null) {
141: boldColoring = boldColoring.apply(dc);
142: } else {
143: boldColoring = dc;
144: }
145:
146: refreshPanel();
147:
148: if (settingName == null
149: || SettingsNames.STATUS_BAR_CARET_DELAY
150: .equals(settingName)) {
151: caretDelay = SettingsUtil.getInteger(kitClass,
152: SettingsNames.STATUS_BAR_CARET_DELAY,
153: SettingsDefaults.defaultStatusBarCaretDelay);
154: if (caretL != null) {
155: caretL.setDelay(caretDelay);
156: }
157: }
158:
159: if (settingName == null
160: || SettingsNames.STATUS_BAR_VISIBLE
161: .equals(settingName)) {
162: boolean wantVisible = SettingsUtil.getBoolean(kitClass,
163: SettingsNames.STATUS_BAR_VISIBLE,
164: SettingsDefaults.defaultStatusBarVisible);
165: setVisible(wantVisible);
166: }
167:
168: }
169: }
170:
171: protected JPanel createPanel() {
172: return new JPanel(new GridBagLayout());
173: }
174:
175: public boolean isVisible() {
176: return visible;
177: }
178:
179: public void setVisible(boolean v) {
180: if (v != visible) {
181: visible = v;
182:
183: if (panel != null || visible) {
184: if (visible) { // need to refresh first
185: refreshPanel();
186: }
187: // fix for issue 13842
188: if (SwingUtilities.isEventDispatchThread()) {
189: getPanel().setVisible(visible);
190: } else {
191: SwingUtilities.invokeLater(new Runnable() {
192: public void run() {
193: getPanel().setVisible(visible);
194: }
195: });
196: }
197: }
198: }
199: }
200:
201: public final JPanel getPanel() {
202: if (panel == null) {
203: panel = createPanel();
204: initPanel();
205: }
206: return panel;
207: }
208:
209: protected void initPanel() {
210: addCell(CELL_POSITION, POS_MAX_STRINGS).setHorizontalAlignment(
211: SwingConstants.CENTER);
212: addCell(CELL_TYPING_MODE, new String[] { insText, ovrText })
213: .setHorizontalAlignment(SwingConstants.CENTER);
214: setText(CELL_TYPING_MODE, insText);
215: addCell(CELL_MAIN, null);
216: }
217:
218: public void propertyChange(PropertyChangeEvent evt) {
219: String propName = evt.getPropertyName();
220:
221: if (EditorUI.COMPONENT_PROPERTY.equals(propName)) {
222: JTextComponent component = (JTextComponent) evt
223: .getNewValue();
224: if (component != null) { // just installed
225: component.addPropertyChangeListener(this );
226:
227: caret = component.getCaret();
228: if (caret != null) {
229: caret.addChangeListener(caretL);
230: }
231:
232: settingsChange(null);
233: refreshPanel();
234:
235: } else { // just deinstalled
236: component = (JTextComponent) evt.getOldValue();
237:
238: component.removePropertyChangeListener(this );
239:
240: caret = component.getCaret();
241: if (caret != null) {
242: caret.removeChangeListener(caretL);
243: }
244:
245: }
246:
247: } else if ("caret".equals(propName)) {
248: if (caret != null) {
249: caret.removeChangeListener(caretL);
250: }
251:
252: caret = (Caret) evt.getNewValue();
253: if (caret != null) {
254: caret.addChangeListener(caretL);
255: }
256: }
257:
258: // Refresh the panel after each property-change
259: if (EditorUI.OVERWRITE_MODE_PROPERTY.equals(propName)) {
260: caretL.actionPerformed(null); // refresh immediately
261:
262: } else { // not overwrite mode change
263: caretL.stateChanged(null);
264: }
265: }
266:
267: private void applyColoring() {
268: }
269:
270: public int getCellCount() {
271: return cellList.size();
272: }
273:
274: public JLabel addCell(String name, String[] widestStrings) {
275: return addCell(-1, name, widestStrings);
276: }
277:
278: public JLabel addCell(int i, String name, String[] widestStrings) {
279: Cell c = new Cell(name, widestStrings);
280: addCellImpl(i, c);
281: return c;
282: }
283:
284: public void addCustomCell(int i, JLabel c) {
285: addCellImpl(i, c);
286: }
287:
288: private void addCellImpl(int i, JLabel c) {
289: synchronized (cellList) {
290: ArrayList newCellList = new ArrayList(cellList);
291: int cnt = newCellList.size();
292: if (i < 0 || i > cnt) {
293: i = cnt;
294: }
295: newCellList.add(i, c);
296:
297: cellList = newCellList;
298: }
299:
300: refreshPanel();
301: }
302:
303: public JLabel getCellByName(String name) {
304: Iterator i = cellList.iterator();
305: while (i.hasNext()) {
306: JLabel c = (JLabel) i.next();
307: if (name.equals(c.getName())) {
308: return c;
309: }
310: }
311: return null;
312: }
313:
314: public String getText(String cellName) {
315: JLabel cell = getCellByName(cellName);
316: return (cell != null) ? cell.getText() : null;
317: }
318:
319: public void setText(String cellName, String text) {
320: setText(cellName, text, null);
321: }
322:
323: public void setBoldText(String cellName, String text) {
324: setText(cellName, text, boldColoring);
325: }
326:
327: public void setText(String cellName, String text,
328: Coloring extraColoring) {
329: JLabel cell = getCellByName(cellName);
330: if (cell != null) {
331: Coloring c = coloring;
332: if (extraColoring != null) {
333: c = extraColoring.apply(c);
334: }
335: c.apply(cell);
336: cell.setText(text);
337: }
338: }
339:
340: /*
341: * Refresh the whole panel by removing all the components and adding only
342: * those that appear in the cell-list.
343: */
344: private void refreshPanel() {
345: SwingUtilities.invokeLater(new Runnable() {
346: public void run() {
347: if (isVisible()) { // refresh only if visible
348: // Apply coloring to all cells
349: Iterator it = cellList.iterator();
350: while (it.hasNext()) {
351: JLabel c = (JLabel) it.next();
352: if (c instanceof Cell) {
353: coloring.apply(c);
354: }
355: }
356:
357: // Layout cells
358: GridBagConstraints gc = new GridBagConstraints();
359: gc.gridx = GridBagConstraints.RELATIVE;
360: gc.gridwidth = 1;
361: gc.gridheight = 1;
362:
363: it = cellList.iterator();
364: while (it.hasNext()) {
365: JLabel c = (JLabel) it.next();
366: boolean main = CELL_MAIN.equals(c.getName());
367: if (main) {
368: gc.fill = GridBagConstraints.HORIZONTAL;
369: gc.weightx = 1.0;
370: }
371: getPanel().add(c, gc);
372: if (main) {
373: gc.fill = GridBagConstraints.NONE;
374: gc.weightx = 0;
375: }
376: }
377: }
378: }
379: });
380: }
381:
382: class CaretListener implements ChangeListener, ActionListener {
383:
384: Timer timer;
385:
386: CaretListener(int delay) {
387: timer = new Timer(delay, new WeakTimerListener(this ));
388: timer.setRepeats(false);
389: }
390:
391: void setDelay(int delay) {
392: timer.setInitialDelay(delay);
393: }
394:
395: public void stateChanged(ChangeEvent evt) {
396: timer.restart();
397: }
398:
399: public void actionPerformed(ActionEvent evt) {
400: Caret c = caret;
401: JTextComponent component = editorUI.getComponent();
402:
403: if (component != null) {
404: if (c != null) {
405: BaseDocument doc = Utilities.getDocument(editorUI
406: .getComponent());
407: if (doc != null) {
408: int pos = c.getDot();
409: String s = Utilities.debugPosition(doc, pos);
410: setText(CELL_POSITION, s);
411: }
412: }
413:
414: Boolean b = (Boolean) editorUI
415: .getProperty(EditorUI.OVERWRITE_MODE_PROPERTY);
416: boolean om = (b != null && b.booleanValue());
417: if (om != overwriteModeDisplayed) {
418: overwriteModeDisplayed = om;
419: setText(CELL_TYPING_MODE,
420: overwriteModeDisplayed ? ovrText : insText);
421: }
422: }
423: }
424:
425: }
426:
427: static class Cell extends JLabel {
428:
429: Dimension maxDimension;
430:
431: String[] widestStrings;
432:
433: static final long serialVersionUID = -2554600362177165648L;
434:
435: Cell(String name, String[] widestStrings) {
436: setName(name);
437: setBorder(CELL_BORDER);
438: setOpaque(true);
439: this .widestStrings = widestStrings;
440: }
441:
442: private void updateSize() {
443: Font f = getFont();
444: if (maxDimension == null) {
445: maxDimension = new Dimension();
446: }
447: if (f != null) {
448: Border b = getBorder();
449: Insets ins = (b != null) ? b.getBorderInsets(this )
450: : NULL_INSETS;
451: FontMetrics fm = getFontMetrics(f);
452: int mw = fm.stringWidth(this .getText());
453: maxDimension.height = fm.getHeight() + ins.top
454: + ins.bottom;
455: if (widestStrings != null) {
456: for (int i = 0; i < widestStrings.length; i++) {
457: mw = Math.max(mw, fm
458: .stringWidth(widestStrings[i]));
459: }
460: }
461: maxDimension.width = mw + ins.left + ins.right;
462: }
463: }
464:
465: public Dimension getPreferredSize() {
466: if (maxDimension == null) {
467: maxDimension = new Dimension();
468: }
469: return new Dimension(maxDimension);
470: }
471:
472: public void setFont(Font f) {
473: super.setFont(f);
474: updateSize();
475: }
476:
477: }
478:
479: }
|