001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.db.sql.visualeditor.querybuilder;
042:
043: import java.awt.Color;
044: import java.awt.datatransfer.StringSelection;
045: import java.awt.event.*;
046: import java.awt.event.ActionListener;
047:
048: import javax.swing.JTable;
049: import javax.swing.table.DefaultTableModel;
050: import javax.swing.JMenuItem;
051: import javax.swing.JPopupMenu;
052:
053: import java.sql.Blob;
054: import java.sql.Clob;
055: import java.sql.Timestamp;
056: import java.sql.Date;
057: import java.sql.Time;
058: import java.sql.ResultSet;
059: import java.sql.ResultSetMetaData;
060: import java.sql.SQLException;
061:
062: import java.text.DateFormat;
063:
064: import org.openide.util.NbBundle;
065: import org.openide.NotifyDescriptor;
066: import org.openide.DialogDisplayer;
067: import org.openide.util.Lookup;
068: import org.openide.util.datatransfer.ExClipboard;
069:
070: import org.netbeans.modules.db.sql.visualeditor.Log;
071:
072: /**
073: * A table for displaying query results in the query editor
074: * @author Sanjay Dhamankar, Jim Davidson
075: */
076: public class QueryBuilderResultTable extends JTable implements
077: ActionListener, KeyListener {
078:
079: private DefaultTableModel resultTableModel = null;
080: private QueryBuilder _queryBuilder;
081: private JPopupMenu resultTablePopup;
082:
083: public QueryBuilderResultTable() {
084: this (null);
085: }
086:
087: /** Constructor which takes the parent as parameter */
088: public QueryBuilderResultTable(QueryBuilder queryBuilder) {
089:
090: super ();
091:
092: _queryBuilder = queryBuilder;
093: resultTableModel = new DefaultTableModel() {
094: public boolean isCellEditable(int row, int column) {
095: return false;
096: }
097: };
098: this .setModel(resultTableModel);
099:
100: resultTablePopup = new JPopupMenu();
101: JMenuItem menuItem;
102: menuItem = new JMenuItem(NbBundle.getMessage(
103: QueryBuilderInputTable.class, "LBL_CopyCellValue")); // NOI18N
104: menuItem.addActionListener(this );
105: resultTablePopup.add(menuItem);
106: menuItem = new JMenuItem(NbBundle.getMessage(
107: QueryBuilderInputTable.class, "LBL_CopyRowValues")); // NOI18N
108: menuItem.addActionListener(this );
109: resultTablePopup.add(menuItem);
110:
111: MouseListener resultTablePopupListener = new ResultTablePopupListener();
112: super .addMouseListener(resultTablePopupListener);
113: this .setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
114: // this.setMinimumSize(new Dimension(200, 30) );
115: // this.setPreferredSize(new Dimension(200, 30) );
116:
117: // change foreground color to Dark Gray ...
118: this .setForeground(Color.DARK_GRAY);
119: addKeyListener(this );
120: }
121:
122: /** ignore */
123: public void keyTyped(KeyEvent e) {
124: }
125:
126: /** ignore */
127: public void keyReleased(KeyEvent e) {
128: }
129:
130: /** Handle the key pressed event and change the focus if a particular
131: * key combination is pressed. */
132: public void keyPressed(KeyEvent e) {
133: if (_queryBuilder != null)
134: _queryBuilder.handleKeyPress(e);
135: }
136:
137: /**
138: * Clear the model
139: */
140: void clearModel() {
141: ((DefaultTableModel) this .getModel()).setRowCount(0);
142: }
143:
144: /**
145: * Update the table model from the ResultSet
146: * @param the result set associated with the table
147: */
148: public void displayResultSet(ResultSet rs) {
149: displayResultSet(rs, 40, true);
150: }
151:
152: public boolean displayResultSet(ResultSet rs, int maxEntries,
153: boolean infoMsgIfTruncated) {
154: // Check validity of ResultSet
155: ResultSetMetaData rsmd;
156: boolean resultsTruncated = false;
157: try {
158: if ((rs == null) || ((rsmd = rs.getMetaData()) == null)) {
159: //Thread.dumpStack();
160: Log.getLogger().warning(
161: "Exception - unable to get query result ! "); // NOI18N
162: return resultsTruncated;
163: }
164:
165: // Get Column Names
166: int numberOfColumns = rsmd.getColumnCount();
167: Log.getLogger().finest(
168: " rsmd.getColumnCount(): " + numberOfColumns); // NOI18N
169:
170: // Create a vector of column names, for headers
171: String[] dbColumnNames = new String[numberOfColumns];
172: for (int i = 1; i <= numberOfColumns; i++) {
173: dbColumnNames[i - 1] = rsmd.getColumnName(i);
174: }
175:
176: // Set Column Headers; this only works with DefaultTableModel
177: resultTableModel.setColumnIdentifiers(dbColumnNames);
178:
179: // Discard all rows in the current model
180: resultTableModel.setRowCount(0);
181:
182: // Process the result set, producing a vector
183: // For each row, produce a 1-d array that gets added to the Model
184:
185: // Add a check to diaplay ONLY first 40 entries
186: // Add buttons "PREVIOUS", "NEXT" under the result table and
187: // show the proper entires. This is to avoid the
188: // OutOfMemoryException
189:
190: // int maxEntries = 40;
191: int count = 0;
192: while (rs.next() && count < maxEntries + 1) {
193: if (count >= maxEntries) {
194: resultsTruncated = true;
195: break;
196: }
197: Object[] row = new Object[numberOfColumns];
198: for (int i = 1; i <= numberOfColumns; i++) {
199: // since this is an array, we start at 0
200:
201: // Do not show the values of Blob & Clob
202: if (rsmd.getColumnType(i) == java.sql.Types.BLOB) {
203: Blob blobData = rs.getBlob(i);
204: // Added check to fix
205: // 5064319 : ServerNav> View Data on a Db2 Table with
206: // BLOB column throws NPE
207: if (blobData != null)
208: row[i - 1] = "[BLOB of size "
209: + blobData.length() + "]"; //NOI18N
210: } else if (rsmd.getColumnType(i) == java.sql.Types.CLOB) {
211: Clob clobData = rs.getClob(i);
212: // Added check to fix
213: // 5064319 : ServerNav> View Data on a Db2 Table with
214: // BLOB column throws NPE
215: if (clobData != null)
216: row[i - 1] = "[CLOB of size "
217: + clobData.length() + "]"; //NOI18N
218: }
219: // convert timestamp to the current locale
220: else if (rsmd.getColumnType(i) == java.sql.Types.TIMESTAMP) {
221: Timestamp timeStampData = rs.getTimestamp(i);
222:
223: // Added check to fix
224: // 5062947 : Null Date Breaks Viewing Table Data
225: if (timeStampData != null) {
226: row[i - 1] = DateFormat
227: .getDateTimeInstance(
228: DateFormat.SHORT,
229: DateFormat.MEDIUM).format(
230: timeStampData);
231: }
232: }
233: // convert date to the current locale
234: else if (rsmd.getColumnType(i) == java.sql.Types.DATE) {
235: Date dateData = rs.getDate(i);
236: // Added check to fix
237: // 5062947 : Null Date Breaks Viewing Table Data
238: if (dateData != null) {
239: row[i - 1] = DateFormat.getDateInstance(
240: DateFormat.SHORT).format(dateData);
241: }
242: }
243: // convert time to the current locale
244: else if (rsmd.getColumnType(i) == java.sql.Types.TIME) {
245: Time timeData = rs.getTime(i);
246: // Added check to fix
247: // 5062947 : Null Date Breaks Viewing Table Data
248: if (timeData != null) {
249: row[i - 1] = java.text.DateFormat
250: .getTimeInstance(DateFormat.MEDIUM)
251: .format(timeData);
252: }
253: } else {
254: row[i - 1] = rs.getObject(i);
255: }
256: }
257: resultTableModel.addRow(row);
258: count++;
259: }
260: if (resultsTruncated && infoMsgIfTruncated) {
261: String msg = NbBundle.getMessage(
262: QueryBuilderResultTable.class,
263: "MAX_ENTRIES_DISPLAYED", Integer
264: .toString(maxEntries)); // NOI18N
265: NotifyDescriptor d = new NotifyDescriptor.Message(msg
266: + "\n\n", NotifyDescriptor.INFORMATION_MESSAGE); // NOI18N
267: DialogDisplayer.getDefault().notify(d);
268: }
269: } catch (SQLException sqle) {
270: sqle.printStackTrace();
271: Log.getLogger()
272: .warning("Exception - unable to build table"); // NOI18N
273: } finally {
274: if (rs != null) {
275: try {
276: rs.close();
277: } catch (Exception exc) {
278:
279: }
280: }
281: }
282: return resultsTruncated;
283:
284: }
285:
286: // Mouse listener -- bring up background menu
287: class ResultTablePopupListener extends MouseAdapter {
288:
289: public void mousePressed(MouseEvent e) {
290: maybeShowPopup(e);
291: }
292:
293: public void mouseReleased(MouseEvent e) {
294: mousePressed(e);
295: }
296:
297: private void maybeShowPopup(MouseEvent e) {
298: if (e.isPopupTrigger()) {
299: JTable source = (JTable) (e.getSource());
300: int row = source.rowAtPoint(e.getPoint());
301: int column = source.columnAtPoint(e.getPoint());
302: // Make sure the row where click occurred is selected.
303: if (row != -1) {
304: source.setRowSelectionInterval(row, row);
305: }
306: resultTablePopup.show(e.getComponent(), e.getX(), e
307: .getY());
308: }
309: }
310: }
311:
312: // Respond to a selection from the popup menu
313: public void actionPerformed(ActionEvent e) {
314:
315: JMenuItem source = (JMenuItem) (e.getSource());
316: if (source.getText().equals(
317: NbBundle.getMessage(QueryBuilderInputTable.class,
318: "LBL_CopyCellValue"))) // NOI18N
319: {
320: Object o = getValueAt(getSelectedRow(), getSelectedColumn());
321: setClipboard(o.toString());
322: } else if (source.getText().equals(
323: NbBundle.getMessage(QueryBuilderInputTable.class,
324: "LBL_CopyRowValues"))) // NOI18N
325: {
326: int[] rows = getSelectedRows();
327: StringBuffer output = new StringBuffer();
328: for (int i = 0; i < rows.length; i++) {
329: for (int col = 0; col < getColumnCount(); col++) {
330: if (col > 0) {
331: output.append('\t');
332: }
333: Object o = getValueAt(rows[i], col);
334: output.append(o.toString());
335: }
336: output.append('\n');
337: }
338: setClipboard(output.toString());
339: }
340: }
341:
342: private void setClipboard(String contents) {
343: ExClipboard clipboard = (ExClipboard) Lookup.getDefault()
344: .lookup(ExClipboard.class);
345: StringSelection strSel = new StringSelection(contents);
346: clipboard.setContents(strSel, strSel);
347: }
348: }
|