1 /* Copyright (c) 2001-2011, The HSQL Development Group 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of the HSQL Development Group nor the names of its 15 * contributors may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, 22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 32 package org.hsqldb.util; 33 34 import java.io.File; 35 import java.io.FileInputStream; 36 import java.io.FileOutputStream; 37 import java.io.IOException; 38 import java.lang.reflect.Constructor; 39 import java.lang.reflect.InvocationTargetException; 40 import java.security.AccessControlException; 41 import java.sql.Connection; 42 import java.sql.DatabaseMetaData; 43 import java.sql.Driver; 44 import java.sql.DriverManager; 45 import java.sql.ResultSet; 46 import java.sql.ResultSetMetaData; 47 import java.sql.SQLException; 48 import java.sql.Statement; 49 import java.text.DecimalFormat; 50 import java.util.ArrayList; 51 import java.util.Enumeration; 52 import java.util.HashMap; 53 import java.util.HashSet; 54 import java.util.Hashtable; 55 import java.util.Iterator; 56 import java.util.Locale; 57 import java.util.Properties; 58 import java.util.Vector; 59 60 import java.awt.BorderLayout; 61 import java.awt.Component; 62 import java.awt.Container; 63 import java.awt.Cursor; 64 import java.awt.Dimension; 65 import java.awt.Event; 66 import java.awt.Font; 67 import java.awt.Insets; 68 import java.awt.Toolkit; 69 import java.awt.event.ActionEvent; 70 import java.awt.event.ActionListener; 71 import java.awt.event.KeyEvent; 72 import java.awt.event.KeyListener; 73 import java.awt.event.MouseEvent; 74 import java.awt.event.MouseListener; 75 import java.awt.event.WindowEvent; 76 import java.awt.event.WindowListener; 77 import javax.swing.ButtonGroup; 78 import javax.swing.ImageIcon; 79 import javax.swing.JApplet; 80 import javax.swing.JButton; 81 import javax.swing.JCheckBoxMenuItem; 82 import javax.swing.JComponent; 83 import javax.swing.JFileChooser; 84 import javax.swing.JFrame; 85 import javax.swing.JLabel; 86 import javax.swing.JMenu; 87 import javax.swing.JMenuBar; 88 import javax.swing.JMenuItem; 89 import javax.swing.JOptionPane; 90 import javax.swing.JPanel; 91 import javax.swing.JPopupMenu; 92 import javax.swing.JRadioButtonMenuItem; 93 import javax.swing.JScrollPane; 94 import javax.swing.JSplitPane; 95 import javax.swing.JTable; 96 import javax.swing.JTextArea; 97 import javax.swing.JToolBar; 98 import javax.swing.JTree; 99 import javax.swing.KeyStroke; 100 import javax.swing.RootPaneContainer; 101 import javax.swing.SwingUtilities; 102 import javax.swing.table.TableModel; 103 import javax.swing.tree.DefaultMutableTreeNode; 104 import javax.swing.tree.DefaultTreeModel; 105 import javax.swing.tree.MutableTreeNode; 106 import javax.swing.tree.TreeNode; 107 import javax.swing.tree.TreePath; 108 109 import org.hsqldb.lib.RCData; 110 import org.hsqldb.lib.java.JavaSystem; 111 112 //dmarshall@users - 20020101 - original swing port of DatabaseManager 113 //sqlbob@users 20020401 - patch 537501 by ulrivo - commandline arguments 114 //sqlbob@users 20020407 - patch 1.7.0 - reengineering and enhancements 115 //nickferguson@users 20021005 - patch 1.7.1 - enhancements 116 //deccles@users 2004 - 2008 - bug fixes and enhancements 117 //weconsultants@users 20041109 - version 1.8.0 - reengineering and enhancements: 118 // Added: Goodies 'Look and Feel'. 119 // Added: a Font Changer(Font Type\Style). 120 // Added: a Color Changer (foreground\bckground). 121 // Added: RowCounts for each JTree table nodes. 122 // Added: OneTouchExpandable attribute to JSplitPanes. 123 // Moved: setFramePositon code to a CommonSwing.setFramePositon() Method. 124 // Added: call to new method to handle exception processing (CommonSwing.errorMessage()); 125 // Added: Added a new pane added at the bottom of the Frame. (Status Icon and StatusLine). 126 // Added: 2 Methods (setStatusMessage()), one overrides the other. One to change the ruung status 127 // another to allow a message to be posted without changing the Status Icon if needed. 128 // Added: Added a customCursor for the current wait cursor 129 // Added: Ability to switch the current LAF while runing (Native,Java or Motif) 130 //unsaved@users 2005xxxx - improvements and bug fixes 131 132 /** 133 * Swing Tool for managing a JDBC database.<p> 134 * <pre> 135 * Usage: java DatabaseManagerSwing [--options] 136 * where options include: 137 * --driver <classname> jdbc driver class 138 * --url <name> jdbc url 139 * --user <name> username used for connection 140 * --password <password> password for this user 141 * --dir <path> default directory 142 * --script <file> reads from script file 143 * --urlid <urlid> get connection info from RC file 144 * --rcfile <file> use instead of default (with urlid) 145 * --noexit Don't exit JVM 146 * </pre> 147 * 148 * Note that the sys-table switch will not work for Oracle, because Oracle 149 * does not categorize their system tables correctly in the JDBC Metadata. 150 * 151 * @author dmarshall@users 152 * @author Bob Preston (sqlbob@users dot sourceforge.net) 153 * @version 2.3.0 154 * @since 1.7.0 155 */ 156 public class DatabaseManagerSwing extends JApplet 157 implements ActionListener, WindowListener, KeyListener, MouseListener { 158 159 /* 160 * This is down here because it is an implementation note, not a 161 * Javadoc comment! 162 * Tue Apr 26 16:38:54 EDT 2005 163 * Switched default switch method from "-switch" to "--switch" because 164 * "-switch" usage is ambiguous as used here. Single switches should 165 * be reserved for single-letter switches which can be mixed like 166 * "-u -r -l" = "-url". -blaine 167 */ 168 private static String homedir = null; 169 private boolean isOracle = false; // Need some workarounds for Oracle 170 171 static { 172 try { 173 Class c = Class.forName("sun.security.action.GetPropertyAction"); 174 Constructor constructor = c.getConstructor(new Class[]{ 175 String.class }); 176 java.security.PrivilegedAction a = 177 (java.security.PrivilegedAction) constructor.newInstance( 178 new Object[]{ "user.home" }); 179 180 homedir = (String) java.security.AccessController.doPrivileged(a); 181 } catch (IllegalAccessException e) { 182 System.err.println( 183 "Failed to get home directory.\n" 184 + "Therefore not retrieving/storing user preferences.\n(" 185 + e.getMessage() + ')'); 186 } catch (NoSuchMethodException e) { 187 System.err.println( 188 "Failed to get home directory.\n" 189 + "Therefore not retrieving/storing user preferences.\n(" 190 + e.getMessage() + ')'); 191 } catch (ClassNotFoundException e) { 192 System.err.println( 193 "Failed to get home directory.\n" 194 + "Therefore not retrieving/storing user preferences.\n(" 195 + e.getMessage() + ')'); 196 } catch (InstantiationException e) { 197 System.err.println( 198 "Failed to get home directory.\n" 199 + "Therefore not retrieving/storing user preferences.\n(" 200 + e.getMessage() + ')'); 201 } catch (InvocationTargetException e) { 202 System.err.println( 203 "Failed to get home directory.\n" 204 + "Therefore not retrieving/storing user preferences.\n(" 205 + e.getMessage() + ')'); 206 } catch (AccessControlException e) { 207 System.err.println( 208 "Failed to get home directory.\n" 209 + "Therefore not retrieving/storing user preferences.\n(" 210 + e.getMessage() + ')'); 211 } 212 } 213 214 ArrayList localActionList = new ArrayList(); 215 private JFrame jframe = null; 216 private static final String DEFAULT_RCFILE = homedir + "/dbmanager.rc"; 217 private static boolean TT_AVAILABLE = false; 218 219 static { 220 try { 221 Class.forName(DatabaseManagerSwing.class.getPackage().getName() 222 + ".Transfer"); 223 224 TT_AVAILABLE = true; 225 } catch (Throwable t) { 226 227 //System.err.println("Failed to get " 228 //+ DatabaseManagerSwing.class.getPackage().getName() 229 //+ ".Transfer: " + t); 230 // Enable this print statement for debugging class access problems. 231 } 232 } 233 234 private static final String HELP_TEXT = 235 "See the HSQLDB Utilities Guide, forums and mailing lists \n" 236 + "at http://hsqldb.org.\n\n" 237 + "Please paste the following version identifier with any\n" 238 + "problem reports or help requests: $Revision: 5221 $" 239 + (TT_AVAILABLE ? "" 240 : ("\n\nTransferTool classes are not in CLASSPATH.\n" 241 + "To enable the Tools menu, add 'transfer.jar' " 242 + "to your class path.")); 243 ; 244 private static final String ABOUT_TEXT = 245 "$Revision: 5221 $ of DatabaseManagerSwing\n\n" 246 + "Copyright (c) 2001-2010, The HSQL Development Group.\n" 247 + "http://hsqldb.org (Utilities Guide available at this site).\n\n\n" 248 + "You may use and redistribute according to the HSQLDB\n" 249 + "license documented in the source code and at the web\n" 250 + "site above." 251 + (TT_AVAILABLE ? "\n\nTransferTool options are available." 252 : ""); 253 static final String NL = System.getProperty("line.separator"); 254 static final String NULL_STR = "[null]"; 255 static int iMaxRecent = 24; 256 Connection cConn; 257 Connection rowConn; // holds the connetion for getting table row counts 258 DatabaseMetaData dMeta; 259 Statement sStatement; 260 JMenu mRecent; 261 String[] sRecent; 262 int iRecent; 263 JTextArea txtCommand; 264 JScrollPane txtCommandScroll; 265 JButton butExecute; 266 JTree tTree; 267 JScrollPane tScrollPane; 268 DefaultTreeModel treeModel; 269 TableModel tableModel; 270 DefaultMutableTreeNode rootNode; 271 JPanel pResult; 272 long lTime; 273 GridSwing gResult; 274 275 /** 276 * I think this is used to store model info whether we're using Grid 277 * output or not (this object is queried for data to display for 278 * text output mode). 279 * If so, the presentation-independent model part should be moved 280 * to an appropriately-named class instead of storing pure data in 281 * a Swing-specific class. 282 */ 283 JTable gResultTable; 284 JScrollPane gScrollPane; 285 JTextArea txtResult; 286 JScrollPane txtResultScroll; 287 JSplitPane nsSplitPane; // Contains query over results 288 JSplitPane ewSplitPane; // Contains tree beside nsSplitPane 289 boolean bHelp; 290 RootPaneContainer fMain; 291 static boolean bMustExit; 292 293 /** Value of this variable only retained if huge input script read in. */ 294 String sqlScriptBuffer = null; 295 JToolBar jtoolbar; 296 private boolean showSchemas = true; 297 private boolean showTooltips = true; 298 private boolean autoRefresh = true; 299 private boolean gridFormat = true; 300 301 // Added: (weconsultants@users) 302 static DatabaseManagerSwing refForFontDialogSwing; 303 boolean displayRowCounts = false; 304 boolean showSys = false; 305 boolean showIndexDetails = true; 306 String currentLAF = null; 307 JPanel pStatus; 308 static JButton iReadyStatus; 309 JRadioButtonMenuItem rbAllSchemas = new JRadioButtonMenuItem("*"); 310 JMenuItem mitemAbout = new JMenuItem("About", 'A'); 311 JMenuItem mitemHelp = new JMenuItem("Help", 'H'); 312 JMenuItem mitemUpdateSchemas = new JMenuItem("Update Schemas"); 313 JCheckBoxMenuItem boxAutoCommit = 314 new JCheckBoxMenuItem(AUTOCOMMIT_BOX_TEXT); 315 JCheckBoxMenuItem boxLogging = new JCheckBoxMenuItem(LOGGING_BOX_TEXT); 316 JCheckBoxMenuItem boxShowSchemas = 317 new JCheckBoxMenuItem(SHOWSCHEMAS_BOX_TEXT); 318 JCheckBoxMenuItem boxAutoRefresh = 319 new JCheckBoxMenuItem(AUTOREFRESH_BOX_TEXT); 320 JCheckBoxMenuItem boxTooltips = new JCheckBoxMenuItem(SHOWTIPS_BOX_TEXT); 321 JCheckBoxMenuItem boxRowCounts = new JCheckBoxMenuItem(ROWCOUNTS_BOX_TEXT); 322 JCheckBoxMenuItem boxShowGrid = new JCheckBoxMenuItem(GRID_BOX_TEXT); 323 JCheckBoxMenuItem boxShowSys = new JCheckBoxMenuItem(SHOWSYS_BOX_TEXT); 324 325 // Consider adding GTK and Plaf L&Fs. 326 JRadioButtonMenuItem rbNativeLF = 327 new JRadioButtonMenuItem("Native Look & Feel"); 328 JRadioButtonMenuItem rbJavaLF = 329 new JRadioButtonMenuItem("Java Look & Feel"); 330 JRadioButtonMenuItem rbMotifLF = 331 new JRadioButtonMenuItem("Motif Look & Feel"); 332 JLabel jStatusLine; 333 static String READY_STATUS = "Ready"; 334 private static final String AUTOCOMMIT_BOX_TEXT = "Autocommit mode"; 335 private static final String LOGGING_BOX_TEXT = "Logging mode"; 336 private static final String SHOWSCHEMAS_BOX_TEXT = "Show schemas"; 337 private static final String AUTOREFRESH_BOX_TEXT = "Auto-refresh tree"; 338 private static final String SHOWTIPS_BOX_TEXT = "Show Tooltips"; 339 private static final String ROWCOUNTS_BOX_TEXT = "Show row counts"; 340 private static final String SHOWSYS_BOX_TEXT = "Show system tables"; 341 private static final String GRID_BOX_TEXT = 342 "Show results in Grid (a.o.t. Text)"; 343 344 // variables to hold the default cursors for these top level swing objects 345 // so we can restore them when we exit our thread 346 Cursor fMainCursor; 347 Cursor txtCommandCursor; 348 Cursor txtResultCursor; 349 HashMap tipMap = new HashMap(); 350 private JMenu mnuSchemas = new JMenu("Schemas"); 351 352 /** 353 * Wait Cursor 354 */ 355 356 // Changed: (weconsultants@users): commonted out the, out of the box, cursor to use a custom cursor 357 private final Cursor waitCursor = new Cursor(Cursor.WAIT_CURSOR); 358 359 //getToolkit().createCustomCursor(CommonSwing.getIcon("SystemCursor"), 360 // new Point(4, 4), "HourGlass cursor"); 361 // (ulrivo): variables set by arguments from the commandline 362 static String defDriver = "org.hsqldb.jdbcDriver"; 363 static String defURL = "jdbc:hsqldb:mem:."; 364 static String defUser = "SA"; 365 static String defPassword = ""; 366 static String defScript; 367 static String defDirectory; 368 private String schemaFilter = null; 369 DatabaseManagerSwing()370 public DatabaseManagerSwing() { 371 jframe = new JFrame("HSQLDB DatabaseManager"); 372 fMain = jframe; 373 } 374 ; 375 DatabaseManagerSwing(JFrame frameIn)376 public DatabaseManagerSwing(JFrame frameIn) { 377 jframe = frameIn; 378 fMain = jframe; 379 } 380 ; 381 init()382 public void init() { 383 384 javax.swing.AbstractButton btn; 385 386 fMain = this; 387 388 main(); 389 390 for (int i = 0; i < localActionList.size(); i++) { 391 btn = (javax.swing.AbstractButton) localActionList.get(i); 392 393 btn.setEnabled(false); 394 } 395 396 Connection c = null; 397 boolean auto = false; 398 399 if (getParameter("jdbcDriver") != null) { 400 auto = true; 401 defDriver = getParameter("jdbcDriver"); 402 } 403 404 if (getParameter("jdbcUrl") != null) { 405 auto = true; 406 defURL = getParameter("jdbcUrl"); 407 } 408 409 if (getParameter("jdbcUser") != null) { 410 auto = true; 411 defUser = getParameter("jdbcUser"); 412 } 413 414 if (getParameter("jdbcPassword") != null) { 415 auto = true; 416 defPassword = getParameter("jdbcPassword"); 417 } 418 419 try { 420 setWaiting("Initializing"); 421 422 //insertTestData(); 423 //updateAutoCommitBox(); 424 c = (auto 425 ? ConnectionDialogSwing.createConnection(defDriver, defURL, 426 defUser, defPassword) 427 : ConnectionDialogSwing.createConnection(jframe, "Connect")); 428 } catch (Exception e) { 429 430 // Added: (weconsultants@users) 431 CommonSwing.errorMessage(e); 432 } finally { 433 setWaiting(null); 434 } 435 436 if (c != null) { 437 connect(c); 438 } 439 440 if (getParameter("loadSampleData") != null 441 && getParameter("loadSampleData").equals("true")) { 442 insertTestData(); 443 444 try { 445 Thread.sleep(1000); 446 } catch (InterruptedException ie) {} 447 ; 448 449 // I don't know why, but the tree refresh below sometimes 450 // doesn't show all tables unless I put this delay here. 451 refreshTree(); 452 } 453 454 if (getParameter("schemaFilter") != null) { 455 schemaFilter = getParameter("schemaFilter"); 456 } 457 } 458 459 /** 460 * Run with --help switch for usage instructions. 461 * 462 * @throws IllegalArgumentException for the obvious reason 463 */ main(String[] arg)464 public static void main(String[] arg) { 465 466 System.getProperties().put("sun.java2d.noddraw", "true"); 467 468 // (ulrivo): read all arguments from the command line 469 String currentArg; 470 String lowerArg; 471 String urlid = null; 472 String rcFile = null; 473 boolean autoConnect = false; 474 boolean urlidConnect = false; 475 476 bMustExit = true; 477 478 for (int i = 0; i < arg.length; i++) { 479 currentArg = arg[i]; 480 lowerArg = arg[i].toLowerCase(); 481 482 if (lowerArg.startsWith("--")) { 483 lowerArg = lowerArg.substring(1); 484 } 485 486 if (lowerArg.equals("-noexit") || lowerArg.equals("-help")) { 487 488 // 489 } else if (i == arg.length - 1) { 490 throw new IllegalArgumentException("No value for argument " 491 + currentArg); 492 } 493 494 i++; 495 496 if (lowerArg.equals("-driver")) { 497 defDriver = arg[i]; 498 autoConnect = true; 499 } else if (lowerArg.equals("-url")) { 500 defURL = arg[i]; 501 autoConnect = true; 502 } else if (lowerArg.equals("-user")) { 503 defUser = arg[i]; 504 autoConnect = true; 505 } else if (lowerArg.equals("-password")) { 506 defPassword = arg[i]; 507 autoConnect = true; 508 } else if (lowerArg.equals("-urlid")) { 509 urlid = arg[i]; 510 urlidConnect = true; 511 } else if (lowerArg.equals("-rcfile")) { 512 rcFile = arg[i]; 513 urlidConnect = true; 514 } else if (lowerArg.equals("-dir")) { 515 defDirectory = arg[i]; 516 } else if (lowerArg.equals("-script")) { 517 defScript = arg[i]; 518 } else if (lowerArg.equals("-noexit")) { 519 bMustExit = false; 520 521 i--; 522 } else if (lowerArg.equals("-help")) { 523 showUsage(); 524 525 return; 526 } else { 527 /* Syntax ERRORS should either throw or exit with non-0 status. 528 * In our case, it may be unsafe to exit, so we throw. 529 * (I.e. should provide easy way for caller to programmatically 530 * determine that there was an invocation problem). 531 */ 532 throw new IllegalArgumentException( 533 "invalid argrument " + currentArg + " try: java... " 534 + DatabaseManagerSwing.class.getName() + " --help"); 535 536 // No reason to localize, since the main syntax message is 537 // not localized. 538 } 539 } 540 541 DatabaseManagerSwing m = 542 new DatabaseManagerSwing(new JFrame("HSQL Database Manager")); 543 544 // Added: (weconsultants@users): Need databaseManagerSwing for later Reference 545 refForFontDialogSwing = m; 546 547 m.main(); 548 549 Connection c = null; 550 551 m.setWaiting("Initializing"); 552 553 try { 554 if (autoConnect && urlidConnect) { 555 throw new IllegalArgumentException( 556 "You may not specify both (urlid) AND (url/user/password)."); 557 } 558 559 if (autoConnect) { 560 c = ConnectionDialogSwing.createConnection(defDriver, defURL, 561 defUser, defPassword); 562 } else if (urlidConnect) { 563 if (urlid == null) { 564 throw new IllegalArgumentException( 565 "You must specify an 'urlid' to use an RC file"); 566 } 567 568 autoConnect = true; 569 570 String rcfilepath = (rcFile == null) ? DEFAULT_RCFILE 571 : rcFile; 572 RCData rcdata = new RCData(new File(rcfilepath), urlid); 573 574 c = rcdata.getConnection( 575 null, System.getProperty("javax.net.ssl.trustStore")); 576 } else { 577 c = ConnectionDialogSwing.createConnection(m.jframe, 578 "Connect"); 579 } 580 } catch (Exception e) { 581 582 // Added: (weconsultants@users) 583 CommonSwing.errorMessage(e); 584 } finally { 585 m.setWaiting(null); 586 } 587 588 if (c != null) { 589 m.connect(c); 590 } 591 592 // Added: (weconsultants@users): For preloadng FontDialogSwing 593 FontDialogSwing.creatFontDialog(refForFontDialogSwing); 594 m.start(); 595 } 596 597 /** 598 * This stuff is all quick, except for the refreshTree(). 599 * This unit can be kicked off in main Gui thread. The refreshTree 600 * will be backgrounded and this method will return. 601 */ connect(Connection c)602 public void connect(Connection c) { 603 604 schemaFilter = null; 605 606 if (c == null) { 607 return; 608 } 609 610 if (cConn != null) { 611 try { 612 cConn.close(); 613 } catch (SQLException e) { 614 615 // Added: (weconsultants@users) 616 CommonSwing.errorMessage(e); 617 } 618 } 619 620 cConn = c; 621 622 // Added: (weconsultants@users) Need to barrow to get the table rowcounts 623 rowConn = c; 624 625 try { 626 dMeta = cConn.getMetaData(); 627 isOracle = (dMeta.getDatabaseProductName().indexOf("Oracle") >= 0); 628 sStatement = cConn.createStatement(); 629 630 updateAutoCommitBox(); 631 632 // Workaround for EXTREME SLOWNESS getting this info from O. 633 showIndexDetails = !isOracle; 634 635 Driver driver = DriverManager.getDriver(dMeta.getURL()); 636 ConnectionSetting newSetting = new ConnectionSetting( 637 dMeta.getDatabaseProductName(), driver.getClass().getName(), 638 dMeta.getURL(), 639 dMeta.getUserName().replaceAll("@localhost", ""), ""); 640 Hashtable settings = 641 ConnectionDialogCommon.loadRecentConnectionSettings(); 642 643 ConnectionDialogCommon.addToRecentConnectionSettings(settings, 644 newSetting); 645 ConnectionDialogSwing.setConnectionSetting(newSetting); 646 refreshTree(); 647 clearResultPanel(); 648 649 if (fMain instanceof JApplet) { 650 getAppletContext().showStatus( 651 "JDBC Connection established to a " 652 + dMeta.getDatabaseProductName() + " v. " 653 + dMeta.getDatabaseProductVersion() + " database as '" 654 + dMeta.getUserName() + "'."); 655 } 656 } catch (SQLException e) { 657 658 // Added: (weconsultants@users) 659 CommonSwing.errorMessage(e); 660 } catch (IOException e) { 661 662 // Added: (weconsultants@users) 663 CommonSwing.errorMessage(e); 664 } catch (Exception e) { 665 CommonSwing.errorMessage(e); 666 } 667 } 668 showUsage()669 private static void showUsage() { 670 671 System.out.println( 672 "Usage: java DatabaseManagerSwing [--options]\n" 673 + "where options include:\n" 674 + " --help show this message\n" 675 + " --driver <classname> jdbc driver class\n" 676 + " --url <name> jdbc url\n" 677 + " --user <name> username used for connection\n" 678 + " --password <password> password for this user\n" 679 + " --urlid <urlid> use url/user/password/driver in rc file\n" 680 + " --rcfile <file> (defaults to 'dbmanager.rc' in home dir)\n" 681 + " --dir <path> default directory\n" 682 + " --script <file> reads from script file\n" 683 + " --noexit do not call system.exit()"); 684 } 685 insertTestData()686 private void insertTestData() { 687 688 try { 689 DatabaseManagerCommon.createTestTables(sStatement); 690 txtCommand.setText( 691 DatabaseManagerCommon.createTestData(sStatement)); 692 693 for (int i = 0; i < DatabaseManagerCommon.testDataSql.length; 694 i++) { 695 addToRecent(DatabaseManagerCommon.testDataSql[i]); 696 } 697 698 executeCurrentSQL(); 699 } catch (SQLException e) { 700 701 // Added: (weconsultants@users) 702 CommonSwing.errorMessage(e); 703 } 704 } 705 setMustExit(boolean b)706 public void setMustExit(boolean b) { 707 this.bMustExit = b; 708 } 709 710 private DBMPrefs prefs = null; 711 main()712 public void main() { 713 714 JMenu jmenu; 715 JMenuItem mitem; 716 717 try { 718 prefs = new DBMPrefs(fMain instanceof JApplet); 719 } catch (Exception e) { 720 /* 721 System.err.println( 722 "Failed to load preferences. Proceeding with defaults:\n"); 723 */ 724 } 725 726 if (prefs == null) { 727 setLF(CommonSwing.Native); 728 } else { 729 autoRefresh = prefs.autoRefresh; 730 displayRowCounts = prefs.showRowCounts; 731 showSys = prefs.showSysTables; 732 showSchemas = prefs.showSchemas; 733 gridFormat = prefs.resultGrid; 734 showTooltips = prefs.showTooltips; 735 736 setLF(prefs.laf); 737 } 738 739 // (ulrivo): An actual icon. N.b., this adds some tips to the tip map 740 fMain.getContentPane().add(createToolBar(), "North"); 741 742 if (fMain instanceof java.awt.Frame) { 743 ((java.awt.Frame) fMain).setIconImage( 744 CommonSwing.getIcon("Frame")); 745 } 746 747 if (fMain instanceof java.awt.Window) { 748 ((java.awt.Window) fMain).addWindowListener(this); 749 } 750 751 JMenuBar bar = new JMenuBar(); 752 753 // used shortcuts: CERGTSIUDOLM 754 String[] fitems = { 755 "-Connect...", "--", "OOpen Script...", "-Save Script...", 756 "-Save Result...", "--", "-Exit" 757 }; 758 759 jmenu = addMenu(bar, "File", fitems); 760 761 // All actions after Connect and the divider are local. 762 for (int i = 2; i < jmenu.getItemCount(); i++) { 763 mitem = jmenu.getItem(i); 764 765 if (mitem != null) { 766 localActionList.add(mitem); 767 } 768 } 769 770 Object[] vitems = { 771 "RRefresh Tree", boxAutoRefresh, "--", boxRowCounts, boxShowSys, 772 boxShowSchemas, boxShowGrid 773 }; 774 775 addMenu(bar, "View", vitems); 776 777 String[] sitems = { 778 "SSELECT", "IINSERT", "UUPDATE", "DDELETE", "EEXECUTE", "---", 779 "-CREATE TABLE", "-DROP TABLE", "-CREATE INDEX", "-DROP INDEX", 780 "--", "CCOMMIT*", "LROLLBACK*", "-CHECKPOINT*", "-SCRIPT", "-SET", 781 "-SHUTDOWN", "--", "-Test Script" 782 }; 783 784 addMenu(bar, "Command", sitems); 785 786 mRecent = new JMenu("Recent"); 787 788 mRecent.setMnemonic(KeyEvent.VK_R); 789 bar.add(mRecent); 790 791 ButtonGroup lfGroup = new ButtonGroup(); 792 793 lfGroup.add(rbNativeLF); 794 lfGroup.add(rbJavaLF); 795 lfGroup.add(rbMotifLF); 796 boxShowSchemas.setSelected(showSchemas); 797 boxShowGrid.setSelected(gridFormat); 798 boxTooltips.setSelected(showTooltips); 799 boxShowGrid.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, 800 Event.CTRL_MASK)); 801 boxAutoRefresh.setSelected(autoRefresh); 802 boxRowCounts.setSelected(displayRowCounts); 803 boxShowSys.setSelected(showSys); 804 rbNativeLF.setActionCommand("LFMODE:" + CommonSwing.Native); 805 rbJavaLF.setActionCommand("LFMODE:" + CommonSwing.Java); 806 rbMotifLF.setActionCommand("LFMODE:" + CommonSwing.Motif); 807 tipMap.put(mitemUpdateSchemas, "Refresh the schema list in this menu"); 808 tipMap.put(rbAllSchemas, "Display items in all schemas"); 809 tipMap.put(mitemAbout, "Display product information"); 810 tipMap.put(mitemHelp, "Display advice for obtaining help"); 811 tipMap.put(boxAutoRefresh, 812 "Refresh tree (and schema list) automatically" 813 + "when YOU modify database objects"); 814 tipMap.put(boxShowSchemas, 815 "Display object names in tree-like schemaname.basename"); 816 tipMap.put(rbNativeLF, 817 "Set Look and Feel to Native for your platform"); 818 tipMap.put(rbJavaLF, "Set Look and Feel to Java"); 819 tipMap.put(rbMotifLF, "Set Look and Feel to Motif"); 820 boxTooltips.setToolTipText("Display tooltips (hover text), like this"); 821 tipMap.put(boxAutoCommit, 822 "Shows current Auto-commit mode. Click to change"); 823 tipMap.put( 824 boxLogging, 825 "Shows current JDBC DriverManager logging mode. Click to change"); 826 tipMap.put(boxShowSys, "Show system tables in table tree to the left"); 827 tipMap.put(boxShowGrid, "Show query results in grid (in text if off)"); 828 tipMap.put(boxRowCounts, "Show row counts with table names in tree"); 829 boxAutoRefresh.setMnemonic(KeyEvent.VK_C); 830 boxShowSchemas.setMnemonic(KeyEvent.VK_Y); 831 boxAutoCommit.setMnemonic(KeyEvent.VK_A); 832 boxShowSys.setMnemonic(KeyEvent.VK_Y); 833 boxShowGrid.setMnemonic(KeyEvent.VK_G); 834 boxRowCounts.setMnemonic(KeyEvent.VK_C); 835 boxLogging.setMnemonic(KeyEvent.VK_L); 836 rbAllSchemas.setMnemonic(KeyEvent.VK_ASTERISK); 837 rbNativeLF.setMnemonic(KeyEvent.VK_N); 838 rbJavaLF.setMnemonic(KeyEvent.VK_J); 839 rbMotifLF.setMnemonic(KeyEvent.VK_M); 840 mitemUpdateSchemas.setMnemonic(KeyEvent.VK_U); 841 842 Object[] soptions = { 843 844 // Added: (weconsultants@users) New menu options 845 rbNativeLF, rbJavaLF, rbMotifLF, "--", "-Set Fonts", "--", 846 boxAutoCommit, "--", "-Disable MaxRows", "-Set MaxRows to 100", 847 "--", boxLogging, "--", "-Insert test data" 848 }; 849 850 addMenu(bar, "Options", soptions); 851 852 String[] stools = { 853 "-Dump", "-Restore", "-Transfer" 854 }; 855 856 jmenu = addMenu(bar, "Tools", stools); 857 858 jmenu.setEnabled(TT_AVAILABLE); 859 localActionList.add(jmenu); 860 861 for (int i = 0; i < jmenu.getItemCount(); i++) { 862 mitem = jmenu.getItem(i); 863 864 if (mitem != null) { 865 localActionList.add(mitem); 866 } 867 } 868 869 mnuSchemas.setMnemonic(KeyEvent.VK_S); 870 bar.add(mnuSchemas); 871 872 JMenu mnuHelp = new JMenu("Help"); 873 874 mnuHelp.setMnemonic(KeyEvent.VK_H); 875 mnuHelp.add(mitemAbout); 876 mnuHelp.add(mitemHelp); 877 mnuHelp.add(boxTooltips); 878 rbAllSchemas.addActionListener(schemaListListener); 879 880 // May be illegal: 881 mitemUpdateSchemas.addActionListener(new ActionListener() { 882 883 public void actionPerformed(ActionEvent actionevent) { 884 updateSchemaList(); 885 } 886 }); 887 mitemHelp.addActionListener(new ActionListener() { 888 889 public void actionPerformed(ActionEvent actionevent) { 890 891 JOptionPane.showMessageDialog(fMain.getContentPane(), 892 HELP_TEXT, "HELP", 893 JOptionPane.INFORMATION_MESSAGE); 894 } 895 }); 896 mitemAbout.addActionListener(new ActionListener() { 897 898 public void actionPerformed(ActionEvent actionevent) { 899 900 JOptionPane.showMessageDialog(fMain.getContentPane(), 901 ABOUT_TEXT, "About", 902 JOptionPane.INFORMATION_MESSAGE); 903 } 904 }); 905 boxTooltips.addActionListener(new ActionListener() { 906 907 public void actionPerformed(ActionEvent actionevent) { 908 909 showTooltips = boxTooltips.isSelected(); 910 911 resetTooltips(); 912 } 913 }); 914 bar.add(mnuHelp); 915 916 if (fMain instanceof JApplet) { 917 ((JApplet) fMain).setJMenuBar(bar); 918 } else if (fMain instanceof JFrame) { 919 ((JFrame) fMain).setJMenuBar(bar); 920 } 921 922 initGUI(); 923 924 sRecent = new String[iMaxRecent]; 925 926 // Modified: (weconsultants@users)Mode code to CommonSwing for general use 927 if (!(fMain instanceof JApplet)) { 928 CommonSwing.setFramePositon((JFrame) fMain); 929 } 930 931 // Modified: (weconsultants@users) Changed from deprecated show() 932 ((Component) fMain).setVisible(true); 933 934 // (ulrivo): load query from command line 935 if (defScript != null) { 936 if (defDirectory != null) { 937 defScript = defDirectory + File.separator + defScript; 938 } 939 940 // if insert stmet is thousands of records...skip showing it 941 // as text. Too huge. 942 sqlScriptBuffer = DatabaseManagerCommon.readFile(defScript); 943 944 if (4096 <= sqlScriptBuffer.length()) { 945 int eoThirdLine = sqlScriptBuffer.indexOf('\n'); 946 947 if (eoThirdLine > 0) { 948 eoThirdLine = sqlScriptBuffer.indexOf('\n', 949 eoThirdLine + 1); 950 } 951 952 if (eoThirdLine > 0) { 953 eoThirdLine = sqlScriptBuffer.indexOf('\n', 954 eoThirdLine + 1); 955 } 956 957 if (eoThirdLine < 1) { 958 eoThirdLine = 100; 959 } 960 961 txtCommand.setText( 962 "............... Script File loaded: " + defScript 963 + " ..................... \n" 964 + "............... Click Execute or Clear " 965 + "...................\n" 966 + sqlScriptBuffer.substring(0, eoThirdLine + 1) 967 + "..........................................." 968 + "..............................\n" 969 + "............................................." 970 + "............................\n"); 971 txtCommand.setEnabled(false); 972 } else { 973 txtCommand.setText(sqlScriptBuffer); 974 975 sqlScriptBuffer = null; 976 977 txtCommand.setEnabled(true); 978 } 979 } 980 981 // This must be done AFTER all tip texts are put into the map 982 resetTooltips(); 983 txtCommand.requestFocus(); 984 } 985 addMenu(JMenuBar b, String name, Object[] items)986 private JMenu addMenu(JMenuBar b, String name, Object[] items) { 987 988 JMenu menu = new JMenu(name); 989 990 menu.setMnemonic(name.charAt(0)); 991 addMenuItems(menu, items); 992 b.add(menu); 993 994 return menu; 995 } 996 addMenuItems(JMenu f, Object[] m)997 private void addMenuItems(JMenu f, Object[] m) { 998 999 /* 1000 * This method needs to be completely written or just 1001 * obliterated and we'll use the Menu objects directly. 1002 * Problem is, passing in Strings for menu elements makes it 1003 * extremely difficult to use non-text menu items (an important 1004 * part of a good Gui), hot-keys, mnemonic keys, tooltips. 1005 * Note the "trick" required here to set hot-keys. 1006 */ 1007 Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); 1008 1009 for (int i = 0; i < m.length; i++) { 1010 if (m[i].equals("--")) { 1011 f.addSeparator(); 1012 } else if (m[i].equals("---")) { 1013 1014 // (ulrivo): full size on screen with less than 640 width 1015 if (d.width >= 640) { 1016 f.addSeparator(); 1017 } else { 1018 return; 1019 } 1020 } else { 1021 JMenuItem item; 1022 1023 if (m[i] instanceof JMenuItem) { 1024 item = (JMenuItem) m[i]; 1025 } else if (m[i] instanceof String) { 1026 item = new JMenuItem(((String) m[i]).substring(1)); 1027 1028 char c = ((String) m[i]).charAt(0); 1029 1030 if (c != '-') { 1031 KeyStroke key = 1032 KeyStroke.getKeyStroke(c, Event.CTRL_MASK); 1033 1034 item.setAccelerator(key); 1035 } 1036 } else { 1037 throw new RuntimeException( 1038 "Unexpected element for menu item creation: " 1039 + m[i].getClass().getName()); 1040 } 1041 1042 item.addActionListener(this); 1043 f.add(item); 1044 } 1045 } 1046 } 1047 keyPressed(KeyEvent k)1048 public void keyPressed(KeyEvent k) {} 1049 keyReleased(KeyEvent k)1050 public void keyReleased(KeyEvent k) {} 1051 keyTyped(KeyEvent k)1052 public void keyTyped(KeyEvent k) { 1053 1054 if (k.getKeyChar() == '\n' && k.isControlDown()) { 1055 k.consume(); 1056 executeCurrentSQL(); 1057 } 1058 } 1059 1060 Thread dummyThread = new Thread("dummy"); 1061 actionPerformed(ActionEvent ev)1062 public void actionPerformed(ActionEvent ev) { 1063 1064 String s = ev.getActionCommand(); 1065 1066 if (s == null) { 1067 if (ev.getSource() instanceof JMenuItem) { 1068 s = ((JMenuItem) ev.getSource()).getText(); 1069 } 1070 } 1071 1072 if (s == null) {} 1073 else if (s.equals("Exit")) { 1074 windowClosing(null); 1075 } else if (s.equals("Transfer")) { 1076 Transfer.work(null); 1077 } else if (s.equals("Dump")) { 1078 Transfer.work(new String[]{ "-d" }); 1079 } else if (s.equals("Restore")) { 1080 JOptionPane.showMessageDialog( 1081 fMain.getContentPane(), 1082 "Use Ctrl-R or the View menu to\n" 1083 + "update nav. tree after Restoration", "Suggestion", 1084 JOptionPane.INFORMATION_MESSAGE); 1085 1086 // Regardless of whether autoRefresh is on, half of 1087 // Restore runs asynchronously, so we could only 1088 // update the tree from within the Transfer class. 1089 Transfer.work(new String[]{ "-r" }); 1090 1091 // Would be better to put the modal suggestion here, after the 1092 // user selects the import file, but that messes up the z 1093 // layering of the 3 windows already displayed. 1094 } else if (s.equals(LOGGING_BOX_TEXT)) { 1095 JavaSystem.setLogToSystem(boxLogging.isSelected()); 1096 } else if (s.equals(AUTOREFRESH_BOX_TEXT)) { 1097 autoRefresh = boxAutoRefresh.isSelected(); 1098 1099 refreshTree(); 1100 } else if (s.equals("Refresh Tree")) { 1101 refreshTree(); 1102 } else if (s.startsWith("#")) { 1103 int i = Integer.parseInt(s.substring(1)); 1104 1105 txtCommand.setText(sRecent[i]); 1106 } else if (s.equals("Connect...")) { 1107 Connection newCon = null; 1108 1109 try { 1110 setWaiting("Connecting"); 1111 1112 newCon = ConnectionDialogSwing.createConnection(jframe, 1113 "Connect"); 1114 } finally { 1115 setWaiting(null); 1116 } 1117 1118 connect(newCon); 1119 } else if (s.equals(GRID_BOX_TEXT)) { 1120 gridFormat = boxShowGrid.isSelected(); 1121 1122 displayResults(); 1123 } else if (s.equals("Open Script...")) { 1124 JFileChooser f = new JFileChooser("."); 1125 1126 f.setDialogTitle("Open Script..."); 1127 1128 // (ulrivo): set default directory if set from command line 1129 if (defDirectory != null) { 1130 f.setCurrentDirectory(new File(defDirectory)); 1131 } 1132 1133 int option = f.showOpenDialog((Component) fMain); 1134 1135 if (option == JFileChooser.APPROVE_OPTION) { 1136 File file = f.getSelectedFile(); 1137 1138 if (file != null) { 1139 sqlScriptBuffer = 1140 DatabaseManagerCommon.readFile(file.getAbsolutePath()); 1141 1142 if (4096 <= sqlScriptBuffer.length()) { 1143 int eoThirdLine = sqlScriptBuffer.indexOf('\n'); 1144 1145 if (eoThirdLine > 0) { 1146 eoThirdLine = sqlScriptBuffer.indexOf('\n', 1147 eoThirdLine 1148 + 1); 1149 } 1150 1151 if (eoThirdLine > 0) { 1152 eoThirdLine = sqlScriptBuffer.indexOf('\n', 1153 eoThirdLine 1154 + 1); 1155 } 1156 1157 if (eoThirdLine < 1) { 1158 eoThirdLine = 100; 1159 } 1160 1161 txtCommand.setText( 1162 "............... Script File loaded: " + file 1163 + " ..................... \n" 1164 + "............... Click Execute or Clear " 1165 + "...................\n" 1166 + sqlScriptBuffer.substring(0, eoThirdLine + 1) 1167 + "........................................." 1168 + "................................\n" 1169 + "..........................................." 1170 + "..............................\n"); 1171 txtCommand.setEnabled(false); 1172 } else { 1173 txtCommand.setText(sqlScriptBuffer); 1174 1175 sqlScriptBuffer = null; 1176 1177 txtCommand.setEnabled(true); 1178 } 1179 } 1180 } 1181 } else if (s.equals("Save Script...")) { 1182 JFileChooser f = new JFileChooser("."); 1183 1184 f.setDialogTitle("Save Script"); 1185 1186 // (ulrivo): set default directory if set from command line 1187 if (defDirectory != null) { 1188 f.setCurrentDirectory(new File(defDirectory)); 1189 } 1190 1191 int option = f.showSaveDialog((Component) fMain); 1192 1193 if (option == JFileChooser.APPROVE_OPTION) { 1194 File file = f.getSelectedFile(); 1195 1196 if (file != null) { 1197 DatabaseManagerCommon.writeFile(file.getAbsolutePath(), 1198 txtCommand.getText()); 1199 } 1200 } 1201 } else if (s.equals("Save Result...")) { 1202 JFileChooser f = new JFileChooser("."); 1203 1204 f.setDialogTitle("Save Result..."); 1205 1206 // (ulrivo): set default directory if set from command line 1207 if (defDirectory != null) { 1208 f.setCurrentDirectory(new File(defDirectory)); 1209 } 1210 1211 int option = f.showSaveDialog((Component) fMain); 1212 1213 if (option == JFileChooser.APPROVE_OPTION) { 1214 File file = f.getSelectedFile(); 1215 1216 if (file != null) { 1217 showResultInText(); 1218 DatabaseManagerCommon.writeFile(file.getAbsolutePath(), 1219 txtResult.getText()); 1220 } 1221 } 1222 } else if (s.equals(SHOWSYS_BOX_TEXT)) { 1223 showSys = boxShowSys.isSelected(); 1224 1225 refreshTree(); 1226 } else if (s.equals(ROWCOUNTS_BOX_TEXT)) { 1227 displayRowCounts = boxRowCounts.isSelected(); 1228 1229 refreshTree(); 1230 } else if (s.startsWith("LFMODE:")) { 1231 setLF(s.substring("LFMODE:".length())); 1232 } else if (s.equals("Set Fonts")) { 1233 1234 // Added: (weconsultants@users) 1235 FontDialogSwing.creatFontDialog(refForFontDialogSwing); 1236 } else if (s.equals(AUTOCOMMIT_BOX_TEXT)) { 1237 try { 1238 cConn.setAutoCommit(boxAutoCommit.isSelected()); 1239 } catch (SQLException e) { 1240 boxAutoCommit.setSelected(!boxAutoCommit.isSelected()); 1241 1242 // Added: (weconsultants@users) 1243 CommonSwing.errorMessage(e); 1244 } 1245 } else if (s.equals("COMMIT*")) { 1246 try { 1247 cConn.commit(); 1248 showHelp(new String[] { 1249 "", "COMMIT executed" 1250 }); 1251 } catch (SQLException e) { 1252 1253 // Added: (weconsultants@users) 1254 CommonSwing.errorMessage(e); 1255 } 1256 } else if (s.equals("Insert test data")) { 1257 insertTestData(); 1258 refreshTree(); 1259 } else if (s.equals("ROLLBACK*")) { 1260 try { 1261 cConn.rollback(); 1262 showHelp(new String[] { 1263 "", "ROLLBACK executed" 1264 }); 1265 } catch (SQLException e) { 1266 1267 // Added: (weconsultants@users) 1268 CommonSwing.errorMessage(e); 1269 } 1270 } else if (s.equals("Disable MaxRows")) { 1271 try { 1272 sStatement.setMaxRows(0); 1273 } catch (SQLException e) { 1274 1275 // Added: (weconsultants@users) 1276 CommonSwing.errorMessage(e); 1277 } 1278 } else if (s.equals("Set MaxRows to 100")) { 1279 try { 1280 sStatement.setMaxRows(100); 1281 } catch (SQLException e) { 1282 CommonSwing.errorMessage(e); 1283 } 1284 } else if (s.equals("SELECT")) { 1285 showHelp(DatabaseManagerCommon.selectHelp); 1286 } else if (s.equals("INSERT")) { 1287 showHelp(DatabaseManagerCommon.insertHelp); 1288 } else if (s.equals("UPDATE")) { 1289 showHelp(DatabaseManagerCommon.updateHelp); 1290 } else if (s.equals("DELETE")) { 1291 showHelp(DatabaseManagerCommon.deleteHelp); 1292 } else if (s.equals("EXECUTE")) { 1293 executeCurrentSQL(); 1294 } else if (s.equals("CREATE TABLE")) { 1295 showHelp(DatabaseManagerCommon.createTableHelp); 1296 } else if (s.equals("DROP TABLE")) { 1297 showHelp(DatabaseManagerCommon.dropTableHelp); 1298 } else if (s.equals("CREATE INDEX")) { 1299 showHelp(DatabaseManagerCommon.createIndexHelp); 1300 } else if (s.equals("DROP INDEX")) { 1301 showHelp(DatabaseManagerCommon.dropIndexHelp); 1302 } else if (s.equals("CHECKPOINT*")) { 1303 try { 1304 cConn.createStatement().executeUpdate("CHECKPOINT"); 1305 showHelp(new String[] { 1306 "", "CHECKPOINT executed" 1307 }); 1308 } catch (SQLException e) { 1309 CommonSwing.errorMessage(e); 1310 } 1311 } else if (s.equals("SCRIPT")) { 1312 showHelp(DatabaseManagerCommon.scriptHelp); 1313 } else if (s.equals("SHUTDOWN")) { 1314 showHelp(DatabaseManagerCommon.shutdownHelp); 1315 } else if (s.equals("SET")) { 1316 showHelp(DatabaseManagerCommon.setHelp); 1317 } else if (s.equals("Test Script")) { 1318 showHelp(DatabaseManagerCommon.testHelp); 1319 } else if (s.equals(SHOWSCHEMAS_BOX_TEXT)) { 1320 showSchemas = boxShowSchemas.isSelected(); 1321 1322 refreshTree(); 1323 } else { 1324 throw new RuntimeException("Unexpected action triggered: " + s); 1325 } 1326 } 1327 displayResults()1328 private void displayResults() { 1329 1330 if (gridFormat) { 1331 setResultsInGrid(); 1332 } else { 1333 setResultsInText(); 1334 } 1335 } 1336 setResultsInGrid()1337 private void setResultsInGrid() { 1338 1339 pResult.removeAll(); 1340 pResult.add(gScrollPane, BorderLayout.CENTER); 1341 pResult.doLayout(); 1342 gResult.fireTableChanged(null); 1343 pResult.repaint(); 1344 } 1345 setResultsInText()1346 private void setResultsInText() { 1347 1348 pResult.removeAll(); 1349 pResult.add(txtResultScroll, BorderLayout.CENTER); 1350 pResult.doLayout(); 1351 showResultInText(); 1352 pResult.repaint(); 1353 } 1354 showHelp(String[] help)1355 private void showHelp(String[] help) { 1356 1357 txtCommand.setText(help[0]); 1358 1359 bHelp = true; 1360 1361 pResult.removeAll(); 1362 pResult.add(txtResultScroll, BorderLayout.CENTER); 1363 pResult.doLayout(); 1364 txtResult.setText(help[1]); 1365 pResult.repaint(); 1366 txtCommand.requestFocus(); 1367 txtCommand.setCaretPosition(help[0].length()); 1368 } 1369 windowActivated(WindowEvent e)1370 public void windowActivated(WindowEvent e) {} 1371 windowDeactivated(WindowEvent e)1372 public void windowDeactivated(WindowEvent e) {} 1373 windowClosed(WindowEvent e)1374 public void windowClosed(WindowEvent e) {} 1375 windowDeiconified(WindowEvent e)1376 public void windowDeiconified(WindowEvent e) {} 1377 windowIconified(WindowEvent e)1378 public void windowIconified(WindowEvent e) {} 1379 windowOpened(WindowEvent e)1380 public void windowOpened(WindowEvent e) {} 1381 windowClosing(WindowEvent ev)1382 public void windowClosing(WindowEvent ev) { 1383 1384 stop(); 1385 1386 try { 1387 if (cConn != null) { 1388 cConn.close(); 1389 } 1390 1391 if (prefs != null) { 1392 prefs.autoRefresh = autoRefresh; 1393 prefs.showRowCounts = displayRowCounts; 1394 prefs.showSysTables = showSys; 1395 prefs.showSchemas = showSchemas; 1396 prefs.resultGrid = gridFormat; 1397 prefs.showTooltips = showTooltips; 1398 prefs.laf = currentLAF; 1399 1400 prefs.store(); 1401 } 1402 } catch (Exception e) { 1403 1404 // Added: (weconsultants@users) 1405 CommonSwing.errorMessage(e); 1406 } 1407 1408 if (fMain instanceof java.awt.Window) { 1409 ((java.awt.Window) fMain).dispose(); 1410 } 1411 1412 if (bMustExit) { 1413 System.exit(0); 1414 } 1415 } 1416 clear()1417 private void clear() { 1418 1419 sqlScriptBuffer = null; 1420 1421 txtCommand.setText(""); 1422 txtCommand.setEnabled(true); 1423 } 1424 1425 private String busyText = null; 1426 backgroundIt(Runnable r, String description)1427 private void backgroundIt(Runnable r, String description) { 1428 1429 if (busyText != null) { 1430 Toolkit.getDefaultToolkit().beep(); 1431 1432 return; 1433 } 1434 1435 // set Waiting mode here. Inverse op must be called by final() 1436 // in the Thread.run() of every background thread. 1437 setWaiting(description); 1438 SwingUtilities.invokeLater(r); 1439 } 1440 clearResultPanel()1441 private void clearResultPanel() { 1442 1443 gResult.setHead(new Object[0]); 1444 gResult.clear(); 1445 1446 if (gridFormat) { 1447 gResult.fireTableChanged(null); 1448 } else { 1449 showResultInText(); 1450 } 1451 } 1452 setWaiting(String description)1453 public void setWaiting(String description) { 1454 1455 busyText = description; 1456 1457 if (busyText == null) { 1458 1459 // restore the cursors we saved 1460 if (fMain instanceof java.awt.Frame) { 1461 ((java.awt.Frame) fMain).setCursor(fMainCursor); 1462 } else { 1463 ((Component) fMain).setCursor(fMainCursor); 1464 } 1465 1466 txtCommand.setCursor(txtCommandCursor); 1467 txtResult.setCursor(txtResultCursor); 1468 1469 /** @todo: Enable actionButtons */ 1470 } else { 1471 1472 // save the old cursors 1473 if (fMainCursor == null) { 1474 fMainCursor = ((fMain instanceof java.awt.Frame) 1475 ? (((java.awt.Frame) fMain).getCursor()) 1476 : (((Component) fMain).getCursor())); 1477 txtCommandCursor = txtCommand.getCursor(); 1478 txtResultCursor = txtResult.getCursor(); 1479 } 1480 1481 // set the cursors to the wait cursor 1482 if (fMain instanceof java.awt.Frame) { 1483 ((java.awt.Frame) fMain).setCursor(waitCursor); 1484 } else { 1485 ((Component) fMain).setCursor(waitCursor); 1486 } 1487 1488 txtCommand.setCursor(waitCursor); 1489 txtResult.setCursor(waitCursor); 1490 1491 /** @todo: Disable actionButtons */ 1492 } 1493 1494 setStatusLine(busyText, ((busyText == null) ? gResult.getRowCount() 1495 : 0)); 1496 } 1497 1498 private Runnable enableButtonRunnable = new Runnable() { 1499 1500 public void run() { 1501 jbuttonClear.setEnabled(true); 1502 jbuttonExecute.setEnabled(true); 1503 } 1504 }; 1505 private Runnable disableButtonRunnable = new Runnable() { 1506 1507 public void run() { 1508 jbuttonClear.setEnabled(false); 1509 jbuttonExecute.setEnabled(false); 1510 } 1511 }; 1512 private Thread buttonUpdaterThread = null; 1513 private static final int BUTTON_CHECK_PERIOD = 500; 1514 private Runnable buttonUpdater = new Runnable() { 1515 1516 public void run() { 1517 1518 boolean havesql; 1519 1520 while (true) { 1521 try { 1522 Thread.sleep(BUTTON_CHECK_PERIOD); 1523 } catch (InterruptedException ie) {} 1524 1525 if (buttonUpdaterThread == null) { // Pointer to me 1526 return; 1527 } 1528 1529 havesql = (txtCommand.getText().length() > 0); 1530 1531 if (jbuttonClear.isEnabled() != havesql) { 1532 SwingUtilities.invokeLater(havesql ? enableButtonRunnable 1533 : disableButtonRunnable); 1534 } 1535 } 1536 } 1537 }; 1538 private JButton jbuttonClear; 1539 private JButton jbuttonExecute; 1540 start()1541 public void start() { 1542 1543 if (buttonUpdaterThread == null) { 1544 buttonUpdaterThread = new Thread(buttonUpdater); 1545 } 1546 1547 buttonUpdaterThread.start(); 1548 } 1549 stop()1550 public void stop() { 1551 1552 System.err.println("Stopping"); 1553 1554 Thread t = buttonUpdaterThread; 1555 1556 if (t != null) { 1557 t.setContextClassLoader(null); 1558 } 1559 1560 buttonUpdaterThread = null; 1561 } 1562 1563 private Runnable treeRefreshRunnable = new Runnable() { 1564 1565 public void run() { 1566 1567 try { 1568 directRefreshTree(); 1569 } catch (RuntimeException re) { 1570 CommonSwing.errorMessage(re); 1571 1572 throw re; 1573 } finally { 1574 setWaiting(null); 1575 } 1576 } 1577 }; 1578 1579 /** 1580 * Schedules to run in a Gui-safe thread 1581 */ executeCurrentSQL()1582 protected void executeCurrentSQL() { 1583 1584 if (txtCommand.getText().length() < 1) { 1585 CommonSwing.errorMessage("No SQL to execute"); 1586 1587 return; 1588 } 1589 1590 backgroundIt(new StatementExecRunnable(), "Executing SQL"); 1591 } 1592 1593 protected class StatementExecRunnable implements Runnable { 1594 run()1595 public void run() { 1596 1597 gResult.clear(); 1598 1599 try { 1600 if (txtCommand.getText().startsWith("-->>>TEST<<<--")) { 1601 testPerformance(); 1602 } else { 1603 executeSQL(); 1604 } 1605 1606 updateResult(); 1607 displayResults(); 1608 updateAutoCommitBox(); 1609 1610 // System.gc(); 1611 } catch (RuntimeException re) { 1612 CommonSwing.errorMessage(re); 1613 1614 throw re; 1615 } finally { 1616 setWaiting(null); 1617 } 1618 } 1619 } 1620 ; 1621 executeSQL()1622 private void executeSQL() { 1623 1624 String[] g = new String[1]; 1625 String sql = null; 1626 1627 try { 1628 lTime = System.currentTimeMillis(); 1629 sql = ((sqlScriptBuffer == null ? txtCommand.getText() 1630 : sqlScriptBuffer)); 1631 1632 sStatement.execute(sql); 1633 1634 int r = sStatement.getUpdateCount(); 1635 1636 if (r == -1) { 1637 ResultSet rs = sStatement.getResultSet(); 1638 1639 try { 1640 formatResultSet(rs); 1641 } catch (Throwable t) { 1642 g[0] = "Error displaying the ResultSet"; 1643 1644 gResult.setHead(g); 1645 1646 String s = t.getMessage(); 1647 1648 g[0] = s; 1649 1650 gResult.addRow(g); 1651 } 1652 } else { 1653 g[0] = "update count"; 1654 1655 gResult.setHead(g); 1656 1657 g[0] = "" + r; 1658 1659 gResult.addRow(g); 1660 } 1661 1662 lTime = System.currentTimeMillis() - lTime; 1663 1664 if (sqlScriptBuffer == null) { 1665 addToRecent(sql); 1666 txtCommand.setEnabled(true); // clear() does this otherwise 1667 } else { 1668 clear(); 1669 } 1670 } catch (SQLException e) { 1671 lTime = System.currentTimeMillis() - lTime; 1672 g[0] = "SQL Error"; 1673 1674 gResult.setHead(g); 1675 1676 String s = e.getMessage(); 1677 1678 s += " / Error Code: " + e.getErrorCode(); 1679 s += " / State: " + e.getSQLState(); 1680 g[0] = s; 1681 1682 gResult.addRow(g); 1683 1684 // Added: (weconsultants@users) 1685 CommonSwing.errorMessage(e); 1686 1687 return; 1688 } 1689 1690 if (autoRefresh) { 1691 1692 // We're already running in a "busy" thread. Just update the 1693 // status text. 1694 setStatusLine("Refreshing object tree", 0); 1695 1696 String upper = sql.toUpperCase(Locale.ENGLISH); 1697 1698 // This test can be very liberal. Too liberal will just do 1699 // some extra refreshes. Too conservative will display 1700 // obsolete info. 1701 if (upper.indexOf("ALTER") > -1 || upper.indexOf("DROP") > -1 1702 || upper.indexOf("CREATE") > -1) { 1703 directRefreshTree(); 1704 } 1705 } 1706 } 1707 1708 /** 1709 * Could somebody explain what the purpose of this method is? 1710 * Contrary to the method name, it looks like it displays 1711 * results only if gridFormat is off (seems like it does 1712 * nothing otherwise, except for clearing help text and moving focus). 1713 */ updateResult()1714 private void updateResult() { 1715 1716 if (gridFormat) { 1717 1718 // in case 'help' has removed the grid 1719 if (bHelp) { 1720 pResult.removeAll(); 1721 pResult.add(gScrollPane, BorderLayout.CENTER); 1722 pResult.doLayout(); 1723 gResult.fireTableChanged(null); 1724 pResult.repaint(); 1725 1726 bHelp = false; 1727 } 1728 } else { 1729 showResultInText(); 1730 } 1731 1732 txtCommand.selectAll(); 1733 txtCommand.requestFocus(); 1734 } 1735 1736 /** 1737 * We let Swing handle displaying nulls (which it generally does by 1738 * printing nothing for them), except for the case of database 1739 * VARCHARs, because this is the only class where there is any 1740 * ambiguity about whether there is a null stored or not. 1741 */ formatResultSet(ResultSet r)1742 private void formatResultSet(ResultSet r) { 1743 1744 if (r == null) { 1745 String[] g = new String[1]; 1746 1747 g[0] = "Result"; 1748 1749 gResult.setHead(g); 1750 1751 g[0] = "(empty)"; 1752 1753 gResult.addRow(g); 1754 1755 return; 1756 } 1757 1758 try { 1759 ResultSetMetaData m = r.getMetaData(); 1760 int col = m.getColumnCount(); 1761 Object[] h = new Object[col]; 1762 boolean[] isVarChar = new boolean[col]; 1763 1764 for (int i = 1; i <= col; i++) { 1765 h[i - 1] = m.getColumnLabel(i); 1766 isVarChar[i - 1] = (m.getColumnType(i) 1767 == java.sql.Types.VARCHAR); 1768 } 1769 1770 gResult.setHead(h); 1771 1772 while (r.next()) { 1773 for (int i = 1; i <= col; i++) { 1774 try { 1775 h[i - 1] = r.getObject(i); 1776 1777 if (r.wasNull()) { 1778 h[i - 1] = (isVarChar[i - 1] ? NULL_STR 1779 : null); 1780 } 1781 } catch (SQLException e) {} 1782 } 1783 1784 gResult.addRow(h); 1785 } 1786 1787 r.close(); 1788 } catch (SQLException e) { 1789 1790 // Added: (weconsultants@users) 1791 CommonSwing.errorMessage(e); 1792 } 1793 } 1794 testPerformance()1795 private void testPerformance() { 1796 1797 String all = txtCommand.getText(); 1798 StringBuffer b = new StringBuffer(); 1799 long total = 0; 1800 1801 for (int i = 0; i < all.length(); i++) { 1802 char c = all.charAt(i); 1803 1804 if (c != '\n') { 1805 b.append(c); 1806 } 1807 } 1808 1809 all = b.toString(); 1810 1811 String[] g = new String[4]; 1812 1813 g[0] = "ms"; 1814 g[1] = "count"; 1815 g[2] = "sql"; 1816 g[3] = "error"; 1817 1818 gResult.setHead(g); 1819 1820 int max = 1; 1821 1822 lTime = System.currentTimeMillis() - lTime; 1823 1824 while (!all.equals("")) { 1825 int i = all.indexOf(';'); 1826 String sql; 1827 1828 if (i != -1) { 1829 sql = all.substring(0, i); 1830 all = all.substring(i + 1); 1831 } else { 1832 sql = all; 1833 all = ""; 1834 } 1835 1836 if (sql.startsWith("--#")) { 1837 max = Integer.parseInt(sql.substring(3)); 1838 1839 continue; 1840 } else if (sql.startsWith("--")) { 1841 continue; 1842 } 1843 1844 g[2] = sql; 1845 1846 long l = 0; 1847 1848 try { 1849 l = DatabaseManagerCommon.testStatement(sStatement, sql, max); 1850 total += l; 1851 g[0] = "" + l; 1852 g[1] = "" + max; 1853 g[3] = ""; 1854 } catch (SQLException e) { 1855 g[0] = g[1] = "n/a"; 1856 g[3] = e.toString(); 1857 1858 // Added: (weconsultants@users) 1859 CommonSwing.errorMessage(e); 1860 } 1861 1862 gResult.addRow(g); 1863 System.out.println(l + " ms : " + sql); 1864 } 1865 1866 g[0] = "" + total; 1867 g[1] = "total"; 1868 g[2] = ""; 1869 1870 gResult.addRow(g); 1871 1872 lTime = System.currentTimeMillis() - lTime; 1873 } 1874 showResultInText()1875 private void showResultInText() { 1876 1877 Object[] col = gResult.getHead(); 1878 int width = col.length; 1879 int[] size = new int[width]; 1880 Vector data = gResult.getData(); 1881 Object[] row; 1882 int height = data.size(); 1883 1884 for (int i = 0; i < width; i++) { 1885 size[i] = col[i].toString().length(); 1886 } 1887 1888 for (int i = 0; i < height; i++) { 1889 row = (Object[]) data.elementAt(i); 1890 1891 for (int j = 0; j < width; j++) { 1892 String item = ((row[j] == null) ? "" 1893 : row[j].toString()); 1894 int l = item.length(); 1895 1896 if (l > size[j]) { 1897 size[j] = l; 1898 } 1899 } 1900 } 1901 1902 StringBuffer b = new StringBuffer(); 1903 1904 for (int i = 0; i < width; i++) { 1905 b.append(col[i]); 1906 1907 for (int l = col[i].toString().length(); l <= size[i]; l++) { 1908 b.append(' '); 1909 } 1910 } 1911 1912 b.append(NL); 1913 1914 for (int i = 0; i < width; i++) { 1915 for (int l = 0; l < size[i]; l++) { 1916 b.append('-'); 1917 } 1918 1919 b.append(' '); 1920 } 1921 1922 b.append(NL); 1923 1924 for (int i = 0; i < height; i++) { 1925 row = (Object[]) data.elementAt(i); 1926 1927 for (int j = 0; j < width; j++) { 1928 String item = ((row[j] == null) ? "" 1929 : row[j].toString()); 1930 1931 b.append(item); 1932 1933 for (int l = item.length(); l <= size[j]; l++) { 1934 b.append(' '); 1935 } 1936 } 1937 1938 b.append(NL); 1939 } 1940 1941 // b.append(NL + height + " row(s) in " + lTime + " ms"); 1942 // There is no reason why this report should be text-output-specific. 1943 // Moving it to bottom of the setWaiting method (where the report 1944 // gets written to the status line). 1945 // I'm only doing the rowcount now. Add the time report there if 1946 // you are so inclined. 1947 txtResult.setText(b.toString()); 1948 } 1949 addToRecent(String s)1950 private void addToRecent(String s) { 1951 1952 for (int i = 0; i < iMaxRecent; i++) { 1953 if (s.equals(sRecent[i])) { 1954 return; 1955 } 1956 } 1957 1958 if (sRecent[iRecent] != null) { 1959 mRecent.remove(iRecent); 1960 } 1961 1962 sRecent[iRecent] = s; 1963 1964 if (s.length() > 43) { 1965 s = s.substring(0, 40) + "..."; 1966 } 1967 1968 JMenuItem item = new JMenuItem(s); 1969 1970 item.setActionCommand("#" + iRecent); 1971 item.addActionListener(this); 1972 mRecent.insert(item, iRecent); 1973 1974 iRecent = (iRecent + 1) % iMaxRecent; 1975 } 1976 1977 // empty implementations for mouse listener. We're only using 1978 // mouseReleased mouseClicked(final MouseEvent mouseEvent)1979 public final void mouseClicked(final MouseEvent mouseEvent) {} 1980 mouseEntered(final MouseEvent mouseEvent)1981 public final void mouseEntered(final MouseEvent mouseEvent) {} 1982 mouseExited(final MouseEvent mouseEvent)1983 public final void mouseExited(final MouseEvent mouseEvent) {} 1984 1985 // Check for handlePopup in both mousePressed and mouseReleased. According to 1986 // MouseEvent javadocs it's necessary for cross platform compatibility. 1987 // We keep a record of the last alreadyHandled mouseEvent so we don't do it twice. 1988 private MouseEvent alreadyHandled = null; 1989 1990 // mousePressed calls handlePopup, which creates the context-sensitive 1991 // helper menu. mousePressed(final MouseEvent e)1992 public final void mousePressed(final MouseEvent e) { 1993 1994 if (alreadyHandled == e) { 1995 return; 1996 } 1997 1998 handlePopup(e); 1999 2000 alreadyHandled = e; 2001 } 2002 2003 // mouseReleased calls handlePopup, which creates the context-sensitive 2004 // helper menu. mouseReleased(final MouseEvent e)2005 public final void mouseReleased(final MouseEvent e) { 2006 2007 if (alreadyHandled == e) { 2008 return; 2009 } 2010 2011 handlePopup(e); 2012 2013 alreadyHandled = e; 2014 } 2015 2016 // based on the table or column right-clicked on, create some helper 2017 // actions for common sql statements handlePopup(MouseEvent e)2018 public final void handlePopup(MouseEvent e) { 2019 2020 //System.out.println("Handle popup"); 2021 // if this is not a mouse action for popups then do nothing and return 2022 if (!e.isPopupTrigger()) { 2023 return; 2024 } 2025 2026 // make sure the source of this mouse event was from the tree 2027 Object source = e.getSource(); 2028 2029 if (!(source instanceof JTree)) { 2030 return; 2031 } 2032 2033 JTree tree = (JTree) source; 2034 TreePath treePath = tree.getPathForLocation(e.getX(), e.getY()); 2035 2036 // if we couldn't find a tree path that corresponds to the 2037 // right-click, then return 2038 if (treePath == null) { 2039 return; 2040 } 2041 2042 // create the popup and menus 2043 JPopupMenu popup = new JPopupMenu(); 2044 JMenuItem menuItem; 2045 String menus[] = new String[] { 2046 "Select", "Delete", "Update", "Insert" 2047 }; 2048 2049 // loop throught the menus we want to create, making a PopupListener 2050 // for each one 2051 for (int i = 0; i < menus.length; i++) { 2052 PopupListener popupListener = new PopupListener(menus[i], 2053 treePath); 2054 String title = popupListener.toString(); 2055 2056 if (title == null) { 2057 return; 2058 } 2059 2060 // Some of the menu names can be quite long (especially insert). 2061 // If it's too long, abbreviate it 2062 if (title.length() > 40) { 2063 title = title.substring(0, 40) + "..."; 2064 } 2065 2066 menuItem = new JMenuItem(title); 2067 2068 menuItem.addActionListener(popupListener); 2069 popup.add(menuItem); 2070 } 2071 2072 popup.show(e.getComponent(), e.getX(), e.getY()); 2073 } 2074 2075 // handles the creation of the command when a popup is triggered 2076 private class PopupListener implements ActionListener { 2077 2078 // used to identify depth while right clicking in tree. 2079 public static final int DEPTH_URL = 1; 2080 public static final int DEPTH_TABLE = 2; 2081 public static final int DEPTH_COLUMN = 3; 2082 String command; 2083 TreePath treePath; 2084 TreePath tablePath; 2085 TreePath columnPath; 2086 String table = null; 2087 String column = null; 2088 PopupListener(String command, TreePath treePath)2089 PopupListener(String command, TreePath treePath) { 2090 2091 super(); 2092 2093 this.command = command; 2094 this.treePath = treePath; 2095 } 2096 2097 // when the popup is triggered, create a command string and set it in 2098 // the txtCommand buffer actionPerformed(ActionEvent ae)2099 public void actionPerformed(ActionEvent ae) { 2100 txtCommand.setText(getCommandString()); 2101 } 2102 2103 // text to display when added to a menu toString()2104 public String toString() { 2105 return getCommandString(); 2106 } 2107 2108 // getCommandString()2109 public String getCommandString() { 2110 2111 int treeDepth = treePath.getPathCount(); 2112 2113 // if we are at TABLE depth, set tablePath and table for use later 2114 if (treeDepth == DEPTH_URL) { 2115 return ""; 2116 } 2117 2118 if (treeDepth == DEPTH_TABLE) { 2119 tablePath = treePath; 2120 table = treePath.getPathComponent(DEPTH_TABLE - 1).toString(); 2121 } 2122 2123 // if we are at TABLE depth, set columnPath, column, tablePath and 2124 // table for use later 2125 if (treeDepth == DEPTH_COLUMN) { 2126 tablePath = treePath.getParentPath(); 2127 table = treePath.getPathComponent(DEPTH_TABLE - 1).toString(); 2128 columnPath = treePath; 2129 column = treePath.getPathComponent(DEPTH_COLUMN 2130 - 1).toString(); 2131 } 2132 2133 // handle command "SELECT". Use table and column if set. 2134 if (command.toUpperCase().equals("SELECT")) { 2135 String result = "SELECT * FROM " + quoteTableName(table); 2136 2137 if (column != null) { 2138 DefaultMutableTreeNode childNode = 2139 (DefaultMutableTreeNode) treePath 2140 .getLastPathComponent(); 2141 String childName = null; 2142 boolean isChar; 2143 2144 if (childNode.getChildCount() > 0) { 2145 childName = childNode.getFirstChild().toString(); 2146 isChar = childName.indexOf("CHAR") >= 0; 2147 result += " WHERE " + quoteObjectName(column); 2148 2149 if (isChar) { 2150 result += " LIKE \'%%\'"; 2151 } else { 2152 result += " = "; 2153 } 2154 } 2155 } 2156 2157 return result; 2158 } 2159 2160 // handle command "UPDATE". Use table and column if set. 2161 else if (command.toUpperCase().equals("UPDATE")) { 2162 String result = "UPDATE " + quoteTableName(table) + " SET "; 2163 2164 if (column != null) { 2165 result += quoteObjectName(column) + " = "; 2166 } 2167 2168 return result; 2169 } 2170 2171 // handle command "DELETE". Use table and column if set. 2172 else if (command.toUpperCase().equals("DELETE")) { 2173 String result = "DELETE FROM " + quoteTableName(table); 2174 2175 if (column != null) { 2176 DefaultMutableTreeNode childNode = 2177 (DefaultMutableTreeNode) treePath 2178 .getLastPathComponent(); 2179 String childName = null; 2180 boolean isChar; 2181 2182 if (childNode.getChildCount() > 0) { 2183 childName = childNode.getFirstChild().toString(); 2184 isChar = childName.indexOf("CHAR") >= 0; 2185 result += " WHERE " + quoteObjectName(column); 2186 2187 if (isChar) { 2188 result += " LIKE \'%%\'"; 2189 } else { 2190 result += " = "; 2191 } 2192 } 2193 } 2194 2195 return result; 2196 } 2197 2198 // handle command "INSERT". Use table and column if set. 2199 else if (command.toUpperCase().equals("INSERT")) { 2200 TreeNode tableNode; 2201 Enumeration enumer; 2202 String columns = ""; 2203 String values = " "; 2204 String comma = ""; 2205 String quote = ""; 2206 2207 // build a string that includes all the columns that need to 2208 // be added, with a parenthesied list of commas, suitable for 2209 // inserting values into. 2210 if (tablePath == null) { 2211 return null; 2212 } 2213 2214 tableNode = (TreeNode) tablePath.getLastPathComponent(); 2215 enumer = tableNode.children(); 2216 2217 while (enumer.hasMoreElements()) { 2218 Object o = enumer.nextElement(); 2219 2220 if (o.toString().equals("Indices")) { 2221 continue; 2222 } 2223 2224 DefaultMutableTreeNode childNode = 2225 (DefaultMutableTreeNode) o; 2226 String childName = null; 2227 2228 if (childNode.getChildCount() == 0) { 2229 continue; 2230 } else { 2231 childName = childNode.getFirstChild().toString(); 2232 } 2233 2234 // If our first child (type) is some sort of char, use '' 2235 // in the string. Makes is more obvious to the user when 2236 // they need to use a string 2237 if (childName.indexOf("CHAR") >= 0) { 2238 quote = "\'\'"; 2239 } else { 2240 quote = ""; 2241 } 2242 2243 columns += comma + quoteObjectName(o.toString()); 2244 values += comma + quote; 2245 comma = ", "; 2246 } 2247 2248 return "INSERT INTO " + quoteTableName(table) + "\n( " 2249 + columns + " )\nVALUES (" + values + ")"; 2250 } else { 2251 return "Got here in error " + command 2252 + ". Should never happen"; 2253 } 2254 } 2255 } 2256 2257 /** 2258 * Perform a limited check (inconclusive) and quote object name if required. 2259 * Gives wrong result if a quoted name contains a dot. 2260 */ quoteTableName(String name)2261 private String quoteTableName(String name) { 2262 2263 int dot = name.indexOf("."); 2264 2265 if (dot < 0) { 2266 int bracket = name.indexOf(" ("); 2267 2268 if (bracket >= 0) { 2269 name = name.substring(0, bracket); 2270 } 2271 2272 return quoteObjectName(name); 2273 } 2274 2275 String partOne = name.substring(0, dot); 2276 String partTwo = name.substring(dot + 1); 2277 int bracket = partTwo.indexOf(" ("); 2278 2279 if (bracket >= 0) { 2280 partTwo = partTwo.substring(0, bracket); 2281 } 2282 2283 return quoteObjectName(partOne) + '.' + quoteObjectName(partTwo); 2284 } 2285 2286 /** 2287 * perform a limited check (inconclusive) and quote object name if required 2288 */ quoteObjectName(String name)2289 private String quoteObjectName(String name) { 2290 2291 /* 2292 if (name.toUpperCase().equals(name) && name.indexOf(' ') < 0) { 2293 return name; 2294 } 2295 */ 2296 return "\"" + name + "\""; 2297 } 2298 initGUI()2299 private void initGUI() { 2300 2301 JPanel pCommand = new JPanel(); 2302 2303 pResult = new JPanel(); 2304 nsSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, pCommand, 2305 pResult); 2306 2307 // Added: (weconsultants@users) 2308 nsSplitPane.setOneTouchExpandable(true); 2309 pCommand.setLayout(new BorderLayout()); 2310 pResult.setLayout(new BorderLayout()); 2311 2312 Font fFont = new Font("Dialog", Font.PLAIN, 12); 2313 2314 txtCommand = new JTextArea(7, 40); 2315 2316 txtCommand.setMargin(new Insets(5, 5, 5, 5)); 2317 txtCommand.addKeyListener(this); 2318 2319 txtCommandScroll = new JScrollPane(txtCommand); 2320 txtResult = new JTextArea(25, 40); 2321 2322 txtResult.setMargin(new Insets(5, 5, 5, 5)); 2323 2324 txtResultScroll = new JScrollPane(txtResult); 2325 2326 txtCommand.setFont(fFont); 2327 txtResult.setFont(new Font("Courier", Font.PLAIN, 12)); 2328 pCommand.add(txtCommandScroll, BorderLayout.CENTER); 2329 2330 gResult = new GridSwing(); 2331 2332 TableSorter sorter = new TableSorter(gResult); 2333 2334 tableModel = sorter; 2335 gResultTable = new JTable(sorter); 2336 2337 sorter.setTableHeader(gResultTable.getTableHeader()); 2338 2339 gScrollPane = new JScrollPane(gResultTable); 2340 2341 gResultTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 2342 gResult.setJTable(gResultTable); 2343 2344 //getContentPane().setLayout(new BorderLayout()); 2345 pResult.add(gScrollPane, BorderLayout.CENTER); 2346 2347 // Set up the tree 2348 rootNode = new DefaultMutableTreeNode("Connection"); 2349 treeModel = new DefaultTreeModel(rootNode); 2350 tTree = new JTree(treeModel); 2351 tScrollPane = new JScrollPane(tTree); 2352 2353 // System.out.println("Adding mouse listener"); 2354 tTree.addMouseListener(this); 2355 tScrollPane.setPreferredSize(new Dimension(200, 400)); 2356 tScrollPane.setMinimumSize(new Dimension(70, 100)); 2357 txtCommandScroll.setPreferredSize(new Dimension(560, 100)); 2358 txtCommandScroll.setMinimumSize(new Dimension(180, 100)); 2359 gScrollPane.setPreferredSize(new Dimension(460, 300)); 2360 2361 ewSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, tScrollPane, 2362 nsSplitPane); 2363 2364 // Added: (weconsultants@users) 2365 ewSplitPane.setOneTouchExpandable(true); 2366 fMain.getContentPane().add(ewSplitPane, BorderLayout.CENTER); 2367 2368 // Added: (weconsultants@users) 2369 jStatusLine = new JLabel(); 2370 iReadyStatus = 2371 new JButton(new ImageIcon(CommonSwing.getIcon("StatusReady"))); 2372 2373 iReadyStatus.setSelectedIcon( 2374 new ImageIcon(CommonSwing.getIcon("StatusRunning"))); 2375 2376 pStatus = new JPanel(); 2377 2378 pStatus.setLayout(new BorderLayout()); 2379 pStatus.add(iReadyStatus, BorderLayout.WEST); 2380 pStatus.add(jStatusLine, BorderLayout.CENTER); 2381 fMain.getContentPane().add(pStatus, "South"); 2382 doLayout(); 2383 2384 if (fMain instanceof java.awt.Window) { 2385 ((java.awt.Window) fMain).pack(); 2386 } else { 2387 ((Container) fMain).validate(); 2388 } 2389 } 2390 2391 /* Simple tree node factory method - set's parent and user object. 2392 */ makeNode(Object userObject, MutableTreeNode parent)2393 private DefaultMutableTreeNode makeNode(Object userObject, 2394 MutableTreeNode parent) { 2395 2396 DefaultMutableTreeNode node = new DefaultMutableTreeNode(userObject); 2397 2398 if (parent != null) { 2399 treeModel.insertNodeInto(node, parent, parent.getChildCount()); 2400 } 2401 2402 return node; 2403 } 2404 2405 private static final String[] usertables = { 2406 "TABLE", "GLOBAL TEMPORARY", "VIEW", "SYSTEM TABLE" 2407 }; 2408 private static final String[] nonSystables = { 2409 "TABLE", "GLOBAL TEMPORARY", "VIEW" 2410 }; 2411 private static final HashSet oracleSysUsers = new HashSet(); 2412 private static final String[] oracleSysSchemas = { 2413 "SYS", "SYSTEM", "OUTLN", "DBSNMP", "OUTLN", "MDSYS", "ORDSYS", 2414 "ORDPLUGINS", "CTXSYS", "DSSYS", "PERFSTAT", "WKPROXY", "WKSYS", 2415 "WMSYS", "XDB", "ANONYMOUS", "ODM", "ODM_MTR", "OLAPSYS", "TRACESVR", 2416 "REPADMIN" 2417 }; 2418 2419 static { 2420 for (int i = 0; i < oracleSysSchemas.length; i++) { 2421 oracleSysUsers.add(oracleSysSchemas[i]); 2422 } 2423 } 2424 2425 /** 2426 * Schedules to run in a Gui-safe thread 2427 */ refreshTree()2428 protected void refreshTree() { 2429 backgroundIt(treeRefreshRunnable, "Refreshing object tree"); 2430 } 2431 2432 /** 2433 * Clear all existing nodes from the tree model and rebuild from scratch. 2434 * 2435 * This method executes in current thread 2436 */ directRefreshTree()2437 protected void directRefreshTree() { 2438 2439 int[] rowCounts; 2440 DefaultMutableTreeNode propertiesNode; 2441 2442 // Added: (weconsultants@users) Moved tableNode here for visibiity nd new DECFM 2443 DefaultMutableTreeNode tableNode; 2444 DecimalFormat DECFMT = new DecimalFormat(" ( ####,###,####,##0 )"); 2445 2446 // First clear the existing tree by simply enumerating 2447 // over the root node's children and removing them one by one. 2448 while (treeModel.getChildCount(rootNode) > 0) { 2449 DefaultMutableTreeNode child = 2450 (DefaultMutableTreeNode) treeModel.getChild(rootNode, 0); 2451 2452 treeModel.removeNodeFromParent(child); 2453 child.removeAllChildren(); 2454 child.removeFromParent(); 2455 } 2456 2457 treeModel.nodeStructureChanged(rootNode); 2458 treeModel.reload(); 2459 tScrollPane.repaint(); 2460 2461 ResultSet result = null; 2462 2463 // Now rebuild the tree below its root 2464 try { 2465 2466 // Start by naming the root node from its URL: 2467 rootNode.setUserObject(dMeta.getURL()); 2468 2469 // get metadata about user tables by building a vector of table names 2470 result = dMeta.getTables(null, null, null, (showSys ? usertables 2471 : nonSystables)); 2472 2473 Vector tables = new Vector(); 2474 Vector schemas = new Vector(); 2475 2476 // sqlbob@users Added remarks. 2477 Vector remarks = new Vector(); 2478 String schema; 2479 2480 while (result.next()) { 2481 schema = result.getString(2); 2482 2483 if ((!showSys) && isOracle 2484 && oracleSysUsers.contains(schema)) { 2485 continue; 2486 } 2487 2488 if (schemaFilter == null || schema.equals(schemaFilter)) { 2489 schemas.addElement(schema); 2490 tables.addElement(result.getString(3)); 2491 remarks.addElement(result.getString(5)); 2492 2493 continue; 2494 } 2495 } 2496 2497 result.close(); 2498 2499 result = null; 2500 2501 // Added: (weconsultants@users) 2502 // Sort not to go into production. Have to sync with 'remarks Vector' for DBMS that has it 2503 // Collections.sort(tables); 2504 // Added: (weconsultants@users) - Add rowCounts if needed. 2505 rowCounts = new int[tables.size()]; 2506 2507 try { 2508 rowCounts = getRowCounts(tables, schemas); 2509 } catch (Exception e) { 2510 2511 // Added: (weconsultants@users) 2512 CommonSwing.errorMessage(e); 2513 } 2514 2515 ResultSet col; 2516 2517 // For each table, build a tree node with interesting info 2518 for (int i = 0; i < tables.size(); i++) { 2519 col = null; 2520 2521 String name; 2522 2523 try { 2524 name = (String) tables.elementAt(i); 2525 2526 if (isOracle && name.startsWith("BIN$")) { 2527 continue; 2528 2529 // Oracle Recyle Bin tables. 2530 // Contains metacharacters which screw up metadata 2531 // queries below. 2532 } 2533 2534 schema = (String) schemas.elementAt(i); 2535 2536 String schemaname = ""; 2537 2538 if (schema != null && showSchemas) { 2539 schemaname = schema + '.'; 2540 } 2541 2542 String rowcount = displayRowCounts 2543 ? (DECFMT.format(rowCounts[i])) 2544 : ""; 2545 String displayedName = schemaname + name + rowcount; 2546 2547 // weconsul@ptd.net Add rowCounts if needed. 2548 tableNode = makeNode(displayedName, rootNode); 2549 col = dMeta.getColumns(null, schema, name, null); 2550 2551 if ((schema != null) && !schema.trim().equals("")) { 2552 makeNode(schema, tableNode); 2553 } 2554 2555 // sqlbob@users Added remarks. 2556 String remark = (String) remarks.elementAt(i); 2557 2558 if ((remark != null) && !remark.trim().equals("")) { 2559 makeNode(remark, tableNode); 2560 } 2561 2562 // This block is very slow for some Oracle tables. 2563 // With a child for each column containing pertinent attributes 2564 while (col.next()) { 2565 String c = col.getString(4); 2566 DefaultMutableTreeNode columnNode = makeNode(c, 2567 tableNode); 2568 String type = col.getString(6); 2569 2570 makeNode("Type: " + type, columnNode); 2571 2572 boolean nullable = col.getInt(11) 2573 != DatabaseMetaData.columnNoNulls; 2574 2575 makeNode("Nullable: " + nullable, columnNode); 2576 } 2577 } finally { 2578 if (col != null) { 2579 try { 2580 col.close(); 2581 } catch (SQLException se) {} 2582 } 2583 } 2584 2585 DefaultMutableTreeNode indexesNode = makeNode("Indices", 2586 tableNode); 2587 2588 if (showIndexDetails) { 2589 ResultSet ind = null; 2590 2591 try { 2592 ind = dMeta.getIndexInfo(null, schema, name, false, 2593 false); 2594 2595 String oldiname = null; 2596 DefaultMutableTreeNode indexNode = null; 2597 2598 // A child node to contain each index - and its attributes 2599 while (ind.next()) { 2600 boolean nonunique = ind.getBoolean(4); 2601 String iname = ind.getString(6); 2602 2603 if ((oldiname == null 2604 || !oldiname.equals(iname))) { 2605 indexNode = makeNode(iname, indexesNode); 2606 2607 makeNode("Unique: " + !nonunique, indexNode); 2608 2609 oldiname = iname; 2610 } 2611 2612 // And the ordered column list for index components 2613 makeNode(ind.getString(9), indexNode); 2614 } 2615 } catch (SQLException se) { 2616 2617 // Workaround for Oracle 2618 if (se.getMessage() == null || ((!se.getMessage() 2619 .startsWith("ORA-25191:")) && (!se.getMessage() 2620 .startsWith("ORA-01702:")) && !se.getMessage() 2621 .startsWith("ORA-01031:"))) { 2622 throw se; 2623 } 2624 } finally { 2625 if (ind != null) { 2626 ind.close(); 2627 2628 ind = null; 2629 } 2630 } 2631 } 2632 } 2633 2634 // Finally - a little additional metadata on this connection 2635 propertiesNode = makeNode("Properties", rootNode); 2636 2637 makeNode("User: " + dMeta.getUserName(), propertiesNode); 2638 makeNode("ReadOnly: " + cConn.isReadOnly(), propertiesNode); 2639 makeNode("AutoCommit: " + cConn.getAutoCommit(), propertiesNode); 2640 makeNode("Driver: " + dMeta.getDriverName(), propertiesNode); 2641 makeNode("Product: " + dMeta.getDatabaseProductName(), 2642 propertiesNode); 2643 makeNode("Version: " + dMeta.getDatabaseProductVersion(), 2644 propertiesNode); 2645 } catch (SQLException se) { 2646 propertiesNode = makeNode("Error getting metadata:", rootNode); 2647 2648 makeNode(se.getMessage(), propertiesNode); 2649 makeNode(se.getSQLState(), propertiesNode); 2650 CommonSwing.errorMessage(se); 2651 } finally { 2652 if (result != null) { 2653 try { 2654 result.close(); 2655 } catch (SQLException se) {} 2656 } 2657 } 2658 2659 treeModel.nodeStructureChanged(rootNode); 2660 treeModel.reload(); 2661 tScrollPane.repaint(); 2662 2663 // We want the Schema List to always be in sync with the displayed tree 2664 updateSchemaList(); 2665 } 2666 2667 // Added: (weconsultants@users) Sets up\changes the running status icon setStatusLine(String busyBaseString, int rowCount)2668 void setStatusLine(String busyBaseString, int rowCount) { 2669 2670 iReadyStatus.setSelected(busyBaseString != null); 2671 2672 if (busyBaseString == null) { 2673 String additionalMsg = ""; 2674 2675 if (schemaFilter != null) { 2676 additionalMsg = " / Tree showing objects in schema '" 2677 + schemaFilter + "'"; 2678 } 2679 2680 if (rowCount > 1) { 2681 additionalMsg += " / " + rowCount + " rows retrieved"; 2682 } 2683 2684 jStatusLine.setText(" " + READY_STATUS + additionalMsg); 2685 } else { 2686 jStatusLine.setText(" " + busyBaseString + "..."); 2687 } 2688 } 2689 2690 // Added: (weconsultants@users) Needed to aggragate counts per table in jTree getRowCounts(Vector inTable, Vector inSchema)2691 protected int[] getRowCounts(Vector inTable, 2692 Vector inSchema) throws Exception { 2693 2694 if (!displayRowCounts) { 2695 return (null); 2696 } 2697 2698 String rowCountSelect = "SELECT COUNT(*) FROM "; 2699 int[] counts; 2700 String name; 2701 2702 counts = new int[inTable.size()]; 2703 2704 try { 2705 Statement select = rowConn.createStatement(); 2706 2707 for (int i = 0; i < inTable.size(); i++) { 2708 try { 2709 String schemaPart = (String) inSchema.elementAt(i); 2710 2711 schemaPart = schemaPart == null ? "" 2712 : ("\"" + schemaPart 2713 + "\".\""); 2714 name = schemaPart + (String) inTable.elementAt(i) + "\""; 2715 2716 ResultSet resultSet = select.executeQuery(rowCountSelect 2717 + name); 2718 2719 while (resultSet.next()) { 2720 counts[i] = resultSet.getInt(1); 2721 } 2722 } catch (Exception e) { 2723 System.err.println("Unable to get row count for table " 2724 + inSchema.elementAt(i) + '.' 2725 + inTable.elementAt(i) 2726 + ". Using value '0': " + e); 2727 } 2728 } 2729 } catch (Exception e) { 2730 CommonSwing.errorMessage(e); 2731 } 2732 2733 return (counts); 2734 } 2735 createToolBar()2736 protected JToolBar createToolBar() { 2737 2738 // Build jtoolbar and jtoolbar Buttons 2739 JToolBar jtoolbar = new JToolBar(); 2740 2741 jtoolbar.putClientProperty("JToolBar.isRollover", Boolean.TRUE); 2742 2743 // I'm dropping "Statement" from "Execute SQL Statement", etc., 2744 // because it may or may not be "one statement", but it is SQL. 2745 // Build jbuttonClear Buttons - blaine 2746 jbuttonClear = 2747 new JButton("Clear SQL", 2748 new ImageIcon(CommonSwing.getIcon("Clear"))); 2749 2750 jbuttonClear.putClientProperty("is3DEnabled", Boolean.TRUE); 2751 tipMap.put(jbuttonClear, "Clear SQL"); 2752 jbuttonClear.addActionListener(new ActionListener() { 2753 2754 public void actionPerformed(ActionEvent actionevent) { 2755 2756 if (sqlScriptBuffer == null 2757 && txtCommand.getText().length() < 1) { 2758 CommonSwing.errorMessage("No SQL to clear"); 2759 2760 return; 2761 } 2762 2763 clear(); 2764 } 2765 }); 2766 2767 jbuttonExecute = 2768 new JButton("Execute SQL", 2769 new ImageIcon(CommonSwing.getIcon("Execute"))); 2770 2771 tipMap.put(jbuttonExecute, "Execute SQL"); 2772 jbuttonExecute.putClientProperty("is3DEnabled", Boolean.TRUE); 2773 jbuttonExecute.addActionListener(new ActionListener() { 2774 2775 public void actionPerformed(ActionEvent actionevent) { 2776 executeCurrentSQL(); 2777 } 2778 }); 2779 jtoolbar.addSeparator(); 2780 jtoolbar.add(jbuttonClear); 2781 jtoolbar.addSeparator(); 2782 jtoolbar.add(jbuttonExecute); 2783 jtoolbar.addSeparator(); 2784 jbuttonClear.setAlignmentY(0.5F); 2785 jbuttonClear.setAlignmentX(0.5F); 2786 jbuttonExecute.setAlignmentY(0.5F); 2787 jbuttonExecute.setAlignmentX(0.5F); 2788 2789 return jtoolbar; 2790 } 2791 updateAutoCommitBox()2792 void updateAutoCommitBox() { 2793 2794 try { 2795 boxAutoCommit.setSelected(cConn.getAutoCommit()); 2796 } catch (SQLException se) { 2797 CommonSwing.errorMessage(se); 2798 } 2799 } 2800 setLF(String newLAF)2801 private void setLF(String newLAF) { 2802 2803 if (currentLAF != null && currentLAF == newLAF) { // No change 2804 return; 2805 } 2806 2807 if (pResult != null && gridFormat) { 2808 pResult.removeAll(); 2809 } 2810 2811 CommonSwing.setSwingLAF((Component) fMain, newLAF); 2812 2813 if (pResult != null && gridFormat) { 2814 setResultsInGrid(); 2815 } 2816 2817 currentLAF = newLAF; 2818 2819 if (currentLAF.equals(CommonSwing.Native)) { 2820 rbNativeLF.setSelected(true); 2821 } else if (currentLAF.equals(CommonSwing.Java)) { 2822 rbJavaLF.setSelected(true); 2823 } else if (currentLAF.equals(CommonSwing.Motif)) { 2824 rbMotifLF.setSelected(true); 2825 } 2826 } 2827 resetTooltips()2828 void resetTooltips() { 2829 2830 Iterator it = tipMap.keySet().iterator(); 2831 JComponent component; 2832 2833 while (it.hasNext()) { 2834 component = (JComponent) it.next(); 2835 2836 component.setToolTipText(showTooltips 2837 ? ((String) tipMap.get(component)) 2838 : (String) null); 2839 } 2840 } 2841 updateSchemaList()2842 private void updateSchemaList() { 2843 2844 ButtonGroup group = new ButtonGroup(); 2845 ArrayList list = new ArrayList(); 2846 ResultSet result = null; 2847 2848 try { 2849 result = dMeta.getSchemas(); 2850 2851 if (result == null) { 2852 throw new SQLException("Failed to get metadata from database"); 2853 } 2854 2855 while (result.next()) { 2856 list.add(result.getString(1)); 2857 } 2858 } catch (SQLException se) { 2859 CommonSwing.errorMessage(se); 2860 } finally { 2861 if (result != null) { 2862 try { 2863 result.close(); 2864 } catch (SQLException se) {} 2865 } 2866 } 2867 2868 mnuSchemas.removeAll(); 2869 rbAllSchemas.setSelected(schemaFilter == null); 2870 group.add(rbAllSchemas); 2871 mnuSchemas.add(rbAllSchemas); 2872 2873 String s; 2874 JRadioButtonMenuItem radioButton; 2875 2876 for (int i = 0; i < list.size(); i++) { 2877 s = (String) list.get(i); 2878 radioButton = new JRadioButtonMenuItem(s); 2879 2880 group.add(radioButton); 2881 mnuSchemas.add(radioButton); 2882 radioButton.setSelected(schemaFilter != null 2883 && schemaFilter.equals(s)); 2884 radioButton.addActionListener(schemaListListener); 2885 radioButton.setEnabled(list.size() > 1); 2886 } 2887 2888 mnuSchemas.addSeparator(); 2889 mnuSchemas.add(mitemUpdateSchemas); 2890 } 2891 2892 ActionListener schemaListListener = (new ActionListener() { 2893 2894 public void actionPerformed(ActionEvent actionevent) { 2895 2896 schemaFilter = actionevent.getActionCommand(); 2897 2898 if (schemaFilter.equals("*")) { 2899 schemaFilter = null; 2900 } 2901 2902 refreshTree(); 2903 } 2904 }); 2905 2906 /** 2907 * Persisted User Preferences for DatabaseManagerSwing. 2908 * 2909 * These are settings for items in the View and Options pulldown menus, 2910 * plus Help/Show Tooltips. 2911 */ 2912 public class DBMPrefs { 2913 2914 public File prefsFile = null; 2915 2916 /** 2917 * The constructor guarantees that this will be null for Applet, 2918 * non-null if using a local preferences file 2919 */ 2920 2921 // Set defaults from Data 2922 boolean autoRefresh = true; 2923 boolean showRowCounts = false; 2924 boolean showSysTables = false; 2925 boolean showSchemas = true; 2926 boolean resultGrid = true; 2927 String laf = CommonSwing.Native; 2928 2929 // Somebody with more time can store the font settings. IMO, that 2930 // menu item shouldn't even be there if the settings aren't persisted. 2931 boolean showTooltips = true; 2932 DBMPrefs(boolean isApplet)2933 public DBMPrefs(boolean isApplet) throws IOException { 2934 2935 if (isApplet) {} 2936 else { 2937 if (homedir == null) { 2938 throw new IOException( 2939 "Skipping preferences since do not know home dir"); 2940 } 2941 2942 prefsFile = new File(homedir, "dbmprefs.properties"); 2943 } 2944 2945 load(); 2946 } 2947 load()2948 public void load() throws IOException { 2949 2950 String tmpString; 2951 2952 if (prefsFile == null) { 2953 2954 // LOAD PREFERENCES FROM APPLET PARAMS 2955 tmpString = getParameter("autoRefresh"); 2956 2957 if (tmpString != null) { 2958 autoRefresh = Boolean.valueOf(tmpString).booleanValue(); 2959 } 2960 2961 tmpString = getParameter("showRowCounts"); 2962 2963 if (tmpString != null) { 2964 showRowCounts = Boolean.valueOf(tmpString).booleanValue(); 2965 } 2966 2967 tmpString = getParameter("showSysTables"); 2968 2969 if (tmpString != null) { 2970 showSysTables = Boolean.valueOf(tmpString).booleanValue(); 2971 } 2972 2973 tmpString = getParameter("showSchemas"); 2974 2975 if (tmpString != null) { 2976 showSchemas = Boolean.valueOf(tmpString).booleanValue(); 2977 } 2978 2979 tmpString = getParameter("resultGrid"); 2980 2981 if (tmpString != null) { 2982 resultGrid = Boolean.valueOf(tmpString).booleanValue(); 2983 } 2984 2985 tmpString = getParameter("laf"); 2986 laf = ((tmpString == null) ? CommonSwing.Native 2987 : tmpString); 2988 tmpString = getParameter("showTooltips"); 2989 2990 if (tmpString != null) { 2991 showTooltips = Boolean.valueOf(tmpString).booleanValue(); 2992 } 2993 } else { 2994 2995 // LOAD PREFERENCES FROM LOCAL PREFERENCES FILE 2996 if (!prefsFile.exists()) { 2997 throw new IOException("No such file: " + prefsFile); 2998 } 2999 3000 Properties props = new Properties(); 3001 3002 try { 3003 FileInputStream fis = new FileInputStream(prefsFile); 3004 3005 props.load(fis); 3006 fis.close(); 3007 } catch (IOException ioe) { 3008 throw new IOException("Failed to read preferences file '" 3009 + prefsFile + "': " 3010 + ioe.getMessage()); 3011 } 3012 3013 tmpString = props.getProperty("autoRefresh"); 3014 3015 if (tmpString != null) { 3016 autoRefresh = Boolean.valueOf(tmpString).booleanValue(); 3017 } 3018 3019 tmpString = props.getProperty("showRowCounts"); 3020 3021 if (tmpString != null) { 3022 showRowCounts = Boolean.valueOf(tmpString).booleanValue(); 3023 } 3024 3025 tmpString = props.getProperty("showSysTables"); 3026 3027 if (tmpString != null) { 3028 showSysTables = Boolean.valueOf(tmpString).booleanValue(); 3029 } 3030 3031 tmpString = props.getProperty("showSchemas"); 3032 3033 if (tmpString != null) { 3034 showSchemas = Boolean.valueOf(tmpString).booleanValue(); 3035 } 3036 3037 tmpString = props.getProperty("resultGrid"); 3038 3039 if (tmpString != null) { 3040 resultGrid = Boolean.valueOf(tmpString).booleanValue(); 3041 } 3042 3043 tmpString = props.getProperty("laf"); 3044 laf = ((tmpString == null) ? CommonSwing.Native 3045 : tmpString); 3046 tmpString = props.getProperty("showTooltips"); 3047 3048 if (tmpString != null) { 3049 showTooltips = Boolean.valueOf(tmpString).booleanValue(); 3050 } 3051 } 3052 } 3053 store()3054 public void store() { 3055 3056 if (prefsFile == null) { 3057 3058 // Can't persist Applet settings. 3059 return; 3060 } 3061 3062 Properties props = new Properties(); 3063 3064 // Boolean.toString(boolean) was new with Java 1.4, so don't use that. 3065 props.setProperty("autoRefresh", (autoRefresh ? tString 3066 : fString)); 3067 props.setProperty("showRowCounts", (showRowCounts ? tString 3068 : fString)); 3069 props.setProperty("showSysTables", (showSysTables ? tString 3070 : fString)); 3071 props.setProperty("showSchemas", (showSchemas ? tString 3072 : fString)); 3073 props.setProperty("resultGrid", (resultGrid ? tString 3074 : fString)); 3075 props.setProperty("laf", laf); 3076 props.setProperty("showTooltips", (showTooltips ? tString 3077 : fString)); 3078 3079 try { 3080 FileOutputStream fos = new FileOutputStream(prefsFile); 3081 3082 props.store(fos, "DatabaseManagerSwing user preferences"); 3083 fos.flush(); 3084 fos.close(); 3085 } catch (IOException ioe) { 3086 throw new RuntimeException( 3087 "Failed to prepare preferences file '" + prefsFile 3088 + "': " + ioe.getMessage()); 3089 } 3090 } 3091 } 3092 3093 private static final String tString = Boolean.TRUE.toString(); 3094 private static final String fString = Boolean.FALSE.toString(); 3095 } 3096