001: /*
002: * ClipBoardCopier.java
003: *
004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
005: *
006: * Copyright 2002-2008, Thomas Kellerer
007: * No part of this code maybe reused without the permission of the author
008: *
009: * To contact the author please send an email to: support@sql-workbench.net
010: *
011: */
012: package workbench.gui.components;
013:
014: import java.awt.Toolkit;
015: import java.awt.datatransfer.Clipboard;
016: import java.awt.datatransfer.StringSelection;
017: import java.io.StringWriter;
018: import java.util.ArrayList;
019: import java.util.Collections;
020: import java.util.List;
021: import javax.swing.JOptionPane;
022: import javax.swing.SwingUtilities;
023: import workbench.WbManager;
024: import workbench.db.ColumnIdentifier;
025: import workbench.db.TableIdentifier;
026: import workbench.db.exporter.SqlRowDataConverter;
027: import workbench.gui.WbSwingUtilities;
028: import workbench.log.LogMgr;
029: import workbench.resource.ResourceMgr;
030: import workbench.resource.Settings;
031: import workbench.storage.DataPrinter;
032: import workbench.storage.DataStore;
033: import workbench.storage.RowData;
034: import workbench.util.ExceptionUtil;
035: import workbench.util.StrBuffer;
036: import workbench.util.StringUtil;
037: import workbench.util.WbThread;
038:
039: /**
040: * A class to copy the data of a {@link workbench.gui.components.WbTable} to
041: * the clipboard. Either as tab-separated text or SQL Statements.
042: *
043: * @author support@sql-workbench.net
044: */
045: public class ClipBoardCopier {
046: private DataStore data;
047: private WbTable client;
048:
049: public ClipBoardCopier(WbTable t) {
050: this .client = t;
051: this .data = client.getDataStore();
052: }
053:
054: /**
055: * Copy data from the table as tab-delimited into the clipboard
056: *
057: * @param includeHeaders if true, then a header line with the column names is copied as well
058: * @param selectedOnly if true, then only selected rows are copied, else all rows
059: * @param showSelectColumns if true, a dialog will be presented to the user to select the columns to be included
060: */
061: public void copyDataToClipboard(boolean includeHeaders,
062: boolean selectedOnly, final boolean showSelectColumns) {
063: if (this .data == null) {
064: WbSwingUtilities.showErrorMessage(client,
065: "No DataStore available!");
066: LogMgr.logError("ClipBoardCopier._copyAsSql()",
067: "Cannot copy without a DataStore!", null);
068: return;
069: }
070:
071: if (this .data.getRowCount() <= 0)
072: return;
073:
074: List<ColumnIdentifier> columnsToCopy = null;
075: if (selectedOnly && !showSelectColumns
076: && this .client.getColumnSelectionAllowed()) {
077: columnsToCopy = getColumnsFromSelection();
078: }
079:
080: if (showSelectColumns) {
081: // Display column selection dialog
082: ColumnSelectionResult result = this .selectColumns(
083: includeHeaders, selectedOnly, true, client
084: .getSelectedRowCount() > 0);
085: if (result == null)
086: return;
087: columnsToCopy = result.columns;
088: includeHeaders = result.includeHeaders;
089: selectedOnly = result.selectedOnly;
090: }
091:
092: try {
093: StringWriter out = null;
094: int count = this .data.getRowCount();
095: int[] rows = null;
096: if (selectedOnly) {
097: rows = this .client.getSelectedRows();
098: count = rows.length;
099: }
100:
101: // Do not use StringUtil.LINE_TERMINATOR for the line terminator
102: // because for some reason this creates additional empty lines
103: // under Windows
104: DataPrinter printer = new DataPrinter(this .data, "\t",
105: "\n", columnsToCopy, includeHeaders);
106: out = new StringWriter(count * 250);
107: printer.writeDataString(out, rows);
108:
109: Clipboard clp = Toolkit.getDefaultToolkit()
110: .getSystemClipboard();
111: WbSwingUtilities.showWaitCursorOnWindow(this .client);
112: StringSelection sel = new StringSelection(out.toString());
113: clp.setContents(sel, sel);
114: } catch (Throwable ex) {
115: if (ex instanceof OutOfMemoryError) {
116: WbManager.getInstance().showOutOfMemoryError();
117: } else {
118: String msg = ResourceMgr.getString("ErrClipCopy");
119: msg = StringUtil.replace(msg, "%errmsg%", ExceptionUtil
120: .getDisplay(ex));
121: WbSwingUtilities.showErrorMessage(client, msg);
122: }
123: LogMgr.logError(this ,
124: "Could not copy text data to clipboard", ex);
125: }
126: WbSwingUtilities.showDefaultCursorOnWindow(this .client);
127: }
128:
129: public void copyAsSqlInsert(boolean selectedOnly,
130: boolean showSelectColumns) {
131: this .copyAsSql(false, selectedOnly, showSelectColumns, false);
132: }
133:
134: public void copyAsSqlDeleteInsert(boolean selectedOnly,
135: boolean showSelectColumns) {
136: this .copyAsSql(false, selectedOnly, showSelectColumns, true);
137: }
138:
139: /**
140: * Copy the data of the client table as SQL UPDATE statements to the clipboard.
141: * Before copying, the primary key columns of the underlying {@link workbench.storage.DataStore}
142: * are checked. If none are present, the user is prompted to select the key columns
143: *
144: * @see workbench.storage.DataStore#hasPkColumns()
145: * @see workbench.gui.components.WbTable#detectDefinedPkColumns()
146: * @see #copyAsSql(boolean, boolean, boolean, boolean)
147: */
148: public void copyAsSqlUpdate(boolean selectedOnly,
149: boolean showSelectColumns) {
150: copyAsSql(true, selectedOnly, showSelectColumns, false);
151: }
152:
153: /**
154: * Copy the data of the client table into the clipboard using SQL statements
155: */
156: public void copyAsSql(final boolean useUpdate,
157: final boolean selectedOnly,
158: final boolean showSelectColumns, final boolean includeDelete) {
159: // For some reason the statusbar will not be updated if
160: // this is run in the AWT thread, so we have to
161: // create a new thread to run the actual copy
162: WbThread t = new WbThread("CopyThread") {
163: public void run() {
164: _copyAsSql(useUpdate, selectedOnly, showSelectColumns,
165: includeDelete);
166: }
167: };
168: t.start();
169: }
170:
171: protected void _copyAsSql(final boolean useUpdate,
172: boolean selectedOnly, final boolean showSelectColumns,
173: final boolean includeDelete) {
174: if (this .data == null) {
175: WbSwingUtilities.showErrorMessage(client,
176: "No DataStore available!");
177: LogMgr.logError("ClipBoardCopier._copyAsSql()",
178: "Cannot copy without a DataStore!", null);
179: return;
180: }
181:
182: if (this .data.getRowCount() <= 0)
183: return;
184:
185: if (useUpdate || includeDelete) {
186: boolean pkOK = this .data.hasPkColumns();
187: if (!pkOK && this .client != null) {
188: this .client.checkPkColumns(true);
189: }
190:
191: // re-check in case the user simply clicked OK during the PK prompt
192: pkOK = this .data.hasPkColumns();
193:
194: // Can't do anything if we don't have PK
195: if (!pkOK) {
196: LogMgr
197: .logError(
198: "ClipBoardCopier._copyAsSql()",
199: "Cannot create UPDATE or DELETE statements without a primary key!",
200: null);
201: String msg = ResourceMgr
202: .getString("ErrCopyNotAvailable");
203: WbSwingUtilities.showErrorMessage(client, msg);
204: return;
205: }
206: }
207:
208: TableIdentifier updateTable = data.getUpdateTable();
209: if (updateTable == null) {
210: updateTable = client.selectUpdateTable();
211: if (updateTable != null) {
212: client.getDataStore().setUpdateTable(updateTable);
213: }
214: }
215:
216: List<ColumnIdentifier> columnsToInclude = null;
217: if (selectedOnly && !showSelectColumns
218: && this .client.getColumnSelectionAllowed()) {
219: columnsToInclude = getColumnsFromSelection();
220: }
221:
222: if (showSelectColumns) {
223: ColumnSelectionResult result = this .selectColumns(false,
224: selectedOnly, false,
225: client.getSelectedRowCount() > 0);
226: if (result == null)
227: return;
228: columnsToInclude = result.columns;
229: selectedOnly = result.selectedOnly;
230: }
231:
232: try {
233: WbSwingUtilities.showWaitCursorOnWindow(this .client);
234: int rows[] = null;
235: if (selectedOnly)
236: rows = this .client.getSelectedRows();
237:
238: SqlRowDataConverter converter = new SqlRowDataConverter(
239: data.getOriginalConnection());
240: converter.setIncludeTableOwner(Settings.getInstance()
241: .getIncludeOwnerInSqlExport());
242: converter.setResultInfo(data.getResultInfo());
243: converter.setSqlLiteralType(Settings.getInstance()
244: .getDefaultCopyDateLiteralType());
245: if (useUpdate) {
246: converter.setCreateUpdate();
247: } else if (includeDelete) {
248: converter.setCreateInsertDelete();
249: } else {
250: converter.setCreateInsert();
251: if (data.getResultInfo().getUpdateTable() == null) {
252: String tbl = data.getInsertTable();
253: TableIdentifier table = new TableIdentifier(tbl);
254: converter.setAlternateUpdateTable(table);
255: }
256: }
257: converter.setColumnsToExport(columnsToInclude);
258: converter.setBlobTypeDbmsLiteral();
259:
260: int count = 0;
261: if (rows != null)
262: count = rows.length;
263: else
264: count = data.getRowCount();
265:
266: StringBuilder result = new StringBuilder(count * 100);
267: RowData rowdata = null;
268:
269: for (int row = 0; row < count; row++) {
270: if (rows == null)
271: rowdata = this .data.getRow(row);
272: else
273: rowdata = data.getRow(rows[row]);
274:
275: StrBuffer sql = converter.convertRowData(rowdata, row);
276: sql.appendTo(result);
277: }
278:
279: Clipboard clp = Toolkit.getDefaultToolkit()
280: .getSystemClipboard();
281: StringSelection sel = new StringSelection(result.toString());
282: clp.setContents(sel, sel);
283: } catch (Throwable e) {
284: if (e instanceof OutOfMemoryError) {
285: WbManager.getInstance().showOutOfMemoryError();
286: } else {
287: String msg = ResourceMgr.getString("ErrClipCopy");
288: msg = StringUtil.replace(msg, "%errmsg%", ExceptionUtil
289: .getDisplay(e));
290: WbSwingUtilities.showErrorMessage(client, msg);
291: }
292: LogMgr.logError(this , "Error when copying as SQL", e);
293: }
294: WbSwingUtilities.showDefaultCursorOnWindow(this .client);
295: }
296:
297: /**
298: * A general purpose method to select specific columns from the result set
299: * this is e.g. used for copying data to the clipboard
300: *
301: */
302: public ColumnSelectionResult selectColumns(boolean includeHeader,
303: boolean selectedOnly, boolean showHeaderSelection,
304: boolean showSelectedRowsSelection) {
305: if (this .data == null)
306: return null;
307:
308: ColumnSelectionResult result = new ColumnSelectionResult();
309: result.includeHeaders = includeHeader;
310: result.selectedOnly = selectedOnly;
311:
312: ColumnIdentifier[] originalCols = this .data.getColumns();
313: ColumnSelectorPanel panel = new ColumnSelectorPanel(
314: originalCols, includeHeader, selectedOnly,
315: showHeaderSelection, showSelectedRowsSelection);
316: panel.selectAll();
317: int choice = JOptionPane
318: .showConfirmDialog(
319: SwingUtilities.getWindowAncestor(this .client),
320: panel,
321: ResourceMgr
322: .getString("MsgSelectColumnsWindowTitle"),
323: JOptionPane.OK_CANCEL_OPTION,
324: JOptionPane.PLAIN_MESSAGE);
325:
326: if (choice == JOptionPane.OK_OPTION) {
327: result.columns = panel.getSelectedColumns();
328: result.includeHeaders = panel.includeHeader();
329: result.selectedOnly = panel.selectedOnly();
330: } else {
331: result = null;
332: }
333: return result;
334: }
335:
336: private List<ColumnIdentifier> getColumnsFromSelection() {
337: int[] cols = this .client.getSelectedColumns();
338: DataStore ds = this .client.getDataStore();
339: if (ds == null)
340: return Collections.emptyList();
341: List<ColumnIdentifier> result = new ArrayList<ColumnIdentifier>(
342: cols.length);
343: for (int i = 0; i < cols.length; i++) {
344: result.add(ds.getResultInfo().getColumn(cols[i]));
345: }
346: return result;
347: }
348: }
349:
350: class ColumnSelectionResult {
351: public boolean includeHeaders;
352: public boolean selectedOnly;
353: public List<ColumnIdentifier> columns;
354: }
|