0001: /* ====================================================================
0002: * Copyright (c) 1998 - 2003 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/QueryPanel.java,v $
0034: * $Revision: 1.21 $
0035: * $Author: dglasser $
0036: * $Date: 2005/06/06 03:06:34 $
0037: *
0038: * --------------------------------------------------------------------
0039: */
0040: package org.glasser.qform;
0041:
0042: import javax.swing.*;
0043: import java.sql.*;
0044: import java.util.*;
0045: import javax.sql.*;
0046: import java.awt.Color;
0047: import java.awt.Dimension;
0048: import java.awt.Component;
0049: import java.awt.Rectangle;
0050: import java.awt.BorderLayout;
0051: import java.awt.Font;
0052: import java.awt.event.*;
0053: import javax.swing.border.*;
0054: import javax.swing.event.*;
0055: import javax.swing.table.*;
0056: import java.io.*;
0057:
0058: import org.glasser.sql.*;
0059: import org.glasser.swing.table.*;
0060: import org.glasser.swing.*;
0061: import org.glasser.util.*;
0062:
0063: public class QueryPanel extends JPanel implements
0064: ResultSetBufferListener, ActionListener {
0065:
0066: private static boolean isJava1point3 = !Util
0067: .isCurrentJavaVersionAtLeast("1.4");
0068:
0069: public static final int NO_RESULTSET = MainPanel.QUERY_PANEL_NO_RESULTSET;
0070: public static final int HAS_RESULTSET = MainPanel.QUERY_PANEL_HAS_RESULTSET;
0071: public static final int OPEN_FOR_ADD = MainPanel.QUERY_PANEL_OPEN_FOR_ADD;
0072: public static final int OPEN_FOR_UPDATE = MainPanel.QUERY_PANEL_OPEN_FOR_UPDATE;
0073: public static final int OPEN_FOR_QUERY = MainPanel.QUERY_PANEL_OPEN_FOR_QUERY;
0074: public static final int OPEN_FOR_CLONE = MainPanel.QUERY_PANEL_OPEN_FOR_CLONE;
0075:
0076: JToolBar toolBar = new JToolBar();
0077:
0078: JButton newQueryButton = new JButton();
0079: JButton whereClauseButton = new JButton();
0080: JButton addRowButton = new JButton();
0081: JButton updateRowButton = new JButton();
0082: JButton deleteRowButton = new JButton();
0083: JButton leftEndButton = new JButton();
0084: JButton leftButton = new JButton();
0085: JButton rightButton = new JButton();
0086: JButton executeButton = new JButton();
0087: JButton refreshButton = new JButton();
0088: JButton cancelButton = new JButton();
0089:
0090: /**
0091: * Maps keystrokes to toolbar buttons that are clicked
0092: * in response to the keystrokes.
0093: */
0094: public Object[][] keyMappings = {
0095: { "control Q", "OPEN_FOR_QUERY", newQueryButton },
0096: { "control W", "WHERE_CLAUSE_QUERY", whereClauseButton },
0097: { "control A", "ADD_RECORD", addRowButton },
0098: { "control M", "MODIFY_RECORD", updateRowButton },
0099: { "DELETE", "DELETE_RECORD", deleteRowButton },
0100: { "control ENTER", "EXECUTE_ACTION", executeButton },
0101: { "control R", "REFRESH", refreshButton },
0102: { "ESCAPE", "CANCEL_ACTION", cancelButton } };
0103:
0104: /**
0105: * Maps keystrokes to buttons that are clicked if the form tab is selected,
0106: * or are forward to the grid table (as KeyEvents) if the grid tab is selected.
0107: */
0108: public Object[][] keyMappings2 = {
0109: { "control HOME", leftEndButton },
0110: { "HOME", leftEndButton }, { "END", null },
0111: { "control END", null }, { "PAGE_DOWN", rightButton },
0112: { "PAGE_UP", leftButton }, { "DOWN", null }, { "UP", null } };
0113:
0114: /**
0115: * An instance of this class handles a single keystroke that invokes different
0116: * behavior depending on what tab is selected. If the grid tab is selected,
0117: * it simply sends a KeyEvent corresponding to its KeyStroke to the grid table.
0118: * If the form tab is selected, it will call doClick() on a particular button (provided
0119: * it has been passed a button in its constructor.)
0120: */
0121: private class ActionKeyManager extends AbstractAction {
0122:
0123: KeyStroke keyStroke = null;
0124:
0125: JButton toClick = null;
0126:
0127: public ActionKeyManager(KeyStroke keyStroke, JButton toClick) {
0128: this .keyStroke = keyStroke;
0129: this .toClick = toClick;
0130: }
0131:
0132: public void actionPerformed(ActionEvent e) {
0133: Component selectedTab = tabbedPane.getSelectedComponent();
0134: if (selectedTab == formTab) {
0135: if (toClick != null && toClick.isEnabled())
0136: toClick.doClick();
0137: } else if (selectedTab == gridTab) {
0138: gridTable.processActionKey(keyStroke);
0139: }
0140: }
0141:
0142: }
0143:
0144: JButton popupButton = new JButton(". . .");
0145:
0146: JLabel statusLabel = new JLabel() {
0147: public void setText(String s) {
0148:
0149: // always make sure there's some text there, so the
0150: // label maintains its preferredSize.
0151: if (s == null || s.length() == 0) {
0152: s = " ";
0153: }
0154: super .setText(s);
0155: }
0156: };
0157:
0158: Object[][] toolBarConfig = {
0159: { newQueryButton, "OPEN_FOR_QUERY", "DataQuery2_20.png",
0160: "New query. (Ctrl-Q)" },
0161: { whereClauseButton, "WHERE_CLAUSE_QUERY",
0162: "SQLWizard32.gif",
0163: "Query with custom WHERE clause. (Ctrl-W)" },
0164: { addRowButton, "ADD_RECORD", "NewRow20.gif",
0165: "Add a row to the current table. (Ctrl-A)" },
0166: { updateRowButton, "MODIFY_RECORD", "UpdateRow20.png",
0167: "Modify current row. (Ctrl-M)" },
0168: { deleteRowButton, "DELETE_RECORD", "DeleteRow20.png",
0169: "Delete the current row. (Del)", "1" },
0170: { leftEndButton, "GOTO_FIRST", "VCRBegin20.png",
0171: "Move to first record. (Home)" },
0172: { leftButton, "GOTO_PREVIOUS", "VCRBack20.png",
0173: "Move to previous record." },
0174: { rightButton, "GOTO_NEXT", "VCRForward20.png",
0175: "Move to next record.", "1" },
0176: { executeButton, "EXECUTE_ACTION", "ExecuteProject20.gif",
0177: "Execute operation (Ctrl-Enter)" },
0178: { refreshButton, "REFRESH", "Redo20.png",
0179: "Re-execute the current query. (Ctrl-R)" },
0180: { cancelButton, "CANCEL_ACTION", "Stop20.png",
0181: "Cancel operation (ESC)", "1" },
0182: { popupButton, "SHOW_POPUP", null, "More options...", "1" }
0183:
0184: };
0185:
0186: private boolean[][] toolBarStates = {
0187: // Q W A U D 1st prev next exec refrsh canc
0188: { true, true, true, false, false, false, false, false,
0189: false, false, false, true } // QUERY_PANEL_NO_RESULTSET = 3;
0190: ,
0191: { true, true, true, true, true, true, true, true, false,
0192: true, false, true } // QUERY_PANEL_RESULTSET = 4;
0193: ,
0194: { false, false, false, false, false, false, false, false,
0195: true, false, true, false } // QUERY_PANEL_OPEN_FOR_ADD = 5;
0196: ,
0197: { false, false, false, false, false, false, false, false,
0198: true, false, true, false } // QUERY_PANEL_OPEN_FOR_UPDATE = 6;
0199: ,
0200: { false, false, false, false, false, false, false, false,
0201: true, false, true, false } // QUERY_PANEL_OPEN_FOR_QUERY = 7;
0202: ,
0203: { false, false, false, false, false, false, false, false,
0204: true, false, true, false } // QUERY_PANEL_OPEN_FOR_CLONE = 8;
0205: };
0206:
0207: String[] columnNames = null;
0208:
0209: /**
0210: * To see debugging output from this class, start the program with the switch
0211: * -DQueryPanel.debug
0212: */
0213: private static boolean debug = System
0214: .getProperty("QueryPanel.debug") != null;
0215:
0216: private static Object[][] exportSelectedConfig = {
0217: { "To INSERT Statements...", "EXPORT_SELECTED_INSERT",
0218: null, "Export selected rows as INSERT statements." },
0219: { "To CSV File...", "EXPORT_SELECTED_CSV", null,
0220: "Export selected rows as comma-separated values." } };
0221:
0222: private static Object[][] exportAllConfig = {
0223: { "To INSERT Statements...", "EXPORT_ALL_INSERT", null,
0224: "Export all rows read as INSERT statements." },
0225: { "To CSV File...", "EXPORT_ALL_CSV", null,
0226: "Export all rows read as comma-separated values." } };
0227:
0228: private static Object[][] selectedOrAllConfig = {
0229: { "_Selected Row(s)", exportSelectedConfig, "S", null },
0230: { "_All Rows", exportAllConfig, "A", null } };
0231:
0232: private static Object[][] gridTabPopupConfig = {
0233: { "Window title...", "WINDOW_TITLE", "W",
0234: "Set the title for this window." },
0235: { "Table Metadata", "QUERYPANEL_TABLE_METADATA", "T",
0236: "View medadata for this table." },
0237: { "Select visible columns...", "COLUMN_MAP_DIALOG", "V",
0238: "Select which columns will be displayed in this table." },
0239: { "CHECKBOX_Long-form dates", "TOGGLE_LONGFORM_DATES", "L",
0240: "Dispay dates in long format." },
0241: { "CHECKBOX_Horizontal scrollbar",
0242: "TOGGLE_HORIZONTAL_SCROLLBAR", "H",
0243: "Show or hide the horizontal scrollbar." } };
0244:
0245: private static Object[][] gridTabSubmenuConfig = {
0246: { "Select visible columns...", "COLUMN_MAP_DIALOG", "V",
0247: "Select which columns will be displayed in this table." },
0248: { "CHECKBOX_Long-form dates", "TOGGLE_LONGFORM_DATES", "L",
0249: "Dispay dates in long format." },
0250: { "CHECKBOX_Horizontal scrollbar",
0251: "TOGGLE_HORIZONTAL_SCROLLBAR", "H",
0252: "Show or hide the horizontal scrollbar." } };
0253:
0254: private static Object[][] gridTabPopupStateMappings = {
0255:
0256: { new Integer(NO_RESULTSET),
0257: new boolean[] { true, true, true, true, true } },
0258: { new Integer(HAS_RESULTSET),
0259: new boolean[] { true, true, true, true, true } } };
0260:
0261: private static HashMap gridPopupStateMap = Util
0262: .buildMap(gridTabPopupStateMappings);
0263:
0264: private static Object[][] extraOperationsPopupConfig = {
0265: { "Window title...", "WINDOW_TITLE", null,
0266: "Set the title for this window." },
0267: { "Table Metadata", "QUERYPANEL_TABLE_METADATA", null,
0268: "View medadata for this table." },
0269: { "Clone Record", "CLONE_RECORD", null,
0270: "Clone the current record." },
0271: { "_Grid View ", gridTabSubmenuConfig, "G",
0272: "Configure grid view tab." },
0273: { "_Export", selectedOrAllConfig, "X",
0274: "Export query results to a file." } };
0275:
0276: private static Object[][] formTabPopupConfig = {
0277: { "Window title...", "WINDOW_TITLE", "W",
0278: "Set the title for this window." },
0279: { "Table Metadata", "QUERYPANEL_TABLE_METADATA", "T",
0280: "View medadata for this table." },
0281: { "Add Record", "ADD_RECORD", "A",
0282: "Add a record through the current query form." },
0283: { "Modify Record", "MODIFY_RECORD", "M",
0284: "Modify the current record." },
0285: { "Delete Record", "DELETE_RECORD", "D",
0286: "Delete the current record." },
0287: { "Clone Record", "CLONE_RECORD", "L",
0288: "Clone the current record." } };
0289:
0290: private static Object[][] formPopupStateMappings = {
0291: {
0292: new Integer(NO_RESULTSET),
0293: new boolean[] { true, true, true, false, false,
0294: false } },
0295: {
0296: new Integer(HAS_RESULTSET),
0297: new boolean[] { true, true, true, true, true, true } } };
0298:
0299: HashMap formPopupStateMap = Util.buildMap(formPopupStateMappings);
0300:
0301: boolean[][] extraOpStates = { { true, true, false, true, false },
0302: { true, true, true, true, true },
0303: { false, false, false, false, false },
0304: { false, false, false, false, false },
0305: { false, false, false, false, false },
0306: { false, false, false, false, false } };
0307:
0308: private String[] stateNames = { null, null, null, "NO_RESULTSET",
0309: "HAS_RESULTSET", "OPEN_FOR_ADD", "OPEN_FOR_UPDATE",
0310: "OPEN_FOR_QUERY", "OPEN_FOR_CLONE" };
0311:
0312: Vector v;
0313: String tableName;
0314: String tableOwner;
0315: BaseForm baseForm = null;
0316:
0317: JPopupMenu extraItemsPopup = new JPopupMenu();
0318:
0319: javax.swing.JPopupMenu gridTabPopup = new JPopupMenu();
0320: javax.swing.JPopupMenu formTabPopup = new JPopupMenu();
0321:
0322: PopupMenuManager gridPopupManager = new PopupMenuManager(
0323: gridTabPopup);
0324:
0325: PopupMenuManager formPopupManager = new PopupMenuManager(
0326: formTabPopup);
0327:
0328: private JMenuItem[] gridTabPopupItems = null;
0329:
0330: private JMenuItem[] formTabPopupItems = null;
0331:
0332: private JCheckBoxMenuItem[] horizontalScrollbarMenuItems = null;
0333:
0334: private JCheckBoxMenuItem[] longformTimestampMenuItems = null;
0335:
0336: JTabbedPane tabbedPane = new JTabbedPane();
0337:
0338: JPanel formTab = new JPanel();
0339:
0340: JPanel gridTab = new JPanel();
0341:
0342: class GridTable extends JTable {
0343:
0344: /**
0345: * Sends a KeyEvent for the given KeyStroke to the gridTable. The
0346: * KeyStroke should be an "action" key like HOME, PGUP, etc., not
0347: * a letter key. This allows the JTable to be scrolled programmatically
0348: * in response to user-pressed keys, even when it doesn't have the focus.
0349: */
0350: public void processActionKey(KeyStroke keyStroke) {
0351:
0352: processKeyEvent(new KeyEvent(this , KeyEvent.KEY_PRESSED,
0353: System.currentTimeMillis(), keyStroke
0354: .getModifiers(), keyStroke.getKeyCode(),
0355: KeyEvent.CHAR_UNDEFINED));
0356: }
0357:
0358: };
0359:
0360: GridTable gridTable = new GridTable();
0361:
0362: PushButtonTableHeader gridTableHeader = new PushButtonTableHeader();
0363:
0364: JScrollPane gridScrollPane = new JScrollPane(gridTable);
0365:
0366: int state = NO_RESULTSET;
0367:
0368: final static int SELECT = 0;
0369: final static int DELETE = 1;
0370: final static int COUNT = 2;
0371: final static int INSERT = 3;
0372: final static int UPDATE = 4;
0373: final static int PK_SELECT = 5;
0374:
0375: final static int margin = 2;
0376:
0377: public String getTableName() {
0378: return tableName;
0379: }
0380:
0381: DataSource dataSource = null;
0382:
0383: StatusMessageDisplay status = null;
0384:
0385: TableInfo tableInfo = null;
0386:
0387: Integer dataSourceId = null;
0388:
0389: private String windowTitle = null;
0390:
0391: private String dataSourceDisplayName = null;
0392:
0393: SmartEventListenerList listeners = new SmartEventListenerList();
0394:
0395: FormattedCellRenderer longDateRenderer = new FormattedCellRenderer(
0396: null);
0397:
0398: FormattedCellRenderer defaultDateRenderer = new FormattedCellRenderer(
0399: java.text.DateFormat.getDateInstance());
0400:
0401: public void displayLongTimestampsInGrid(boolean b) {
0402:
0403: if (b) {
0404: gridTable.setDefaultRenderer(java.util.Date.class,
0405: longDateRenderer);
0406: } else {
0407: gridTable.setDefaultRenderer(java.util.Date.class,
0408: defaultDateRenderer);
0409: }
0410:
0411: for (int j = 0; j < longformTimestampMenuItems.length; j++) {
0412: longformTimestampMenuItems[j].setSelected(b);
0413: }
0414:
0415: AbstractTableModel model = (AbstractTableModel) gridTable
0416: .getModel();
0417: if (model != null) {
0418: model.fireTableDataChanged();
0419: }
0420: }
0421:
0422: QueryPanel(TableInfo ti, DataSource dataSource,
0423: Integer dataSourceId, StatusMessageDisplay status,
0424: ActionListener actionListener, Set editableTypes) {
0425:
0426: super ();
0427:
0428: this .tableInfo = ti;
0429: this .dataSource = dataSource;
0430: this .dataSourceId = dataSourceId;
0431: this .status = status;
0432:
0433: tableName = ti.getTableName();
0434:
0435: setLayout(new BorderLayout());
0436: add(tabbedPane, BorderLayout.CENTER);
0437:
0438: // add the toolbar buttons
0439: toolBar.addSeparator();
0440: toolBar.setBorder(new EmptyBorder(7, 10, 7, 5));
0441: GUIHelper.configureToolbar(toolBar, toolBarConfig,
0442: "org/glasser/qform/images", new Dimension(36, 36),
0443: actionListener);
0444: popupButton.setFont(new Font("Serif", Font.BOLD, 13));
0445: toolBar.setFloatable(false);
0446:
0447: popupButton.removeActionListener(actionListener);
0448: popupButton.addActionListener(this );
0449:
0450: add(toolBar, BorderLayout.NORTH);
0451:
0452: // this.getViewport().setLayout(new javax.swing.ViewportLayout());
0453: // this.getViewport().setLayout(null);
0454: try {
0455: tableOwner = ti.getTableSchem();
0456: if ((tableOwner != null && tableOwner.length() == 0)
0457: || tableOwner == "<DEFAULT SCHEMA>") {
0458: tableOwner = null;
0459: }
0460:
0461: // ResultSet tableInfo = dbInfo.getColumns(null, tableOwner, tableName, "%");
0462:
0463: Column[] columns = ti.getColumns();
0464:
0465: v = new Vector(columns.length);
0466:
0467: columnNames = new String[columns.length];
0468:
0469: for (int j = 0; j < columns.length; j++) {
0470:
0471: Column col = columns[j];
0472: columnNames[j] = col.getColumnName();
0473:
0474: tableOwner = col.getTableSchema();
0475: String columnName = col.getColumnName();
0476: JLabel label = new JLabel(columnName);
0477:
0478: // add a TextBox to the Vector for this field
0479: TextBox textBox = new TextBox(columnName, col
0480: .getDataType(), col.getTypeName(), col
0481: .getColumnSize(), col.getNullable(), col
0482: .getOrdinal(), label);
0483:
0484: textBox.setPkComponent(col.getPkComponent());
0485:
0486: textBox.setEditableTypes(editableTypes);
0487:
0488: textBox.setEditable(false);
0489: v.addElement(textBox);
0490: }
0491:
0492: baseForm = new BaseForm(v);
0493:
0494: JScrollPane sp = new JScrollPane(baseForm);
0495: formTab.setLayout(new BorderLayout());
0496: formTab.add(sp, BorderLayout.CENTER);
0497:
0498: sp.getVerticalScrollBar().setUnitIncrement(30);
0499: sp.getHorizontalScrollBar().setUnitIncrement(30);
0500:
0501: tabbedPane.addTab("Form View", formTab);
0502:
0503: gridTab.setLayout(new BorderLayout());
0504:
0505: gridTable.setTableHeader(gridTableHeader);
0506:
0507: gridTable.setModel(new ResultSetTableModel(columnNames));
0508: gridTab.add(gridScrollPane, BorderLayout.CENTER);
0509:
0510: tabbedPane.addTab("Grid View", gridTab);
0511:
0512: MenuItemListener menuItemListener = new MenuItemListener(
0513: status);
0514:
0515: GUIHelper.buildMenu(extraItemsPopup,
0516: extraOperationsPopupConfig, actionListener,
0517: menuItemListener, menuItemListener);
0518: GUIHelper.buildMenu(gridTabPopup, gridTabPopupConfig,
0519: actionListener, menuItemListener, menuItemListener);
0520: GUIHelper.buildMenu(formTabPopup, formTabPopupConfig,
0521: actionListener, menuItemListener, menuItemListener);
0522:
0523: horizontalScrollbarMenuItems = new JCheckBoxMenuItem[2];
0524: horizontalScrollbarMenuItems[0] = (JCheckBoxMenuItem) GUIHelper
0525: .findMenuItemByActionCommand(extraItemsPopup,
0526: "TOGGLE_HORIZONTAL_SCROLLBAR");
0527: horizontalScrollbarMenuItems[1] = (JCheckBoxMenuItem) GUIHelper
0528: .findMenuItemByActionCommand(gridTabPopup,
0529: "TOGGLE_HORIZONTAL_SCROLLBAR");
0530:
0531: longformTimestampMenuItems = new JCheckBoxMenuItem[2];
0532: longformTimestampMenuItems[0] = (JCheckBoxMenuItem) GUIHelper
0533: .findMenuItemByActionCommand(extraItemsPopup,
0534: "TOGGLE_LONGFORM_DATES");
0535: longformTimestampMenuItems[1] = (JCheckBoxMenuItem) GUIHelper
0536: .findMenuItemByActionCommand(gridTabPopup,
0537: "TOGGLE_LONGFORM_DATES");
0538:
0539: gridTabPopupItems = GUIHelper.getMenuItems(gridTabPopup);
0540: formTabPopupItems = GUIHelper.getMenuItems(formTabPopup);
0541:
0542: baseForm.addPopupMenuManager(formPopupManager);
0543:
0544: gridScrollPane.addMouseListener(gridPopupManager);
0545: gridTable.addMouseListener(gridPopupManager);
0546: gridTableHeader.addMouseListener(gridPopupManager);
0547:
0548: gridScrollPane
0549: .setToolTipText("Right-click for options menu.");
0550: gridTable.setToolTipText("Right-click for options menu.");
0551:
0552: setHorizontalScrollBarVisible(true);
0553:
0554: gridTable.getSelectionModel().addListSelectionListener(
0555: new ListSelectionListener() {
0556:
0557: int lastSelection = -1;
0558:
0559: /**
0560: * Called whenever the value of the selection changes.
0561: * @param e the event that characterizes the change.
0562: */
0563: public void valueChanged(ListSelectionEvent e) {
0564:
0565: // convert this to a one-based index.
0566: int selection = gridTable.getSelectedRow();
0567:
0568: if (selection > -1
0569: && selection != baseForm
0570: .getCursorVal()
0571: && state == HAS_RESULTSET) {
0572:
0573: // if(selection == lastSelection) {
0574: //// new Throwable().printStackTrace();
0575: // return;
0576: // }
0577: if (debug)
0578: System.out.println("SELECTED ROW "
0579: + selection);
0580: lastSelection = selection;
0581: baseForm.showRow(selection);
0582: displayRowNum(selection + 1);
0583:
0584: }
0585: }
0586: });
0587:
0588: // add a ListTableModel sorter that will sort the ResultSetTableModel whenever
0589: // a column header is clicked.
0590: gridTableHeader
0591: .addMouseListener(new ListTableModelSorter());
0592:
0593: statusLabel.setText(null);
0594: statusLabel.setBorder(new CompoundBorder(
0595: new ThinBevelBorder(ThinBevelBorder.RAISED),
0596: new EmptyBorder(5, 5, 5, 5)));
0597:
0598: statusLabel.setFont(new Font("Dialog", Font.PLAIN, 10));
0599: statusLabel.setForeground(Color.black);
0600:
0601: this .add(statusLabel, BorderLayout.SOUTH);
0602:
0603: // set all the key bindings that allow the form to be manipulated
0604: // with keys.
0605: for (int j = 0; j < keyMappings.length; j++) {
0606: Object[] row = keyMappings[j];
0607: Object key = row[0];
0608: String actionName = (String) row[1];
0609: JButton button = (JButton) row[2];
0610: KeyStroke keyStroke = null;
0611: if (key instanceof KeyStroke)
0612: keyStroke = (KeyStroke) key;
0613: else
0614: keyStroke = KeyStroke.getKeyStroke((String) key);
0615:
0616: getInputMap(
0617: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
0618: .put(keyStroke, actionName);
0619: getActionMap().put(actionName,
0620: new ButtonClicker(button));
0621: }
0622:
0623: for (int j = 0; j < keyMappings2.length; j++) {
0624: KeyStroke key = KeyStroke
0625: .getKeyStroke((String) keyMappings2[j][0]);
0626: JButton button = (JButton) keyMappings2[j][1];
0627: Action action = new ActionKeyManager(key, button);
0628: String cmd = "_KEY_" + j;
0629: getInputMap(
0630: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
0631: .put(key, cmd);
0632: getActionMap().put(cmd, action);
0633:
0634: // set these bindings for the tabbedPane as well, to replace the existing ones.
0635: tabbedPane.getInputMap(JComponent.WHEN_FOCUSED).put(
0636: key, cmd);
0637: tabbedPane.getActionMap().put(cmd, action);
0638: }
0639:
0640: // this code fixes inconsistent focus behavior between JDK 1.3 and 1.4.
0641: tabbedPane.addChangeListener(new ChangeListener() {
0642: public void stateChanged(ChangeEvent e) {
0643: Component c = tabbedPane.getSelectedComponent();
0644: if (c == formTab) {
0645: if (state == HAS_RESULTSET
0646: || state == NO_RESULTSET) {
0647: tabbedPane.requestFocus();
0648: }
0649: } else if (c == gridTab) {
0650: if (state == HAS_RESULTSET) {
0651: tabbedPane.requestFocus();
0652: }
0653: }
0654: }
0655: });
0656:
0657: setState(NO_RESULTSET);
0658:
0659: } catch (Exception ex) {
0660: if (debug)
0661: System.out
0662: .println("Exception in QueryPanel constructor: "
0663: + ex.toString());
0664: ex.printStackTrace();
0665: GUIHelper.exceptionMsg(ex);
0666:
0667: }
0668: }
0669:
0670: public TableInfo getTableInfo() {
0671: return tableInfo;
0672: }
0673:
0674: public Integer getDataSourceId() {
0675: return dataSourceId;
0676: }
0677:
0678: public boolean getHasPK() {
0679: return baseForm.getHasPK();
0680: }
0681:
0682: public int getState() {
0683: return state;
0684: }
0685:
0686: public Vector[] getCurrentRowset() {
0687: return baseForm.getCurrentRowset();
0688: }
0689:
0690: public int getCursorVal() {
0691: return baseForm.getCursorVal();
0692: }
0693:
0694: public void setWindowTitle(String windowTitle) {
0695: this .windowTitle = windowTitle;
0696: }
0697:
0698: public String getWindowTitle() {
0699: return windowTitle;
0700: }
0701:
0702: public void setDataSourceDisplayName(String dataSourceDisplayName) {
0703: this .dataSourceDisplayName = dataSourceDisplayName;
0704: }
0705:
0706: public String getDataSourceDisplayName() {
0707: return dataSourceDisplayName;
0708: }
0709:
0710: boolean formTabFrozen = false;
0711:
0712: public void freezeFormTab(boolean b) {
0713: if (debug)
0714: System.out.println("TRC: " + getClass().getName()
0715: + ".freezeFormTab(" + b + ")");
0716:
0717: if (formTabFrozen == b)
0718: return;
0719:
0720: if (b) {
0721: tabbedPane.setSelectedComponent(formTab);
0722: tabbedPane.remove(gridTab);
0723: formTabFrozen = true;
0724: } else {
0725: tabbedPane.addTab("Grid View", gridTab);
0726: formTabFrozen = false;
0727: }
0728: }
0729:
0730: public void setState(int state) {
0731: this .state = state;
0732:
0733: if (debug)
0734: System.out.println("QueryPanel.setState("
0735: + stateNames[state] + ")");
0736:
0737: boolean focusFirstField = false;
0738:
0739: switch (state) {
0740: case HAS_RESULTSET:
0741: setFieldsEditable(false);
0742: showRequiredFields(false);
0743: showRowNum(baseForm.getCursorVal());
0744: freezeFormTab(false);
0745: break;
0746: case OPEN_FOR_QUERY:
0747: clearFields();
0748: clearRowNumDisplay();
0749: setFieldsEditable(true);
0750: showRequiredFields(false);
0751: freezeFormTab(true);
0752: focusFirstField = true;
0753: break;
0754: case NO_RESULTSET:
0755: status.setStatusMessage(null);
0756: clearRowNumDisplay();
0757: clearFields();
0758: setFieldsEditable(false);
0759: showRequiredFields(false);
0760: freezeFormTab(false);
0761: break;
0762: case OPEN_FOR_ADD:
0763: clearFields();
0764: clearRowNumDisplay();
0765: setFieldsEditable(true);
0766: showRequiredFields(true);
0767: freezeFormTab(true);
0768: focusFirstField = true;
0769: break;
0770: case OPEN_FOR_UPDATE:
0771: setFieldsEditable(true);
0772: clearRowNumDisplay();
0773: showRequiredFields(true);
0774: freezeFormTab(true);
0775: focusFirstField = true;
0776: break;
0777: case OPEN_FOR_CLONE:
0778: clearFields();
0779: clearRowNumDisplay();
0780: setFieldsEditable(true);
0781: showRequiredFields(true);
0782: freezeFormTab(true);
0783: baseForm.populateFields(baseForm.getCurrentRowClone());
0784: focusFirstField = true;
0785: break;
0786:
0787: }
0788:
0789: boolean[] menuStates = this .extraOpStates[state - 3];
0790: JMenuItem[] menuItems = GUIHelper.getMenuItems(extraItemsPopup);
0791: for (int j = 0; j < menuItems.length; j++) {
0792: menuItems[j].setEnabled(menuStates[j]);
0793: }
0794:
0795: Integer n = new Integer(state);
0796: menuStates = (boolean[]) gridPopupStateMap.get(n);
0797: if (menuStates == null) {
0798: gridPopupManager.setPopupEnabled(false);
0799: } else {
0800: gridPopupManager.setPopupEnabled(true);
0801: for (int j = 0; j < gridTabPopupItems.length; j++) {
0802: gridTabPopupItems[j].setEnabled(menuStates[j]);
0803: }
0804: }
0805:
0806: menuStates = (boolean[]) formPopupStateMap.get(n);
0807: if (menuStates == null) {
0808: formPopupManager.setPopupEnabled(false);
0809: } else {
0810: formPopupManager.setPopupEnabled(true);
0811: for (int j = 0; j < formTabPopupItems.length; j++) {
0812: formTabPopupItems[j].setEnabled(menuStates[j]);
0813: }
0814: }
0815:
0816: boolean[] buttonStates = this .toolBarStates[state - 3];
0817: for (int j = 0; j < buttonStates.length; j++) {
0818: JButton button = (JButton) toolBarConfig[j][0];
0819: button.setEnabled(buttonStates[j]);
0820: }
0821:
0822: fireEvent(QueryPanelEvent.STATE_CHANGED);
0823:
0824: // the focus is set after the event is fired, because it could
0825: // change it
0826: if (focusFirstField) {
0827: focusFirstTextBox();
0828: } else {
0829: tabbedPane.requestFocus();
0830: }
0831:
0832: }
0833:
0834: public int getTabState() {
0835: return state;
0836: }
0837:
0838: public boolean hasCurrentResultSet() {
0839: return baseForm.hasCurrentResultSet();
0840: }
0841:
0842: // protected void finalize() throws Throwable {
0843: // if(debug) System.out.println("QueryPanel.finalize() called.");
0844: // try {
0845: //// baseForm.setResultSetBuffer(null);
0846: // } catch(Exception ex) {
0847: // ex.printStackTrace();
0848: // GUIHelper.exceptionMsg(ex);
0849: // }
0850: // }
0851:
0852: public void showState() {
0853: // if(debug) System.out.println("Scrollpane: " + toString());
0854: // if(debug) System.out.println("JPanel: " + baseForm.toString());
0855: // if(debug) System.out.println("backBuffer: size = " + backBuffer.size() + ", cursor = " + backBuffer.cursor);
0856: }
0857:
0858: /**
0859: * Toggle the editable state of all textboxes on the form.
0860: */
0861: public void setFieldsEditable(boolean b) {
0862: baseForm.setFieldsEditable(b);
0863: }
0864:
0865: void showRequiredFields(boolean b) {
0866: baseForm.showRequiredFields(b);
0867: }
0868:
0869: /**
0870: * Clears the text fields.
0871: */
0872: public void clearFields() {
0873: baseForm.clearFields();
0874: }
0875:
0876: /**
0877: *
0878: * Construct an SQL statement from the values entered in the form
0879: */
0880: public String getSQL(int type) throws UnknownPrimaryKeyException {
0881:
0882: String header = "SELECT * ";
0883:
0884: StringBuffer buffer = null;
0885: switch (type) {
0886: case INSERT:
0887: // get only the fields that have something
0888: // in them to build the insert statement with.
0889: ArrayList list = new ArrayList(v.size());
0890: for (int j = 0; j < v.size(); j++) {
0891: TextBox textBox = (TextBox) v.get(j);
0892: if (!Util.isNothing(textBox.getText())) {
0893: list.add(textBox);
0894: }
0895: }
0896: buffer = new StringBuffer(200);
0897: buffer.append("INSERT INTO ");
0898: buffer.append(getQualifiedTableName());
0899: buffer.append(" (");
0900: for (int j = 0; j < list.size(); j++) {
0901: TextBox tb = (TextBox) list.get(j);
0902: if (j > 0)
0903: buffer.append(", ");
0904: buffer.append(tb.getColumnName());
0905: }
0906:
0907: buffer.append(") VALUES (");
0908: for (int j = 0; j < list.size(); j++) {
0909: TextBox tb = (TextBox) list.get(j);
0910: if (j > 0)
0911: buffer.append(", ");
0912: buffer.append(tb.getValueClause(false));
0913: }
0914:
0915: buffer.append(")");
0916:
0917: return buffer.toString();
0918:
0919: case DELETE:
0920: header = "DELETE FROM " + this .getQualifiedTableName()
0921: + " " + baseForm.getPkWhereClause();
0922: return header;
0923: case COUNT:
0924: header = "SELECT COUNT(*) ";
0925: break;
0926: case UPDATE:
0927: String setClause = baseForm.getSetClause();
0928: if (setClause == null)
0929: return null; // no fields were edited.
0930: return "UPDATE " + getQualifiedTableName() + " SET "
0931: + setClause + " " + baseForm.getPkWhereClause();
0932: case PK_SELECT:
0933: return "SELECT * " + getFromClause() + " WHERE "
0934: + getPkWhereClause();
0935: case SELECT:
0936: default:
0937: header = "SELECT * ";
0938: break;
0939: }
0940:
0941: String SQL = header + getFromClause() + " " + getWhereClause();
0942:
0943: if (debug)
0944: System.out.println("SQL: " + SQL);
0945:
0946: return SQL;
0947: }
0948:
0949: private String getFromClause() {
0950:
0951: return "FROM " + getQualifiedTableName();
0952:
0953: }
0954:
0955: public String getQualifiedTableName() {
0956:
0957: if (tableInfo == null)
0958: return null;
0959: return tableInfo.getQualifiedTableName();
0960:
0961: }
0962:
0963: public String getWhereClause() {
0964:
0965: String whereClause = null;
0966:
0967: for (int j = 0; j < v.size(); j++) {
0968: String condition = ((TextBox) v.elementAt(j))
0969: .getCondition();
0970: if (condition != null) {
0971: if (whereClause == null)
0972: whereClause = condition;
0973: else
0974: whereClause += (" AND " + condition);
0975: }
0976: }
0977: if (whereClause == null)
0978: whereClause = "";
0979:
0980: return whereClause;
0981: }
0982:
0983: /**
0984: * This builds a WHERE clause from the PK fields of the currently displayed row,
0985: * based on the values displayed in the form.
0986: */
0987: public String getPkWhereClause() throws UnknownPrimaryKeyException {
0988:
0989: Vector fields = v;
0990: ArrayList pkFields = new ArrayList();
0991: for (int j = 0; j < fields.size(); j++) {
0992: TextBox field = (TextBox) fields.get(j);
0993: if (field.isPkComponent()) {
0994: pkFields.add(field);
0995: } else if (baseForm.hasPK == false) {
0996: int dataType = field.getDataType().intValue();
0997: if (field.isTypeDisplayable()
0998: && field.isNullable() == false
0999: && field.getLength() > 0
1000: && ((DBUtil.isCharType(dataType) && field
1001: .getLength() < 51) || DBUtil
1002: .isNumericType(dataType))) {
1003: pkFields.add(field);
1004: }
1005: }
1006: }
1007:
1008: if (pkFields.size() == 0) {
1009: throw new UnknownPrimaryKeyException();
1010: }
1011:
1012: StringBuffer buffer = new StringBuffer();
1013: boolean needAnd = false;
1014: for (int j = 0; j < pkFields.size(); j++) {
1015: String condition = ((TextBox) pkFields.get(j))
1016: .getCondition();
1017: if (condition != null) {
1018: if (needAnd) {
1019: buffer.append(" AND ");
1020: } else {
1021: needAnd = true;
1022: }
1023: buffer.append(condition);
1024: }
1025: }
1026:
1027: return buffer.toString();
1028:
1029: }
1030:
1031: /**
1032: * Opens the form for a query.
1033: */
1034: public void newQuery() {
1035: setState(OPEN_FOR_QUERY);
1036: }
1037:
1038: public void addRow() {
1039: setState(OPEN_FOR_ADD);
1040: }
1041:
1042: public void cloneRecord() {
1043: setState(OPEN_FOR_CLONE);
1044: }
1045:
1046: public void focusFirstTextBox() {
1047: baseForm.focusFirstTextBox();
1048: }
1049:
1050: /**
1051: * Cancels a pending add, update or query.
1052: */
1053: public void cancelPendingAction() {
1054: if (this .hasCurrentResultSet()) {
1055: current();
1056:
1057: setState(HAS_RESULTSET);
1058:
1059: } else {
1060: setState(NO_RESULTSET);
1061:
1062: }
1063: }
1064:
1065: public void deleteCurrentRow() {
1066:
1067: int reply = JOptionPane
1068: .showConfirmDialog(this ,
1069: "Do you want to delete the current row?",
1070: "QueryForm", JOptionPane.YES_NO_OPTION,
1071: JOptionPane.QUESTION_MESSAGE);
1072:
1073: if (reply == JOptionPane.NO_OPTION)
1074: return;
1075:
1076: // get the SQL statement to do the delete.
1077: String SQL = null;
1078:
1079: try {
1080: SQL = getSQL(DELETE);
1081: } catch (Exception ex) {
1082: String msg = "This record cannot be deleted because the primary key for this table is unknown, and could not be adequately surmised by the application.";
1083:
1084: GUIHelper.errMsg(this , msg, "Application Error");
1085: return;
1086: }
1087:
1088: if (debug)
1089: System.out.println(SQL);
1090: int rowsDeleted = -1;
1091: Connection conn = null;
1092: Statement s = null;
1093: boolean saveAutoCommit = false;
1094: boolean success = false;
1095: try {
1096: conn = dataSource.getConnection();
1097: s = conn.createStatement();
1098: saveAutoCommit = conn.getAutoCommit();
1099: if (saveAutoCommit)
1100: conn.setAutoCommit(false);
1101: rowsDeleted = s.executeUpdate(SQL);
1102: if (debug)
1103: System.out.println("Num rows deleted: " + rowsDeleted);
1104: if (rowsDeleted < 1) {
1105: GUIHelper
1106: .errMsg(
1107: this ,
1108: "The current row was not deleted because it has "
1109: + "been deleted or modified by another user.",
1110: "Operation Failed");
1111: return;
1112: } else if (rowsDeleted > 1) {
1113: GUIHelper
1114: .errMsg(
1115: this ,
1116: "The delete operation will be rolled back because more than one row was deleted.",
1117: "Operation Failed");
1118: return;
1119: }
1120:
1121: conn.commit();
1122: success = true;
1123:
1124: int rowNum = baseForm.removeCurrentRow();
1125: if (debug)
1126: System.out.println("rowNum is " + rowNum);
1127:
1128: ResultSetTableModel model = (ResultSetTableModel) gridTable
1129: .getModel();
1130: model.fireTableDataChanged();
1131:
1132: if (rowNum < 0) {
1133: setState(NO_RESULTSET);
1134: updateStatusMessage();
1135:
1136: } else {
1137: baseForm.current();
1138: updateStatusMessage();
1139: }
1140:
1141: } catch (Exception ex) {
1142: String msg = "The following error occurred while attempting to delete the current record:\n\n"
1143: + ex.getMessage();
1144: GUIHelper.errMsg(this , msg, "Database Error");
1145: } finally {
1146: if (success == false && conn != null) {
1147: try {
1148: conn.rollback();
1149: } catch (Exception ex) {
1150: ex.printStackTrace();
1151: }
1152: }
1153: DBUtil.closeStatement(s);
1154: try {
1155: if (saveAutoCommit)
1156: conn.setAutoCommit(true);
1157: } catch (Exception ex) {
1158: ex.printStackTrace();
1159: }
1160: DBUtil.closeConnection(conn);
1161: }
1162: }
1163:
1164: public void executeAdd() {
1165:
1166: boolean hasInput = false;
1167: for (int j = 0; j < v.size(); j++) {
1168: TextBox textBox = (TextBox) v.get(j);
1169: if (!Util.isNothing(textBox.getText())) {
1170: hasInput = true;
1171: break;
1172: }
1173: }
1174:
1175: if (!hasInput) {
1176: GUIHelper
1177: .errMsg(
1178: this ,
1179: "You must provide a value for at least one field to insert a row.",
1180: null);
1181: return;
1182: }
1183:
1184: Connection conn = null;
1185: try {
1186:
1187: String sql = getSQL(INSERT);
1188: if (debug)
1189: System.out.println(sql);
1190:
1191: // this call was added to work around an apparent bug in Access, where
1192: // if a current resultset was still open with unread records,
1193: // then the refresh query (the runQuery call below) would not find
1194: // the row that was just inserted.
1195: this .maybeCloseCurrentConnection();
1196: conn = dataSource.getConnection();
1197: Statement s = conn.createStatement();
1198: s.executeUpdate(sql);
1199: DBUtil.closeStatement(s);
1200: s = null;
1201: DBUtil.closeConnection(conn);
1202: conn = null;
1203: try {
1204: String pkWhereClause = getPkWhereClause();
1205: runQuery(pkWhereClause, NO_RESULTSET);
1206: } catch (UnknownPrimaryKeyException upkex) {
1207:
1208: setState(NO_RESULTSET);
1209:
1210: GUIHelper
1211: .warningMsg(
1212: this ,
1213: "The row you entered has been successfully inserted, however it could not be re-read from the "
1214: + "database and displayed because the primary key for this table is unknown."
1215: + "\n\nYou may re-display the inserted row by searching for it with a form query. (Ctrl-Q)",
1216: null);
1217:
1218: }
1219: } catch (Exception ex) {
1220: ex.printStackTrace();
1221: this .clearCurrentResultSet();
1222: GUIHelper.errMsg(this ,
1223: "The following database error occurred:\n"
1224: + ex.getClass().getName() + "\n"
1225: + ex.getMessage(), "Database Error");
1226: } finally {
1227:
1228: DBUtil.closeConnection(conn);
1229: }
1230: }
1231:
1232: public void executeUpdate() {
1233:
1234: setState(HAS_RESULTSET);
1235:
1236: Connection conn = null;
1237: ResultSet rs = null;
1238: Statement s = null;
1239: boolean saveAutoCommit = false;
1240: boolean autoCommitChanged = false;
1241:
1242: String sql = null;
1243:
1244: try {
1245: sql = getSQL(UPDATE);
1246: } catch (UnknownPrimaryKeyException ex) {
1247:
1248: // refresh the fields with the existing data
1249: current();
1250:
1251: GUIHelper
1252: .errMsg(
1253: this ,
1254: "This record cannot be updated because the primary key for this table is unknown, and could not be adequately surmised by the application.",
1255: "Application Error");
1256:
1257: return;
1258: }
1259:
1260: try {
1261:
1262: if (debug)
1263: System.out.println(sql);
1264: if (sql == null)
1265: return;
1266:
1267: conn = dataSource.getConnection();
1268: saveAutoCommit = conn.getAutoCommit();
1269: if (saveAutoCommit) {
1270: conn.setAutoCommit(false);
1271: autoCommitChanged = true;
1272: }
1273:
1274: s = conn.createStatement();
1275: int rowsUpdated = s.executeUpdate(sql);
1276: if (rowsUpdated > 1) {
1277: System.err.println("Too many rows updated: "
1278: + rowsUpdated + ". SQL: " + sql);
1279: conn.rollback();
1280: GUIHelper.errMsg(this ,
1281: "The update has been rolled back because "
1282: + rowsUpdated
1283: + " rows would have been modified.",
1284: "Database Error");
1285: if (saveAutoCommit)
1286: conn.setAutoCommit(true);
1287: return;
1288: }
1289: s.close();
1290: conn.commit();
1291: s = conn.createStatement();
1292:
1293: // this should not fail because of an UnknownPrimaryKeyException, since
1294: // the call to getSQL(UPDATE) succeeded.
1295: String sql2 = getSQL(PK_SELECT);
1296: rs = s.executeQuery(sql2);
1297: if (rs.next()) {
1298: baseForm.replaceCurrentRow(rs);
1299: } else {
1300: throw new RuntimeException(
1301: "Refresh query returned no rows!");
1302: }
1303:
1304: } catch (Exception ex) {
1305: ex.printStackTrace();
1306: try {
1307: System.err.print("DATABASE ERROR, ROLLING BACK.");
1308: if (conn != null)
1309: conn.rollback();
1310: } catch (Exception ex2) {
1311: ex2.printStackTrace();
1312: }
1313:
1314: try {
1315: if (autoCommitChanged)
1316: conn.setAutoCommit(saveAutoCommit);
1317: } catch (Exception ex2) {
1318: ex2.printStackTrace();
1319: }
1320: GUIHelper.errMsg(this ,
1321: "The following database error occurred:\n"
1322: + ex.getClass().getName() + "\n"
1323: + ex.getMessage(), "Database Error");
1324: showRowNum(baseForm.current());
1325: } finally {
1326: DBUtil.closeResultSet(rs);
1327: DBUtil.closeStatement(s);
1328: DBUtil.closeConnection(conn);
1329: }
1330: }
1331:
1332: /**
1333: * Executes a query based on criteria entered into the form.
1334: */
1335: public void runQuery() {
1336: runQuery(getWhereClause(), -1);
1337: }
1338:
1339: private Stack historyList = new Stack();
1340:
1341: private boolean lastQueryBlank = false;
1342:
1343: public java.util.List getHistoryList() {
1344: return historyList;
1345: }
1346:
1347: Connection currentConn = null;
1348: ResultSet currentResultSet = null;
1349:
1350: private void maybeCloseCurrentConnection() {
1351:
1352: if (currentResultSet != null) {
1353: if (debug)
1354: System.out.println("QUERYPANEL: CLOSING RESULTSET");
1355: DBUtil.closeResultSet(currentResultSet);
1356: currentResultSet = null;
1357: } else {
1358: if (debug)
1359: System.out
1360: .println("QUERYPANEL: CURRENT RESULTSET IS NULL");
1361: }
1362:
1363: if (currentConn != null) {
1364: if (debug)
1365: System.out.println("QUERYPANEL: CLOSING CONNECTION");
1366: DBUtil.closeConnection(currentConn);
1367: currentConn = null;
1368: } else {
1369: if (debug)
1370: System.out
1371: .println("QUERYPANEL: CURRENT RESULTSET IS NULL");
1372: }
1373:
1374: }
1375:
1376: private void clearCurrentResultSet() {
1377: maybeCloseCurrentConnection();
1378: baseForm.removeResultSetBuffer();
1379: ((ResultSetTableModel) gridTable.getModel()).setDataList(null);
1380: }
1381:
1382: public void dispose() {
1383: if (debug)
1384: System.out
1385: .println("QueryPanel.dispose(), closing connection.");
1386: this .clearCurrentResultSet();
1387: }
1388:
1389: public void runQuery(String whereClause, int noResultsTabState) {
1390: if (debug)
1391: System.out.println(whereClause);
1392:
1393: // close any currently open resultsets and connections.
1394: maybeCloseCurrentConnection();
1395:
1396: // remove any "sort arrows" from the grid table header.
1397: gridTableHeader.setSortedColumn(-1, false);
1398:
1399: Connection queryConn = null;
1400: ResultSet rs = null;
1401:
1402: String SQL = "SELECT * " + getFromClause();
1403: if (whereClause != null
1404: && (whereClause = whereClause.trim()).length() > 0) {
1405: SQL = SQL + " WHERE " + whereClause;
1406: }
1407:
1408: if (debug)
1409: System.out.println("SQL: " + SQL);
1410:
1411: try {
1412: queryConn = dataSource.getConnection();
1413: endReached = false;
1414:
1415: Statement s = queryConn.createStatement();
1416: rs = s.executeQuery(SQL);
1417:
1418: ResultSetBuffer buffer = new ResultSetBuffer(rs, 250);
1419: buffer.addResultSetBufferListener(this );
1420:
1421: if (baseForm.setResultSetBuffer(buffer)) {
1422:
1423: if (baseForm.isEndOfResultsReached() == false) {
1424: currentConn = queryConn;
1425: currentResultSet = rs;
1426: } else {
1427: DBUtil.closeResultSet(rs);
1428: DBUtil.closeConnection(queryConn);
1429: }
1430:
1431: showRowNum(0);
1432:
1433: setState(HAS_RESULTSET);
1434:
1435: // push the SQL for this query onto the stack of
1436: // previous queries. Don't do it if it already matches
1437: // the one on the top of the stack, however.
1438: if (whereClause != null && whereClause.length() > 0) {
1439: lastQueryBlank = false;
1440: if (historyList.size() > 0) {
1441: String lastQuery = (String) historyList.peek();
1442: if (lastQuery.equals(whereClause) == false) {
1443: historyList.push(whereClause);
1444: }
1445: } else {
1446: historyList.push(whereClause);
1447: }
1448: } else {
1449: lastQueryBlank = true;
1450: }
1451:
1452: // gridTable.setModel(new ResultSetTableModel(buffer));
1453: // ResultSetTableModel model = (ResultSetTableModel) gridTable.getModel();
1454: ((ResultSetTableModel) gridTable.getModel())
1455: .setDataList(buffer);
1456: // model.setColumnMappings(visibleGridColumns);
1457: // model.fireTableDataChanged();
1458:
1459: } else { // no results were found.
1460:
1461: DBUtil.closeResultSet(rs);
1462: DBUtil.closeConnection(queryConn);
1463:
1464: ((ResultSetTableModel) gridTable.getModel())
1465: .setDataList(null);
1466:
1467: // if a valid state was passed in, set the window to that state.
1468: if (noResultsTabState != -1)
1469: setState(noResultsTabState);
1470:
1471: // alert the user.
1472: GUIHelper.infoMsg(this ,
1473: "This query did not return any rows.", null);
1474: }
1475: } catch (SQLException ex) {
1476: ex.printStackTrace();
1477: DBUtil.closeResultSet(rs);
1478: DBUtil.closeConnection(queryConn);
1479: GUIHelper.errMsg(this ,
1480: "The following database error occurred:\n"
1481: + ex.getClass().getName() + "\n"
1482: + ex.getMessage(), "Database Error");
1483: if (debug)
1484: System.out.println("Query exception: " + ex.toString());
1485:
1486: if (noResultsTabState != -1)
1487: setState(noResultsTabState);
1488: }
1489: }
1490:
1491: public void rerunLastQuery() {
1492: int currentSelection = baseForm.getCursorVal();
1493: if (lastQueryBlank)
1494: runQuery(null, this .NO_RESULTSET);
1495: else
1496: runQuery((String) historyList.peek(), this .NO_RESULTSET);
1497: boolean b = baseForm.maybeShowRow(currentSelection);
1498: if (b)
1499: showRowNum(currentSelection);
1500: }
1501:
1502: /**
1503: * Displays the current record in the resultset.
1504: */
1505: public void current() {
1506: showRowNum(baseForm.current());
1507: }
1508:
1509: boolean endReached = false;
1510:
1511: boolean atBeginningFlag = false;
1512:
1513: /**
1514: * Displays the next record in the resultset.
1515: */
1516: public void next() {
1517:
1518: try {
1519:
1520: if (state != HAS_RESULTSET) {
1521: GUIHelper.infoMsg(this ,
1522: "There are no query results to display.", null);
1523: return;
1524: }
1525:
1526: int nextRecNum = baseForm.next();
1527: if (nextRecNum > 0) {
1528: showRowNum(nextRecNum);
1529: } else {
1530:
1531: status.setStatusMessage("End of resultset reached.");
1532:
1533: // if there are no more rows in the resultset, display a message.
1534: boolean isEnabled = rightButton.isEnabled();
1535:
1536: // the enabled state of the button is checked first. It's turned off while
1537: // the message box is popped up to prevent multiple popups when the user
1538: // presses and holds the PGDN key.
1539: if (isEnabled) {
1540: rightButton.setEnabled(false);
1541: GUIHelper.infoMsg(this ,
1542: "There are no more records to display.",
1543: null);
1544: rightButton.setEnabled(true);
1545: displayRowNum();
1546: current();
1547: }
1548: }
1549: } catch (Exception ex) {
1550: GUIHelper.errMsg(this , "An unexpected error occurred:\n"
1551: + ex.getClass().getName() + "\n" + ex.getMessage(),
1552: "Application Error");
1553: if (debug)
1554: System.out.println("next() exception: "
1555: + ex.getMessage());
1556: ex.printStackTrace();
1557:
1558: }
1559:
1560: }
1561:
1562: /**
1563: * Displays the previous record.
1564: */
1565: public void previous() {
1566:
1567: if (state != HAS_RESULTSET) {
1568: GUIHelper.infoMsg(this ,
1569: "There are no query results to display.", null);
1570: return;
1571: }
1572:
1573: int prevRowNum = baseForm.previous();
1574: if (prevRowNum > -1) {
1575: showRowNum(prevRowNum);
1576: } else {
1577: boolean isEnabled = leftButton.isEnabled();
1578:
1579: // the enabled state of the button is checked first. It's turned off while
1580: // the message box is popped up to prevent multiple popups when the user
1581: // presses and holds the PGUP key.
1582: if (isEnabled) {
1583: status
1584: .setStatusMessage("Beginning of resultset reached.");
1585: leftButton.setEnabled(false);
1586: GUIHelper.infoMsg(this ,
1587: "There are no previous records to display.",
1588: null);
1589: leftButton.setEnabled(true);
1590: displayRowNum();
1591: }
1592: }
1593: }
1594:
1595: /**
1596: * Displays the first record.
1597: */
1598: public void first() {
1599:
1600: if (state != HAS_RESULTSET) {
1601: GUIHelper.infoMsg(this ,
1602: "There are no query results to display.", null);
1603: return;
1604: }
1605:
1606: if (baseForm.isAtBeginning()) {
1607: status.setStatusMessage("Beginning of resultset reached.");
1608: boolean isEnabled = leftEndButton.isEnabled();
1609:
1610: // the enabled state of the button is checked first. It's turned off while
1611: // the message box is popped up to prevent multiple popups when the user
1612: // presses and holds the HOME key.
1613: if (isEnabled) {
1614: leftEndButton.setEnabled(false);
1615: GUIHelper.infoMsg(this ,
1616: "The first record is already displayed.", null);
1617: leftEndButton.setEnabled(true);
1618: displayRowNum();
1619: }
1620: return;
1621: }
1622:
1623: baseForm.first();
1624: gridTable.getSelectionModel().setSelectionInterval(0, 0);
1625: displayRowNum();
1626: }
1627:
1628: public void updateStatusMessage() {
1629:
1630: Component visibleTab = tabbedPane.getSelectedComponent();
1631:
1632: switch (state) {
1633: case NO_RESULTSET:
1634: statusLabel.setText(null);
1635: if (visibleTab == this .gridTab) {
1636: status
1637: .setStatusMessage("Right-click for options menu.");
1638: } else {
1639: status.setStatusMessage(null);
1640: }
1641: break;
1642: case HAS_RESULTSET:
1643: displayRowNum();
1644: break;
1645: default:
1646: status.setStatusMessage(null);
1647: }
1648: }
1649:
1650: public void showRowNum(int rowNum) {
1651: if (debug)
1652: System.out.println("TRACE:" + getClass().getName()
1653: + ".showRowNum()");
1654: displayRowNum(rowNum + 1);
1655:
1656: // select the row for this record in the table.
1657: gridTable.getSelectionModel().setSelectionInterval(rowNum,
1658: rowNum);
1659:
1660: // now make sure the selected row is visible.
1661: Rectangle r = gridTable.getCellRect(rowNum, 0, true);
1662: gridTable.scrollRectToVisible(r);
1663: }
1664:
1665: public void displayRowNum() {
1666: int num = baseForm.getCursorVal();
1667: if (num > -1)
1668: displayRowNum(num + 1);
1669: }
1670:
1671: public void clearRowNumDisplay() {
1672: statusLabel.setText(null);
1673: }
1674:
1675: public void displayRowNum(int rowNum) {
1676: boolean endReached = baseForm.isEndOfResultsReached();
1677: StringBuffer buffer = new StringBuffer(50);
1678: buffer.append(" Row ");
1679: buffer.append(rowNum);
1680: buffer.append(" of ");
1681: buffer.append(baseForm.getRowsRead());
1682: if (endReached == false)
1683: buffer.append(" read.");
1684: // status.setStatusMessage(buffer.toString());
1685:
1686: statusLabel.setText(buffer.toString());
1687: }
1688:
1689: class GetCount extends Thread {
1690:
1691: int rowCount = -1;
1692:
1693: public int getRowCount() {
1694: return rowCount;
1695: }
1696:
1697: public void run() {
1698: Connection conn = null;
1699: try {
1700: conn = dataSource.getConnection();
1701: String SQL = getSQL(COUNT);
1702: Statement s = conn.createStatement();
1703: ResultSet rst = s.executeQuery(SQL);
1704: if (rst.next())
1705: rowCount = rst.getInt(1);
1706: } catch (Exception ex) {
1707: rowCount = -100;
1708: ex.printStackTrace();
1709: GUIHelper.exceptionMsg(ex);
1710: } finally {
1711: DBUtil.closeConnection(conn);
1712: }
1713: }
1714: }
1715:
1716: // static ColumnMapDialog columnMapDialog = new ColumnMapDialog(null);
1717: //
1718: // static {
1719: // GUIHelper.centerWindowOnScreen(columnMapDialog);
1720: // }
1721:
1722: int[] visibleGridColumns = null;
1723:
1724: public int[] getVisibleGridColumns() {
1725: return visibleGridColumns;
1726: }
1727:
1728: public String[] getColumnNames() {
1729: return columnNames;
1730: }
1731:
1732: public void setVisibleGridColumns(int[] visibleGridColumns) {
1733: this .visibleGridColumns = visibleGridColumns;
1734: if (visibleGridColumns != null) {
1735: ResultSetTableModel model = (ResultSetTableModel) gridTable
1736: .getModel();
1737: model.setColumnMappings(visibleGridColumns);
1738: model.fireTableStructureChanged();
1739: }
1740:
1741: gridTableHeader.setSortedColumn(-1, false);
1742: }
1743:
1744: /**
1745: * This method is called to notify a listener that a ResultSetBuffer has
1746: * read more rows from its ResultSet.
1747: */
1748: public void moreRowsRead(ResultSetBufferEvent e) {
1749:
1750: // we'll remove any arrows from the table header that might indicate
1751: // a sorted buffer, to let the user no that the buffer contents may no
1752: // longer be in sorted order.
1753: gridTableHeader.setSortedColumn(-1, true);
1754: displayRowNum();
1755:
1756: }
1757:
1758: /**
1759: * This method is called to notify a listener that a ResultSetBuffer has
1760: * read the last row of its ResultSet.
1761: */
1762: public void endOfResultsReached(ResultSetBufferEvent e) {
1763: this .maybeCloseCurrentConnection();
1764: displayRowNum();
1765: }
1766:
1767: public void bufferSorted(ResultSetBufferEvent e) {
1768: int rowNum = baseForm.getCurrentRowNum();
1769: baseForm.showRow(rowNum);
1770: this .showRowNum(rowNum);
1771: displayRowNum();
1772:
1773: // this works around an apparent bug in JDK 1.3
1774: // that causes garbage to appear in the area of the JScrollPane
1775: // not covered by the JTable, when the JTable is narrower
1776: // than the JScrollPane.
1777: if (isJava1point3 && isHorizontalScrollBarVisible()) {
1778: gridScrollPane.repaint();
1779: }
1780:
1781: }
1782:
1783: /**
1784: * This returns an array containing the indexes of all of the
1785: * rows selected in the grid table. If there is no current ResultSet,
1786: * null is returned. If no table rows are selected, a single-element
1787: * array containing the index of the row displayed in the form is
1788: * returned.
1789: */
1790: public int[] getSelectedIndexes() {
1791:
1792: int[] selectedIndexes = gridTable.getSelectedRows();
1793: if (selectedIndexes == null || selectedIndexes.length == 0) {
1794: int cursor = baseForm.getCursorVal();
1795: if (cursor < 0)
1796: return null;
1797: return new int[] { cursor };
1798: }
1799: return selectedIndexes;
1800: }
1801:
1802: public void actionPerformed(ActionEvent e) {
1803: String command = e.getActionCommand();
1804: if (command.equals("SHOW_POPUP")) {
1805: extraItemsPopup.show(popupButton, 0, 36);
1806: }
1807: }
1808:
1809: public void addQueryPanelListener(QueryPanelListener listener) {
1810:
1811: listeners.add(QueryPanelListener.class, listener);
1812:
1813: }
1814:
1815: public void fireEvent(int type) {
1816: QueryPanelEvent event = new QueryPanelEvent(this , type);
1817: listeners.fireSmartEvent(event);
1818: }
1819:
1820: public void setHorizontalScrollBarVisible(boolean b) {
1821:
1822: boolean oldState = this .isHorizontalScrollBarVisible();
1823:
1824: if (b) {
1825: gridTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
1826: gridScrollPane
1827: .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
1828: } else {
1829: gridTable
1830: .setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
1831: gridScrollPane
1832: .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
1833: }
1834:
1835: for (int j = 0; j < horizontalScrollbarMenuItems.length; j++) {
1836: horizontalScrollbarMenuItems[j].setSelected(b);
1837: }
1838:
1839: // notify listeners if the state has changed.
1840: if (b != oldState)
1841: this
1842: .fireEvent(QueryPanelEvent.HORIZONTAL_SCROLLBAR_STATE_CHANGED);
1843: }
1844:
1845: public boolean isHorizontalScrollBarVisible() {
1846: return gridTable.getAutoResizeMode() == JTable.AUTO_RESIZE_OFF;
1847: }
1848:
1849: public void setSelectedTab(int tabIndex) {
1850: tabbedPane.setSelectedIndex(tabIndex);
1851: }
1852:
1853: }
|