001: //The contents of this file are subject to the Mozilla Public License Version 1.1
002: //(the "License"); you may not use this file except in compliance with the
003: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
004: //
005: //Software distributed under the License is distributed on an "AS IS" basis,
006: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
007: //for the specific language governing rights and
008: //limitations under the License.
009: //
010: //The Original Code is "The Columba Project"
011: //
012: //The Initial Developers of the Original Code are Frederik Dietz and Timo Stich.
013: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
014: //
015: //All Rights Reserved.
016:
017: package org.columba.core.gui.statusbar;
018:
019: import java.awt.Component;
020: import java.awt.Insets;
021: import java.awt.event.ActionEvent;
022: import java.awt.event.ActionListener;
023:
024: import javax.swing.BorderFactory;
025: import javax.swing.Icon;
026: import javax.swing.JButton;
027: import javax.swing.JLabel;
028: import javax.swing.JProgressBar;
029: import javax.swing.Timer;
030: import javax.swing.event.ChangeEvent;
031: import javax.swing.event.ChangeListener;
032:
033: import org.columba.api.command.IWorkerStatusController;
034: import org.columba.api.statusbar.IStatusBar;
035: import org.columba.api.statusbar.IStatusBarExtension;
036: import org.columba.core.command.TaskManager;
037: import org.columba.core.command.TaskManagerEvent;
038: import org.columba.core.command.TaskManagerListener;
039: import org.columba.core.command.Worker;
040: import org.columba.core.connectionstate.ConnectionStateImpl;
041: import org.columba.core.gui.base.JStatusBar;
042: import org.columba.core.resourceloader.IconKeys;
043: import org.columba.core.resourceloader.ImageLoader;
044:
045: /**
046: * A status bar intended to be displayed at the bottom of each window.
047: * <p>
048: * Implementation notes:
049: * <p>
050: * An update timer is used to only update the statusbar, every xx seconds. As a
051: * nice side-effect, all swing method calls happen in the awt-event dispatcher
052: * thread automatically. If we don't do this, we have to wrap every swing method
053: * in a Runnable interface and execute it using SwingUtilities.invokeLater().
054: * <p>
055: * Note, that without an update timer, the statusbar text and most importantly
056: * the progressbar are updated very frequently, using very small updates. But,
057: * because these are called using invokeLater(), all have to be placed in the
058: * awt-event dispatcher queue. This makes things very slow. We discovered, when
059: * moving around 1000 messages and updating the progressbar for every message,
060: * it will take more time to update the statusbar than actually moving the
061: * messages.
062: * <p>
063: * There's another Timer, addWorkerTimer which makes sure that only Workers who
064: * are alive for at most 2000 ms will appear in the statusbar. This prevents the
065: * statusbar from flicker, caused by many smaller tasks which usually tend to
066: * hide the parent task. For example when downloaded POP3 messages and using
067: * filters which move message to different folders. Without the addWorkerTimer
068: * you would see all those little move tasks. Instead now, you only see the POP3
069: * tasks which is much more comfortable for the user.
070: * <p>
071: * There's yet another Timer ;-), clearTextTimer which automatically clears the
072: * statusbar after a delay of 2000 ms.
073: */
074: public class StatusBar extends JStatusBar implements
075: TaskManagerListener, ActionListener, ChangeListener, IStatusBar {
076:
077: /**
078: * update status every 10 ms
079: */
080: private static final int UPDATE_TIMER_INTERVAL = 10;
081:
082: /**
083: * Constant definining the delay used when using
084: * clearDisplayTextWithDelay(). Defined to be 2000 millisec.
085: */
086: private static final int CLEAR_TIMER_DELAY = 2000;
087:
088: /**
089: * time to wait until statusbar will show a tasks progress
090: */
091: private static final int ADDWORKER_TIMER_INTERVAL = 2000;
092:
093: protected static Icon onlineIcon = ImageLoader
094: .getSmallIcon(IconKeys.ONLINE);
095:
096: protected static Icon offlineIcon = ImageLoader
097: .getSmallIcon(IconKeys.OFFLINE);
098:
099: /**
100: * showing status messages
101: */
102: private JLabel label;
103:
104: /**
105: * showing progress info
106: */
107: private JProgressBar progressBar;
108:
109: /**
110: * button opening task manager dialog
111: */
112: //private JButton taskButton;
113: /**
114: * Currently displayed worker
115: */
116: private Worker displayedWorker;
117:
118: /**
119: * manager of all running tasks
120: */
121: private TaskManager taskManager;
122:
123: /**
124: * connection state button
125: */
126: private JButton onlineButton;
127:
128: /** Timer to use when clearing status bar text after a certain timeout */
129: private Timer clearTextTimer;
130:
131: /**
132: * Timer makes sure that statusbar is only updated every xx ms, to make that
133: * its not getting flooded with too many update notifications
134: */
135: private Timer updateTimer;
136:
137: private Timer addWorkerTimer;
138:
139: /**
140: * last displayed message
141: */
142: private String lastMessage;
143:
144: private TaskManagerEvent currentEvent;
145:
146: public StatusBar(TaskManager tm) {
147: super ();
148:
149: taskManager = tm;
150: tm.addTaskManagerListener(this );
151: ConnectionStateImpl.getInstance().addChangeListener(this );
152:
153: // setBorder(BorderFactory.createEmptyBorder(1, 2, 1, 2));
154:
155: initComponents();
156:
157: // layoutComponents();
158:
159: // update connection state
160: stateChanged(null);
161:
162: clearTextTimer = new Timer(CLEAR_TIMER_DELAY, this );
163:
164: // init update timer
165: updateTimer = new Timer(UPDATE_TIMER_INTERVAL, this );
166: // updateTimer.start();
167:
168: addWorkerTimer = new Timer(ADDWORKER_TIMER_INTERVAL, this );
169:
170: }
171:
172: /**
173: * init components
174: */
175: private void initComponents() {
176:
177: label = new JLabel("");
178: label.setAlignmentX(Component.LEFT_ALIGNMENT);
179:
180: onlineButton = new JButton();
181: onlineButton.setMargin(new Insets(0, 0, 0, 0));
182: onlineButton.setBorder(BorderFactory.createEmptyBorder(1, 1, 1,
183: 1));
184: onlineButton.setRolloverEnabled(true);
185: onlineButton.setActionCommand("ONLINE");
186: onlineButton.addActionListener(this );
187:
188: progressBar = new JProgressBar(0, 100);
189:
190: progressBar.setStringPainted(false);
191: progressBar.setBorderPainted(false);
192: progressBar.setValue(0);
193:
194: // taskButton = new JButton();
195: // taskButton.setIcon(ImageLoader.getImageIcon("group_small.png"));
196: // taskButton.setToolTipText("Show list of running tasks");
197: // taskButton.setRolloverEnabled(true);
198: // taskButton.setActionCommand("TASKMANAGER");
199: // taskButton.addActionListener(this);
200: //
201: // taskButton.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
202:
203: setMainLeftComponent(label);
204:
205: addRightComponent(progressBar, 100);
206: //addRightComponent(taskButton, 30);
207: addRightComponent(onlineButton, 30);
208: }
209:
210: public void addComponent(IStatusBarExtension ext) {
211: if (ext == null)
212: throw new IllegalArgumentException("extension == null");
213:
214: addRightComponent(ext.getView());
215: }
216:
217: /**
218: * layout components
219: */
220: // protected void layoutComponents() {
221: // setLayout(new BorderLayout());
222: //
223: // leftMainPanel = new JPanel();
224: // leftMainPanel.setLayout(new BorderLayout());
225: //
226: // JPanel taskPanel = new JPanel();
227: // taskPanel.setLayout(new BorderLayout());
228: //
229: // // Border border = getDefaultBorder();
230: // //Border margin = new EmptyBorder(0, 0, 0, 2);
231: //
232: // // taskPanel.setBorder(new CompoundBorder(border, margin));
233: //
234: // taskPanel.add(taskButton, BorderLayout.CENTER);
235: //
236: // leftMainPanel.add(taskPanel, BorderLayout.WEST);
237: // JPanel labelPanel = new JPanel();
238: // labelPanel.setLayout(new BorderLayout());
239: // // margin = new EmptyBorder(0, 10, 0, 10);
240: // // labelPanel.setBorder(new CompoundBorder(border, margin));
241: //
242: // // margin = new EmptyBorder(0, 0, 0, 2);
243: // labelPanel.add(label, BorderLayout.CENTER);
244: //
245: // leftMainPanel.add(labelPanel, BorderLayout.CENTER);
246: //
247: // add(leftMainPanel, BorderLayout.CENTER);
248: //
249: // mainRightPanel = new JPanel();
250: // mainRightPanel.setLayout(new BorderLayout());
251: //
252: // JPanel progressPanel = new JPanel();
253: // progressPanel.setLayout(new BorderLayout());
254: // // progressPanel.setBorder(new CompoundBorder(border, margin));
255: //
256: // progressPanel.add(progressBar, BorderLayout.CENTER);
257: //
258: // JPanel rightPanel = new JPanel();
259: // rightPanel.setLayout(new BorderLayout());
260: //
261: // rightPanel.add(progressPanel, BorderLayout.CENTER);
262: //
263: // JPanel onlinePanel = new JPanel();
264: // onlinePanel.setLayout(new BorderLayout());
265: // // onlinePanel.setBorder(new CompoundBorder(border, margin));
266: //
267: // onlinePanel.add(onlineButton, BorderLayout.CENTER);
268: //
269: // rightPanel.add(onlinePanel, BorderLayout.EAST);
270: // add(rightPanel, BorderLayout.EAST);
271: // }
272: // public Border getDefaultBorder() {
273: // return UIManager.getBorder("TableHeader.cellBorder");
274: // }
275: /**
276: * @see org.columba.api.statusbar.IStatusBar#displayTooltipMessage(java.lang.String)
277: */
278: public void displayTooltipMessage(String message) {
279: label.setText(message);
280: }
281:
282: public void workerAdded(TaskManagerEvent e) {
283:
284: if (getDisplayedWorker() == null) {
285:
286: currentEvent = e;
287:
288: if (taskManager.getWorkers().length == 1) {
289: setDisplayedWorker(currentEvent.getWorker());
290:
291: // update text and progress bar
292: updateTimer.restart();
293:
294: addWorkerTimer.stop();
295: } else {
296:
297: addWorkerTimer.restart();
298: }
299:
300: }
301: }
302:
303: public void workerRemoved(TaskManagerEvent e) {
304:
305: if (e.getWorker() == displayedWorker) {
306:
307: // remember last message
308: lastMessage = e.getWorker().getDisplayText();
309:
310: // immediately update text and progress bar
311: // updateGui();
312:
313: Worker[] workers = taskManager.getWorkers();
314: setDisplayedWorker(workers.length > 0 ? workers[0] : null);
315: }
316:
317: // if only one task left
318: if (taskManager.getWorkers().length == 0) {
319:
320: // stop update timer
321: updateTimer.stop();
322:
323: // set text
324: label.setText(lastMessage);
325:
326: // clear text with delay
327: clearTextTimer.restart();
328: }
329:
330: }
331:
332: public void actionPerformed(ActionEvent e) {
333: if (e.getSource() == updateTimer) {
334: // update timer event
335: updateGui();
336: return;
337: }
338:
339: if (e.getSource() == clearTextTimer) {
340:
341: // clear label
342: label.setText("");
343:
344: // stop clear timer
345: clearTextTimer.stop();
346:
347: return;
348: }
349:
350: if (e.getSource() == addWorkerTimer) {
351:
352: if (taskManager.exists(currentEvent.getWorker())) {
353:
354: setDisplayedWorker(currentEvent.getWorker());
355:
356: // update text and progress bar
357: updateTimer.restart();
358:
359: addWorkerTimer.stop();
360:
361: return;
362: } else {
363:
364: addWorkerTimer.stop();
365: return;
366: }
367: }
368:
369: String command = e.getActionCommand();
370:
371: if (command.equals("ONLINE")) {
372: ConnectionStateImpl.getInstance().setOnline(
373: !ConnectionStateImpl.getInstance().isOnline());
374: } else if (command.equals("TASKMANAGER")) {
375: TaskManagerDialog.createInstance();
376: } else if (command.equals("CANCEL_ACTION")) {
377: displayedWorker.cancel();
378: }
379: }
380:
381: /**
382: * Update statusbar with currently selected worker status.
383: * <p>
384: * Runs in awt-event dispatcher thread
385: */
386: private void updateGui() {
387: // System.out.println("update-gui");
388:
389: if (displayedWorker != null) {
390: label.setText(displayedWorker.getDisplayText());
391: progressBar.setValue(displayedWorker.getProgressBarValue());
392: progressBar.setMaximum(displayedWorker
393: .getProgessBarMaximum());
394: }
395:
396: }
397:
398: /**
399: * Sets the worker to be displayed.
400: */
401: protected void setDisplayedWorker(Worker w) {
402: displayedWorker = w;
403:
404: }
405:
406: /**
407: * Returns the worker currently displayed.
408: */
409: public IWorkerStatusController getDisplayedWorker() {
410: return displayedWorker;
411: }
412:
413: /**
414: * Returns the task manager this status bar is attached to.
415: */
416: public TaskManager getTaskManager() {
417: return taskManager;
418: }
419:
420: public void stateChanged(ChangeEvent e) {
421: if (ConnectionStateImpl.getInstance().isOnline()) {
422: onlineButton.setIcon(onlineIcon);
423: // TODO (@author fdietz): i18n
424: onlineButton.setToolTipText("You are in ONLINE state");
425: } else {
426: onlineButton.setIcon(offlineIcon);
427: // TODO (@author fdietz): i18n
428: onlineButton.setToolTipText("You are in OFFLINE state");
429: }
430: }
431: }
|