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 JPanel panel2;
47 private final JSplitPane split1;
48 private final JSplitPane split2;
49 private final ResultSetTable resultSetTable;
50 private final ConsoleTextArea textArea;
51 private final DatabaseInfoTree infoTree;
52 private final TextSearchPanel textSearchPanel;
53 private final JLabel statusBar;
54 private final List<String> historyList;
55 private final ExecutorService executorService;
57 private Environment env;
58 private Map<JComponent, TextSearch> textSearchMap;
59 private int historyIndex;
60 private JComponent focused;
65 final JSplitPane split1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
66 final DatabaseInfoTree infoTree = new DatabaseInfoTree(this);
67 final ResultSetTable resultSetTable = new ResultSetTable(this);
68 final JTableHeader resultSetTableHeader = resultSetTable.getTableHeader();
69 final ConsoleTextArea textArea = new ConsoleTextArea(this);
70 this.op = new WindowOutputProcessor(this, resultSetTable, textArea);
71 this.menu = new Menu(this);
72 this.panel1 = new JPanel(new BorderLayout());
73 this.panel2 = new JPanel(new BorderLayout());
75 this.split2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
76 this.resultSetTable = resultSetTable;
77 this.textArea = textArea;
78 this.infoTree = infoTree;
79 this.textSearchPanel = new TextSearchPanel(op);
80 this.statusBar = new JLabel(" ");
81 this.historyList = new LinkedList<String>();
82 this.historyIndex = 0;
83 this.executorService = Executors.newScheduledThreadPool(3,
84 DaemonThreadFactory.getInstance());
86 // OutputProcessor as frame
87 op.setTitle(res.get(".title"));
88 op.setIconImage(Utilities.getImageIcon("stew.png").getImage());
89 op.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
90 // splitpane (infotree and sub-splitpane)
91 split1.setResizeWeight(0.6f);
92 split1.setDividerSize(4);
93 // splitpane (table and textarea)
94 split2.setOrientation(VERTICAL_SPLIT);
95 split2.setDividerSize(6);
96 split2.setResizeWeight(0.6f);
98 textArea.setMargin(new Insets(4, 8, 4, 4));
99 textArea.setLineWrap(true);
100 textArea.setWrapStyleWord(false);
102 this.textSearchMap = new LinkedHashMap<JComponent, TextSearch>();
103 final TextSearchPanel textSearchPanel = this.textSearchPanel;
104 final Map<JComponent, TextSearch> textSearchMap = this.textSearchMap;
105 textSearchMap.put(infoTree, infoTree);
106 textSearchMap.put(resultSetTable, resultSetTable);
107 textSearchMap.put(resultSetTableHeader,
108 new ResultSetTable.TableHeaderTextSearch(resultSetTable,
109 resultSetTableHeader));
110 textSearchMap.put(textArea, textArea);
111 for (Entry<JComponent, TextSearch> entry : textSearchMap.entrySet()) {
112 final JComponent c = entry.getKey();
113 c.addFocusListener(new FocusAdapter() {
115 public void focusGained(FocusEvent e) {
117 textSearchPanel.setCurrentTarget(textSearchMap.get(c));
120 textSearchPanel.addTarget(entry.getValue());
123 statusBar.setForeground(Color.BLUE);
126 * split2 = ResultSetTable + TextArea
127 * +----------------------------+
129 * | +------------------------+ |
130 * | | scroll(resultSetTable) | |
131 * | +------------------------+ |
132 * | +------------------------+ |
134 * | | +--------------------+ | |
135 * | | | scroll(textArea) | | |
136 * | | +--------------------+ | |
137 * | | | textSearchPanel | | |
138 * | | +--------------------+ | |
139 * | +------------------------+ |
140 * +----------------------------+
141 * when DatabaseInfoTree is visible
142 * +-----------------------------------+
144 * | +-------------------------------+ |
146 * | | +------------+ +------------+ | |
147 * | | | scroll | | split2 | | |
148 * | | | (infoTree) | | | | |
149 * | | +------------+ +------------+ | |
150 * | +-------------------------------+ |
151 * +-----------------------------------+
153 * +-----------------------------------+
154 * when DatabaseInfoTree is not visible
155 * +-----------------------------------+
157 * | +-------------------------------+ |
159 * | +-------------------------------+ |
160 * +-----------------------------------+
162 * +-----------------------------------+
164 panel2.add(new JScrollPane(textArea, VERTICAL_SCROLLBAR_ALWAYS, HORIZONTAL_SCROLLBAR_NEVER),
165 BorderLayout.CENTER);
166 panel2.add(textSearchPanel, BorderLayout.SOUTH);
167 split2.setTopComponent(new JScrollPane(resultSetTable));
168 split2.setBottomComponent(panel2);
169 op.add(panel1, BorderLayout.CENTER);
170 op.add(statusBar, BorderLayout.PAGE_END);
171 op.setJMenuBar(menu);
172 // [Restores Configs]
173 op.addPropertyChangeListener(menu);
174 infoTree.addPropertyChangeListener(menu);
175 resultSetTable.addPropertyChangeListener(menu);
176 statusBar.addPropertyChangeListener(menu);
178 op.removePropertyChangeListener(menu);
179 infoTree.removePropertyChangeListener(menu);
180 resultSetTable.removePropertyChangeListener(menu);
181 // XXX cannot restore config of status-bar at following code
182 // statusBar.removePropertyChangeListener(menu);
184 op.addWindowListener(new WindowAdapter() {
186 public void windowClosing(WindowEvent e) {
190 ContextMenu.create(infoTree, infoTree);
191 ContextMenu.create(resultSetTable);
192 ContextMenu.create(resultSetTable.getRowHeader(), resultSetTable, "ResultSetTable");
193 ContextMenu.create(resultSetTableHeader, resultSetTable, "ResultSetTableColumnHeader");
194 ContextMenu.createForText(textArea);
198 public void launch(Environment env) {
200 op.setEnvironment(env);
202 op.output(new Prompt(env));
203 textArea.requestFocus();
208 Thread.setDefaultUncaughtExceptionHandler(this);
213 public void uncaughtException(Thread t, Throwable e) {
214 log.fatal(e, "%s", t);
215 op.showErrorDialog(e);
219 public void anyActionPerformed(AnyActionEvent ev) {
220 log.atEnter("anyActionPerformed", ev);
223 resultSetTable.editingCanceled(new ChangeEvent(ev.getSource()));
224 final Object source = ev.getSource();
225 if (ev.isAnyOf(newWindow)) {
227 } else if (ev.isAnyOf(closeWindow)) {
229 } else if (ev.isAnyOf(quit)) {
231 } else if (ev.isAnyOf(showInfoTree)) {
232 setInfoTreePaneVisibility(((JCheckBoxMenuItem)source).isSelected());
235 } else if (ev.isAnyOf(cut, copy, paste, selectAll)) {
236 if (focused != null) {
238 if (ev.isAnyOf(cut)) {
239 if (focused instanceof JTextComponent) {
240 cmd = "cut-to-clipboard";
244 } else if (ev.isAnyOf(copy)) {
245 if (focused instanceof JTextComponent) {
246 cmd = "copy-to-clipboard";
248 cmd = ev.getActionCommand();
250 } else if (ev.isAnyOf(paste)) {
251 if (focused instanceof JTextComponent) {
252 cmd = "paste-from-clipboard";
253 } else if (focused instanceof DatabaseInfoTree) {
256 cmd = ev.getActionCommand();
258 } else if (ev.isAnyOf(selectAll)) {
259 if (focused instanceof JTextComponent) {
262 cmd = ev.getActionCommand();
267 if (cmd.length() == 0) {
268 log.debug("no action: %s, cmd=%s",
270 ev.getActionCommand());
272 final Action action = focused.getActionMap().get(cmd);
273 log.debug("convert to plain Action Event: orig=%s", ev);
274 action.actionPerformed(new ActionEvent(focused, ACTION_PERFORMED, cmd));
277 } else if (ev.isAnyOf(find)) {
278 textSearchPanel.setCurrentTarget(textSearchMap.get(focused));
279 textSearchPanel.setVisible(true);
280 } else if (ev.isAnyOf(toggleFocus)) {
281 if (textArea.isFocusOwner()) {
282 resultSetTable.requestFocus();
284 textArea.requestFocus();
286 } else if (ev.isAnyOf(clearMessage)) {
289 } else if (ev.isAnyOf(showStatusBar)) {
290 statusBar.setVisible(((JCheckBoxMenuItem)source).isSelected());
291 } else if (ev.isAnyOf(showColumnNumber)) {
292 resultSetTable.anyActionPerformed(ev);
293 } else if (ev.isAnyOf(refresh)) {
295 } else if (ev.isAnyOf(autoAdjustModeNone,
296 autoAdjustModeHeader,
298 autoAdjustModeHeaderAndValue)) {
299 resultSetTable.setAutoAdjustMode(ev.getActionCommand());
300 } else if (ev.isAnyOf(widenColumnWidth, narrowColumnWidth, adjustColumnWidth)) {
301 resultSetTable.anyActionPerformed(ev);
302 } else if (ev.isAnyOf(executeCommand, execute)) {
303 executeCommand(textArea.getEditableText());
304 } else if (ev.isAnyOf(breakCommand)) {
305 env.getOutputProcessor().close();
306 env.setOutputProcessor(new WindowOutputProcessor.Bypass(op));
307 op.output(res.get("i.cancelled"));
309 } else if (ev.isAnyOf(lastHistory)) {
311 } else if (ev.isAnyOf(nextHistory)) {
313 } else if (ev.isAnyOf(sendRollback)) {
314 if (confirmCommitable()
315 && showConfirmDialog(op, res.get("i.confirm-rollback"), null, OK_CANCEL_OPTION) == OK_OPTION) {
316 executeCommand("rollback");
318 } else if (ev.isAnyOf(sendCommit)) {
319 if (confirmCommitable()
320 && showConfirmDialog(op, res.get("i.confirm-commit"), null, OK_CANCEL_OPTION) == OK_OPTION) {
321 executeCommand("commit");
323 } else if (ev.isAnyOf(connect)) {
324 env.updateConnectorMap();
325 if (env.getConnectorMap().isEmpty()) {
326 showMessageDialog(op, res.get("w.no-connector"));
329 Object[] a = ConnectorEntry.toList(env.getConnectorMap().values()).toArray();
330 final String m = res.get("i.choose-connection");
331 Object value = showInputDialog(op, m, null, PLAIN_MESSAGE, null, a, a[0]);
333 ConnectorEntry c = (ConnectorEntry)value;
334 executeCommand("connect " + c.getId());
336 } else if (ev.isAnyOf(disconnect)) {
337 executeCommand("disconnect");
338 } else if (ev.isAnyOf(postProcessModeNone,
339 postProcessModeFocus,
340 postProcessModeShake,
341 postProcessModeBlink)) {
342 op.setPostProcessMode(ev.getActionCommand());
343 } else if (ev.isAnyOf(inputEcryptionKey)) {
345 } else if (ev.isAnyOf(editConnectors)) {
347 } else if (ev.isAnyOf(sortResult)) {
348 resultSetTable.doSort(resultSetTable.getSelectedColumn());
349 } else if (ev.isAnyOf(importFile, exportFile, showAbout)) {
350 op.anyActionPerformed(ev);
351 } else if (ev.isAnyOf(showHelp)) {
353 } else if (ev.isAnyOf(ResultSetTable.ActionKey.findColumnName)) {
354 resultSetTable.getTableHeader().requestFocus();
355 textSearchPanel.setVisible(true);
356 } else if (ev.isAnyOf(ResultSetTable.ActionKey.jumpToColumn)) {
357 resultSetTable.anyActionPerformed(ev);
358 } else if (ev.isAnyOf(ConsoleTextArea.ActionKey.insertText)) {
359 textArea.anyActionPerformed(ev);
361 log.warn("not expected: Event=%s", ev);
363 } catch (Exception ex) {
364 op.showErrorDialog(ex);
366 log.atExit("dispatch");
370 * Controls visibility of DatabaseInfoTree pane.
373 void setInfoTreePaneVisibility(boolean show) {
376 split1.setTopComponent(new JScrollPane(infoTree));
377 split1.setBottomComponent(split2);
379 panel1.add(split1, BorderLayout.CENTER);
380 infoTree.setEnabled(true);
383 infoTree.refreshRoot(env);
384 } catch (SQLException ex) {
386 op.showErrorDialog(ex);
391 infoTree.setEnabled(false);
393 panel1.add(split2, BorderLayout.CENTER);
395 SwingUtilities.updateComponentTreeUI(op);
398 private void loadConfiguration() {
399 Configuration cnf = Configuration.load(Bootstrap.getDirectory());
400 op.setSize(cnf.getSize());
401 op.setLocation(cnf.getLocation());
402 split2.setDividerLocation(cnf.getDividerLocation());
403 statusBar.setVisible(cnf.isShowStatusBar());
404 resultSetTable.setShowColumnNumber(cnf.isShowTableColumnNumber());
405 split1.setDividerLocation(cnf.getDividerLocation0());
406 op.setAlwaysOnTop(cnf.isAlwaysOnTop());
407 resultSetTable.setAutoAdjustMode(cnf.getAutoAdjustMode());
408 op.setPostProcessMode(cnf.getPostProcessMode());
409 setInfoTreePaneVisibility(cnf.isShowInfoTree());
410 changeFont("monospaced", Font.PLAIN, 1.0d);
413 private void saveConfiguration() {
414 Configuration cnf = Configuration.load(Bootstrap.getDirectory());
415 if ((op.getExtendedState() & Frame.MAXIMIZED_BOTH) == 0) {
416 // only not maximized
417 cnf.setSize(op.getSize());
418 cnf.setLocation(op.getLocation());
419 cnf.setDividerLocation(split2.getDividerLocation());
420 cnf.setDividerLocation0(split1.getDividerLocation());
422 cnf.setShowStatusBar(statusBar.isVisible());
423 cnf.setShowTableColumnNumber(resultSetTable.isShowColumnNumber());
424 cnf.setShowInfoTree(infoTree.isEnabled());
425 cnf.setAlwaysOnTop(op.isAlwaysOnTop());
426 cnf.setAutoAdjustMode(resultSetTable.getAutoAdjustMode());
427 cnf.setPostProcessMode(op.getPostProcessMode());
432 * Configuration (Bean) for saving and loading.
434 @SuppressWarnings("all")
435 public static final class Configuration {
437 private static final Logger log = Logger.getLogger(Configuration.class);
439 private transient File directory;
441 private Dimension size;
442 private Point location;
443 private int dividerLocation;
444 private int dividerLocation0;
445 private boolean showStatusBar;
446 private boolean showTableColumnNumber;
447 private boolean showInfoTree;
448 private boolean alwaysOnTop;
449 private String autoAdjustMode;
450 private String postProcessMode;
452 public Configuration() {
453 this.size = new Dimension(640, 480);
454 this.location = new Point(200, 200);
455 this.dividerLocation = -1;
456 this.dividerLocation0 = -1;
457 this.showStatusBar = false;
458 this.showTableColumnNumber = false;
459 this.showInfoTree = false;
460 this.alwaysOnTop = false;
461 this.autoAdjustMode = AnyActionKey.autoAdjustMode.toString();
462 this.postProcessMode = AnyActionKey.postProcessMode.toString();
465 void setDirectory(File directory) {
466 this.directory = directory;
470 final File file = getFile(directory);
471 log.debug("save Configuration to: [%s]", file);
473 XMLEncoder encoder = new XMLEncoder(new FileOutputStream(file));
475 encoder.writeObject(this);
479 } catch (Exception ex) {
484 static Configuration load(File directory) {
485 final File file = getFile(directory);
486 log.debug("load Configuration from: [%s]", file);
489 XMLDecoder decoder = new XMLDecoder(new FileInputStream(file));
491 final Configuration instance = (Configuration)decoder.readObject();
492 instance.setDirectory(directory);
497 } catch (Exception ex) {
501 final Configuration instance = new Configuration();
502 instance.setDirectory(directory);
506 private static File getFile(File systemDirectory) {
507 final File file = new File(systemDirectory, Configuration.class.getName() + ".xml");
508 return file.getAbsoluteFile();
511 public Dimension getSize() {
515 public void setSize(Dimension size) {
519 public Point getLocation() {
523 public void setLocation(Point location) {
524 this.location = location;
527 public int getDividerLocation() {
528 return dividerLocation;
531 public void setDividerLocation(int dividerLocation) {
532 this.dividerLocation = dividerLocation;
535 public int getDividerLocation0() {
536 return dividerLocation0;
539 public void setDividerLocation0(int dividerLocation0) {
540 this.dividerLocation0 = dividerLocation0;
543 public boolean isShowStatusBar() {
544 return showStatusBar;
547 public void setShowStatusBar(boolean showStatusBar) {
548 this.showStatusBar = showStatusBar;
551 public boolean isShowTableColumnNumber() {
552 return showTableColumnNumber;
555 public void setShowTableColumnNumber(boolean showTableColumnNumber) {
556 this.showTableColumnNumber = showTableColumnNumber;
559 public boolean isShowInfoTree() {
563 public void setShowInfoTree(boolean showInfoTree) {
564 this.showInfoTree = showInfoTree;
567 public boolean isAlwaysOnTop() {
571 public void setAlwaysOnTop(boolean alwaysOnTop) {
572 this.alwaysOnTop = alwaysOnTop;
575 public String getAutoAdjustMode() {
576 return autoAdjustMode;
579 public void setAutoAdjustMode(String autoAdjustMode) {
580 this.autoAdjustMode = autoAdjustMode;
583 public String getPostProcessMode() {
584 return postProcessMode;
587 public void setPostProcessMode(String postProcessMode) {
588 this.postProcessMode = postProcessMode;
593 private void changeFont(String family, int style, double sizeRate) {
594 FontControlLookAndFeel.change(family, style, sizeRate);
595 SwingUtilities.updateComponentTreeUI(op);
596 Font newfont = textArea.getFont();
597 if (newfont != null) {
598 statusBar.setFont(newfont.deriveFont(newfont.getSize() * 0.8f));
602 void handleError(Throwable th) {
604 op.showErrorDialog(th);
607 static void invoke() {
608 invoke(new WindowLauncher());
611 static void invoke(WindowLauncher instance) {
612 final Environment env = new Environment();
613 env.setOutputProcessor(new WindowOutputProcessor.Bypass(instance.op));
614 instance.launch(env);
618 * Starts to exit application.
621 for (WindowLauncher instance : new ArrayList<WindowLauncher>(instances)) {
624 } catch (Exception ex) {
625 log.warn(ex, "error occurred when closing all instances");
631 * Closes this window.
634 instances.remove(this);
638 executorService.shutdown();
645 * Confirms whether pressed YES or not at dialog.
647 * @return true if pressed YES
649 private boolean confirmYes(String message) {
650 return showConfirmDialog(op, message, "", YES_NO_OPTION) == YES_OPTION;
653 private boolean confirmCommitable() {
654 if (env.getCurrentConnection() == null) {
655 showMessageDialog(op, res.get("w.not-connect"), null, OK_OPTION);
658 if (env.getCurrentConnector().isReadOnly()) {
659 showMessageDialog(op, res.get("w.connector-readonly"), null, OK_OPTION);
665 private void retrieveHistory(int value) {
666 if (historyList.isEmpty()) {
669 historyIndex += value;
670 if (historyIndex >= historyList.size()) {
672 } else if (historyIndex < 0) {
673 historyIndex = historyList.size() - 1;
675 textArea.replace(historyList.get(historyIndex));
676 final int endPosition = textArea.getEndPosition();
677 textArea.setSelectionStart(endPosition);
678 textArea.moveCaretPosition(endPosition);
679 textArea.requestFocus();
683 * Requests to close this window.
685 void requestClose() {
686 if (instances.size() == 1) {
688 } else if (env.getCurrentConnection() == null || confirmYes(res.get("i.confirm-close"))) {
694 * Requests to exit this application.
697 if (confirmYes(res.get("i.confirm-quit"))) {
702 private void refreshResult() {
703 if (resultSetTable.getModel() instanceof ResultSetTableModel) {
704 ResultSetTableModel m = resultSetTable.getResultSetTableModel();
705 if (m.isSameConnection(env.getCurrentConnection())) {
706 final String s = m.getCommandString();
707 if (s != null && s.length() > 0) {
714 private void editEncryptionKey() {
715 JPasswordField password = new JPasswordField(20);
716 Object[] a = {res.get("i.input-encryption-key"), password};
717 if (showConfirmDialog(op, a, null, OK_CANCEL_OPTION) == OK_OPTION) {
718 CipherPassword.setSecretKey(String.valueOf(password.getPassword()));
722 private void editConnectorMap() {
723 env.updateConnectorMap();
724 if (env.getCurrentConnector() != null) {
725 showMessageDialog(op, res.get("i.reconnect-after-edited-current-connector"));
727 ConnectorMapEditDialog dialog = new ConnectorMapEditDialog(op, env);
729 dialog.setModal(true);
730 dialog.setLocationRelativeTo(op);
731 dialog.setVisible(true);
732 env.updateConnectorMap();
735 private static void showHelp() {
736 final String htmlFileName = "MANUAL_ja.html";
737 if (Desktop.isDesktopSupported()) {
738 Desktop desktop = Desktop.getDesktop();
739 if (desktop.isSupported(Desktop.Action.OPEN)) {
740 File file = new File(htmlFileName);
744 } catch (IOException ex) {
745 throw new RuntimeException(ex);
750 final String msg = res.get("e.cannot-open-help-automatically", htmlFileName);
751 WindowOutputProcessor.showInformationMessageDialog(getRootFrame(), msg, "");
756 * Executes a command.
757 * @param commandString
759 void executeCommand(String commandString) {
760 assert commandString != null;
761 if (!commandString.equals(textArea.getEditableText())) {
762 textArea.replace(commandString);
765 if (commandString.trim().length() == 0) {
768 final String cmd = commandString;
769 final Environment env = this.env;
770 final DatabaseInfoTree infoTree = this.infoTree;
771 final JLabel statusBar = this.statusBar;
772 final OutputProcessor opref = env.getOutputProcessor();
775 executorService.execute(new Runnable() {
778 Connection conn = env.getCurrentConnection();
779 long time = System.currentTimeMillis();
780 if (!Command.invoke(env, cmd)) {
783 if (infoTree.isEnabled()) {
785 if (env.getCurrentConnection() != conn) {
787 if (env.getCurrentConnection() != null) {
788 infoTree.refreshRoot(env);
791 } catch (Throwable th) {
795 if (env.getOutputProcessor() == opref) {
796 time = System.currentTimeMillis() - time;
797 statusBar.setText(res.get("i.statusbar-message", time / 1000f, cmd));
798 AnyAction invoker = new AnyAction(this);
799 invoker.doLater("callDoPostProcess");
802 @SuppressWarnings("unused")
803 void callDoPostProcess() {
804 WindowLauncher.this.doPostProcess();
807 } catch (Exception ex) {
808 throw new RuntimeException(ex);
810 historyIndex = historyList.size();
812 if (historyList.contains(commandString)) {
813 historyList.remove(commandString);
815 historyList.add(commandString);
817 historyIndex = historyList.size();
820 void doPreProcess() {
821 ((Menu)op.getJMenuBar()).setEnabledStates(true);
822 resultSetTable.setEnabled(false);
823 textArea.setEnabled(false);
827 void doPostProcess() {
828 ((Menu)op.getJMenuBar()).setEnabledStates(false);
829 resultSetTable.setEnabled(true);
830 textArea.setEnabled(true);
831 op.output(new Prompt(env));
835 static void wakeup() {
836 for (WindowLauncher instance : new ArrayList<WindowLauncher>(instances)) {
838 SwingUtilities.updateComponentTreeUI(instance.op);
839 } catch (Exception ex) {
846 private static final class WakeupTimerTask extends TimerTask {
847 private final AnyAction aa = new AnyAction(this);
850 aa.doLater("callWakeup");
852 @SuppressWarnings("unused")
862 public static void main(String... args) {
863 final int residentCycle = Bootstrap.getPropertyAsInt("net.argius.stew.ui.window.resident",
865 if (residentCycle > 0) {
866 final long msec = residentCycle * 60000L;
867 Timer timer = new Timer(true);
868 timer.scheduleAtFixedRate(new WakeupTimerTask(), msec, msec);
870 EventQueue.invokeLater(new WindowLauncher());