0001: /* ====================================================================
0002: * Copyright (c) 1998 - 2004 David F. Glasser. All rights
0003: * reserved.
0004: *
0005: * This file is part of the QueryForm Database Tool.
0006: *
0007: * The QueryForm Database Tool is free software; you can redistribute it
0008: * and/or modify it under the terms of the GNU General Public License as
0009: * published by the Free Software Foundation; either version 2 of the
0010: * License, or (at your option) any later version.
0011: *
0012: * The QueryForm Database Tool is distributed in the hope that it will
0013: * be useful, but WITHOUT ANY WARRANTY; without even the implied
0014: * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
0015: * See the GNU General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * along with the QueryForm Database Tool; if not, write to:
0019: *
0020: * The Free Software Foundation, Inc.,
0021: * 59 Temple Place, Suite 330
0022: * Boston, MA 02111-1307 USA
0023: *
0024: * or visit http://www.gnu.org.
0025: *
0026: * ====================================================================
0027: *
0028: * This product includes software developed by the
0029: * Apache Software Foundation (http://www.apache.org/).
0030: *
0031: * ====================================================================
0032: *
0033: * $Source: /cvsroot/qform/qform/src/org/glasser/qform/MainPanel.java,v $
0034: * $Revision: 1.35 $
0035: * $Author: dglasser $
0036: * $Date: 2005/06/06 03:06:34 $
0037: *
0038: * --------------------------------------------------------------------
0039: */
0040: package org.glasser.qform;
0041:
0042: import java.awt.*;
0043: import java.awt.event.*;
0044: import java.io.*;
0045: import java.net.URL;
0046: import java.sql.*;
0047: import java.util.HashMap;
0048: import java.util.ArrayList;
0049: import java.util.Arrays;
0050: import java.util.Vector;
0051: import java.util.HashSet;
0052: import java.util.NoSuchElementException;
0053: import java.util.ResourceBundle;
0054: import java.util.Properties;
0055: import java.util.Set;
0056: import java.util.HashSet;
0057: import java.util.StringTokenizer;
0058: import javax.sql.*;
0059: import javax.swing.*;
0060: import javax.swing.border.*;
0061: import javax.swing.event.*;
0062: import javax.xml.parsers.*;
0063:
0064: import org.glasser.sql.*;
0065: import org.glasser.swing.*;
0066: import org.glasser.util.Formatter;
0067: import org.glasser.util.Util;
0068: import org.glasser.util.ExtensionClassLoader;
0069: import org.glasser.util.comparators.*;
0070: import org.w3c.dom.*;
0071: import org.xml.sax.*;
0072:
0073: public class MainPanel extends MDIPanel implements ActionListener,
0074: InternalFrameListener, QueryPanelListener {
0075:
0076: private static ResourceBundle bundle = ResourceBundle
0077: .getBundle("org.glasser.qform.Resources");
0078:
0079: private boolean debug = System.getProperty("MainPanel.debug") != null;
0080:
0081: private boolean showSystemTables = System
0082: .getProperty("show.system.tables") != null;
0083:
0084: Frame parent = null;
0085:
0086: String configFileName = null;
0087:
0088: Config config = null;
0089:
0090: LocalDataSourceConfigDialog configDialog = null;
0091:
0092: ColumnMapDialog columnMapDialog = null;
0093:
0094: TableSelector tableSelector = null;
0095:
0096: LoginDialog loginDialog = null;
0097:
0098: WhereClauseDialog whereClauseDialog = null;
0099:
0100: ExportDialog exportDialog = null;
0101:
0102: AppendOverwriteDialog overwriteDialog = null;
0103:
0104: JDialog aboutDialog = null;
0105:
0106: JDialog sysInfoDialog = null;
0107:
0108: ThirdPartyLafDialog tpLafDialog = null;
0109:
0110: Component[] dialogs = null;
0111:
0112: static JButton tbNew = new JButton();
0113: static JButton newFormButton = new JButton();
0114: static JButton tbMetaData = new JButton();
0115:
0116: static Object[][] toolBarConfig = {
0117: { tbNew, "DATA_SOURCE_DIALOG", "DataConnection20.png",
0118: "Create, modify or connect to a data source.", "1" },
0119: { newFormButton, "NEW_QUERY_FORM", "New20.gif",
0120: "Select a table to query." },
0121: { tbMetaData, "TABLE_METADATA", "BCard20.png",
0122: "Select a table to view its metadata." }
0123:
0124: };
0125:
0126: private boolean[][] toolBarStates = { { true, false, false, } // NO_CONNECTIONS = 0;
0127: , { true, true, true, } // HAS_CONNECTIONS = 1;
0128: , { true, true, true, } // ALL_FRAMES_ICONIFIED = 2;
0129: , { true, true, true, } // QUERY_PANEL_NO_RESULTSET = 3;
0130: , { true, true, true, } // QUERY_PANEL_RESULTSET = 4;
0131: , { true, true, true, } // QUERY_PANEL_OPEN_FOR_ADD = 5;
0132: , { true, true, true, } // QUERY_PANEL_OPEN_FOR_UPDATE = 6;
0133: , { true, true, true, } // QUERY_PANEL_OPEN_FOR_QUERY = 7;
0134: , { true, true, true, } // QUERY_PANEL_OPEN_FOR_CLONE = 5;
0135: , { true, true, true, } // TABLE_INFO_PANEL
0136: };
0137:
0138: static String[][] connectMenuConfig = {
0139: { "Data Source...", "DATA_SOURCE_DIALOG", "D",
0140: "Create, edit or connect to a data source." },
0141: { "Table Metadata...", "TABLE_METADATA", "T",
0142: "View metadata for a table." },
0143: { "Close Window", "CLOSE_WINDOW", "C",
0144: "Close the current window." },
0145: { "Exit", "EXIT", "X", "Exit the program." } };
0146:
0147: static String[][] connectMenuConfig_ = { { "DATA_SOURCE_DIALOG" },
0148: { "TABLE_METADATA" }, { "CLOSE_WINDOW" }, { "EXIT" } };
0149:
0150: private boolean[][] connectMenuStates = {
0151: { true, false, false, true } // NO_CONNECTIONS = 0;
0152: , { true, true, false, true } // HAS_CONNECTIONS = 1;
0153: , { true, true, false, true } // ALL_FRAMES_ICONIFIED = 2;
0154: , { true, true, true, true } // QUERY_PANEL_NO_RESULTSET = 3;
0155: , { true, true, true, true } // QUERY_PANEL_RESULTSET = 4;
0156: , { true, true, true, true } // QUERY_PANEL_OPEN_FOR_ADD = 5;
0157: , { true, true, true, true } // QUERY_PANEL_OPEN_FOR_UPDATE = 6;
0158: , { true, true, true, true } // QUERY_PANEL_OPEN_FOR_QUERY = 7;
0159: , { true, true, true, true } // QUERY_PANEL_OPEN_FOR_CLONE = 8;
0160: , { true, true, true, true } // TABLE_INFO_PANEL
0161: };
0162:
0163: private static Object[][] exportSelectedConfig = {
0164: { "To INSERT Statements...", "EXPORT_SELECTED_INSERT", "I",
0165: "Export selected rows as INSERT statements." },
0166: { "To CSV File...", "EXPORT_SELECTED_CSV", "C",
0167: "Export selected rows as comma-separated values." } };
0168:
0169: private static Object[][] exportSelectedConfig_ = {
0170: { "EXPORT_SELECTED_INSERT" }, { "EXPORT_SELECTED_CSV" } };
0171:
0172: private static Object[][] exportAllConfig = {
0173: { "To INSERT Statements...", "EXPORT_ALL_INSERT", "I",
0174: "Export all rows read as INSERT statements." },
0175: { "To CSV File...", "EXPORT_ALL_CSV", "C",
0176: "Export all rows read as comma-separated values." } };
0177:
0178: private static Object[][] exportAllConfig_ = {
0179: { "EXPORT_ALL_INSERT" }, { "EXPORT_ALL_CSV" } };
0180:
0181: private static Object[][] selectedOrAllConfig = {
0182: { "_Selected Row(s)", exportSelectedConfig, "S", null },
0183: { "_All Rows", exportAllConfig, "A", null } };
0184:
0185: private static Object[][] selectedOrAllConfig_ = {
0186: { "SELECTED_ROWS", exportSelectedConfig_ },
0187: { "ALL_ROWS", exportAllConfig_ } };
0188:
0189: private static Object[][] gridViewSubConfig = {
0190: { "Select visible columns...", "COLUMN_MAP_DIALOG", "V",
0191: "Select which columns will be displayed in this table." },
0192: { "CHECKBOX_Horizontal scrollbar",
0193: "TOGGLE_HORIZONTAL_SCROLLBAR", "H",
0194: "Show or hide the horizontal scrollbar." } };
0195:
0196: private static Object[][] gridViewSubConfig_ = {
0197: { "COLUMN_MAP_DIALOG" },
0198: { "TOGGLE_HORIZONTAL_SCROLLBAR", "CHECKBOX" } };
0199:
0200: private static Object[][] gridTabPopupConfig = {
0201: { "Select columns...", "COLUMN_MAP_DIALOG", null,
0202: "Select which columns will be displayed in this table." },
0203: { "Window title...", "WINDOW_TITLE", null,
0204: "Set the title for this window." },
0205: { "Table Metadata", "QUERYPANEL_TABLE_METADATA", null,
0206: "View medadata for this table." },
0207: { "_Export Selected", exportSelectedConfig, null,
0208: "Export selected rows to a file." },
0209: { "_Export All", exportAllConfig, null,
0210: "Export all rows read to a file." } };
0211:
0212: static Object[][] queryformMenuConfig = {
0213: { "New Query Form...", "NEW_QUERY_FORM", "Q",
0214: "Open a new query form." },
0215: { "Window title...", "WINDOW_TITLE", "T",
0216: "Set the window title for the current query form." },
0217: { "Form Query", "OPEN_FOR_QUERY", "F",
0218: "Enter query criteria in the current query form." },
0219: { "Where Clause Query...", "WHERE_CLAUSE_QUERY", "W",
0220: "Enter a custom where clause query." },
0221: { "Add Record", "ADD_RECORD", "A",
0222: "Add a record through the current query form." },
0223: { "Modify Record", "MODIFY_RECORD", "M",
0224: "Modify the current record." },
0225: { "Delete Record", "DELETE_RECORD", "D",
0226: "Delete the current record." },
0227: { "Clone Record", "CLONE_RECORD", "L",
0228: "Clone the current record." },
0229: { "_Grid View ", gridViewSubConfig, "G",
0230: "Configure grid view tab." },
0231: { "_Export", selectedOrAllConfig, "X",
0232: "Export query results to a file." },
0233: { "Excecute Operation", "EXECUTE_ACTION", "E",
0234: "Execute the currently pending operation." },
0235: { "Cancel Operation", "CANCEL_ACTION", "C",
0236: "Cancel the currently pending operation." } };
0237:
0238: static Object[][] queryformMenuConfig_ = { { "NEW_QUERY_FORM", },
0239: { "WINDOW_TITLE", }, { "OPEN_FOR_QUERY", },
0240: { "WHERE_CLAUSE_QUERY", }, { "ADD_RECORD", },
0241: { "MODIFY_RECORD", }, { "DELETE_RECORD", },
0242: { "CLONE_RECORD", }, { "GRID_VIEW", gridViewSubConfig_ },
0243: { "EXPORT", selectedOrAllConfig_ }, { "EXECUTE_ACTION", },
0244: { "CANCEL_ACTION", } };
0245:
0246: public static void main(String[] args) throws Exception {
0247:
0248: convertMenu(connectMenuConfig, "CONNECT");
0249: convertMenu(queryformMenuConfig, "QUERY_FORM");
0250: convertMenu(windowMenuConfig, "WINDOW");
0251: convertMenu(helpMenuConfig, "HELP");
0252: convertMenu(gridViewSubConfig, "GRID_VIEW_SUB");
0253: convertMenu(selectedOrAllConfig, "EXPORT_SUB");
0254: convertMenu(exportAllConfig, "EXPORT_ALL_SUB");
0255: convertMenu(exportSelectedConfig, "EXPORT_SELECTED_SUB");
0256: convertMenu(lafSubConfig, "LOOKANDFEEL_SUB");
0257: convertMenu(gridTabPopupConfig, "GRID_TAB_POPUP");
0258:
0259: }
0260:
0261: private static Object convert(Object[][] config, String menuName) {
0262: Object[][] results = new Object[config.length][];
0263: for (int j = 0; j < config.length; j++) {
0264: boolean isCheckBox = false;
0265: Object subConfig = null;
0266: String action = (String) config[j][0];
0267:
0268: if ("SEPARATOR".equals(action)) {
0269: results[j] = new String[] { action };
0270: continue;
0271: }
0272:
0273: if (config[j].length > 1) {
0274: Object obj = config[j][1];
0275: if ("CHECKBOX".equals(obj)) {
0276: isCheckBox = true;
0277: } else if (obj instanceof Object[][]) {
0278: subConfig = (Object[][]) obj;
0279: }
0280: }
0281:
0282: String prefix = "menu." + menuName + "." + action;
0283: Object[] row = new Object[4];
0284:
0285: if (isCheckBox) {
0286: row[0] = "CHECKBOX_" + prefix + ".label";
0287: } else {
0288: row[0] = prefix + ".label";
0289: }
0290:
0291: if (subConfig != null)
0292: row[1] = convert((Object[][]) subConfig, action
0293: + "_SUB");
0294: else
0295: row[1] = action;
0296: row[2] = prefix + ".mnemonic";
0297: row[3] = prefix + ".tooltip";
0298: results[j] = row;
0299: }
0300:
0301: return results;
0302: }
0303:
0304: private static void convertMenu(Object[][] config, String menuName) {
0305: for (int j = 0; j < config.length; j++) {
0306: Object[] row = config[j];
0307: String label = (String) row[0];
0308: if ("SEPARATOR".equals(label))
0309: continue;
0310: String command = "";
0311: String mnemonic = "";
0312: String tooltip = "";
0313: if (!(row[1] instanceof String)) {
0314: command = label.toUpperCase();
0315: command = command.replace(' ', '_');
0316: command = command.replace('.', ' ');
0317: command = command.trim();
0318: } else {
0319: command = (String) row[1];
0320: }
0321:
0322: if (row.length > 2 && row[2] != null) {
0323: mnemonic = (String) row[2];
0324: }
0325:
0326: if (row.length > 3 && row[3] != null) {
0327: tooltip = (String) row[3];
0328: }
0329: System.out.println("\t\t,{\"menu." + menuName + "."
0330: + command + ".label\",\t\t\t\"" + label + "\"}");
0331: System.out.println("\t\t,{\"menu." + menuName + "."
0332: + command + ".mnemonic\",\t\t\t\"" + mnemonic
0333: + "\"}");
0334: System.out
0335: .println("\t\t,{\"menu." + menuName + "." + command
0336: + ".tooltip\",\t\t\t\"" + tooltip + "\"}");
0337: }
0338: }
0339:
0340: private boolean[][] queryformMenuStates = {
0341: // New WinTitle Query WHERE Add Mod Del Clone Grid Export Exec Cancel
0342: { false, false, false, false, false, false, false, false,
0343: false, false, false, false } // NO_CONNECTIONS = 0;
0344: ,
0345: { true, false, false, false, false, false, false, false,
0346: false, false, false, false } // HAS_CONNECTIONS = 1;
0347: ,
0348: { true, false, false, false, false, false, false, false,
0349: false, false, false, false } // ALL_FRAMES_ICONIFIED = 2;
0350: ,
0351: { true, true, true, true, true, false, false, false, true,
0352: false, false, false } // QUERY_PANEL_NO_RESULTSET = 3;
0353: ,
0354: { true, true, true, true, true, true, true, true, true,
0355: true, false, false } // QUERY_PANEL_RESULTSET = 4;
0356: ,
0357: { true, false, false, false, false, false, false, false,
0358: false, false, true, true } // QUERY_PANEL_OPEN_FOR_ADD = 5;
0359: ,
0360: { true, false, false, false, false, false, false, false,
0361: false, false, true, true } // QUERY_PANEL_OPEN_FOR_UPDATE = 6;
0362: ,
0363: { true, false, false, false, false, false, false, false,
0364: false, false, true, true } // QUERY_PANEL_OPEN_FOR_QUERY = 7;
0365: ,
0366: { true, false, false, false, false, false, false, false,
0367: false, false, true, true } // QUERY_PANEL_OPEN_FOR_CLONE = 8;
0368: ,
0369: { true, false, false, false, false, false, false, false,
0370: false, false, false, false } // TABLE_INFO_PANEL
0371: };
0372:
0373: final static String LOOK_AND_FEEL_SUBMENU_LABEL = "Look and Feel";
0374:
0375: static String[][] lafSubConfig = {
0376: { "Install new...", "INSTALL_LOOK_AND_FEEL", "I",
0377: "Install a third-party Look-and-Feel" },
0378: { "SEPARATOR" } };
0379:
0380: static String[][] lafSubConfig_ = { { "INSTALL_LOOK_AND_FEEL" },
0381: { "SEPARATOR" } };
0382:
0383: static Object[][] windowMenuConfig = {
0384: { "Minimize all", "MINIMIZE_ALL", "N",
0385: "Minimize all windows" },
0386: { "Maximize all", "MAXIMIZE_ALL", "X",
0387: "Maximize all windows" },
0388: { "Restore all", "RESTORE_ALL", "R", "Restore all windows" },
0389: { "Cascade", "CASCADE", "C", "Cascade all windows" },
0390: { "SEPARATOR" },
0391: { "_" + LOOK_AND_FEEL_SUBMENU_LABEL, lafSubConfig, "L",
0392: "Change QueryForm's Look-and-Feel" },
0393: { "SEPARATOR" } };
0394:
0395: static Object[][] windowMenuConfig_ = { { "MINIMIZE_ALL" },
0396: { "MAXIMIZE_ALL" }, { "RESTORE_ALL" }, { "CASCADE" },
0397: { "SEPARATOR" }, { "LOOK_AND_FEEL", lafSubConfig_ },
0398: { "SEPARATOR" } };
0399:
0400: private boolean[][] windowMenuStates = {
0401: { false, false, false, false, true } // NO_CONNECTIONS = 0;
0402: , { false, false, false, false, true } // HAS_CONNECTIONS = 1;
0403: , { false, true, true, true, true } // ALL_FRAMES_ICONIFIED = 2;
0404: , { true, true, true, true, true } // QUERY_PANEL_NO_RESULTSET = 3;
0405: , { true, true, true, true, true } // QUERY_PANEL_RESULTSET = 4;
0406: , { true, true, true, true, true } // QUERY_PANEL_OPEN_FOR_ADD = 5;
0407: , { true, true, true, true, true } // QUERY_PANEL_OPEN_FOR_UPDATE = 6;
0408: , { true, true, true, true, true } // QUERY_PANEL_OPEN_FOR_QUERY = 7;
0409: , { true, true, true, true, true } // QUERY_PANEL_OPEN_FOR_CLONE = 8;
0410: , { true, true, true, true, true } // TABLE_INFO_PANEL
0411: };
0412:
0413: ButtonGroup lafButtonGroup = new ButtonGroup();
0414:
0415: static String[][] helpMenuConfig = {
0416: { "System Information...", "SYSINFO", "I",
0417: "Display system information." },
0418: { "About...", "ABOUT", "A", "Display program information." } };
0419:
0420: static String[][] helpMenuConfig_ = { { "SYSINFO" }, { "ABOUT" } };
0421:
0422: private boolean[][] helpMenuStates = { { true, true } // NO_CONNECTIONS = 0;
0423: , { true, true } // HAS_CONNECTIONS = 1;
0424: , { true, true } // ALL_FRAMES_ICONIFIED = 2;
0425: , { true, true } // QUERY_PANEL_NO_RESULTSET = 3;
0426: , { true, true } // QUERY_PANEL_RESULTSET = 4;
0427: , { true, true } // QUERY_PANEL_OPEN_FOR_ADD = 5;
0428: , { true, true } // QUERY_PANEL_OPEN_FOR_UPDATE = 6;
0429: , { true, true } // QUERY_PANEL_OPEN_FOR_QUERY = 7;
0430: , { true, true } // QUERY_PANEL_OPEN_FOR_CLONE = 8;
0431: , { true, true } // TABLE_INFO_PANEL
0432: };
0433:
0434: JMenu connectMenu = new JMenu("Connect");
0435: JMenu queryformMenu = new JMenu("Query Form");
0436: JMenu windowMenu = new JMenu("Window");
0437: JMenu helpMenu = new JMenu("Help");
0438:
0439: JMenu lafMenu = null;
0440:
0441: Object[][] menus = {
0442: { connectMenu, convert(connectMenuConfig_, "CONNECT"), "C",
0443: connectMenuStates },
0444: { queryformMenu,
0445: convert(queryformMenuConfig_, "QUERY_FORM"), "Q",
0446: queryformMenuStates },
0447: { windowMenu, convert(windowMenuConfig_, "WINDOW"), "W",
0448: windowMenuStates },
0449: { helpMenu, convert(helpMenuConfig_, "HELP"), "H",
0450: helpMenuStates } };
0451:
0452: /**
0453: * These are the messages that are displayed on the statusbar for each
0454: * screen state. The index of each message corresponds to a state number.
0455: */
0456: private final static String[] STATE_MESSAGES = {
0457: "Select \"Data Source...\" from the Connect menu to configure or open a connection. ",
0458: null,
0459: null,
0460: null,
0461: "Use PgUP/PgDN keys to browse results.",
0462: "Enter data for new record. Fields with red borders are required. ",
0463: "Modify the current record. ",
0464: "Enter query criteria. \"%\" may be used as a wildcard in character fields, \"<\" and \">\" in numeric fields. ",
0465: "Modify the primary key and other unique fields before saving cloned record. ",
0466: null };
0467:
0468: JCheckBoxMenuItem horizontalScrollbarMenuItem = null;
0469:
0470: int offset = 0;
0471: int increment = 25;
0472:
0473: private File configFile = null;
0474:
0475: public MainPanel(Frame parent, File configFile) {
0476:
0477: java.util.Date upSince = new java.util.Date();
0478:
0479: this .configFile = configFile;
0480: if (configFile.exists()) {
0481: try {
0482: config = new Config(configFile);
0483: } catch (IOException ex) {
0484: ex.printStackTrace();
0485: String msg = "An error occurred while reading your configuration file: "
0486: + configFile
0487: + ". The program can still run, but preexisting configuration information will not be available.";
0488: GUIHelper.errMsg(parent, msg, "Application Error");
0489: config = new Config();
0490: } catch (Exception ex) {
0491: ex.printStackTrace();
0492: String msg = "An error occurred while parsing your configuration file: "
0493: + configFile
0494: + ". The program can still run, but preexisting configuration information will not be available.";
0495: GUIHelper.errMsg(parent, msg, "Application Error");
0496: config = new Config();
0497: } catch (FactoryConfigurationError er) {
0498: er.printStackTrace();
0499: String msg = "A Factory Configuration Error occurred while reading your configuration file: "
0500: + configFile
0501: + ". This probably occurred because no suitable XML parser could be located in your classpath. "
0502: + "The program can still run, but preexisting configuration information will not be available.";
0503: GUIHelper.errMsg(parent, msg, "Application Error");
0504: config = new Config();
0505: }
0506:
0507: } else {
0508: config = new Config();
0509: }
0510:
0511: this .parent = parent;
0512:
0513: if (this .parent != null) {
0514: if (this .parent instanceof JFrame) {
0515: ((JFrame) this .parent)
0516: .setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
0517: }
0518: this .parent.addWindowListener(new WindowAdapter() {
0519: /**
0520: * Invoked when a window is in the process of being closed.
0521: * The close operation can be overridden at this point.
0522: */
0523: public void windowClosing(WindowEvent e) {
0524: maybeExitProgram();
0525: }
0526: });
0527: }
0528:
0529: configDialog = new LocalDataSourceConfigDialog(parent);
0530: configDialog.setTitle("Available Data Sources");
0531: GUIHelper.centerWindowOnScreen(configDialog);
0532:
0533: tableSelector = new TableSelector(parent);
0534: GUIHelper.centerWindowOnScreen(tableSelector);
0535:
0536: loginDialog = new LoginDialog(parent);
0537: GUIHelper.centerWindowOnScreen(loginDialog);
0538:
0539: columnMapDialog = new ColumnMapDialog(parent);
0540: GUIHelper.centerWindowOnScreen(columnMapDialog);
0541:
0542: whereClauseDialog = new WhereClauseDialog(parent);
0543: GUIHelper.centerWindowOnScreen(whereClauseDialog);
0544:
0545: exportDialog = new ExportDialog(parent);
0546: exportDialog.setTitle("Select Columns For Export");
0547: GUIHelper.centerWindowOnScreen(exportDialog);
0548:
0549: overwriteDialog = new AppendOverwriteDialog(parent);
0550: GUIHelper.centerWindowOnScreen(overwriteDialog);
0551:
0552: tpLafDialog = new ThirdPartyLafDialog(parent);
0553: GUIHelper.centerWindowOnScreen(tpLafDialog);
0554:
0555: sysInfoDialog = new SystemInfoDialog(parent, upSince);
0556: GUIHelper.centerWindowOnScreen(sysInfoDialog);
0557:
0558: // configure the about dialog.
0559: String msg = "<center><h1>QueryForm</h1><h3>Version "
0560: + VersionNumber.VERSION_NUMBER
0561: + "</h3><h3>Copyright © 1998 - 2004, David F. Glasser (dglasser@pobox.com)"
0562: + "</h3><h3><u><font color='blue'>http://qform.sourceforge.net</font><u></h3><p>This product includes software developed by<br>the Apache Software Foundation "
0563: + "(http://www.apache.org/).<p>"
0564: + "Toolbar Icons Copyright © 1998 Dean S. Jones (dean@gallant.com).</center>";
0565: javax.swing.JEditorPane jep = new JEditorPane();
0566: jep.setContentType("text/html");
0567: jep.setEditable(false);
0568: jep.setOpaque(false);
0569: jep.setText(msg);
0570:
0571: aboutDialog = new JDialog(parent);
0572: ActionListener closer = new ActionListener() {
0573: public void actionPerformed(ActionEvent e) {
0574: aboutDialog.setVisible(false);
0575: }
0576: };
0577:
0578: JPanel panel = new JPanel();
0579: panel.setLayout(new BorderLayout());
0580: panel.setBorder(new EmptyBorder(10, 10, 10, 10));
0581:
0582: JPanel bPanel = new JPanel();
0583: JButton okButton = new JButton("OK");
0584:
0585: GUIHelper.buildButtonPanel(bPanel, new Object[][] { { okButton,
0586: "O", null, null } }, closer);
0587:
0588: panel.add(jep, BorderLayout.CENTER);
0589: panel.add(bPanel, BorderLayout.SOUTH);
0590:
0591: aboutDialog.setContentPane(panel);
0592: aboutDialog.setTitle("QueryForm");
0593: aboutDialog.addKeyListener(new EnterEscapeKeyHandler(okButton,
0594: okButton));
0595:
0596: GUIHelper.setAllSizes(jep, new Dimension(450, 280));
0597: aboutDialog.setResizable(false);
0598: aboutDialog.pack();
0599: GUIHelper.centerWindowOnScreen(aboutDialog);
0600:
0601: // add the toolbar buttons
0602: toolBar.addSeparator();
0603: toolBar.setBorder(new EmptyBorder(7, 10, 7, 5));
0604: GUIHelper
0605: .configureToolbar(toolBar, toolBarConfig,
0606: "org/glasser/qform/images", new Dimension(36,
0607: 36), this );
0608:
0609: // now that all of the dialogs have been created, store them in an array for
0610: // easy changing of the look and feel.
0611: Component[] temp = { configDialog, columnMapDialog,
0612: tableSelector, loginDialog, whereClauseDialog,
0613: exportDialog, overwriteDialog, aboutDialog,
0614: tpLafDialog, sysInfoDialog };
0615:
0616: dialogs = temp;
0617:
0618: /////////////////////////////////////////////////////////////////////
0619: /////////////////////////////////////////////////////////////////////
0620: //
0621: // add the menus
0622: //
0623: for (int j = 0; j < menus.length; j++) {
0624: JMenu menu = (JMenu) menus[j][0];
0625: menu.setMnemonic(((String) menus[j][2]).charAt(0));
0626: Object[][] menuItems = (Object[][]) menus[j][1];
0627: GUIHelper.buildMenu(menu, menuItems, this ,
0628: menuItemListener, menuItemListener, bundle);
0629: menuBar.add(menu);
0630: }
0631:
0632: String horizontalScrollbarLabel = bundle
0633: .getString("menu.GRID_VIEW_SUB.TOGGLE_HORIZONTAL_SCROLLBAR.label");
0634:
0635: horizontalScrollbarMenuItem = (JCheckBoxMenuItem) GUIHelper
0636: .findMenuItemByLabelText(queryformMenu,
0637: horizontalScrollbarLabel);
0638: horizontalScrollbarMenuItem.setSelected(true);
0639:
0640: // build the Look And Feel submenu.
0641: this .lafMenu = (JMenu) GUIHelper.findMenuItemByActionCommand(
0642: this .windowMenu, LOOK_AND_FEEL_SUBMENU_LABEL);
0643:
0644: // add the JRE-included LAFs to the menu.
0645: UIManager.LookAndFeelInfo[] lafs = UIManager
0646: .getInstalledLookAndFeels();
0647: for (int j = 0; j < lafs.length; j++) {
0648: UIManager.LookAndFeelInfo info = lafs[j];
0649: this .addOrUpdateLafMenuItem(info.getName(), info
0650: .getClassName());
0651: }
0652:
0653: // now add the third-party LAFs from the config file to the menu.
0654: lafs = config.getThirdPartyLafs();
0655: for (int j = 0; j < lafs.length; j++) {
0656: UIManager.LookAndFeelInfo info = lafs[j];
0657: String lafName = info.getName();
0658: if (Util.isNothing(lafName))
0659: lafName = "Unknown";
0660: String className = info.getClassName();
0661: if (Util.isNothing(className)) {
0662: System.err
0663: .println("Error in configuration file: A third-party-laf element is missing its laf-class attribute.");
0664: continue;
0665: }
0666: this .addOrUpdateLafMenuItem(lafName, className);
0667: }
0668:
0669: this .setScreenState(NO_CONNECTIONS);
0670:
0671: }
0672:
0673: private HashMap lafMenuItems = new HashMap();
0674:
0675: /**
0676: * Adds a JRadioButtonMenuItem for a LookAndFeel to the LookAndFeel submenu. If an item already
0677: * exists for it, the item text is updated to match lafName. This is helpful if the
0678: * LAF was entered into qform.xml manually.
0679: */
0680: private void addOrUpdateLafMenuItem(String lafName,
0681: String lafClassName) {
0682:
0683: // see if the item already exists.
0684: JRadioButtonMenuItem item = (JRadioButtonMenuItem) lafMenuItems
0685: .get(lafClassName);
0686:
0687: // if it does, update it and return.
0688: if (item != null) {
0689: item.setText(lafName);
0690: return;
0691: }
0692:
0693: // otherwise add it.
0694: item = new JRadioButtonMenuItem(lafName);
0695: lafButtonGroup.add(item);
0696: LookAndFeel currentLAF = UIManager.getLookAndFeel();
0697: if (currentLAF != null
0698: && lafClassName.equals(currentLAF.getClass().getName())) {
0699: item.setSelected(true);
0700: }
0701: item.setActionCommand(lafClassName);
0702: lafMenu.add(item);
0703: item.addActionListener(lafManager);
0704: lafMenuItems.put(lafClassName, item);
0705: }
0706:
0707: private ActionListener lafManager = new ActionListener() {
0708: /**
0709: * Invoked when a LookAndFeel menu item is selected.
0710: */
0711: public void actionPerformed(ActionEvent e) {
0712: JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) e
0713: .getSource();
0714: String lafClassName = e.getActionCommand();
0715: if (debug)
0716: System.out.println("Changing look-and-feel: "
0717: + lafClassName);
0718: try {
0719: LookAndFeel laf = null;
0720: try {
0721: Class lafClass = ExtensionClassLoader
0722: .getSingleton().loadClass(lafClassName);
0723: laf = (LookAndFeel) lafClass.newInstance();
0724: if (laf.isSupportedLookAndFeel()) {
0725: addOrUpdateLafMenuItem(laf.getName(), laf
0726: .getClass().getName());
0727:
0728: // if this is a third-party LAF, this will update it in the config file.
0729: // This may be necessary if it was added to the config file manually.
0730: config.maybeUpdateThirdPartyLaf(laf.getName(),
0731: laf.getClass().getName());
0732: setLookAndFeel(laf);
0733: } else {
0734: // Unsupported LAF, so abort the look-and-feel change.
0735:
0736: // re-select the current LAF's menu item.
0737: selectCurrentLafMenuItem();
0738:
0739: int reply = JOptionPane
0740: .showConfirmDialog(
0741: parent,
0742: "The look-and-feel you selected ("
0743: + menuItem.getText()
0744: + ") is not supported on this platform.\n\nDo you want to remove this look-and-feel from QueryForm's configuration file?",
0745: "Application Error",
0746: JOptionPane.YES_NO_OPTION);
0747: if (reply == JOptionPane.YES_OPTION) {
0748:
0749: // delete the LAF from the config file.
0750: config.deleteThirdPartyLaf(lafClassName);
0751: // delete the menu item from the menu.
0752: lafMenu.remove(menuItem);
0753: } else { // disable the menu item, but leave it in the menu.
0754: menuItem.setEnabled(false);
0755: }
0756: }
0757: } catch (ClassNotFoundException cnf) {
0758:
0759: // re-select the current LAF's menu item.
0760: selectCurrentLafMenuItem();
0761:
0762: int reply = JOptionPane
0763: .showConfirmDialog(
0764: parent,
0765: "The look-and-feel you selected ("
0766: + menuItem.getText()
0767: + ") was not found in QueryForm's classpath.\n\nDo you want to remove this look-and-feel from QueryForm's configuration file?",
0768: "Application Error",
0769: JOptionPane.YES_NO_OPTION);
0770: if (reply == JOptionPane.YES_OPTION) {
0771:
0772: // delete the LAF from the config file.
0773: config.deleteThirdPartyLaf(lafClassName);
0774: // delete the menu item from the menu.
0775: lafMenu.remove(menuItem);
0776: } else { // disable the menu item, but leave it in the menu.
0777: menuItem.setEnabled(false);
0778: }
0779: return;
0780: }
0781: } catch (Throwable err) {
0782: err.printStackTrace();
0783: handleSevereLafError(err);
0784: }
0785: }
0786:
0787: };
0788:
0789: /**
0790: * Sets the application's LookAndFeel to the default (Metal) LookAndFeel. If the operation
0791: * fails, the program exits. This method should only be called when/if a call to UIManager.setLookAndFeel()
0792: * fails for some other LookAndFeel.
0793: */
0794: private void restoreDefaultLaf() {
0795: try {
0796: LookAndFeel defaultLAF = (LookAndFeel) Class.forName(
0797: UIManager.getCrossPlatformLookAndFeelClassName())
0798: .newInstance();
0799: setLookAndFeel(defaultLAF);
0800: } catch (Throwable ex) {
0801: ex.printStackTrace();
0802: GUIHelper
0803: .errMsg(
0804: parent,
0805: "The attempt to restore the default Look-and-Feel was unsuccessful. QueryForm will now terminate.",
0806: "Unrecoverable Error");
0807: System.exit(9);
0808: }
0809: }
0810:
0811: /**
0812: * Selects the menu item for the app's current LookAndFeel. Does nothing if
0813: * the menu item is not found in the menu, or if the current LookAndFeel cannot
0814: * be determined.
0815: */
0816: private void selectCurrentLafMenuItem() {
0817: LookAndFeel currentLAF = UIManager.getLookAndFeel();
0818: if (currentLAF == null) {
0819: System.err
0820: .println("WARNING: Could not select menu item for current look-and-feel. UIManager.getLookAndFeel() returned null.");
0821: return;
0822: }
0823:
0824: JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) lafMenuItems
0825: .get(currentLAF.getClass().getName());
0826: if (menuItem != null) {
0827: menuItem.setSelected(true);
0828: } else {
0829: System.err
0830: .println("WARNING: Menu item not found for Look-and-Feel: "
0831: + currentLAF.getName());
0832: }
0833: }
0834:
0835: /**
0836: * This method is called when UIManager.setLookAndFeel() throws a Throwable. It displays an error
0837: * message to the user and attempts to set the app's look and feel to the default (Metal). If the default
0838: * LookAndFeel can't be restored, the program exits, on the assumption that is is irretrievably hosed.
0839: */
0840: private void handleSevereLafError(Throwable err) {
0841:
0842: String s = "An unexpected error has occurred: ";
0843: if (err instanceof Error) {
0844: s = "A severe error has occurred: ";
0845: }
0846:
0847: String msg = s
0848: + err
0849: + "\n\nQueryForm will now attempt to set the default Look-and-Feel so processing can continue.";
0850:
0851: GUIHelper.errMsg(parent, msg, "Application Error");
0852:
0853: // if this call fails, the program exits.
0854: restoreDefaultLaf();
0855: selectCurrentLafMenuItem();
0856: }
0857:
0858: /**
0859: * Sets the LookAndFeel for the app to the given LookAndFeel.
0860: *
0861: * @throws UnsupportedLookAndFeelException if the given LookAndFeel is not suuported.
0862: */
0863: private void setLookAndFeel(LookAndFeel laf)
0864: throws UnsupportedLookAndFeelException {
0865: UIManager.setLookAndFeel(laf);
0866: UIManager.getDefaults().put("ClassLoader",
0867: laf.getClass().getClassLoader());
0868: UIManager.getLookAndFeelDefaults().put("ClassLoader",
0869: laf.getClass().getClassLoader());
0870: SwingUtilities.updateComponentTreeUI(parent);
0871: for (int j = 0; j < dialogs.length; j++) {
0872: SwingUtilities.updateComponentTreeUI(dialogs[j]);
0873: }
0874: setStatusMessage("Look-and-Feel changed to " + laf.getName()
0875: + ".");
0876: System.setProperty("qform.laf", laf.getClass().getName());
0877: }
0878:
0879: /**
0880: * Displays a message indicating that a LookAndFeel is not supported.
0881: */
0882: public void showUnsupportedLafErrorMessage(String lafName,
0883: String lafClassName) {
0884: if (lafName == null)
0885: lafName = "The selected look-and-feel";
0886:
0887: GUIHelper.errMsg(parent, lafName + " (" + lafClassName
0888: + ") is not supported on this platform.",
0889: "Unsupported Look-and-Feel");
0890: }
0891:
0892: public void setMenuState(int state) {
0893: for (int j = 0; j < menus.length; j++) {
0894: JMenu menu = (JMenu) menus[j][0];
0895: boolean[][] states = (boolean[][]) menus[j][3];
0896:
0897: JMenuItem[] items = GUIHelper.getMenuItems(menu);
0898:
0899: for (int k = 0; k < states[state].length; k++) {
0900: items[k].setEnabled(states[state][k]);
0901: }
0902:
0903: QueryPanel qp = getCurrentQueryPanel();
0904: if (qp != null) {
0905: horizontalScrollbarMenuItem.setSelected(qp
0906: .isHorizontalScrollBarVisible());
0907: }
0908: }
0909: }
0910:
0911: public void setToolbarState(int state) {
0912: boolean[] states = toolBarStates[state];
0913: for (int j = 0; j < toolBarConfig.length; j++) {
0914: JButton button = (JButton) toolBarConfig[j][0];
0915: button.setEnabled(states[j]);
0916: }
0917: }
0918:
0919: public void setScreenState(int state) {
0920: setMenuState(state);
0921: setToolbarState(state);
0922: setStatusMessage(STATE_MESSAGES[state]);
0923: screenState = state;
0924: }
0925:
0926: public void setScreenState() {
0927:
0928: JInternalFrame jif = desktop.getSelectedFrame();
0929: if (jif != null) {
0930: JComponent contentPane = (JComponent) jif.getContentPane();
0931: if (contentPane instanceof QueryPanel) {
0932: QueryPanel qp = (QueryPanel) contentPane;
0933: int qpState = qp.getState();
0934: // System.out.println("QueryPanel state is " + qpState);
0935: setScreenState(qpState);
0936: } else if (contentPane instanceof TableInfoPanel) {
0937: setScreenState(MainPanel.TABLE_INFO_PANEL);
0938: }
0939: } else { // no active internal frames
0940: JInternalFrame[] allFrames = desktop.getAllFrames();
0941: if (allFrames != null && allFrames.length > 0) {
0942: setScreenState(this .ALL_FRAMES_ICONIFIED);
0943: } else {
0944: if (dsMap.size() > 0) {
0945: this .setScreenState(this .HAS_CONNECTIONS);
0946: } else {
0947: this .setScreenState(NO_CONNECTIONS);
0948: }
0949: }
0950: }
0951: }
0952:
0953: public static final int NO_CONNECTIONS = 0;
0954: public static final int HAS_CONNECTIONS = 1;
0955: public static final int ALL_FRAMES_ICONIFIED = 2;
0956: public static final int QUERY_PANEL_NO_RESULTSET = 3;
0957: public static final int QUERY_PANEL_HAS_RESULTSET = 4;
0958: public static final int QUERY_PANEL_OPEN_FOR_ADD = 5;
0959: public static final int QUERY_PANEL_OPEN_FOR_UPDATE = 6;
0960: public static final int QUERY_PANEL_OPEN_FOR_QUERY = 7;
0961: public static final int QUERY_PANEL_OPEN_FOR_CLONE = 8;
0962:
0963: public static final int TABLE_INFO_PANEL = 9;
0964:
0965: private int screenState = NO_CONNECTIONS;
0966:
0967: private int nextDataSourceId = 1;
0968:
0969: private HashMap dsMap = new HashMap();
0970:
0971: private HashMap localConfigMap = new HashMap();
0972:
0973: private HashSet pkeysNotSupported = new HashSet();
0974:
0975: private HashSet fkeysNotSupported = new HashSet();
0976:
0977: private HashSet exkeysNotSupported = new HashSet();
0978:
0979: private HashSet establishedConnections = new HashSet();
0980:
0981: private Properties editableTypes = new Properties();
0982:
0983: private HashMap driverClassToEditableTypeMap = new HashMap();
0984:
0985: {
0986: try {
0987: File file = null;
0988:
0989: // first check for a System property called "editable.types".
0990: String filepath = System.getProperty("editable.types");
0991: if (filepath != null) {
0992: file = new File(filepath);
0993: } else {
0994: // otherwise check for a file called qform_editable_types.properties,
0995: // first in the user's home directory, then in the current working directory.
0996: String filename = "qform_editable_types.properties";
0997: File dir = new File(System
0998: .getProperty("user.home", "."));
0999: file = new File(dir, filename);
1000: if (file.exists() == false) {
1001: dir = new File(System.getProperty("user.dir", "."));
1002: file = new File(dir, filename);
1003: }
1004: }
1005: if (file.exists() && file.canRead()) {
1006: FileInputStream fis = new FileInputStream(file);
1007: editableTypes.load(fis);
1008: fis.close();
1009: } else {
1010: // if the System property was used, warn the user that the file wasn't found.
1011: if (filepath != null) {
1012: System.err
1013: .println("WARNING: Editable types file not found: "
1014: + filepath);
1015: }
1016: }
1017:
1018: } catch (Throwable t) {
1019: t.printStackTrace();
1020: }
1021: }
1022:
1023: public void actionPerformed(ActionEvent e) {
1024: try {
1025: _actionPerformed(e);
1026: } catch (NoSuchElementException ex) {
1027: setScreenState();
1028: noConnectionAvailableMessage(null);
1029: return;
1030: } catch (Throwable ex) {
1031: ex.printStackTrace();
1032: GUIHelper.errMsg(parent,
1033: "An unexpected error occurred:\n\n" + ex, null);
1034: }
1035: }
1036:
1037: public void _actionPerformed(ActionEvent e) {
1038: // System.out.println(e.getActionCommand());
1039: Object src = e.getSource();
1040:
1041: // read the tooltip for this component because for some
1042: // actions, we'll want to display the tooltip on the
1043: // statusbar.
1044: String tooltip = null;
1045: try {
1046: // this should always be a JComponent so we won't
1047: // incur the cost of using instanceof
1048: tooltip = ((JComponent) src).getToolTipText();
1049: } catch (Exception ex) {
1050: ex.printStackTrace();
1051: }
1052:
1053: // clear away any existing status message.
1054: setStatusMessage(null);
1055:
1056: String command = e.getActionCommand();
1057: if (command == null)
1058: command = "";
1059: if (command.equals("DATA_SOURCE_DIALOG")) {
1060: setStatusMessage(tooltip);
1061: Vector configs = new Vector(Arrays.asList(config
1062: .getLocalDataSourceConfigs()));
1063: this .configDialog.setList(configs);
1064: configDialog.setVisible(true);
1065: LocalDataSourceConfig ld = configDialog.getSelectedItem();
1066: // System.out.println("SELECTED DATASOURCE: " + ld);
1067: configs = configDialog.getList();
1068: ArrayList list = new ArrayList(configs.size());
1069: list.addAll(configs);
1070: config.setLocalDataSourceConfigs(list);
1071: if (ld != null) {
1072: if (establishedConnections.contains(ld)) {
1073: int reply = JOptionPane
1074: .showConfirmDialog(
1075: this ,
1076: "A connection to this data source has already been \nestablished. Do you want to create another one?",
1077: "QueryForm",
1078: JOptionPane.YES_NO_OPTION);
1079: if (reply == JOptionPane.NO_OPTION) {
1080: setStatusMessage("Operation cancelled.");
1081: return;
1082: }
1083: }
1084: setStatusMessage("Connecting to " + ld.getDisplayName()
1085: + "...");
1086: try {
1087:
1088: DataSource ds = null;
1089:
1090: if (ld.isLoginRequired()) {
1091: String userName = ld.getUser();
1092: String password = ld.getPassword();
1093: if (userName != null && password != null) {
1094: // if we already have a username and password, attempt to login.
1095: ds = DataSourceManager.getLocalDataSource(
1096: ld, userName, password);
1097: } else { // show the login dialog
1098: loginDialog
1099: .setLoginHandler(new LocalDataSourceLoginHandler(
1100: ld));
1101: loginDialog.setUserId(userName);
1102: loginDialog.setPassword(password);
1103: loginDialog.setVisible(true);
1104:
1105: // if this returned null, the user cancelled.
1106: ds = (DataSource) loginDialog
1107: .getLoginResult();
1108: if (ds == null) {
1109: setStatusMessage("Login cancelled.");
1110: return;
1111: }
1112: }
1113: } else { // no login required
1114: ds = DataSourceManager.getLocalDataSource(ld,
1115: null, null);
1116: }
1117:
1118: this .addNewLocalDataSource(ld, ds);
1119:
1120: } catch (ClassNotFoundException ex) {
1121:
1122: GUIHelper.errMsg(parent, "The JDBC driver class ("
1123: + ld.getDriverClassName()
1124: + ") was not found in the classpath.",
1125: "Login Failed");
1126: setStatusMessage("Login failed.");
1127: return;
1128: } catch (Exception ex) {
1129: ex.printStackTrace();
1130: GUIHelper.errMsg(parent, "Login failed: "
1131: + ex.getMessage(), "Login Failed");
1132: setStatusMessage("Login failed.");
1133: return;
1134: }
1135: } else {
1136: // Data source dialog was closed without selecting a database
1137: // to connect to.
1138: setStatusMessage(null);
1139: }
1140: } else if (command.equals("NEW_QUERY_FORM")) {
1141: setStatusMessage("Select table.");
1142: tableSelector.setVisible(true);
1143: Integer sourceId = tableSelector.getSelectedSourceId();
1144: TableInfo ti = tableSelector.getSelectedTableInfo();
1145: if (ti == null) {
1146: setStatusMessage(null);
1147: return;
1148: } else {
1149:
1150: try {
1151: if (ti.getColumns() == null) {
1152: this .setColumnsAndKeys(sourceId, ti);
1153: }
1154:
1155: if (ti.getColumns().length == 0) {
1156: GUIHelper
1157: .errMsg(
1158: parent,
1159: "This QueryForm cannot be created because the database is indicating "
1160: + "that the table or view has no columns or keys.",
1161: "Operation Failed");
1162: setStatusMessage("Operation Failed.");
1163: return;
1164: }
1165:
1166: this .newQueryForm(sourceId, ti);
1167: } catch (NoSuchElementException ex) {
1168: noConnectionAvailableMessage(sourceId);
1169: } catch (Exception ex) {
1170: ex.printStackTrace();
1171: GUIHelper.exceptionMsg(this , ex);
1172: setStatusMessage("");
1173: }
1174: }
1175: } else if (command.equals("OPEN_FOR_QUERY")) {
1176: QueryPanel qp = getCurrentQueryPanel();
1177: qp.setState(qp.OPEN_FOR_QUERY);
1178: setScreenState(QUERY_PANEL_OPEN_FOR_QUERY);
1179: } else if (command.equals("ADD_RECORD")) {
1180:
1181: QueryPanel qp = getCurrentQueryPanel();
1182: qp.setState(qp.OPEN_FOR_ADD);
1183: setScreenState(QUERY_PANEL_OPEN_FOR_ADD);
1184: } else if (command.equals("CLONE_RECORD")) {
1185:
1186: QueryPanel qp = getCurrentQueryPanel();
1187: qp.setState(qp.OPEN_FOR_CLONE);
1188: setScreenState(QUERY_PANEL_OPEN_FOR_CLONE);
1189: } else if (command.equals("MODIFY_RECORD")) {
1190:
1191: QueryPanel qp = getCurrentQueryPanel();
1192: qp.setState(qp.OPEN_FOR_UPDATE);
1193: setScreenState(QUERY_PANEL_OPEN_FOR_UPDATE);
1194: } else if (command.equals("DELETE_RECORD")) {
1195: QueryPanel qp = getCurrentQueryPanel();
1196: qp.deleteCurrentRow();
1197: // setStatusMessage(null);
1198: setScreenState();
1199:
1200: } else if (command.equals("EXECUTE_ACTION")) {
1201:
1202: QueryPanel qp = getCurrentQueryPanel();
1203: try {
1204: switch (qp.getState()) {
1205: case QueryPanel.OPEN_FOR_ADD:
1206: case QueryPanel.OPEN_FOR_CLONE:
1207: qp.executeAdd();
1208: break;
1209: case QueryPanel.OPEN_FOR_QUERY:
1210: qp.runQuery();
1211: break;
1212: case QueryPanel.OPEN_FOR_UPDATE:
1213: qp.executeUpdate();
1214: break;
1215:
1216: }
1217: setScreenState();
1218: } catch (NoSuchElementException ex) {
1219: noConnectionAvailableMessage(qp.getDataSourceId());
1220: return;
1221: }
1222: } else if (command.equals("REFRESH")) {
1223: QueryPanel qp = getCurrentQueryPanel();
1224: qp.rerunLastQuery();
1225: setScreenState();
1226: } else if (command.equals("GOTO_FIRST")) {
1227: QueryPanel qp = getCurrentQueryPanel();
1228: qp.first();
1229: } else if (command.equals("GOTO_NEXT")) {
1230: QueryPanel qp = getCurrentQueryPanel();
1231: qp.next();
1232: } else if (command.equals("GOTO_PREVIOUS")) {
1233: QueryPanel qp = getCurrentQueryPanel();
1234: qp.previous();
1235: } else if (command.equals("CANCEL_ACTION")) {
1236: QueryPanel qp = getCurrentQueryPanel();
1237: qp.cancelPendingAction();
1238: setScreenState(qp.getState());
1239: setStatusMessage("Operation cancelled.");
1240: } else if (command.equals("TOGGLE_HORIZONTAL_SCROLLBAR")) {
1241: QueryPanel qp = getCurrentQueryPanel();
1242: if (qp == null)
1243: return;
1244: qp.setSelectedTab(1);
1245: boolean isVisible = qp.isHorizontalScrollBarVisible();
1246: qp.setHorizontalScrollBarVisible(!isVisible);
1247: } else if (command.equals("TOGGLE_LONGFORM_DATES")) {
1248: QueryPanel qp = getCurrentQueryPanel();
1249: if (qp == null)
1250: return;
1251:
1252: JCheckBoxMenuItem item = (JCheckBoxMenuItem) src;
1253: boolean useLongForm = item.isSelected();
1254: qp.setSelectedTab(1);
1255: qp.displayLongTimestampsInGrid(useLongForm);
1256: }
1257:
1258: else if (command.equals("MINIMIZE_ALL")) {
1259: JInternalFrame[] frames = desktop.getAllFrames();
1260: DesktopManager dm = desktop.getDesktopManager();
1261: for (int j = 0; j < frames.length; j++) {
1262:
1263: try {
1264:
1265: frames[j].setIcon(true);
1266: } catch (Exception ex) {
1267: ex.printStackTrace();
1268: }
1269: // dm.iconifyFrame(frames[j]);
1270: }
1271: } else if (command.equals("MAXIMIZE_ALL")) {
1272: JInternalFrame[] frames = desktop.getAllFrames();
1273: DesktopManager dm = desktop.getDesktopManager();
1274: for (int j = 0; j < frames.length; j++) {
1275: // System.out.println("\n\nframe " + j + ": " + frames[j]);
1276:
1277: try {
1278: JInternalFrame jif = frames[j];
1279: if (jif.isIcon()) {
1280: jif.setIcon(false);
1281: }
1282:
1283: // frames[j].setIcon(false);
1284: frames[j].setMaximum(true);
1285: // dm.maximizeFrame(frames[j]);
1286:
1287: } catch (Exception ex) {
1288: ex.printStackTrace();
1289: }
1290:
1291: }
1292: } else if (command.equals("RESTORE_ALL")) {
1293: JInternalFrame[] frames = desktop.getAllFrames();
1294: DesktopManager dm = desktop.getDesktopManager();
1295: for (int j = 0; j < frames.length; j++) {
1296: // System.out.println("\n\nframe " + j + ": " + frames[j]);
1297:
1298: try {
1299: JInternalFrame jif = frames[j];
1300: if (jif.isIcon()) {
1301: // System.out.println("frame " + j + " is an icon.");
1302: jif.setIcon(false);
1303: } else if (jif.isMaximum()) {
1304: // System.out.println("FRAME " + j + " is maximum.");
1305: jif.setMaximum(false);
1306: Rectangle r = jif.getNormalBounds();
1307: if (r != null)
1308: jif.setBounds(r);
1309: // else System.out.println("normal bounds is null");
1310: }
1311: // else {
1312: // System.out.println("frame " + j + " is already restored.");
1313: // }
1314:
1315: } catch (Exception ex) {
1316: ex.printStackTrace();
1317: }
1318:
1319: // dm.maximizeFrame(frames[j]);
1320:
1321: // if(frames[j].getParent() != null) {
1322: // dm.maximizeFrame(frames[j]);
1323: // }
1324: // else {
1325: // System.out.println("PARENT IS NULL");
1326: // }
1327: }
1328: } else if (command.equals("CASCADE")) {
1329:
1330: int tempOffset = 0;
1331: JInternalFrame[] frames = desktop.getAllFrames();
1332: for (int j = 0; j < frames.length; j++) {
1333: try {
1334:
1335: JInternalFrame jif = frames[j];
1336: if (jif.isIcon()) {
1337: jif.setIcon(false);
1338: } else if (jif.isMaximum()) {
1339: jif.setMaximum(false);
1340: }
1341: jif.setBounds(tempOffset, tempOffset, 500, 300);
1342: jif.setSelected(true);
1343: tempOffset += increment;
1344: } catch (Exception ex) {
1345: }
1346:
1347: }
1348: } else if (command.equals("INSTALL_LOOK_AND_FEEL")) {
1349: tpLafDialog.openDialog();
1350: String className = tpLafDialog.getInput();
1351: if (className == null)
1352: return;
1353: try {
1354: LookAndFeel laf = (LookAndFeel) ExtensionClassLoader
1355: .getSingleton().loadClass(className)
1356: .newInstance();
1357: if (laf.isSupportedLookAndFeel()) {
1358: setLookAndFeel(laf);
1359: this .addOrUpdateLafMenuItem(laf.getName(), laf
1360: .getClass().getName());
1361: config.addOrUpdateThirdPartyLaf(laf.getName(), laf
1362: .getClass().getName());
1363: } else {
1364: this .showUnsupportedLafErrorMessage(laf.getName(),
1365: laf.getClass().getName());
1366: }
1367: } catch (ClassNotFoundException ex) {
1368: GUIHelper.errMsg(this ,
1369: "This look-and-feel class was not found in QueryForm's classpath:\n\n"
1370: + className, null);
1371:
1372: } catch (Throwable t) {
1373: t.printStackTrace();
1374: handleSevereLafError(t);
1375: }
1376: } else if (command.equals("WHERE_CLAUSE_QUERY")) {
1377:
1378: QueryPanel qp = this .getCurrentQueryPanel();
1379: if (qp == null)
1380: return; // shouldn't happen
1381:
1382: setStatusMessage("Use arrow buttons or Alt-P/Alt-N to see history.");
1383: whereClauseDialog.openDialog(qp.getTableName(), qp
1384: .getHistoryList());
1385:
1386: String whereClause = whereClauseDialog.getWhereClause();
1387: if (whereClause == null) {
1388: setStatusMessage("Operation cancelled.");
1389: return;
1390: } else {
1391: setStatusMessage("");
1392: }
1393:
1394: // if a where-clause query returns no data, we want to make
1395: // sure any existing resultsets are cleared from the form.
1396: qp.runQuery(whereClause, qp.NO_RESULTSET);
1397:
1398: // update the state of the main screen based on the
1399: // results of the where-clause query.
1400: setScreenState();
1401:
1402: } else if (command.equals("TABLE_METADATA")) {
1403: Integer sourceId = null;
1404: try {
1405: tableSelector.setVisible(true);
1406: sourceId = tableSelector.getSelectedSourceId();
1407: TableInfo ti = tableSelector.getSelectedTableInfo();
1408:
1409: if (ti == null)
1410: return;
1411: if (ti.getColumns() == null) {
1412: this .setColumnsAndKeys(sourceId, ti);
1413: }
1414:
1415: newTableInfoPanel(ti, sourceId);
1416:
1417: } catch (NoSuchElementException ex) {
1418: noConnectionAvailableMessage(sourceId);
1419: return;
1420: } catch (Exception ex) {
1421: ex.printStackTrace();
1422: GUIHelper.exceptionMsg(this , ex);
1423: return;
1424: }
1425:
1426: } else if (command.equals("CLOSE_WINDOW")) {
1427: JInternalFrame frame = desktop.getSelectedFrame();
1428: if (frame == null)
1429: return;
1430: frame.setVisible(false);
1431: frame.dispose();
1432: }
1433:
1434: if (command.equals("QUERYPANEL_TABLE_METADATA")) {
1435: QueryPanel qp = this .getCurrentQueryPanel();
1436: if (qp == null)
1437: return; // shouldn't happen
1438:
1439: try {
1440:
1441: newTableInfoPanel(qp.getTableInfo(), qp
1442: .getDataSourceId());
1443:
1444: } catch (Exception ex) {
1445: ex.printStackTrace();
1446: GUIHelper.exceptionMsg(this , ex);
1447: return;
1448: }
1449:
1450: }
1451: if (command.equals("COLUMN_MAP_DIALOG")) {
1452: setStatusMessage(tooltip);
1453: QueryPanel qp = this .getCurrentQueryPanel();
1454: if (qp == null)
1455: return; // shouldn't happen
1456:
1457: qp.setSelectedTab(1);
1458:
1459: int[] visibleGridColumns = qp.getVisibleGridColumns();
1460: // System.out.println("VisibleGridColumns is " + visibleGridColumns);
1461:
1462: String[] columnNames = qp.getColumnNames();
1463: // System.out.println("columnNames is " + columnNames);
1464:
1465: columnMapDialog.openDialog(columnNames, visibleGridColumns);
1466: int selections[] = columnMapDialog.getSelections();
1467: if (selections == null)
1468: return;
1469:
1470: setStatusMessage("Ctrl-click to select/deselect columns for display.");
1471: qp.setVisibleGridColumns(selections);
1472: setStatusMessage(null);
1473: setScreenState();
1474:
1475: } else if (command.equals("WINDOW_TITLE")) {
1476: QueryPanel qp = this .getCurrentQueryPanel();
1477: if (qp == null)
1478: return; // shouldn't happen
1479:
1480: String title = qp.getWindowTitle();
1481: String dataSourceName = qp.getDataSourceDisplayName();
1482:
1483: Integer sourceId = qp.getDataSourceId();
1484:
1485: String newTitle = (String) JOptionPane.showInputDialog(
1486: this , "Enter a new title for this window:",
1487: "QueryForm", JOptionPane.INFORMATION_MESSAGE, null,
1488: null, title);
1489: if (newTitle == null)
1490: return;
1491:
1492: String baseName = "(" + sourceId + ") " + newTitle
1493: + " [QUERY";
1494: XInternalFrame frame = (XInternalFrame) desktop
1495: .getSelectedFrame();
1496: frame.setTitle(baseName + " / " + dataSourceName + "]");
1497: frame.getMenuItem().setText(baseName + "]");
1498: qp.setWindowTitle(newTitle);
1499: } else if (command.equals("EXPORT_SELECTED_INSERT")) {
1500: exportResultSet(ExportDialog.EXPORT_INSERT_STATEMENTS, true);
1501: } else if (command.equals("EXPORT_ALL_INSERT")) {
1502: exportResultSet(ExportDialog.EXPORT_INSERT_STATEMENTS,
1503: false);
1504: } else if (command.equals("EXPORT_SELECTED_CSV")) {
1505: exportResultSet(ExportDialog.EXPORT_CSV, true);
1506: } else if (command.equals("EXPORT_ALL_CSV")) {
1507: exportResultSet(ExportDialog.EXPORT_CSV, false);
1508: } else if (command.equals("EXIT")) {
1509: maybeExitProgram();
1510: } else if (command.equals("ABOUT")) {
1511: aboutDialog.setVisible(true);
1512: } else if (command.equals("SYSINFO")) {
1513: // sysInfoDialog.setModal(true);
1514: sysInfoDialog.setVisible(true);
1515: }
1516:
1517: }
1518:
1519: public void noConnectionAvailableMessage(Integer dataSourceId) {
1520: if (dataSourceId != null) {
1521: LocalDataSourceConfig config = (LocalDataSourceConfig) localConfigMap
1522: .get(dataSourceId);
1523: GUIHelper
1524: .errMsg(
1525: parent,
1526: "There are currently no connections available in the connection pool for this data source:\n\n\""
1527: + config.getDisplayName()
1528: + "\"\n\nYou may create another pool by reconnecting through the data source dialog, or free a connection by reading in the remainder of any open resultsets for this data source, or closing a window with an open resultset.",
1529: "Connection Not Available");
1530: } else {
1531: GUIHelper
1532: .errMsg(
1533: parent,
1534: "There are currently no connections available in the connection pool for this data source. "
1535: + "\n\nYou may create another pool by reconnecting through the data source dialog, or free a connection by reading in the remainder of any open resultsets for this data source, or closing a window with an open resultset.",
1536: "Connection Not Available");
1537: }
1538: }
1539:
1540: private void exportResultSet(int exportType, boolean selectedOnly) {
1541: QueryPanel qp = this .getCurrentQueryPanel();
1542: if (qp == null)
1543: return; // shouldn't happen
1544:
1545: File f = null;
1546: boolean append = false;
1547: while (true) {
1548: f = this .getOutputFile(null);
1549: if (f == null) {
1550: setStatusMessage("Export cancelled.");
1551: return;
1552: }
1553: if (f.exists()) {
1554: if (f.canWrite() == false) {
1555: GUIHelper
1556: .warningMsg(
1557: this ,
1558: "The selected file or destination directory cannot be written. Please choose another output file.",
1559: "Invalid Selection");
1560: continue;
1561: }
1562:
1563: overwriteDialog.openDialog(f.getAbsolutePath(), true);
1564: String option = overwriteDialog.getSelection();
1565: if (option == null
1566: || option.equals(overwriteDialog.CANCEL_OPTION)) {
1567: setStatusMessage("Export cancelled.");
1568: return;
1569: } else if (option.equals(overwriteDialog.APPEND_OPTION)) {
1570: append = true;
1571: }
1572: break;
1573: } else {
1574: break;
1575: }
1576:
1577: }
1578:
1579: //System.out.println("Exporting to " + f.getAbsolutePath());
1580:
1581: TableInfo tableInfo = qp.getTableInfo();
1582:
1583: exportDialog.openDialog(tableInfo, exportType);
1584:
1585: String[] columnNames = exportDialog.getColumnNames();
1586: if (columnNames == null) {
1587: setStatusMessage("Operation cancelled.");
1588: return;
1589: }
1590:
1591: Formatter[] formatters = exportDialog.getFormatters();
1592: String tableName = exportDialog.getTableName();
1593:
1594: String terminal = exportDialog.getTerminal();
1595: if (terminal != null && terminal.trim().length() == 0)
1596: terminal = null;
1597:
1598: int[] selectedIndexes = null;
1599: if (selectedOnly)
1600: selectedIndexes = qp.getSelectedIndexes();
1601:
1602: Vector[] currentRowset = qp.getCurrentRowset();
1603:
1604: try {
1605:
1606: PrintWriter writer = new PrintWriter(new FileWriter(f
1607: .getAbsolutePath(), append));
1608: if (exportType == ExportDialog.EXPORT_INSERT_STATEMENTS) {
1609: ExportManager.exportInsertStatements(writer, Arrays
1610: .asList(currentRowset), selectedIndexes,
1611: tableName, columnNames, formatters, terminal);
1612: } else {
1613: ExportManager.exportDelimited(writer, Arrays
1614: .asList(currentRowset), selectedIndexes, ",",
1615: columnNames, formatters, terminal);
1616: }
1617: writer.close();
1618: GUIHelper.infoMsg(this , "Results saved successfully.",
1619: "QueryForm");
1620: } catch (Exception ex) {
1621: ex.printStackTrace();
1622: GUIHelper.exceptionMsg(this , ex);
1623: }
1624: }
1625:
1626: private QueryPanel getCurrentQueryPanel() {
1627: JInternalFrame frame = desktop.getSelectedFrame();
1628: if (frame == null)
1629: return null;
1630: Container c = frame.getContentPane();
1631: if (c instanceof QueryPanel)
1632: return (QueryPanel) c;
1633: return null;
1634: }
1635:
1636: public void newTableInfoPanel(TableInfo ti, Integer dataSourceId)
1637: throws NoSuchMethodException {
1638: LocalDataSourceConfig config = (LocalDataSourceConfig) localConfigMap
1639: .get(dataSourceId);
1640: TableInfoPanel tip = new TableInfoPanel(ti, config
1641: .getDisplayName());
1642:
1643: String baseName = "(" + dataSourceId + ") " + ti.getTableName()
1644: + " [METADATA";
1645:
1646: XInternalFrame jif = new XInternalFrame(baseName + " / "
1647: + config.getDisplayName() + "]", true, true, true, true);
1648:
1649: jif.getMenuItem().setText(baseName + "]");
1650: jif.setContentPane(tip);
1651: this .desktop.add(jif);
1652: jif.addInternalFrameListener(this );
1653: windowMenu.add(jif.getMenuItem());
1654: jif.pack();
1655: offset += increment;
1656: if (offset > (10 * increment))
1657: offset = 0;
1658: jif.setBounds(offset, offset, 500, 300);
1659: jif.setVisible(true);
1660:
1661: // desktop.getDesktopManager().maximizeFrame(jif);
1662: setScreenState(MainPanel.TABLE_INFO_PANEL);
1663: }
1664:
1665: private final static String DEFAULT_SCHEMA = "<DEFAULT SCHEMA>";
1666:
1667: MethodComparator tableTypeComparator = new MethodComparator(
1668: org.glasser.sql.TableInfo.class, "getTableType", false,
1669: false, TableInfo.NAME_COMPARATOR, false);
1670:
1671: public void addNewLocalDataSource(LocalDataSourceConfig ld,
1672: DataSource ds) throws SQLException {
1673:
1674: Connection conn = null;
1675: try {
1676:
1677: Integer id = new Integer(nextDataSourceId++);
1678:
1679: // we'll clone this config because it may be modified and connected
1680: // to again, and we want to keep the original information associated
1681: // with this connection intact.
1682: LocalDataSourceConfig config = (LocalDataSourceConfig) ld
1683: .clone();
1684: conn = ds.getConnection();
1685: setStatusMessage("Fetching table list...");
1686: DatabaseMetaData dbmd = conn.getMetaData();
1687:
1688: ResultSet rs = null;
1689: if (showSystemTables) {
1690: rs = dbmd.getTables(null, null, "%", null);
1691: } else {
1692: rs = dbmd.getTables(null, null, "%", new String[] {
1693: "VIEW", "TABLE" });
1694: }
1695:
1696: TableInfo[] tis = DBUtil.getTableInfos(rs);
1697:
1698: Arrays.sort(tis, tableTypeComparator);
1699:
1700: rs.close();
1701: HashMap map = DBUtil.getTableInfoLists(tis, DEFAULT_SCHEMA);
1702: this .tableSelector.addDataSource(id, config
1703: .getDisplayName(), map);
1704: this .dsMap.put(id, ds);
1705: this .localConfigMap.put(id, config.clone());
1706: setStatusMessage("Connected to " + config.getDisplayName()
1707: + ".");
1708:
1709: // put the original (uncloned) config in a set se we'll know we're already
1710: // connected to it.
1711: establishedConnections.add(ld);
1712:
1713: if (screenState == NO_CONNECTIONS) {
1714: setScreenState(HAS_CONNECTIONS);
1715: }
1716: } finally {
1717: DBUtil.closeConnection(conn);
1718: }
1719:
1720: }
1721:
1722: public void newQueryForm(Integer dataSourceId, TableInfo ti)
1723: throws SQLException, NoSuchElementException {
1724:
1725: // make sure the TableInfo has its columns set.
1726: if (ti.getColumns() == null) {
1727: setColumnsAndKeys(dataSourceId, ti);
1728: }
1729:
1730: if (ti.getColumns().length == 0) {
1731: throw new SQLException(
1732: "This QueryForm cannot be created because the database is indicating that the table or view has no columns.");
1733: }
1734:
1735: DataSource ds = (DataSource) dsMap.get(dataSourceId);
1736: LocalDataSourceConfig config = (LocalDataSourceConfig) localConfigMap
1737: .get(dataSourceId);
1738:
1739: String windowTitle = ti.getTableName();
1740: String dataSourceName = config.getDisplayName();
1741:
1742: Set editableTypes = getEditableTypes(config
1743: .getDriverClassName());
1744:
1745: QueryPanel qp = new QueryPanel(ti, ds, dataSourceId, this ,
1746: this , editableTypes);
1747: qp.addQueryPanelListener(this );
1748: qp.setWindowTitle(windowTitle);
1749: qp.setDataSourceDisplayName(dataSourceName);
1750:
1751: String baseName = "(" + dataSourceId + ") " + windowTitle
1752: + " [QUERY";
1753:
1754: XInternalFrame jif = new XInternalFrame(baseName + " / "
1755: + dataSourceName + "]", true, true, true, true);
1756: jif.setContentPane(qp);
1757: this .desktop.add(jif);
1758: jif.addInternalFrameListener(this );
1759: jif.getMenuItem().setText(baseName + "]");
1760: windowMenu.add(jif.getMenuItem());
1761: jif.pack();
1762: offset += increment;
1763: if (offset > (10 * increment))
1764: offset = 0;
1765: jif.setBounds(offset, offset, 500, 300);
1766: jif.setVisible(true);
1767:
1768: // desktop.getDesktopManager().maximizeFrame(jif);
1769: setScreenState(QUERY_PANEL_NO_RESULTSET);
1770:
1771: }
1772:
1773: public void maybeExitProgram() {
1774:
1775: try {
1776: // int reply = JOptionPane.showConfirmDialog(this,
1777: // "Exit the program?",
1778: // "Confirm Exit",
1779: // JOptionPane.YES_NO_OPTION);
1780: //
1781: // if(reply == JOptionPane.NO_OPTION) return;
1782:
1783: File f = configFile;
1784:
1785: // System.out.println("Parent directory is " + f.getParent());
1786: if (f.exists() && f.canWrite() == false) {
1787: GUIHelper
1788: .warningMsg(
1789: this ,
1790: "The configuration file, "
1791: + f.getCanonicalPath()
1792: + ", is read-only. Configuration changes will not be saved.",
1793: "QueryForm");
1794: System.exit(0);
1795: }
1796: setStatusMessage("Saving configuration to "
1797: + f.getAbsolutePath() + ".");
1798:
1799: File tempfile = File.createTempFile("qformxml", null);
1800: // System.out.println("tempfile is " + tempfile.getAbsolutePath());
1801: config.writeConfig(tempfile);
1802: // f.delete();
1803:
1804: FileOutputStream fos = new FileOutputStream(f);
1805: FileInputStream fis = new FileInputStream(tempfile);
1806:
1807: int inchar = -1;
1808: while ((inchar = fis.read()) != -1)
1809: fos.write(inchar);
1810:
1811: fis.close();
1812: fos.close();
1813: tempfile.deleteOnExit();
1814:
1815: // System.out.println("Now tempfile is " + tempfile.getAbsolutePath());
1816:
1817: System.exit(0);
1818: } catch (Throwable ex) {
1819: System.out.println(ex.getMessage());
1820: ex.printStackTrace();
1821: GUIHelper
1822: .errMsg(
1823: this ,
1824: "An error occurred while saving the configuration. Changes to the configuration file have not been saved.",
1825: "Application Error");
1826: System.exit(-1);
1827: }
1828:
1829: }
1830:
1831: public void setStatusMessage(String msg) {
1832: // System.out.println("STATUS: " + msg);
1833: super .setStatusMessage(msg);
1834: }
1835:
1836: /**
1837: * Invoked when a internal frame has been opened.
1838: * This is an empty implementation which can be overriden by subclasses.
1839: * @see javax.swing.JInternalFrame#show
1840: */
1841: public void internalFrameOpened(InternalFrameEvent e) {
1842: // System.out.println("TRC: " + getClass().getName() + ".internalFrameOpened()");
1843: setScreenState();
1844: }
1845:
1846: /**
1847: * Invoked when an internal frame is activated.
1848: * This is an empty implementation which can be overriden by subclasses.
1849: * @see javax.swing.JInternalFrame#setSelected
1850: */
1851: public void internalFrameActivated(InternalFrameEvent e) {
1852: // System.out.println("TRC: " + getClass().getName() + ".internalFrameActivated()");
1853: setScreenState();
1854:
1855: }
1856:
1857: /**
1858: * Invoked when an internal frame is in the process of being closed.
1859: * The close operation can be overridden at this point.
1860: * This is an empty implementation which can be overriden by subclasses.
1861: * @see javax.swing.JInternalFrame#setDefaultCloseOperation
1862: */
1863: public void internalFrameClosing(InternalFrameEvent e) {
1864: // System.out.println("TRC: " + getClass().getName() + ".internalFrameClosing()");
1865: setScreenState();
1866:
1867: }
1868:
1869: /**
1870: * Invoked when an internal frame is de-activated.
1871: * This is an empty implementation which can be overriden by subclasses.
1872: * @see javax.swing.JInternalFrame#setSelected
1873: */
1874: public void internalFrameDeactivated(InternalFrameEvent e) {
1875: // System.out.println("TRC: " + getClass().getName() + ".internalFrameDeactivated()");
1876: setScreenState();
1877: }
1878:
1879: /**
1880: * Invoked when an internal frame has been closed.
1881: * This is an empty implementation which can be overriden by subclasses.
1882: * @see javax.swing.JInternalFrame#setClosed
1883: */
1884: public void internalFrameClosed(InternalFrameEvent e) {
1885: if (debug)
1886: System.out.println("TRC: " + getClass().getName()
1887: + ".internalFrameClosed()");
1888: JInternalFrame f = (JInternalFrame) e.getSource();
1889: Container c = f.getContentPane();
1890: if (c instanceof QueryPanel) {
1891: QueryPanel qp = (QueryPanel) c;
1892:
1893: // make sure the current connection is
1894: // closed on the query panel
1895: qp.dispose();
1896: }
1897:
1898: // this hopefully will mitigate a memory leak in some
1899: // JREs whereby a JInternalFrame never gets garbage collected.
1900: // We'll remove it's reference to the contentpane in the hopes
1901: // that it (the contentpane) will be garbage collected.
1902: f.setContentPane(new JPanel());
1903:
1904: }
1905:
1906: /**
1907: * Invoked when an internal frame is iconified.
1908: * This is an empty implementation which can be overriden by subclasses.
1909: * @see javax.swing.JInternalFrame#setIcon
1910: */
1911: public void internalFrameIconified(InternalFrameEvent e) {
1912: // System.out.println("TRC: " + getClass().getName() + ".internalFrameIconified()");
1913: setScreenState();
1914: }
1915:
1916: /**
1917: * Invoked when an internal frame is de-iconified.
1918: * This is an empty implementation which can be overriden by subclasses.
1919: * @see javax.swing.JInternalFrame#setIcon
1920: */
1921: public void internalFrameDeiconified(InternalFrameEvent e) {
1922: // System.out.println("TRC: " + getClass().getName() + ".internalFrameDeiconified()");
1923: setScreenState();
1924: }
1925:
1926: protected void setColumnsAndKeys(Integer sourceId, TableInfo ti)
1927: throws SQLException, NoSuchElementException {
1928: setColumns(sourceId, ti);
1929:
1930: if (System.getProperty("no.foreign.keys") != null) {
1931: fkeysNotSupported.add(sourceId);
1932: }
1933:
1934: if (this .pkeysNotSupported.contains(sourceId) == false) {
1935: try {
1936: setPrimaryKeys(sourceId, ti);
1937: } catch (SQLException ex) {
1938: System.err
1939: .println("WARNING: Primary keys could not be read for data source ID = "
1940: + sourceId);
1941: pkeysNotSupported.add(sourceId);
1942: }
1943: }
1944:
1945: if (this .fkeysNotSupported.contains(sourceId) == false) {
1946: try {
1947: setForeignKeys(sourceId, ti);
1948: } catch (SQLException ex) {
1949: System.err
1950: .println("WARNING: Foreign keys could not be read for data source ID = "
1951: + sourceId);
1952: fkeysNotSupported.add(sourceId);
1953: }
1954: }
1955:
1956: if (this .exkeysNotSupported.contains(sourceId) == false) {
1957: try {
1958: setExportedKeys(sourceId, ti);
1959: } catch (SQLException ex) {
1960: System.err
1961: .println("WARNING: Exported keys could not be read for data source ID = "
1962: + sourceId);
1963: exkeysNotSupported.add(sourceId);
1964: }
1965: }
1966: }
1967:
1968: public void setColumns(Integer sourceId, TableInfo ti)
1969: throws SQLException, NoSuchElementException {
1970: // System.out.println("TRC: " + getClass().getName() + ".setColumns("
1971: // + sourceId + ", " + ti.getTableName());
1972:
1973: DataSource ds = (DataSource) dsMap.get(sourceId);
1974: Connection conn = null;
1975: ResultSet rs = null;
1976:
1977: try {
1978: conn = ds.getConnection();
1979: DatabaseMetaData dbmd = conn.getMetaData();
1980: rs = dbmd.getColumns(ti.getTableCat(), ti.getTableSchem(),
1981: ti.getTableName(), "%");
1982: Column[] cols = DBUtil.getColumns(rs);
1983: ti.setColumns(cols);
1984: } finally {
1985: DBUtil.closeResultSet(rs);
1986: DBUtil.closeConnection(conn);
1987: }
1988: }
1989:
1990: public void setPrimaryKeys(Integer sourceId, TableInfo ti)
1991: throws SQLException {
1992:
1993: DataSource ds = (DataSource) dsMap.get(sourceId);
1994: Connection conn = null;
1995: ResultSet rs = null;
1996:
1997: try {
1998: conn = ds.getConnection();
1999: DatabaseMetaData dbmd = conn.getMetaData();
2000: rs = dbmd.getPrimaryKeys(ti.getTableCat(), ti
2001: .getTableSchem(), ti.getTableName());
2002: while (rs.next()) {
2003: String colName = rs.getString("COLUMN_NAME");
2004: Column col = ti.getColumn(colName);
2005: if (col == null) {
2006: System.err
2007: .println("WARNING: NO COLUMN FOUND MATCHING PK COLUMN "
2008: + colName);
2009: } else {
2010: col.setPkComponent(true);
2011: }
2012: }
2013: } finally {
2014: DBUtil.closeResultSet(rs);
2015: DBUtil.closeConnection(conn);
2016: }
2017: }
2018:
2019: public void setForeignKeys(Integer sourceId, TableInfo ti)
2020: throws SQLException {
2021:
2022: DataSource ds = (DataSource) dsMap.get(sourceId);
2023: Connection conn = null;
2024: ResultSet rs = null;
2025:
2026: try {
2027: conn = ds.getConnection();
2028: DatabaseMetaData dbmd = conn.getMetaData();
2029:
2030: rs = dbmd.getImportedKeys(ti.getTableCat(), ti
2031: .getTableSchem(), ti.getTableName());
2032:
2033: ForeignKey[] fkeys = DBUtil.getForeignKeys(rs);
2034:
2035: for (int j = 0; j < fkeys.length; j++) {
2036: Vector fkeyColumns = fkeys[j].getForeignKeyColumns();
2037: for (int k = 0; fkeyColumns != null
2038: && k < fkeyColumns.size(); k++) {
2039: ForeignKeyColumn fkc = (ForeignKeyColumn) fkeyColumns
2040: .get(k);
2041: fkc.setLocalColumn(ti.getColumn(fkc
2042: .getLocalColumnName()));
2043: }
2044: }
2045:
2046: ti.setForeignKeys(fkeys);
2047: } finally {
2048: DBUtil.closeResultSet(rs);
2049: DBUtil.closeConnection(conn);
2050: }
2051: }
2052:
2053: public void setExportedKeys(Integer sourceId, TableInfo ti)
2054: throws SQLException {
2055:
2056: DataSource ds = (DataSource) dsMap.get(sourceId);
2057: Connection conn = null;
2058: ResultSet rs = null;
2059:
2060: try {
2061: conn = ds.getConnection();
2062: DatabaseMetaData dbmd = conn.getMetaData();
2063:
2064: rs = dbmd.getExportedKeys(ti.getTableCat(), ti
2065: .getTableSchem(), ti.getTableName());
2066:
2067: ForeignKey[] fkeys = DBUtil.getForeignKeys(rs);
2068:
2069: for (int j = 0; j < fkeys.length; j++) {
2070: Vector fkeyColumns = fkeys[j].getForeignKeyColumns();
2071: for (int k = 0; fkeyColumns != null
2072: && k < fkeyColumns.size(); k++) {
2073: ForeignKeyColumn fkc = (ForeignKeyColumn) fkeyColumns
2074: .get(k);
2075: fkc.setLocalColumn(ti.getColumn(fkc
2076: .getForeignColumnName()));
2077: }
2078: }
2079:
2080: ti.setExportedKeys(fkeys);
2081: } finally {
2082: DBUtil.closeResultSet(rs);
2083: DBUtil.closeConnection(conn);
2084: }
2085: }
2086:
2087: JFileChooser fileChooser = new JFileChooser();
2088:
2089: private File getOutputFile(String title) {
2090:
2091: if (title != null)
2092: fileChooser.setDialogTitle(title);
2093: int option = fileChooser.showSaveDialog(this );
2094: if (option == fileChooser.CANCEL_OPTION)
2095: return null;
2096: File f = fileChooser.getSelectedFile();
2097:
2098: // remember the selected directory.
2099: File newDir = f.getParentFile().getAbsoluteFile();
2100: fileChooser.setCurrentDirectory(newDir);
2101: return f;
2102:
2103: }
2104:
2105: public void queryPanelStateChanged(QueryPanelEvent e) {
2106: setScreenState();
2107: }
2108:
2109: public void queryPanelHorizontalScrollbarStateChanged(
2110: QueryPanelEvent event) {
2111: QueryPanel qp = getCurrentQueryPanel();
2112: this .horizontalScrollbarMenuItem.setSelected(qp
2113: .isHorizontalScrollBarVisible());
2114: }
2115:
2116: private Set getEditableTypes(String driverClassName) {
2117:
2118: Set set = (Set) driverClassToEditableTypeMap
2119: .get(driverClassName);
2120: if (set != null)
2121: return set;
2122:
2123: // see if the DriverClassList class knows anything about this driver type.
2124: set = DriverClassList.getEditableTypes(driverClassName);
2125: if (set == null)
2126: set = new HashSet();
2127: driverClassToEditableTypeMap.put(driverClassName, set);
2128:
2129: // see if any editable types were configured in the file for this driver type
2130: String types = editableTypes.getProperty(driverClassName);
2131: if (types != null) {
2132: try {
2133: StringTokenizer st = new StringTokenizer(types);
2134: while (st.hasMoreTokens()) {
2135: Integer i = new Integer(st.nextToken());
2136: set.add(i);
2137: if (debug) {
2138: System.out.println("Adding editable type " + i
2139: + " for driver " + driverClassName);
2140: }
2141: }
2142: } catch (Exception ex) {
2143: System.err
2144: .println("Error parsing editable types for driver class: "
2145: + driverClassName);
2146: }
2147: }
2148:
2149: return set;
2150: }
2151:
2152: }
|