1 package net.argius.stew.ui.window;
3 import static java.awt.event.ActionEvent.ACTION_PERFORMED;
4 import static javax.swing.JOptionPane.*;
5 import static javax.swing.JSplitPane.VERTICAL_SPLIT;
6 import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER;
7 import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS;
8 import static net.argius.stew.ui.window.AnyActionKey.*;
11 import java.awt.event.*;
14 import java.lang.Thread.UncaughtExceptionHandler;
17 import java.util.Map.Entry;
18 import java.util.List;
19 import java.util.Timer;
20 import java.util.concurrent.*;
23 import javax.swing.event.*;
24 import javax.swing.table.*;
25 import javax.swing.text.*;
27 import net.argius.stew.*;
28 import net.argius.stew.ui.*;
31 * The Launcher implementation for GUI(Swing).
33 public final class WindowLauncher implements
37 UncaughtExceptionHandler {
39 private static final Logger log = Logger.getLogger(WindowLauncher.class);
40 private static final ResourceManager res = ResourceManager.getInstance(WindowLauncher.class);
41 private static final List<WindowLauncher> instances = Collections.synchronizedList(new ArrayList<WindowLauncher>());
43 private final WindowOutputProcessor op;
44 private final Menu menu;
45 private final JPanel panel1;
46 private final JSplitPane split1;
47 private final JSplitPane split2;
48 private final ResultSetTable resultSetTable;
49 private final ConsoleTextArea textArea;
50 private final DatabaseInfoTree infoTree;
51 private final TextSearchPanel textSearchPanel;
52 private final JLabel statusBar;
53 private final List<String> historyList;
54 private final ExecutorService executorService;
56 private Environment env;
57 private Map<JComponent, TextSearch> textSearchMap;
58 private int historyIndex;
59 private JComponent focused;
64 final JSplitPane split1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
65 final DatabaseInfoTree infoTree = new DatabaseInfoTree(this);
66 final ResultSetTable resultSetTable = new ResultSetTable(this);
67 final JTableHeader resultSetTableHeader = resultSetTable.getTableHeader();
68 final ConsoleTextArea textArea = new ConsoleTextArea(this);
69 this.op = new WindowOutputProcessor(this, resultSetTable, textArea);
70 this.menu = new Menu(this);
71 this.panel1 = new JPanel(new BorderLayout());
73 this.split2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
74 this.resultSetTable = resultSetTable;
75 this.textArea = textArea;
76 this.infoTree = infoTree;
77 this.textSearchPanel = new TextSearchPanel(op);
78 this.statusBar = new JLabel(" ");
79 this.historyList = new LinkedList<String>();
80 this.historyIndex = 0;
81 this.executorService = Executors.newScheduledThreadPool(3,
82 DaemonThreadFactory.getInstance());
84 // OutputProcessor as frame
85 op.setTitle(res.get(".title"));
86 op.setIconImage(Utilities.getImageIcon("stew.png").getImage());
87 op.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
88 // splitpane (infotree and sub-splitpane)
89 split1.setResizeWeight(0.6f);
90 split1.setDividerSize(4);
91 // splitpane (table and textarea)
92 split2.setOrientation(VERTICAL_SPLIT);
93 split2.setDividerSize(6);
94 split2.setResizeWeight(0.6f);
96 textArea.setMargin(new Insets(4, 8, 4, 4));
97 textArea.setLineWrap(true);
98 textArea.setWrapStyleWord(false);
100 this.textSearchMap = new LinkedHashMap<JComponent, TextSearch>();
101 final TextSearchPanel textSearchPanel = this.textSearchPanel;
102 final Map<JComponent, TextSearch> textSearchMap = this.textSearchMap;
103 textSearchMap.put(infoTree, infoTree);
104 textSearchMap.put(resultSetTable, resultSetTable);
105 textSearchMap.put(resultSetTableHeader,
106 new ResultSetTable.TableHeaderTextSearch(resultSetTable,
107 resultSetTableHeader));
108 textSearchMap.put(textArea, textArea);
109 for (Entry<JComponent, TextSearch> entry : textSearchMap.entrySet()) {
110 final JComponent c = entry.getKey();
111 c.addFocusListener(new FocusAdapter() {
113 public void focusGained(FocusEvent e) {
115 textSearchPanel.setCurrentTarget(textSearchMap.get(c));
118 textSearchPanel.addTarget(entry.getValue());
121 statusBar.setForeground(Color.BLUE);
124 * split2 = ResultSetTable + TextArea
125 * +----------------------------+
127 * | +------------------------+ |
128 * | | scroll(resultSetTable) | |
129 * | +------------------------+ |
130 * | +------------------------+ |
131 * | | scroll(textArea) | |
132 * | +------------------------+ |
133 * +----------------------------+
134 * when DatabaseInfoTree is visible
135 * +-----------------------------------+
137 * | +-------------------------------+ |
139 * | | +------------+ +------------+ | |
140 * | | | scroll | | split2 | | |
141 * | | | (infoTree) | | | | |
142 * | | +------------+ +------------+ | |
143 * | +-------------------------------+ |
144 * | | textSearchPanel | |
145 * | +-------------------------------+ |
146 * +-----------------------------------+
148 * +-----------------------------------+
149 * when DatabaseInfoTree is not visible
150 * +-----------------------------------+
152 * | +-------------------------------+ |
154 * | +-------------------------------+ |
155 * | | textSearchPanel | |
156 * | +-------------------------------+ |
157 * +-----------------------------------+
159 * +-----------------------------------+
161 split2.setTopComponent(new JScrollPane(resultSetTable));
162 split2.setBottomComponent(new JScrollPane(textArea, VERTICAL_SCROLLBAR_ALWAYS, HORIZONTAL_SCROLLBAR_NEVER));
163 op.add(panel1, BorderLayout.CENTER);
164 op.add(statusBar, BorderLayout.PAGE_END);
165 op.setJMenuBar(menu);
166 // [Restores Configs]
167 op.addPropertyChangeListener(menu);
168 infoTree.addPropertyChangeListener(menu);
169 resultSetTable.addPropertyChangeListener(menu);
170 statusBar.addPropertyChangeListener(menu);
172 op.removePropertyChangeListener(menu);
173 infoTree.removePropertyChangeListener(menu);
174 resultSetTable.removePropertyChangeListener(menu);
175 // XXX cannot restore config of status-bar at following code
176 // statusBar.removePropertyChangeListener(menu);
178 ContextMenu.create(infoTree, infoTree);
179 ContextMenu.create(resultSetTable);
180 ContextMenu.create(resultSetTable.getRowHeader(), resultSetTable, "ResultSetTable");
181 ContextMenu.create(resultSetTableHeader, resultSetTable, "ResultSetTableColumnHeader");
182 ContextMenu.createForText(textArea);
186 public void launch(Environment env) {
188 op.setEnvironment(env);
190 op.output(new Prompt(env));
191 textArea.requestFocus();
196 Thread.setDefaultUncaughtExceptionHandler(this);
201 public void uncaughtException(Thread t, Throwable e) {
202 log.fatal(e, "%s", t);
203 op.showErrorDialog(e);
207 public void anyActionPerformed(AnyActionEvent ev) {
208 log.atEnter("anyActionPerformed", ev);
211 resultSetTable.editingCanceled(new ChangeEvent(ev.getSource()));
212 final Object source = ev.getSource();
213 if (ev.isAnyOf(newWindow)) {
215 } else if (ev.isAnyOf(closeWindow)) {
217 } else if (ev.isAnyOf(quit)) {
219 } else if (ev.isAnyOf(showInfoTree)) {
220 setInfoTreePaneVisibility(((JCheckBoxMenuItem)source).isSelected());
223 } else if (ev.isAnyOf(cut, copy, paste, selectAll)) {
224 if (focused != null) {
226 if (ev.isAnyOf(cut)) {
227 if (focused instanceof JTextComponent) {
228 cmd = "cut-to-clipboard";
232 } else if (ev.isAnyOf(copy)) {
233 if (focused instanceof JTextComponent) {
234 cmd = "copy-to-clipboard";
236 cmd = ev.getActionCommand();
238 } else if (ev.isAnyOf(paste)) {
239 if (focused instanceof JTextComponent) {
240 cmd = "paste-from-clipboard";
241 } else if (focused instanceof DatabaseInfoTree) {
244 cmd = ev.getActionCommand();
246 } else if (ev.isAnyOf(selectAll)) {
247 if (focused instanceof JTextComponent) {
250 cmd = ev.getActionCommand();
255 if (cmd.length() == 0) {
256 log.debug("no action: %s, cmd=%s",
258 ev.getActionCommand());
260 final Action action = focused.getActionMap().get(cmd);
261 log.debug("convert to plain Action Event: orig=%s", ev);
262 action.actionPerformed(new ActionEvent(focused, ACTION_PERFORMED, cmd));
265 } else if (ev.isAnyOf(find)) {
266 textSearchPanel.setCurrentTarget(textSearchMap.get(focused));
267 textSearchPanel.setVisible(true);
268 } else if (ev.isAnyOf(toggleFocus)) {
269 if (textArea.isFocusOwner()) {
270 infoTree.requestFocus();
271 } else if (infoTree.isFocusOwner()) {
272 resultSetTable.requestFocus();
274 textArea.requestFocus();
276 } else if (ev.isAnyOf(clearMessage)) {
279 } else if (ev.isAnyOf(showStatusBar)) {
280 statusBar.setVisible(((JCheckBoxMenuItem)source).isSelected());
281 } else if (ev.isAnyOf(showColumnNumber)) {
282 resultSetTable.anyActionPerformed(ev);
283 } else if (ev.isAnyOf(refresh)) {
285 } else if (ev.isAnyOf(autoAdjustModeNone,
286 autoAdjustModeHeader,
288 autoAdjustModeHeaderAndValue)) {
289 resultSetTable.setAutoAdjustMode(ev.getActionCommand());
290 } else if (ev.isAnyOf(widenColumnWidth, narrowColumnWidth, adjustColumnWidth)) {
291 resultSetTable.anyActionPerformed(ev);
292 } else if (ev.isAnyOf(executeCommand, execute)) {
293 executeCommand(textArea.getEditableText());
294 } else if (ev.isAnyOf(breakCommand)) {
295 env.getOutputProcessor().close();
296 env.setOutputProcessor(new WindowOutputProcessor.Bypass(op));
297 op.output(res.get("i.cancelled"));
299 } else if (ev.isAnyOf(lastHistory)) {
301 } else if (ev.isAnyOf(nextHistory)) {
303 } else if (ev.isAnyOf(showAllHistories)) {
304 if (historyList.isEmpty()) {
305 op.showInformationMessageDialog(res.get("w.no-histories"), null);
307 final String msg = res.get("i.choose-history", historyList.size());
308 final String lastCommand = historyList.get(historyList.size() - 1);
309 Object value = op.showInputDialog(msg, null, historyList.toArray(), lastCommand);
311 textArea.replace((String)value);
312 textArea.prepareSubmitting();
315 } else if (ev.isAnyOf(sendRollback)) {
316 if (confirmCommitable()
317 && showConfirmDialog(op, res.get("i.confirm-rollback"), null, OK_CANCEL_OPTION) == OK_OPTION) {
318 executeCommand("rollback");
320 } else if (ev.isAnyOf(sendCommit)) {
321 if (confirmCommitable()
322 && showConfirmDialog(op, res.get("i.confirm-commit"), null, OK_CANCEL_OPTION) == OK_OPTION) {
323 executeCommand("commit");
325 } else if (ev.isAnyOf(connect)) {
326 env.updateConnectorMap();
327 if (env.getConnectorMap().isEmpty()) {
328 showMessageDialog(op, res.get("w.no-connector"));
331 Object[] a = ConnectorEntry.toList(env.getConnectorMap().values()).toArray();
332 final String m = res.get("i.choose-connection");
333 Object value = showInputDialog(op, m, null, PLAIN_MESSAGE, null, a, a[0]);
335 ConnectorEntry c = (ConnectorEntry)value;
336 executeCommand("connect " + c.getId());
338 } else if (ev.isAnyOf(disconnect)) {
339 executeCommand("disconnect");
340 } else if (ev.isAnyOf(postProcessModeNone,
341 postProcessModeFocus,
342 postProcessModeShake,
343 postProcessModeBlink)) {
344 op.setPostProcessMode(ev.getActionCommand());
345 } else if (ev.isAnyOf(inputEcryptionKey)) {
347 } else if (ev.isAnyOf(editConnectors)) {
349 } else if (ev.isAnyOf(sortResult)) {
350 resultSetTable.doSort(resultSetTable.getSelectedColumn());
351 } else if (ev.isAnyOf(importFile, exportFile, showAbout)) {
352 op.anyActionPerformed(ev);
353 } else if (ev.isAnyOf(showHelp)) {
355 } else if (ev.isAnyOf(ResultSetTable.ActionKey.findColumnName)) {
356 resultSetTable.getTableHeader().requestFocus();
357 textSearchPanel.setVisible(true);
358 } else if (ev.isAnyOf(ResultSetTable.ActionKey.jumpToColumn)) {
359 resultSetTable.anyActionPerformed(ev);
360 } else if (ev.isAnyOf(ConsoleTextArea.ActionKey.insertText)) {
361 textArea.anyActionPerformed(ev);
363 log.warn("not expected: Event=%s", ev);
365 } catch (Exception ex) {
366 op.showErrorDialog(ex);
368 log.atExit("dispatch");
372 * Controls visibility of DatabaseInfoTree pane.
375 void setInfoTreePaneVisibility(boolean show) {
378 split1.setTopComponent(new JScrollPane(infoTree));
379 split1.setBottomComponent(split2);
381 panel1.add(split1, BorderLayout.CENTER);
382 panel1.add(textSearchPanel, BorderLayout.PAGE_END);
383 infoTree.setEnabled(true);
386 infoTree.refreshRoot(env);
387 } catch (SQLException ex) {
389 op.showErrorDialog(ex);
394 infoTree.setEnabled(false);
396 panel1.add(split2, BorderLayout.CENTER);
397 panel1.add(textSearchPanel, BorderLayout.PAGE_END);
399 SwingUtilities.updateComponentTreeUI(op);
402 private void loadConfiguration() {
403 Configuration cnf = Configuration.load();
404 op.setSize(cnf.getSize());
405 op.setLocation(cnf.getLocation());
406 split2.setDividerLocation(cnf.getDividerLocation());
407 statusBar.setVisible(cnf.isShowStatusBar());
408 resultSetTable.setShowColumnNumber(cnf.isShowTableColumnNumber());
409 split1.setDividerLocation(cnf.getDividerLocation0());
410 op.setAlwaysOnTop(cnf.isAlwaysOnTop());
411 resultSetTable.setAutoAdjustMode(cnf.getAutoAdjustMode());
412 op.setPostProcessMode(cnf.getPostProcessMode());
413 setInfoTreePaneVisibility(cnf.isShowInfoTree());
414 changeFont("monospaced", Font.PLAIN, 1.0d);
417 private void saveConfiguration() {
418 Configuration cnf = Configuration.load();
419 if ((op.getExtendedState() & Frame.MAXIMIZED_BOTH) == 0) {
420 // only not maximized
421 cnf.setSize(op.getSize());
422 cnf.setLocation(op.getLocation());
423 cnf.setDividerLocation(split2.getDividerLocation());
424 cnf.setDividerLocation0(split1.getDividerLocation());
426 cnf.setShowStatusBar(statusBar.isVisible());
427 cnf.setShowTableColumnNumber(resultSetTable.isShowColumnNumber());
428 cnf.setShowInfoTree(infoTree.isEnabled());
429 cnf.setAlwaysOnTop(op.isAlwaysOnTop());
430 cnf.setAutoAdjustMode(resultSetTable.getAutoAdjustMode());
431 cnf.setPostProcessMode(op.getPostProcessMode());
436 * Configuration (Bean) for saving and loading.
438 @SuppressWarnings("all")
439 public static final class Configuration {
441 private static final Logger log = Logger.getLogger(Configuration.class);
443 private Dimension size;
444 private Point location;
445 private int dividerLocation;
446 private int dividerLocation0;
447 private boolean showStatusBar;
448 private boolean showTableColumnNumber;
449 private boolean showInfoTree;
450 private boolean alwaysOnTop;
451 private String autoAdjustMode;
452 private String postProcessMode;
454 public Configuration() {
455 this.size = new Dimension(640, 480);
456 this.location = new Point(200, 200);
457 this.dividerLocation = -1;
458 this.dividerLocation0 = -1;
459 this.showStatusBar = false;
460 this.showTableColumnNumber = false;
461 this.showInfoTree = false;
462 this.alwaysOnTop = false;
463 this.autoAdjustMode = AnyActionKey.autoAdjustMode.toString();
464 this.postProcessMode = AnyActionKey.postProcessMode.toString();
468 final File file = getFile();
469 log.debug("save Configuration to: [%s]", file.getAbsolutePath());
471 XMLEncoder encoder = new XMLEncoder(new FileOutputStream(file));
473 encoder.writeObject(this);
477 } catch (Exception ex) {
482 static Configuration load() {
483 final File file = getFile();
484 log.debug("load Configuration from: [%s]", file.getAbsolutePath());
487 XMLDecoder decoder = new XMLDecoder(new FileInputStream(file));
489 return (Configuration)decoder.readObject();
493 } catch (Exception ex) {
497 return new Configuration();
500 private static File getFile() {
501 return Bootstrap.getSystemFile(Configuration.class.getName() + ".xml");
504 public Dimension getSize() {
508 public void setSize(Dimension size) {
512 public Point getLocation() {
516 public void setLocation(Point location) {
517 this.location = location;
520 public int getDividerLocation() {
521 return dividerLocation;
524 public void setDividerLocation(int dividerLocation) {
525 this.dividerLocation = dividerLocation;
528 public int getDividerLocation0() {
529 return dividerLocation0;
532 public void setDividerLocation0(int dividerLocation0) {
533 this.dividerLocation0 = dividerLocation0;
536 public boolean isShowStatusBar() {
537 return showStatusBar;
540 public void setShowStatusBar(boolean showStatusBar) {
541 this.showStatusBar = showStatusBar;
544 public boolean isShowTableColumnNumber() {
545 return showTableColumnNumber;
548 public void setShowTableColumnNumber(boolean showTableColumnNumber) {
549 this.showTableColumnNumber = showTableColumnNumber;
552 public boolean isShowInfoTree() {
556 public void setShowInfoTree(boolean showInfoTree) {
557 this.showInfoTree = showInfoTree;
560 public boolean isAlwaysOnTop() {
564 public void setAlwaysOnTop(boolean alwaysOnTop) {
565 this.alwaysOnTop = alwaysOnTop;
568 public String getAutoAdjustMode() {
569 return autoAdjustMode;
572 public void setAutoAdjustMode(String autoAdjustMode) {
573 this.autoAdjustMode = autoAdjustMode;
576 public String getPostProcessMode() {
577 return postProcessMode;
580 public void setPostProcessMode(String postProcessMode) {
581 this.postProcessMode = postProcessMode;
586 private void changeFont(String family, int style, double sizeRate) {
587 FontControlLookAndFeel.change(family, style, sizeRate);
588 SwingUtilities.updateComponentTreeUI(op);
589 Font newfont = textArea.getFont();
590 if (newfont != null) {
591 statusBar.setFont(newfont.deriveFont(newfont.getSize() * 0.8f));
595 void handleError(Throwable th) {
597 op.showErrorDialog(th);
600 static void invoke() {
601 invoke(new WindowLauncher());
604 static void invoke(WindowLauncher instance) {
605 final Environment env = new Environment();
606 env.setOutputProcessor(new WindowOutputProcessor.Bypass(instance.op));
607 instance.launch(env);
611 * Starts to exit application.
614 for (WindowLauncher instance : new ArrayList<WindowLauncher>(instances)) {
617 } catch (Exception ex) {
618 log.warn(ex, "error occurred when closing all instances");
624 * Closes this window.
627 instances.remove(this);
631 executorService.shutdown();
638 * Confirms whether pressed YES or not at dialog.
640 * @return true if pressed YES
642 private boolean confirmYes(String message) {
643 return showConfirmDialog(op, message, "", YES_NO_OPTION) == YES_OPTION;
646 private boolean confirmCommitable() {
647 if (env.getCurrentConnection() == null) {
648 showMessageDialog(op, res.get("w.not-connect"), null, OK_OPTION);
651 if (env.getCurrentConnector().isReadOnly()) {
652 showMessageDialog(op, res.get("w.connector-readonly"), null, OK_OPTION);
658 private void retrieveHistory(int value) {
659 if (historyList.isEmpty()) {
662 historyIndex += value;
663 if (historyIndex >= historyList.size()) {
665 } else if (historyIndex < 0) {
666 historyIndex = historyList.size() - 1;
668 textArea.replace(historyList.get(historyIndex));
669 textArea.prepareSubmitting();
673 * Requests to close this window.
675 void requestClose() {
676 if (instances.size() == 1) {
678 } else if (env.getCurrentConnection() == null || confirmYes(res.get("i.confirm-close"))) {
684 * Requests to exit this application.
687 if (confirmYes(res.get("i.confirm-quit"))) {
692 private void refreshResult() {
693 if (resultSetTable.getModel() instanceof ResultSetTableModel) {
694 ResultSetTableModel m = resultSetTable.getResultSetTableModel();
695 if (m.isSameConnection(env.getCurrentConnection())) {
696 final String s = m.getCommandString();
697 if (s != null && s.length() > 0) {
704 private void editEncryptionKey() {
705 JPasswordField password = new JPasswordField(20);
706 Object[] a = {res.get("i.input-encryption-key"), password};
707 if (showConfirmDialog(op, a, null, OK_CANCEL_OPTION) == OK_OPTION) {
708 CipherPassword.setSecretKey(String.valueOf(password.getPassword()));
712 private void editConnectorMap() {
713 env.updateConnectorMap();
714 if (env.getCurrentConnector() != null) {
715 showMessageDialog(op, res.get("i.reconnect-after-edited-current-connector"));
717 ConnectorMapEditDialog dialog = new ConnectorMapEditDialog(op, env);
719 dialog.setModal(true);
720 dialog.setLocationRelativeTo(op);
721 dialog.setVisible(true);
722 env.updateConnectorMap();
725 private static void showHelp() {
726 final File localeFile = new File("MANUAL_" + Locale.getDefault().getLanguage() + ".html");
727 final File htmlFile = (localeFile.exists()) ? localeFile : new File("MANUAL.html");
728 boolean wasOpened = false;
729 if (Desktop.isDesktopSupported()) {
730 Desktop desktop = Desktop.getDesktop();
731 if (desktop.isSupported(Desktop.Action.OPEN)) {
732 if (htmlFile.exists()) {
734 desktop.open(htmlFile);
736 } catch (IOException ex) {
737 throw new RuntimeException(ex);
743 final String msg = String.format("%s%nfile=%s",
744 res.get("e.cannot-open-help-automatically", htmlFile),
745 htmlFile.getAbsolutePath());
746 WindowOutputProcessor.showInformationMessageDialog(getRootFrame(), msg, "");
751 * Executes a command.
752 * @param commandString
754 void executeCommand(String commandString) {
755 assert commandString != null;
756 if (!commandString.equals(textArea.getEditableText())) {
757 textArea.replace(commandString);
760 if (commandString.trim().length() == 0) {
763 final String cmd = commandString;
764 final Environment env = this.env;
765 final DatabaseInfoTree infoTree = this.infoTree;
766 final JLabel statusBar = this.statusBar;
767 final OutputProcessor opref = env.getOutputProcessor();
770 executorService.execute(new Runnable() {
773 Connection conn = env.getCurrentConnection();
774 long time = System.currentTimeMillis();
775 if (!Command.invoke(env, cmd)) {
778 if (infoTree.isEnabled()) {
780 if (env.getCurrentConnection() != conn) {
782 if (env.getCurrentConnection() != null) {
783 infoTree.refreshRoot(env);
786 } catch (Throwable th) {
790 if (env.getOutputProcessor() == opref) {
791 time = System.currentTimeMillis() - time;
792 statusBar.setText(res.get("i.statusbar-message", time / 1000f, cmd));
793 AnyAction invoker = new AnyAction(this);
794 invoker.doLater("callDoPostProcess");
797 @SuppressWarnings("unused")
798 void callDoPostProcess() {
799 WindowLauncher.this.doPostProcess();
802 } catch (Exception ex) {
803 throw new RuntimeException(ex);
805 historyIndex = historyList.size();
807 if (historyList.contains(commandString)) {
808 historyList.remove(commandString);
810 historyList.add(commandString);
812 historyIndex = historyList.size();
815 void doPreProcess() {
816 ((Menu)op.getJMenuBar()).setEnabledStates(true);
817 resultSetTable.setEnabled(false);
818 textArea.setEnabled(false);
822 void doPostProcess() {
823 ((Menu)op.getJMenuBar()).setEnabledStates(false);
824 resultSetTable.setEnabled(true);
825 textArea.setEnabled(true);
826 op.output(new Prompt(env));
830 static void wakeup() {
831 for (WindowLauncher instance : new ArrayList<WindowLauncher>(instances)) {
833 SwingUtilities.updateComponentTreeUI(instance.op);
834 } catch (Exception ex) {
841 private static final class WakeupTimerTask extends TimerTask {
842 private final AnyAction aa = new AnyAction(this);
845 aa.doLater("callWakeup");
847 @SuppressWarnings("unused")
857 public static void main(String... args) {
858 final int residentCycle = Bootstrap.getPropertyAsInt("net.argius.stew.ui.window.resident",
860 if (residentCycle > 0) {
861 final long msec = residentCycle * 60000L;
862 Timer timer = new Timer(true);
863 timer.scheduleAtFixedRate(new WakeupTimerTask(), msec, msec);
865 EventQueue.invokeLater(new WindowLauncher());