0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.db.explorer.dataview;
0043:
0044: import java.awt.GridBagConstraints;
0045: import java.awt.GridBagLayout;
0046: import java.awt.Insets;
0047: import java.awt.datatransfer.DataFlavor;
0048: import java.awt.datatransfer.StringSelection;
0049: import java.awt.datatransfer.Transferable;
0050: import java.awt.dnd.DropTarget;
0051: import java.awt.dnd.DropTargetDragEvent;
0052: import java.awt.dnd.DropTargetDropEvent;
0053: import java.awt.dnd.DropTargetEvent;
0054: import java.awt.dnd.DropTargetListener;
0055: import java.awt.event.ActionEvent;
0056: import java.awt.event.ActionListener;
0057: import java.awt.event.MouseAdapter;
0058: import java.awt.event.MouseEvent;
0059: import java.io.ObjectStreamException;
0060: import java.sql.Connection;
0061: import java.sql.ResultSet;
0062: import java.sql.ResultSetMetaData;
0063: import java.sql.SQLException;
0064: import java.sql.Statement;
0065: import java.sql.Types;
0066: import java.text.MessageFormat;
0067: import java.util.Enumeration;
0068: import java.util.HashMap;
0069: import java.util.Iterator;
0070: import java.util.ResourceBundle;
0071: import java.util.StringTokenizer;
0072: import java.util.Vector;
0073: import javax.swing.AbstractListModel;
0074: import javax.swing.JButton;
0075: import javax.swing.JComboBox;
0076: import javax.swing.JLabel;
0077: import javax.swing.JMenuItem;
0078: import javax.swing.JPanel;
0079: import javax.swing.JPopupMenu;
0080: import javax.swing.JScrollPane;
0081: import javax.swing.JSplitPane;
0082: import javax.swing.JTable;
0083: import javax.swing.JTextArea;
0084: import javax.swing.MutableComboBoxModel;
0085: import javax.swing.SwingUtilities;
0086: import javax.swing.table.AbstractTableModel;
0087: import org.netbeans.api.db.explorer.DatabaseException;
0088: import org.netbeans.modules.db.explorer.infos.ColumnNodeInfo;
0089: import org.netbeans.modules.db.explorer.infos.DatabaseNodeInfo;
0090: import org.netbeans.modules.db.explorer.nodes.ConnectionNode;
0091: import org.openide.DialogDisplayer;
0092: import org.openide.NotifyDescriptor;
0093: import org.openide.awt.Mnemonics;
0094: import org.openide.nodes.Node;
0095: import org.openide.nodes.NodeTransfer;
0096: import org.openide.util.Lookup;
0097: import org.openide.util.NbBundle;
0098: import org.openide.util.RequestProcessor;
0099: import org.openide.util.Task;
0100: import org.openide.util.TaskListener;
0101: import org.openide.util.datatransfer.ExClipboard;
0102: import org.openide.util.datatransfer.ExTransferable;
0103: import org.openide.util.datatransfer.MultiTransferObject;
0104: import org.openide.windows.TopComponent;
0105:
0106: public class DataViewWindow extends TopComponent {
0107:
0108: // TODO: remove this class, replace by the SQL editor
0109:
0110: private JTextArea queryarea;
0111: private JTable jtable;
0112: private DataModel dbadaptor;
0113: private JComboBox rcmdscombo;
0114: private JLabel status;
0115: private ResourceBundle bundle;
0116: private Node node;
0117: private JPopupMenu tablePopupMenu;
0118: static final long serialVersionUID = 6855188441469780252L;
0119:
0120: public DataViewWindow(DatabaseNodeInfo info, String query)
0121: throws SQLException {
0122: node = info.getNode();
0123:
0124: bundle = NbBundle
0125: .getBundle("org.netbeans.modules.db.resources.Bundle"); //NOI18N
0126:
0127: this .getAccessibleContext().setAccessibleDescription(
0128: bundle.getString("ACS_DataViewWindowA11yDesc")); //NOI18N
0129:
0130: Node tempNode = node;
0131: while (!(tempNode instanceof ConnectionNode))
0132: tempNode = tempNode.getParentNode();
0133:
0134: String title = tempNode.getDisplayName();
0135: int idx = title.indexOf(" ["); //NOI18N
0136: title = title.substring(0, idx);
0137: setName(title);
0138: setToolTipText(bundle.getString("CommandEditorTitle") + " "
0139: + tempNode.getDisplayName()); //NOI18N
0140:
0141: GridBagLayout layout = new GridBagLayout();
0142: GridBagConstraints con = new GridBagConstraints();
0143: setLayout(layout);
0144:
0145: // Data model
0146: dbadaptor = new DataModel(info);
0147:
0148: // Query area and button
0149: JPanel subpane = new JPanel();
0150: GridBagLayout sublayout = new GridBagLayout();
0151: GridBagConstraints subcon = new GridBagConstraints();
0152: subpane.setLayout(sublayout);
0153:
0154: // query label
0155: subcon.fill = GridBagConstraints.HORIZONTAL;
0156: subcon.weightx = 0.0;
0157: subcon.weighty = 0.0;
0158: subcon.gridx = 0;
0159: subcon.gridy = 0;
0160: subcon.gridwidth = 3;
0161: subcon.insets = new Insets(0, 0, 5, 0);
0162: subcon.anchor = GridBagConstraints.SOUTH;
0163: JLabel queryLabel = new JLabel();
0164: Mnemonics.setLocalizedText(queryLabel, bundle
0165: .getString("QueryLabel"));
0166: queryLabel.getAccessibleContext().setAccessibleDescription(
0167: bundle.getString("ACS_DataViewQueryLabelA11yDesc"));
0168: sublayout.setConstraints(queryLabel, subcon);
0169: subpane.add(queryLabel);
0170:
0171: // query area
0172: subcon.fill = GridBagConstraints.BOTH;
0173: subcon.weightx = 1.0;
0174: subcon.weighty = 1.0;
0175: subcon.gridx = 0;
0176: subcon.gridwidth = 3;
0177: subcon.gridy = 1;
0178: queryarea = new JTextArea(query, 3, 70);
0179: queryarea.setLineWrap(true);
0180: queryarea.setWrapStyleWord(true);
0181: queryarea.setDropTarget(new DropTarget(queryarea,
0182: new ViewDropTarget()));
0183: queryarea.getAccessibleContext().setAccessibleName(
0184: bundle.getString("ACS_DataViewTextAreaA11yName")); //NOI18N
0185: queryarea.getAccessibleContext().setAccessibleDescription(
0186: bundle.getString("ACS_DataViewTextAreaA11yDesc")); //NOI18N
0187: queryarea.setToolTipText(bundle
0188: .getString("ACS_DataViewTextAreaA11yDesc")); //NOI18N
0189: queryLabel.setLabelFor(queryarea);
0190:
0191: JScrollPane scrollpane = new JScrollPane(queryarea);
0192: subcon.insets = new Insets(0, 0, 5, 0);
0193: sublayout.setConstraints(scrollpane, subcon);
0194: subpane.add(scrollpane);
0195:
0196: // combo label
0197: subcon.fill = GridBagConstraints.HORIZONTAL;
0198: subcon.weightx = 0.0;
0199: subcon.weighty = 0.0;
0200: subcon.gridx = 0;
0201: subcon.gridy = 2;
0202: subcon.gridwidth = 1;
0203: subcon.insets = new Insets(0, 0, 5, 5);
0204: subcon.anchor = GridBagConstraints.CENTER;
0205: JLabel comboLabel = new JLabel();
0206: Mnemonics.setLocalizedText(comboLabel, bundle
0207: .getString("HistoryLabel")); //NOI18N
0208: comboLabel.getAccessibleContext().setAccessibleDescription(
0209: bundle.getString("ACS_DataViewHistoryLabelA11yDesc")); //NOI18N
0210: sublayout.setConstraints(comboLabel, subcon);
0211: subpane.add(comboLabel);
0212:
0213: // Combo recent commands
0214: subcon.fill = GridBagConstraints.HORIZONTAL;
0215: subcon.weightx = 1.0;
0216: subcon.weighty = 0.0;
0217: subcon.gridx = 1;
0218: subcon.gridy = 2;
0219: subcon.gridwidth = 1;
0220: subcon.insets = new Insets(0, 0, 5, 5);
0221: subcon.anchor = GridBagConstraints.SOUTH;
0222: rcmdscombo = new JComboBox(new ComboModel());
0223: rcmdscombo.getAccessibleContext().setAccessibleName(
0224: bundle.getString("ACS_DataViewComboBoxA11yName")); //NOI18N
0225: rcmdscombo.getAccessibleContext().setAccessibleDescription(
0226: bundle.getString("ACS_DataViewComboBoxA11yDesc")); //NOI18N
0227: rcmdscombo.setToolTipText(bundle
0228: .getString("ACS_DataViewComboBoxA11yDesc")); //NOI18N
0229: comboLabel.setLabelFor(rcmdscombo);
0230: sublayout.setConstraints(rcmdscombo, subcon);
0231: subpane.add(rcmdscombo);
0232: rcmdscombo.addActionListener(new ActionListener() {
0233: public void actionPerformed(ActionEvent e) {
0234: JComboBox source = (JComboBox) e.getSource();
0235: RecentCommand cmd = (RecentCommand) source
0236: .getSelectedItem();
0237: if (cmd != null)
0238: setCommand(cmd.getCommand());
0239: }
0240: });
0241:
0242: // Button Execute
0243: subcon.gridx = 2;
0244: subcon.gridy = 2;
0245: subcon.weightx = 0.0;
0246: subcon.weighty = 0.0;
0247: subcon.insets = new Insets(0, 0, 5, 0);
0248: subcon.fill = GridBagConstraints.HORIZONTAL;
0249: subcon.anchor = GridBagConstraints.SOUTH;
0250: final JButton fetchbtn = new JButton();
0251: Mnemonics.setLocalizedText(fetchbtn, bundle
0252: .getString("ExecuteButton"));
0253: fetchbtn.setToolTipText(bundle
0254: .getString("ACS_ExecuteButtonA11yDesc")); //NOI18N
0255: sublayout.setConstraints(fetchbtn, subcon);
0256: subpane.add(fetchbtn);
0257: fetchbtn.addActionListener(new ActionListener() {
0258: public void actionPerformed(ActionEvent e) {
0259: fetchbtn.setEnabled(false);
0260: Task t = RequestProcessor.getDefault().create(
0261: new Runnable() {
0262: public void run() {
0263: executeCommand();
0264: }
0265: });
0266: t.addTaskListener(new TaskListener() {
0267: public void taskFinished(Task task) {
0268: fetchbtn.setEnabled(true);
0269: }
0270: });
0271: RequestProcessor.getDefault().post(t, 0);
0272: }
0273: });
0274: // status line
0275: subcon.fill = GridBagConstraints.HORIZONTAL;
0276: subcon.weightx = 1.0;
0277: subcon.weighty = 0.0;
0278: subcon.gridx = 0;
0279: subcon.gridy = 3;
0280: subcon.gridwidth = 3;
0281: subcon.insets = new Insets(0, 0, 5, 0);
0282: subcon.anchor = GridBagConstraints.SOUTH;
0283: status = new JLabel(" "); //NOI18N
0284: status.setBorder(new javax.swing.border.LineBorder(
0285: java.awt.Color.gray));
0286: status.getAccessibleContext().setAccessibleDescription(
0287: bundle.getString("ACS_DataViewStatusLabelA11yDesc")); //NOI18N
0288: sublayout.setConstraints(status, subcon);
0289: subpane.add(status);
0290:
0291: JPanel subpane2 = new JPanel();
0292: GridBagLayout sublayout2 = new GridBagLayout();
0293: GridBagConstraints subcon2 = new GridBagConstraints();
0294: subpane2.setLayout(sublayout2);
0295:
0296: // table label
0297: subcon2.fill = GridBagConstraints.HORIZONTAL;
0298: subcon2.weightx = 0.0;
0299: subcon2.weighty = 0.0;
0300: subcon2.gridx = 0;
0301: subcon2.gridy = 0;
0302: subcon2.gridwidth = 1;
0303: subcon2.insets = new Insets(5, 0, 0, 0);
0304: subcon2.anchor = GridBagConstraints.SOUTH;
0305: JLabel tableLabel = new JLabel();
0306: Mnemonics.setLocalizedText(tableLabel, bundle
0307: .getString("ResultsLabel"));
0308: tableLabel.getAccessibleContext().setAccessibleDescription(
0309: bundle.getString("ACS_DataViewResultsLabelA11yDesc")); //NOI18N
0310: sublayout2.setConstraints(tableLabel, subcon2);
0311: subpane2.add(tableLabel);
0312:
0313: // content popup menu on table with results
0314: tablePopupMenu = new JPopupMenu();
0315: JMenuItem miCopyValue = new JMenuItem(bundle
0316: .getString("CopyCellValue")); //NOI18N
0317: miCopyValue.addActionListener(new ActionListener() {
0318: public void actionPerformed(ActionEvent e) {
0319: try {
0320: Object o = jtable.getValueAt(jtable
0321: .getSelectedRow(), jtable
0322: .getSelectedColumn());
0323: String output = (o != null) ? o.toString() : ""; //NOI18N
0324: ExClipboard clipboard = (ExClipboard) Lookup
0325: .getDefault().lookup(ExClipboard.class);
0326: StringSelection strSel = new StringSelection(output);
0327: clipboard.setContents(strSel, strSel);
0328: } catch (ArrayIndexOutOfBoundsException exc) {
0329: }
0330: }
0331: });
0332: tablePopupMenu.add(miCopyValue);
0333:
0334: JMenuItem miCopyRowValues = new JMenuItem(bundle
0335: .getString("CopyRowValues")); //NOI18N
0336: miCopyRowValues.addActionListener(new ActionListener() {
0337: public void actionPerformed(ActionEvent e) {
0338: try {
0339: int[] rows = jtable.getSelectedRows();
0340: int[] columns;
0341: if (jtable.getRowSelectionAllowed()) {
0342: columns = new int[jtable.getColumnCount()];
0343: for (int a = 0; a < columns.length; a++)
0344: columns[a] = a;
0345: } else {
0346: columns = jtable.getSelectedColumns();
0347: }
0348: if (rows != null && columns != null) {
0349: StringBuffer output = new StringBuffer();
0350: for (int row = 0; row < rows.length; row++) {
0351: for (int column = 0; column < columns.length; column++) {
0352: if (column > 0)
0353: output.append('\t'); //NOI18N
0354: Object o = jtable.getValueAt(rows[row],
0355: columns[column]);
0356: output.append(o != null ? o.toString()
0357: : ""); //NOI18N
0358: }
0359: output.append('\n'); //NOI18N
0360: }
0361: ExClipboard clipboard = (ExClipboard) Lookup
0362: .getDefault().lookup(ExClipboard.class);
0363: StringSelection strSel = new StringSelection(
0364: output.toString());
0365: clipboard.setContents(strSel, strSel);
0366: }
0367: } catch (ArrayIndexOutOfBoundsException exc) {
0368: }
0369: }
0370: });
0371: tablePopupMenu.add(miCopyRowValues);
0372:
0373: // Table with results
0374: // TableSorter sorter = new TableSorter();
0375: jtable = new JTable(dbadaptor/*sorter*/);
0376: jtable.getAccessibleContext().setAccessibleName(
0377: bundle.getString("ACS_DataViewTableA11yName")); //NOI18N
0378: jtable.getAccessibleContext().setAccessibleDescription(
0379: bundle.getString("ACS_DataViewTableA11yDesc")); //NOI18N
0380: jtable.setToolTipText(bundle
0381: .getString("ACS_DataViewTableA11yDesc")); //NOI18N
0382: jtable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
0383: // sorter.addMouseListenerToHeaderInTable(table);
0384: jtable.addMouseListener(new MouseAdapter() {
0385: public void mouseReleased(MouseEvent e) {
0386: if (e.getButton() == MouseEvent.BUTTON3) {
0387: int row = jtable.rowAtPoint(e.getPoint());
0388: int column = jtable.columnAtPoint(e.getPoint());
0389: boolean inSelection = false;
0390: int[] rows = jtable.getSelectedRows();
0391: for (int a = 0; a < rows.length; a++)
0392: if (rows[a] == row) {
0393: inSelection = true;
0394: break;
0395: }
0396: if (!jtable.getRowSelectionAllowed()) {
0397: inSelection = false;
0398: int[] columns = jtable.getSelectedColumns();
0399: for (int a = 0; a < columns.length; a++)
0400: if (columns[a] == column) {
0401: inSelection = true;
0402: break;
0403: }
0404: }
0405: if (!inSelection)
0406: jtable.changeSelection(row, column, false,
0407: false);
0408: tablePopupMenu.show(jtable, e.getX(), e.getY());
0409: }
0410: }
0411: });
0412: tableLabel.setLabelFor(jtable);
0413:
0414: scrollpane = new JScrollPane(jtable);
0415: subcon2.fill = GridBagConstraints.BOTH;
0416: subcon2.weightx = 1.0;
0417: subcon2.weighty = 1.0;
0418: subcon2.gridx = 0;
0419: subcon2.gridy = 1;
0420: subcon2.gridwidth = 1;
0421: sublayout2.setConstraints(scrollpane, subcon2);
0422: subpane2.add(scrollpane);
0423:
0424: // Add it into splitview
0425: con.weightx = 1.0;
0426: con.weighty = 1.0;
0427: con.fill = GridBagConstraints.BOTH;
0428: con.gridx = 0;
0429: con.gridwidth = 1;
0430: con.gridy = 1;
0431: con.insets = new Insets(12, 12, 11, 11);
0432:
0433: JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
0434: subpane, subpane2);
0435: layout.setConstraints(split, con);
0436: add(split);
0437: }
0438:
0439: /**Overriden to provide preferred value
0440: * for unique TopComponent Id returned by getID. Returned value is used as starting
0441: * value for creating unique TopComponent ID.
0442: * Value should be preferably unique, but need not be.
0443: * @since 4.13
0444: */
0445: protected String preferredID() {
0446: return getName();
0447: }
0448:
0449: /** Overriden to explicitely set persistence type of DataViewWindow
0450: * to PERSISTENCE_NEVER */
0451: public int getPersistenceType() {
0452: return TopComponent.PERSISTENCE_NEVER;
0453: }
0454:
0455: /** Returns query used by panel.
0456: */
0457: public String getCommand() {
0458: return queryarea.getText();
0459: }
0460:
0461: /** Sets query used by panel.
0462: */
0463: public void setCommand(String command) {
0464: queryarea.setText(command);
0465: }
0466:
0467: public boolean executeCommand() {
0468: String command = queryarea.getText().trim();
0469: boolean ret;
0470:
0471: try {
0472: dbadaptor.execute(command);
0473:
0474: RecentCommand rcmd = new RecentCommand(command);
0475: ((ComboModel) rcmdscombo.getModel()).addElement(rcmd);
0476: ret = true;
0477: } catch (Exception exc) {
0478: ret = false;
0479: status.setText(bundle.getString("CommandFailed")); //NOI18N
0480: org.openide.DialogDisplayer.getDefault().notify(
0481: new NotifyDescriptor.Message(bundle
0482: .getString("DataViewFetchErrorPrefix")
0483: + exc.getMessage(),
0484: NotifyDescriptor.ERROR_MESSAGE)); //NOI18N
0485: }
0486:
0487: return ret;
0488: }
0489:
0490: class ColDef {
0491: private String name;
0492: private boolean writable;
0493: private boolean bric;
0494: int datatype;
0495:
0496: public ColDef(String name, boolean flag) {
0497: this .name = name;
0498: writable = flag;
0499: }
0500:
0501: public String getName() {
0502: return name;
0503: }
0504:
0505: public void setName(String name) {
0506: this .name = name;
0507: }
0508:
0509: public int getDataType() {
0510: return datatype;
0511: }
0512:
0513: public void setDataType(int type) {
0514: datatype = type;
0515: }
0516:
0517: public boolean isWritable() {
0518: return writable;
0519: }
0520:
0521: public void setWritable(boolean flag) {
0522: writable = flag;
0523: }
0524:
0525: public boolean isBestRowIdentifierColumn() {
0526: return bric;
0527: }
0528:
0529: public void setBestRowIdentifierColumn(boolean flag) {
0530: bric = flag;
0531: }
0532: }
0533:
0534: static int tstrg = 0;
0535: static int gtcmd = 0;
0536:
0537: class RecentCommand {
0538: private String command;
0539:
0540: /** The command with no new lines */
0541: private String shortCommand;
0542:
0543: public RecentCommand(String cmd) {
0544: command = cmd;
0545: shortCommand = getShortCommand();
0546: }
0547:
0548: public String toString() {
0549: return shortCommand;
0550: }
0551:
0552: public String getCommand() {
0553: return command;
0554: }
0555:
0556: public boolean equals(Object obj) {
0557: if (obj instanceof RecentCommand)
0558: return ((RecentCommand) obj).getShortCommand().equals(
0559: shortCommand);
0560:
0561: return super .equals(obj);
0562: }
0563:
0564: /**
0565: * Gets the command String for display in the JComboBox without
0566: * new lines.
0567: *
0568: * @return the command for display in the JComboBox
0569: */
0570: private String getShortCommand() {
0571: StringTokenizer tokenizer = new StringTokenizer(command);
0572: StringBuffer buffer = new StringBuffer();
0573: while (tokenizer.hasMoreElements()) {
0574: buffer.append(tokenizer.nextElement());
0575: buffer.append(" ");
0576: }
0577: return buffer.toString();
0578: }
0579: }
0580:
0581: class ComboModel extends AbstractListModel implements
0582: MutableComboBoxModel {
0583: Vector commands;
0584: Object selected;
0585:
0586: static final long serialVersionUID = -5831993904798984334L;
0587:
0588: public ComboModel() {
0589: this (new Vector(1));
0590: }
0591:
0592: public ComboModel(Vector elems) {
0593: commands = elems;
0594: }
0595:
0596: public Object getSelectedItem() {
0597: return selected;
0598: }
0599:
0600: public void setSelectedItem(Object anItem) {
0601: selected = anItem;
0602: fireContentsChanged(this , -1, -1);
0603: }
0604:
0605: public void addElement(Object obj) {
0606: if (!commands.contains(obj)) {
0607: commands.add(obj);
0608: fireContentsChanged(this , -1, -1);
0609: }
0610: }
0611:
0612: public void removeElement(Object obj) {
0613: commands.removeElement(obj);
0614: fireContentsChanged(this , -1, -1);
0615: }
0616:
0617: public void insertElementAt(Object obj, int index) {
0618: if (!commands.contains(obj)) {
0619: commands.insertElementAt(obj, index);
0620: fireContentsChanged(this , -1, -1);
0621: }
0622: }
0623:
0624: public void removeElementAt(int index) {
0625: commands.removeElementAt(index);
0626: fireContentsChanged(this , -1, -1);
0627: }
0628:
0629: public int getSize() {
0630: return commands.size();
0631: }
0632:
0633: public Object getElementAt(int index) {
0634: return commands.get(index);
0635: }
0636: }
0637:
0638: class ViewDropTarget implements DropTargetListener {
0639: /** User is starting to drag over us */
0640: public void dragEnter(DropTargetDragEvent dtde) {
0641: dtde.acceptDrag(dtde.getDropAction());
0642: }
0643:
0644: /** User drags over us */
0645: public void dragOver(DropTargetDragEvent dtde) {
0646: }
0647:
0648: public void dropActionChanged(DropTargetDragEvent dtde) {
0649: }
0650:
0651: /** User exits the dragging */
0652: public void dragExit(DropTargetEvent dte) {
0653: }
0654:
0655: private ColumnNodeInfo getNodeInfo(Transferable t) {
0656: Node n = NodeTransfer.node(t, NodeTransfer.MOVE);
0657: if (n != null)
0658: return (ColumnNodeInfo) n
0659: .getCookie(ColumnNodeInfo.class);
0660:
0661: n = NodeTransfer.node(t, NodeTransfer.COPY);
0662: if (n != null)
0663: return (ColumnNodeInfo) n
0664: .getCookie(ColumnNodeInfo.class);
0665:
0666: return null;
0667: }
0668:
0669: /** Performs the drop action */
0670: public void drop(DropTargetDropEvent dtde) {
0671: String query = null;
0672: Transferable t = dtde.getTransferable();
0673: StringBuffer buff = new StringBuffer();
0674:
0675: try {
0676: DataFlavor multiFlavor = new DataFlavor(
0677: "application/x-java-openide-multinode;class=org.openide.util.datatransfer.MultiTransferObject", // NOI18N
0678: NbBundle
0679: .getBundle(
0680: "org.netbeans.modules.db.resources.Bundle")
0681: .getString(
0682: "transferFlavorsMultiFlavorName"),
0683: MultiTransferObject.class.getClassLoader());
0684:
0685: if (t.isDataFlavorSupported(multiFlavor)) {
0686: MultiTransferObject mobj = (MultiTransferObject) t
0687: .getTransferData(ExTransferable.multiFlavor);
0688: int count = mobj.getCount();
0689: int tabidx = 0;
0690: HashMap tabidxmap = new HashMap();
0691: for (int i = 0; i < count; i++) {
0692: ColumnNodeInfo nfo = getNodeInfo(mobj
0693: .getTransferableAt(i));
0694: if (nfo != null) {
0695: String tablename = nfo.getTable();
0696: Integer tableidx = (Integer) tabidxmap
0697: .get(tablename);
0698: if (tableidx == null)
0699: tabidxmap
0700: .put(tablename,
0701: tableidx = new Integer(
0702: tabidx++));
0703: if (buff.length() > 0)
0704: buff.append(", "); //NOI18N
0705: buff.append("t" + tableidx + "."
0706: + nfo.getName()); //NOI18N
0707: }
0708: }
0709:
0710: StringBuffer frombuff = new StringBuffer();
0711: Iterator iter = tabidxmap.keySet().iterator();
0712: while (iter.hasNext()) {
0713: String tab = (String) iter.next();
0714: if (frombuff.length() > 0)
0715: frombuff.append(", "); //NOI18N
0716: frombuff
0717: .append(tab + " t" + tabidxmap.get(tab)); //NOI18N
0718: }
0719:
0720: query = "select " + buff.toString() + " from "
0721: + frombuff.toString(); //NOI18N
0722:
0723: } else {
0724: ColumnNodeInfo nfo = getNodeInfo(t);
0725: if (nfo != null)
0726: query = "select " + nfo.getName() + " from "
0727: + nfo.getTable(); //NOI18N
0728: }
0729:
0730: if (query != null)
0731: setCommand(query);
0732: } catch (Exception e) {
0733: e.printStackTrace();
0734: }
0735: }
0736: }
0737:
0738: class DataModel extends AbstractTableModel {
0739: DatabaseNodeInfo node_info;
0740: Vector coldef = new Vector();
0741: Vector data = new Vector();
0742: boolean editable = false;
0743:
0744: static final long serialVersionUID = 7729426847826999963L;
0745:
0746: /** Constructor */
0747: public DataModel(DatabaseNodeInfo node_info)
0748: throws SQLException {
0749: this .node_info = node_info;
0750: }
0751:
0752: /** Executes command
0753: * @param command SQL Expression
0754: */
0755: synchronized public void execute(String command)
0756: throws Exception {
0757: if (command.length() == 0) {
0758: status.setText(" "); //NOI18N
0759: return;
0760: }
0761:
0762: status.setText(bundle.getString("CommandRunning")); //NOI18N
0763:
0764: Connection con;
0765: Statement stat;
0766: try {
0767: con = node_info.getConnection();
0768: stat = con.createStatement();
0769: } catch (Exception exc) {
0770: String message = MessageFormat.format(bundle
0771: .getString("EXC_ConnectionError"),
0772: new String[] { exc.getMessage() }); // NOI18N
0773: throw new DatabaseException(message);
0774: }
0775:
0776: ResultSet rs;
0777:
0778: if (command.toLowerCase().startsWith("select")) { //NOI18N
0779: rs = stat.executeQuery(command);
0780:
0781: ResultSetMetaData mdata = rs.getMetaData();
0782:
0783: int cols = mdata.getColumnCount();
0784: // Bug : 5083676
0785: // Data is getting cleared and modified in a independent thread , while the swing
0786: // thread tries to render the table. Hence this sometimes results in a
0787: // ArrayIndexOutOfBoundsException
0788: // Creating two 'work' vectors here and populating required changes in these
0789: // Then replacing the model vectors with these.
0790: Vector coldefWork = new Vector();
0791: Vector dataWork = new Vector();
0792: for (int column = 1; column <= cols; column++) {
0793: boolean writable;
0794: try {
0795: writable = mdata.isWritable(column);
0796: } catch (SQLException exc) {
0797: //patch for FireBirdSQL (isWritable has not been implemented yet)
0798: writable = false;
0799: }
0800: ColDef cd = new ColDef(
0801: mdata.getColumnLabel(column), writable);
0802: cd.setDataType(mdata.getColumnType(column));
0803: coldefWork.add(cd);
0804: }
0805:
0806: // Get all rows.
0807: // In future implementations should be more careful
0808: int rcounter = 0;
0809: // int limit = RootNode.getOption().getFetchLimit();
0810: // int step = RootNode.getOption().getFetchStep();
0811: int limit = 100;
0812: int step = 200;
0813:
0814: String cancel = bundle
0815: .getString("DataViewCancelButton"); //NOI18N
0816: String nextset = bundle
0817: .getString("DataViewNextFetchButton"); //NOI18N
0818: String allset = bundle
0819: .getString("DataViewAllFetchButton"); //NOI18N
0820:
0821: JButton fetchNext = new JButton();
0822: Mnemonics.setLocalizedText(fetchNext, nextset);
0823: fetchNext
0824: .getAccessibleContext()
0825: .setAccessibleDescription(
0826: bundle
0827: .getString("ACS_DataViewNextFetchButtonA11yDesc")); //NOI18N
0828:
0829: JButton fetchAll = new JButton();
0830: Mnemonics.setLocalizedText(fetchAll, allset);
0831: fetchAll
0832: .getAccessibleContext()
0833: .setAccessibleDescription(
0834: bundle
0835: .getString("ACS_DataViewAllFetchButtonA11yDesc")); //NOI18N
0836:
0837: JButton no = new JButton();
0838: Mnemonics.setLocalizedText(no, cancel);
0839: no
0840: .getAccessibleContext()
0841: .setAccessibleDescription(
0842: bundle
0843: .getString("ACS_DataViewCancelButtonA11yDesc")); //NOI18N
0844:
0845: String message;
0846: NotifyDescriptor ndesc;
0847: while (rs.next()) {
0848: Vector row = new Vector(cols);
0849: for (int column = 1; column <= cols; column++)
0850: row.add(rs.getObject(column));
0851: dataWork.addElement(row);
0852:
0853: // Catch row count
0854: if (++rcounter >= limit) {
0855:
0856: message = MessageFormat.format(bundle
0857: .getString("DataViewMessage"),
0858: new Object[] { new Integer(rcounter),
0859: new Integer(step) }); //NOI18N
0860: ndesc = new NotifyDescriptor(
0861: message,
0862: bundle.getString("FetchDataTitle"),
0863: NotifyDescriptor.YES_NO_CANCEL_OPTION,
0864: NotifyDescriptor.QUESTION_MESSAGE,
0865: new Object[] { fetchNext, fetchAll, no },
0866: NotifyDescriptor.CANCEL_OPTION); //NOI18N
0867:
0868: Object ret = DialogDisplayer.getDefault()
0869: .notify(ndesc);
0870: if (fetchAll.equals(ret)) {
0871: limit = Integer.MAX_VALUE;
0872: } else {
0873: if (fetchNext.equals(ret)) {
0874: limit = limit + step;
0875: } else {
0876: // window closed by close button or Esc key
0877: // or the cancel button was pressed
0878: break;
0879: }
0880: }
0881: }
0882: }
0883:
0884: // Replace model in the swing event thread
0885: // Alternative is to lock on the instance and assign it.
0886: final Vector assignData = dataWork;
0887: final Vector assignColdef = coldefWork;
0888: SwingUtilities.invokeAndWait(new Runnable() {
0889: public void run() {
0890: data = assignData;
0891: coldef = assignColdef;
0892: fireTableChanged(null);
0893: }
0894: });
0895: /*
0896: synchronized(coldef){
0897: coldef = assignColdef;
0898: }
0899: synchronized(data){
0900: data = assignData;
0901: }
0902: */
0903: rs.close();
0904: //fireTableChanged(null);
0905: } else {
0906: if (command.toLowerCase().startsWith("delete")
0907: || command.toLowerCase().startsWith("insert")
0908: || command.toLowerCase().startsWith("update")) //NOI18N
0909: stat.executeUpdate(command);
0910: else {
0911: stat.execute(command);
0912:
0913: //refresh DBExplorer nodes
0914: while (!(node instanceof ConnectionNode))
0915: node = node.getParentNode();
0916: Enumeration nodes = node.getChildren().nodes();
0917: while (nodes.hasMoreElements())
0918: ((DatabaseNodeInfo) ((Node) nodes.nextElement())
0919: .getCookie(DatabaseNodeInfo.class))
0920: .refreshChildren();
0921: }
0922: }
0923: status.setText(bundle.getString("CommandExecuted")); //NOI18N
0924: stat.close();
0925: }
0926:
0927: /** Returns column name
0928: * @param column Column index
0929: */
0930: public String getColumnName(int column) {
0931: synchronized (coldef) {
0932: if (column < coldef.size()) {
0933: String cname = ((ColDef) coldef.elementAt(column))
0934: .getName();
0935: return cname;
0936: }
0937:
0938: return ""; //NOI18N
0939: }
0940: }
0941:
0942: /** Returns column renderer/editor class
0943: * @param column Column index
0944: */
0945: public Class getColumnClass(int column) {
0946: synchronized (coldef) {
0947: if (column < coldef.size()) {
0948: int coltype = ((ColDef) coldef.elementAt(column))
0949: .getDataType();
0950: switch (coltype) {
0951: case Types.CHAR:
0952: case Types.VARCHAR:
0953: case Types.LONGVARCHAR:
0954: return String.class;
0955: case Types.BIT:
0956: return Boolean.class;
0957: case Types.TINYINT:
0958: case Types.SMALLINT:
0959: case Types.INTEGER:
0960: return Integer.class;
0961: case Types.BIGINT:
0962: return Long.class;
0963: case Types.FLOAT:
0964: case Types.DOUBLE:
0965: return Double.class;
0966: case Types.DATE:
0967: return java.sql.Date.class;
0968: }
0969: }
0970:
0971: return Object.class;
0972: }
0973: }
0974:
0975: /** Returns true, if cell is editable
0976: */
0977: public boolean isCellEditable(int row, int column) {
0978: synchronized (coldef) {
0979: if (!editable)
0980: return false;
0981:
0982: if (column < coldef.size())
0983: return ((ColDef) coldef.elementAt(column))
0984: .isWritable();
0985:
0986: return false;
0987: }
0988: }
0989:
0990: /** Returns colun count
0991: */
0992: public int getColumnCount() {
0993: synchronized (coldef) {
0994: return coldef.size();
0995: }
0996: }
0997:
0998: /** Returns row count
0999: */
1000: public int getRowCount() {
1001: synchronized (data) {
1002: return data.size();
1003: }
1004: }
1005:
1006: /** Returns value at specified position
1007: */
1008: public Object getValueAt(int aRow, int aColumn) {
1009: synchronized (data) {
1010: Vector row = new Vector();
1011: if (aRow < data.size())
1012: row = (Vector) data.elementAt(aRow);
1013: if (row != null && aColumn < row.size())
1014: return row.elementAt(aColumn);
1015:
1016: return null;
1017: }
1018: }
1019:
1020: private String format(Object value, int type) {
1021: if (value == null)
1022: return "null"; //NOI18N
1023:
1024: switch (type) {
1025: case Types.INTEGER:
1026: case Types.DOUBLE:
1027: case Types.FLOAT:
1028: return value.toString();
1029: case Types.BIT:
1030: return ((Boolean) value).booleanValue() ? "1" : "0"; //NOI18N
1031: case Types.DATE:
1032: return value.toString();
1033: default:
1034: return "\"" + value.toString() + "\""; //NOI18N
1035: }
1036: }
1037:
1038: public void setValueAt(Object value, int row, int column) {
1039: synchronized (coldef) {
1040: int enucol = 0;
1041: StringBuffer where = new StringBuffer();
1042: Enumeration enu = coldef.elements();
1043: while (enu.hasMoreElements()) {
1044: ColDef cd = (ColDef) enu.nextElement();
1045: if (cd.isBestRowIdentifierColumn()) {
1046: String key = cd.getName();
1047: String val = format(getValueAt(row, enucol), cd
1048: .getDataType());
1049: if (where.length() > 0)
1050: where.append(" and "); //NOI18N
1051: where.append(key + " = " + val); //NOI18N
1052: }
1053: enucol++;
1054: }
1055: }
1056: }
1057: }
1058:
1059: protected Object writeReplace() throws ObjectStreamException {
1060: return null;
1061: }
1062: }
|