001: /*
002: * Copyright (C) 2005 Rob Manning
003: * manningr@users.sourceforge.net
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * as published by the Free Software Foundation; either version 2
008: * of the License, or any later version.
009: *
010: * This program is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU General Public License for more details.
014: *
015: * You should have received a copy of the GNU General Public License
016: * along with this program; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018: */
019: package net.sourceforge.squirrel_sql.plugins.dbcopy.gui;
020:
021: import java.awt.BorderLayout;
022: import java.awt.FlowLayout;
023: import java.awt.Frame;
024: import java.awt.GridBagConstraints;
025: import java.awt.GridBagLayout;
026: import java.awt.GridLayout;
027: import java.awt.Insets;
028: import java.awt.event.ActionEvent;
029: import java.awt.event.ActionListener;
030:
031: import javax.swing.BorderFactory;
032: import javax.swing.JButton;
033: import javax.swing.JDialog;
034: import javax.swing.JLabel;
035: import javax.swing.JPanel;
036: import javax.swing.JProgressBar;
037: import javax.swing.SwingConstants;
038: import javax.swing.SwingUtilities;
039:
040: import net.sourceforge.squirrel_sql.fw.gui.GUIUtils;
041: import net.sourceforge.squirrel_sql.fw.util.StringManager;
042: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
043: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
044: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
045:
046: /**
047: * A description of this class goes here...
048: */
049:
050: public class DualProgressBarDialog {
051:
052: private static JProgressBar topBar = null;
053: private static JLabel topMessage = null;
054: private static JProgressBar bottomBar = null;
055: private static JLabel bottomMessage = null;
056: private static JButton cancelButton = null;
057:
058: private static JDialog dialog = null;
059: private static JLabel elapsedTime = null;
060: private static TimeCounter elapsedTimeCounter = null;
061: private static JLabel remainingTime = null;
062: private static TimeCounter remainingTimeCounter = null;
063: private static TimeTracker timeTracker = null;
064: private static RemainingTimeCalculator remainingCalc = null;
065:
066: /** Internationalized strings for this class */
067: private static final StringManager s_stringMgr = StringManagerFactory
068: .getStringManager(DualProgressBarDialog.class);
069:
070: /** Logger for this class. */
071: private final static ILogger log = LoggerController
072: .createLogger(DualProgressBarDialog.class);
073:
074: public static JDialog getDialog(final Frame owner,
075: final String title, final boolean modal,
076: final ActionListener listener) {
077: if (SwingUtilities.isEventDispatchThread()) {
078: _getDialog(owner, title, modal, listener);
079: } else {
080: try {
081: SwingUtilities.invokeAndWait(new Runnable() {
082: public void run() {
083: _getDialog(owner, title, modal, listener);
084: }
085: });
086: } catch (Exception e) {
087: //i18n[DualProgressBarDialog.error.getdialog=getDialog: unable to invokeAndWait for dialog]
088: log
089: .error(
090: s_stringMgr
091: .getString("DualProgressBarDialog.error.getdialog"),
092: e);
093: }
094: }
095:
096: return dialog;
097: }
098:
099: /**
100: * Starts the time tracking thread that updates the elapsed time counter.
101: */
102: public static void startTimer() {
103: if (timeTracker != null) {
104: timeTracker.setRunning(false);
105: }
106: remainingCalc = new RemainingTimeCalculator();
107: timeTracker = new TimeTracker();
108: }
109:
110: /**
111: * Stops the time tracking thread that updates the elapsed time counter.
112: */
113: public static void stopTimer() {
114: if (timeTracker != null) {
115: timeTracker.setRunning(false);
116: }
117: }
118:
119: private static void _getDialog(Frame owner, String title,
120: boolean modal, ActionListener listener) {
121: dialog = new JDialog(owner, title, modal);
122: dialog.getContentPane().setLayout(new BorderLayout());
123: dialog.getContentPane().add(buildPanel(), BorderLayout.CENTER);
124: dialog.getContentPane().add(buildButtonPanel(listener),
125: BorderLayout.SOUTH);
126: dialog.setSize(350, 205);
127: dialog.setLocationRelativeTo(owner);
128: cancelButton
129: .addActionListener(new CancelButtonListener(dialog));
130: dialog.setVisible(true);
131: }
132:
133: /**
134: * @return
135: */
136: private static JPanel buildPanel() {
137: JPanel dataPanel = new JPanel();
138: dataPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0,
139: 10));
140: GridBagLayout gl = new GridBagLayout();
141: dataPanel.setLayout(gl);
142: GridBagConstraints c;
143:
144: c = new GridBagConstraints();
145: c.gridx = 0;
146: c.gridy = 0;
147: c.fill = GridBagConstraints.HORIZONTAL;
148: c.anchor = GridBagConstraints.WEST;
149: // i18n[DualProgressBarDialog.copyingRecordsLabel=Copying records]
150: String topLabelText = s_stringMgr
151: .getString("DualProgressBarDialog.copyingRecordsLabel");
152: topMessage = new JLabel(topLabelText);
153: dataPanel.add(topMessage, c);
154:
155: c = new GridBagConstraints();
156: c.gridx = 0;
157: c.gridy = 1;
158: c.anchor = GridBagConstraints.WEST;
159: c.fill = GridBagConstraints.HORIZONTAL;
160: c.insets = new Insets(0, 0, 10, 0);
161: c.weightx = 1.0;
162: topBar = new JProgressBar(0, 10);
163: dataPanel.add(topBar, c);
164:
165: c = new GridBagConstraints();
166: c.gridx = 0;
167: c.gridy = 2;
168: c.fill = GridBagConstraints.HORIZONTAL;
169: c.anchor = GridBagConstraints.WEST;
170: //i18n[DualProgressBarDialog.copyingTablesLabel=Copying table]
171: String bottomLabelText = s_stringMgr
172: .getString("DualProgressBarDialog.copyingTablesLabel");
173: bottomMessage = new JLabel(bottomLabelText);
174: dataPanel.add(bottomMessage, c);
175:
176: c = new GridBagConstraints();
177: c.gridx = 0;
178: c.gridy = 3;
179: c.anchor = GridBagConstraints.WEST;
180: c.fill = GridBagConstraints.HORIZONTAL;
181: c.insets = new Insets(0, 0, 10, 0);
182: bottomBar = new JProgressBar(0, 10);
183: dataPanel.add(bottomBar, c);
184:
185: c = new GridBagConstraints();
186: c.gridx = 0;
187: c.gridy = 4;
188: c.ipadx = 5;
189: c.anchor = GridBagConstraints.CENTER;
190: c.fill = GridBagConstraints.HORIZONTAL;
191: dataPanel.add(buildTimePanel(), c);
192:
193: return dataPanel;
194: }
195:
196: public static JPanel buildTimePanel() {
197: JPanel result = new JPanel();
198: result.setLayout(new GridLayout(2, 2, 5, 5));
199: JLabel elapsedTimeLabel = new JLabel(s_stringMgr
200: .getString("DualProgressBarDialog.elapsedTimeLabel"));
201: elapsedTimeCounter = new TimeCounter();
202: elapsedTime = new JLabel(elapsedTimeCounter.toString());
203: JLabel remainingTimeLabel = new JLabel(s_stringMgr
204: .getString("DualProgressBarDialog.remainingTimeLabel"));
205: remainingTimeCounter = new TimeCounter();
206: remainingTime = new JLabel(remainingTimeCounter.toString());
207: elapsedTimeLabel.setHorizontalAlignment(SwingConstants.RIGHT);
208: result.add(elapsedTimeLabel);
209: elapsedTime.setHorizontalAlignment(SwingConstants.LEFT);
210: result.add(elapsedTime);
211: remainingTimeLabel.setHorizontalAlignment(SwingConstants.RIGHT);
212: result.add(remainingTimeLabel);
213: remainingTime.setHorizontalAlignment(SwingConstants.LEFT);
214: result.add(remainingTime);
215: return result;
216: }
217:
218: public static JPanel buildButtonPanel(ActionListener listener) {
219: JPanel buttonPanel = new JPanel(new FlowLayout());
220: // i18n[DualProgressBarDialog.cancelButtonLabel=Cancel]
221: String buttonText = s_stringMgr
222: .getString("DualProgressBarDialog.cancelButtonLabel");
223: cancelButton = new JButton(buttonText);
224: if (listener != null) {
225: cancelButton.addActionListener(listener);
226: }
227: buttonPanel.add(cancelButton);
228: return buttonPanel;
229: }
230:
231: public static void setTopMessage(final String message) {
232: if (SwingUtilities.isEventDispatchThread()) {
233: topMessage.setText(message);
234: } else {
235: SwingUtilities.invokeLater(new Runnable() {
236: public void run() {
237: topMessage.setText(message);
238: }
239: });
240: }
241: }
242:
243: public static void setBottomMessage(final String message) {
244: if (SwingUtilities.isEventDispatchThread()) {
245: bottomMessage.setText(message);
246: } else {
247: SwingUtilities.invokeLater(new Runnable() {
248: public void run() {
249: bottomMessage.setText(message);
250: }
251: });
252: }
253: }
254:
255: public static void setTopBarMinMax(final int min, final int max) {
256: if (topBar.getMinimum() == min && topBar.getMaximum() == max) {
257: return;
258: }
259: if (SwingUtilities.isEventDispatchThread()) {
260: topBar.setMinimum(min);
261: topBar.setMaximum(max);
262: } else {
263: SwingUtilities.invokeLater(new Runnable() {
264: public void run() {
265: topBar.setMinimum(min);
266: topBar.setMaximum(max);
267: }
268: });
269: }
270: }
271:
272: public static void setBottomBarMinMax(final int min, final int max) {
273: if (bottomBar.getMinimum() == min
274: && bottomBar.getMaximum() == max) {
275: return;
276: }
277: if (SwingUtilities.isEventDispatchThread()) {
278: bottomBar.setMinimum(min);
279: bottomBar.setMaximum(max);
280: } else {
281: SwingUtilities.invokeLater(new Runnable() {
282: public void run() {
283: bottomBar.setMinimum(min);
284: bottomBar.setMaximum(max);
285: }
286: });
287: }
288: }
289:
290: public static void setTopBarValue(final int value) {
291: if (SwingUtilities.isEventDispatchThread()) {
292: topBar.setValue(value);
293: } else {
294: SwingUtilities.invokeLater(new Runnable() {
295: public void run() {
296: topBar.setValue(value);
297: }
298: });
299: }
300: }
301:
302: public static void setTableCounts(int[] tableCounts) {
303: for (int i = 0; i < tableCounts.length; i++) {
304: remainingCalc.setTotalItems(remainingCalc.getTotalItems()
305: + tableCounts[i]);
306: }
307: }
308:
309: public static void setBottomBarValue(final int value) {
310: if (SwingUtilities.isEventDispatchThread()) {
311: bottomBar.setValue(value);
312: } else {
313: SwingUtilities.invokeLater(new Runnable() {
314: public void run() {
315: bottomBar.setValue(value);
316: }
317: });
318: }
319: }
320:
321: public static void incrementTopBar(final int value) {
322: final int newValue = topBar.getValue() + value;
323: remainingCalc.incrementCurrentItem();
324: GUIUtils.processOnSwingEventThread(new Runnable() {
325: public void run() {
326: topBar.setValue(newValue);
327: }
328: }, true);
329: }
330:
331: public static void incrementBottomBar(final int value) {
332: final int newValue = bottomBar.getValue() + value;
333: if (SwingUtilities.isEventDispatchThread()) {
334: bottomBar.setValue(newValue);
335: } else {
336: SwingUtilities.invokeLater(new Runnable() {
337: public void run() {
338: bottomBar.setValue(newValue);
339: }
340: });
341: }
342: }
343:
344: /**
345: * Sets the visibiility of the progress dialog
346: *
347: * @param visible a boolean value indicating whether or not to make the
348: * dialog visible.
349: */
350: public static void setVisible(final boolean visible) {
351: if (dialog == null) {
352: return;
353: }
354: if (dialog.isVisible() != visible) {
355: if (SwingUtilities.isEventDispatchThread()) {
356: dialog.setVisible(visible);
357: } else {
358: SwingUtilities.invokeLater(new Runnable() {
359: public void run() {
360: dialog.setVisible(visible);
361: }
362: });
363: }
364: }
365: }
366:
367: public static void dispose() {
368: if (dialog == null) {
369: return;
370: }
371: if (SwingUtilities.isEventDispatchThread()) {
372: dialog.dispose();
373: } else {
374: SwingUtilities.invokeLater(new Runnable() {
375: public void run() {
376: dialog.dispose();
377: }
378: });
379: }
380: }
381:
382: /**
383: * Add the specified ActionListener to the cancel button.
384: *
385: * @param listener an ActionListener that will receive ActionEvents from the
386: * cancel button.
387: */
388: public static void addCancelButtonActionListener(
389: ActionListener listener) {
390: if (cancelButton != null) {
391: cancelButton.addActionListener(listener);
392: }
393: }
394:
395: private static class CancelButtonListener implements ActionListener {
396:
397: JDialog _dialog = null;
398:
399: public CancelButtonListener(JDialog dialog) {
400: _dialog = dialog;
401: }
402:
403: public void actionPerformed(ActionEvent e) {
404: if (_dialog != null) {
405: setVisible(false);
406: _dialog.dispose();
407: }
408: }
409: }
410:
411: /**
412: * This thread is responsible for updating the elapsed and remaining time
413: * labels.
414: */
415: private static class TimeTracker implements Runnable {
416:
417: private Thread t = null;
418:
419: private boolean running = true;
420:
421: public TimeTracker() {
422: t = new Thread(this );
423: t.setName("DBCopy Time Tracker");
424: t.start();
425: }
426:
427: public void run() {
428: running = true;
429:
430: while (running) {
431: try {
432: Thread.sleep(1000);
433: } catch (InterruptedException e) {
434: }
435: elapsedTimeCounter.increment();
436: remainingCalc.setTimeElapsed(elapsedTimeCounter);
437: remainingCalc.getTimeRemaining(remainingTimeCounter);
438: SwingUtilities.invokeLater(new Runnable() {
439: public void run() {
440: String timeStr = elapsedTimeCounter.toString();
441: elapsedTime.setText(timeStr);
442: remainingTime.setText(remainingTimeCounter
443: .toString());
444: }
445: });
446: }
447: }
448:
449: public void setRunning(boolean aBoolean) {
450: running = aBoolean;
451: }
452: }
453:
454: private static class TimeCounter {
455:
456: private int seconds = 0;
457: private int minutes = 0;
458: private int hours = 0;
459:
460: public void reset() {
461: seconds = 0;
462: minutes = 0;
463: hours = 0;
464: }
465:
466: public void increment() {
467: if (seconds < 59) {
468: seconds++;
469: return;
470: }
471: if (minutes < 59) {
472: seconds = 0;
473: minutes++;
474: return;
475: }
476: hours++;
477: minutes = 0;
478: seconds = 0;
479: }
480:
481: public int getSeconds() {
482: return seconds;
483: }
484:
485: public void setSeconds(int seconds) {
486: this .seconds = seconds;
487: }
488:
489: public int getMinutes() {
490: return minutes;
491: }
492:
493: public void setMinutes(int minutes) {
494: this .minutes = minutes;
495: }
496:
497: public int getHours() {
498: return hours;
499: }
500:
501: public void setHours(int hours) {
502: this .hours = hours;
503: }
504:
505: public String toString() {
506: StringBuffer result = new StringBuffer();
507: if (hours < 10) {
508: result.append("0");
509: }
510: result.append(hours);
511: result.append(":");
512: if (minutes < 10) {
513: result.append("0");
514: }
515: result.append(minutes);
516: result.append(":");
517: if (seconds < 10) {
518: result.append("0");
519: }
520: result.append(seconds);
521: return result.toString();
522: }
523: }
524:
525: private static class RemainingTimeCalculator {
526:
527: private long currentItem = 0;
528: private long totalItems = 0;
529: private long secondsElapsed = 0;
530: private long secondsRemaining = 0;
531:
532: public void incrementCurrentItem() {
533: if (currentItem < totalItems) {
534: currentItem++;
535: }
536: }
537:
538: public void setCurrentItem(long anInt) {
539: if (currentItem <= totalItems) {
540: currentItem = anInt;
541: } else {
542: System.err.println("currentItem(" + currentItem
543: + ") > totalItems(" + totalItems + ") ");
544: }
545: }
546:
547: public long getTotalItems() {
548: return totalItems;
549: }
550:
551: public void setTotalItems(long anInt) {
552: totalItems = anInt;
553: }
554:
555: public void setTimeElapsed(TimeCounter counter) {
556: secondsElapsed = 0;
557: secondsElapsed += (counter.getHours() * 3600);
558: secondsElapsed += (counter.getMinutes() * 60);
559: secondsElapsed += counter.getSeconds();
560: calculateRemaining();
561: }
562:
563: public TimeCounter getTimeRemaining(TimeCounter counter) {
564: int hoursRemaining = (int) (secondsRemaining / 3600);
565: counter.setHours(hoursRemaining);
566:
567: long hoursRemainder = secondsRemaining
568: - (hoursRemaining * 3600);
569: int minutesRemaining = (int) (hoursRemainder / 60);
570: counter.setMinutes(minutesRemaining);
571:
572: int secondsRemaining = (int) (hoursRemainder - (minutesRemaining * 60));
573: counter.setSeconds(secondsRemaining);
574:
575: return counter;
576: }
577:
578: private void calculateRemaining() {
579: // calculate the average time / item
580: float avgTimePerItem = 0;
581: if (currentItem > 1) {
582: avgTimePerItem = (float) secondsElapsed
583: / (float) (currentItem - 1);
584: } else {
585: avgTimePerItem = secondsElapsed;
586: }
587:
588: // How many items left
589: long itemsLeft = (totalItems - currentItem) + 1;
590:
591: secondsRemaining = (int) (itemsLeft * avgTimePerItem);
592: }
593: }
594: }
|