001: /*
002: * Copyright (C) 2005 Rob Manning
003: * manningr@users.sourceforge.net
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * as published by the Free Software Foundation; either version 2
008: * of the License, or any later version.
009: *
010: * This program is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU General Public License for more details.
014: *
015: * You should have received a copy of the GNU General Public License
016: * along with this program; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018: */
019: package net.sourceforge.squirrel_sql.plugins.dbcopy;
020:
021: import java.awt.event.ActionEvent;
022: import java.awt.event.ActionListener;
023: import java.sql.SQLException;
024:
025: import javax.swing.Icon;
026: import javax.swing.JFrame;
027: import javax.swing.JOptionPane;
028: import javax.swing.ProgressMonitor;
029: import javax.swing.SwingUtilities;
030:
031: import net.sourceforge.squirrel_sql.fw.codereformat.CodeReformator;
032: import net.sourceforge.squirrel_sql.fw.codereformat.CommentSpec;
033: import net.sourceforge.squirrel_sql.fw.dialects.UserCancelledOperationException;
034: import net.sourceforge.squirrel_sql.fw.sql.JDBCTypeMapper;
035: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
036: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
037: import net.sourceforge.squirrel_sql.plugins.dbcopy.event.AnalysisEvent;
038: import net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyEvent;
039: import net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyTableListener;
040: import net.sourceforge.squirrel_sql.plugins.dbcopy.event.ErrorEvent;
041: import net.sourceforge.squirrel_sql.plugins.dbcopy.event.RecordEvent;
042: import net.sourceforge.squirrel_sql.plugins.dbcopy.event.StatementEvent;
043: import net.sourceforge.squirrel_sql.plugins.dbcopy.event.TableEvent;
044: import net.sourceforge.squirrel_sql.plugins.dbcopy.gui.DualProgressBarDialog;
045: import net.sourceforge.squirrel_sql.plugins.dbcopy.util.DBUtil;
046:
047: /**
048: * A description of this class goes here...
049: */
050:
051: public class CopyProgressMonitor extends I18NBaseObject implements
052: CopyTableListener, UICallbacks {
053:
054: private SessionInfoProvider prov = null;
055:
056: /** the window we use to display dialogs to the user */
057: private JFrame parent = null;
058:
059: /** whether or not to delete all table data */
060: private boolean deleteAllTableData = false;
061:
062: /** the class that does the actual copying */
063: private CopyExecutor executor = null;
064:
065: /** Logger for this class. */
066: private final static ILogger log = LoggerController
067: .createLogger(CopyProgressMonitor.class);
068:
069: private ProgressMonitor pm = null;
070:
071: private static CommentSpec[] commentSpecs = new CommentSpec[] {
072: new CommentSpec("/*", "*/"), new CommentSpec("--", "\n") };
073:
074: private static CodeReformator formatter = new CodeReformator(";",
075: commentSpecs);
076:
077: public CopyProgressMonitor(SessionInfoProvider provider) {
078: prov = provider;
079: parent = prov.getCopyDestSession().getApplication()
080: .getMainFrame();
081: }
082:
083: // CopyTableListener interface methods
084:
085: /* (non-Javadoc)
086: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyTableListener#copyStarted()
087: */
088: public void copyStarted(CopyEvent e) {
089: if (pm != null) {
090: pm.setProgress(pm.getMaximum());
091: }
092: prov = e.getSessionInfoProvider();
093: int numTables = prov.getSourceSelectedDatabaseObjects().length;
094: int[] tableCounts = e.getTableCounts();
095:
096: createProgressDialog();
097: DualProgressBarDialog.setBottomBarMinMax(0, numTables);
098: DualProgressBarDialog.setBottomBarValue(0);
099: DualProgressBarDialog.setTopBarValue(0);
100: DualProgressBarDialog.setTableCounts(tableCounts);
101: }
102:
103: /* (non-Javadoc)
104: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyTableListener#tableCopyStarted(net.sourceforge.squirrel_sql.plugins.dbcopy.event.TableEvent)
105: */
106: public void tableCopyStarted(TableEvent e) {
107: String bottomMessage = getMessage(
108: "CopyProgressMonitor.copyingTable", new String[] {
109: e.getTableName(), "" + e.getTableNumber(),
110: "" + e.getTableCount() });
111: DualProgressBarDialog.setBottomMessage(bottomMessage);
112: }
113:
114: /* (non-Javadoc)
115: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyTableListener#recordCopied(net.sourceforge.squirrel_sql.plugins.dbcopy.event.RecordEvent)
116: */
117: public void recordCopied(RecordEvent e) {
118: DualProgressBarDialog.setTopBarMinMax(0, e.getRecordCount());
119: String topMessage = getMessage(
120: "CopyProgressMonitor.copyingRecords", new String[] {
121: "" + e.getRecordNumber(),
122: "" + e.getRecordCount() });
123: DualProgressBarDialog.setTopMessage(topMessage);
124: DualProgressBarDialog.incrementTopBar(1);
125: }
126:
127: /* (non-Javadoc)
128: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyTableListener#statementExecuted(net.sourceforge.squirrel_sql.plugins.dbcopy.event.StatementEvent)
129: */
130: public void statementExecuted(StatementEvent e) {
131: /* Do Nothing */
132: }
133:
134: /* (non-Javadoc)
135: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyTableListener#tableCopyFinished(net.sourceforge.squirrel_sql.plugins.dbcopy.event.TableEvent)
136: */
137: public void tableCopyFinished(TableEvent e) {
138: DualProgressBarDialog.setTopBarValue(0);
139: DualProgressBarDialog.incrementBottomBar(1);
140: }
141:
142: /* (non-Javadoc)
143: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyTableListener#copyFinished(int)
144: */
145: public void copyFinished(int seconds) {
146: DualProgressBarDialog.stopTimer();
147: DualProgressBarDialog.setVisible(false);
148: DualProgressBarDialog.dispose();
149: String title = getMessage("CopyProgressMonitor.successTitle");
150: String message = getMessage(
151: "CopyProgressMonitor.successMessage", seconds);
152: showMessageDialog(message, title,
153: JOptionPane.INFORMATION_MESSAGE);
154: }
155:
156: private String wordWrap(String data, int length) {
157: String result = "";
158: if (data.length() > length) {
159: String[] parts = data.split("\\s");
160: StringBuffer tmp = new StringBuffer();
161: int count = 0;
162: for (int i = 0; i < parts.length; i++) {
163: count += parts[i].length();
164: if (count > length) {
165: count = 0;
166: tmp.append("\n");
167: } else {
168: tmp.append(" ");
169: }
170: tmp.append(parts[i]);
171: }
172: result = tmp.toString();
173: } else {
174: result = data;
175: }
176: return result;
177: }
178:
179: /* (non-Javadoc)
180: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyTableListener#handleError(net.sourceforge.squirrel_sql.plugins.dbcopy.event.ErrorEvent)
181: */
182: public void handleError(ErrorEvent e) {
183: DualProgressBarDialog.stopTimer();
184: DualProgressBarDialog.setVisible(false);
185: if (e.getType() == ErrorEvent.SETUP_AUTO_COMMIT_TYPE) {
186: String exMsg = "";
187: if (e.getException() != null) {
188: exMsg = e.getException().getMessage();
189: }
190: String message = getMessage(
191: "CopyProgressMonitor.setupAutoCommitException",
192: exMsg);
193: String title = getMessage("CopyProgressMonitor.setupAutoCommitExceptionTitle");
194: int messageType = JOptionPane.ERROR_MESSAGE;
195: showMessageDialog(message, title, messageType);
196: }
197: if (e.getType() == ErrorEvent.RESTORE_AUTO_COMMIT_TYPE) {
198: String exMsg = "";
199: if (e.getException() != null) {
200: exMsg = e.getException().getMessage();
201: }
202: String message = getMessage(
203: "CopyProgressMonitor.restoreAutoCommitException",
204: exMsg);
205: String title = getMessage("CopyProgressMonitor.restoreAutoCommitExceptionTitle");
206: int messageType = JOptionPane.ERROR_MESSAGE;
207: showMessageDialog(message, title, messageType);
208: }
209: if (e.getType() == ErrorEvent.SQL_EXCEPTION_TYPE) {
210: String exMessage = wordWrap(e.getException().getMessage(),
211: 80);
212: String sql = formatter.reformat(DBUtil.getLastStatement());
213: String values = DBUtil.getLastStatementValues();
214: String sqlAndValues = sql;
215: if (values != null) {
216: sqlAndValues += values;
217: } else {
218: sqlAndValues += "\n(No bind variables)";
219: }
220: int errorCode = ((SQLException) e.getException())
221: .getErrorCode();
222: log.error("SQL Error code = " + errorCode + " sql = "
223: + sqlAndValues, e.getException());
224: String message = getMessage(
225: "CopyProgressMonitor.sqlErrorMessage",
226: new String[] { exMessage, "" + errorCode,
227: sqlAndValues });
228: String title = getMessage("CopyProgressMonitor.sqlErrorTitle");
229: showMessageDialog(message, title, JOptionPane.ERROR_MESSAGE);
230: }
231: if (e.getType() == ErrorEvent.MAPPING_EXCEPTION_TYPE) {
232: String title = getMessage("CopyProgressMonitor.mappingErrorTitle");
233: String message = getMappingExceptionMessage(e
234: .getException());
235: log.error(message, e.getException());
236: showMessageDialog(message, title, JOptionPane.ERROR_MESSAGE);
237: if (pm != null) {
238: pm.setProgress(pm.getMaximum());
239: }
240: }
241: if (e.getType() == ErrorEvent.USER_CANCELLED_EXCEPTION_TYPE) {
242: String title = getMessage("CopyProgressMonitor.cancelledTitle");
243: String message = getMessage("CopyProgressMonitor.cancelledMessage");
244: showMessageDialog(message, title,
245: JOptionPane.INFORMATION_MESSAGE);
246: }
247: if (e.getType() == ErrorEvent.GENERIC_EXCEPTION) {
248: String exmessage = e.getException().getMessage();
249: String message = getMessage(
250: "CopyProgressMonitor.errorMessage",
251: new String[] { exmessage });
252: String title = getMessage("CopyProgressMonitor.errorTitle");
253: showMessageDialog(message, title,
254: JOptionPane.INFORMATION_MESSAGE);
255:
256: }
257: if (e.getException() != null) {
258: log.error("handleError: exception="
259: + e.getException().getMessage(), e.getException());
260: }
261: // TODO: ask the user if they want to "undo" the changes that the
262: // paste made. Alternatively show them the specific problem and
263: // let them fix it. Then allow them to retry the operation, starting
264: // from the point at which the previous operation failed.
265:
266: }
267:
268: private String getMappingExceptionMessage(Exception e) {
269: String message = "";
270: if (e.getMessage().indexOf(":") != -1) {
271: String[] parts = e.getMessage().split(":");
272: try {
273: int typeCode = Integer.parseInt(parts[1].trim());
274: String typeName = JDBCTypeMapper
275: .getJdbcTypeName(typeCode);
276: message = getMessage(
277: "CopyProgressMonitor.mappingErrorMessage",
278: new String[] { e.getMessage(), typeName });
279: } catch (NumberFormatException nfe) {
280: message = e.getMessage();
281: }
282: } else {
283: message = e.getMessage();
284: }
285: return message;
286: }
287:
288: private void showMessageDialog(final String message,
289: final String title, final int messageType) {
290: final JFrame f = parent;
291: SwingUtilities.invokeLater(new Runnable() {
292: public void run() {
293: JOptionPane.showMessageDialog(f, message, title,
294: messageType);
295: }
296: });
297: }
298:
299: private void createProgressDialog() {
300: ActionListener listener = new ActionListener() {
301: public void actionPerformed(ActionEvent e) {
302: executor.cancel();
303: }
304: };
305: DualProgressBarDialog
306: .getDialog(
307: parent,
308: getMessage("CopyProgressMonitor.copyProgressDialogTitle"),
309: false, listener);
310: DualProgressBarDialog.startTimer();
311: }
312:
313: /**
314: * @param executor The executor to set.
315: */
316: public void setExecutor(CopyExecutor executor) {
317: this .executor = executor;
318: }
319:
320: /**
321: * @return Returns the executor.
322: */
323: public CopyExecutor getExecutor() {
324: return executor;
325: }
326:
327: /**
328: *
329: * @param tableName
330: * @return
331: */
332: private int showConfirmDeleteDialog(String tableName) {
333: final String message = getMessage(
334: "CopyProgressMonitor.deleteRecordsMessage", tableName);
335:
336: final ConfirmMessageResult result = new ConfirmMessageResult();
337:
338: final String[] buttons = { "Yes", "Yes to all", "No", "Cancel" };
339:
340: if (SwingUtilities.isEventDispatchThread()) {
341: result.option = JOptionPane.showOptionDialog(parent,
342: message, "Confirmation",
343: JOptionPane.DEFAULT_OPTION,
344: JOptionPane.QUESTION_MESSAGE, null, buttons,
345: buttons[2]);
346: } else {
347: try {
348: SwingUtilities.invokeAndWait(new Runnable() {
349: public void run() {
350: result.option = JOptionPane.showOptionDialog(
351: parent, message, "Confirmation",
352: JOptionPane.DEFAULT_OPTION,
353: JOptionPane.QUESTION_MESSAGE, null,
354: buttons, buttons[2]);
355: }
356: });
357: } catch (Exception e) {
358: log
359: .error(
360: "showConfirmDeleteDialog: encountered unexpected exception ",
361: e);
362: }
363: }
364: return result.option;
365: }
366:
367: private String showTextInputDialog(final Object message,
368: final String title, final int messageType, final Icon icon,
369: final Object initialValue) {
370:
371: final StringBuffer result = new StringBuffer();
372: if (SwingUtilities.isEventDispatchThread()) {
373: String tmp = (String) JOptionPane.showInputDialog(parent,
374: message, title, messageType, icon, null,
375: initialValue);
376: result.append(tmp);
377: } else {
378: try {
379: SwingUtilities.invokeAndWait(new Runnable() {
380: public void run() {
381: String tmp = (String) JOptionPane
382: .showInputDialog(parent, message,
383: title, messageType, icon, null,
384: initialValue);
385: result.append(tmp);
386: }
387: });
388: } catch (Exception e) {
389: log
390: .error(
391: "showTextInputDialog: encountered unexpected exception ",
392: e);
393: }
394: }
395: return result.toString();
396: }
397:
398: /* (non-Javadoc)
399: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.CopyPreference#deleteTableData(java.lang.String)
400: */
401: public boolean deleteTableData(String tableName)
402: throws UserCancelledOperationException {
403: if (deleteAllTableData) {
404: return true;
405: }
406: int option = showConfirmDeleteDialog(tableName);
407: if (option == 0) { // Yes
408: return true;
409: }
410: if (option == 1) { // Yes to all
411: deleteAllTableData = true;
412: return true;
413: }
414: if (option == 2) { // No
415: return false;
416: }
417: if (option == 3) { // Cancel
418: throw new UserCancelledOperationException();
419: }
420: return false;
421: }
422:
423: public boolean appendRecordsToExisting(String tableName) {
424: // TODO: Maybe prompt the user to ask to append the records,
425: // ignoring errors for constraint violations?
426: return false;
427: }
428:
429: class ConfirmMessageResult {
430: int option;
431: }
432:
433: /* (non-Javadoc)
434: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyTableListener#analyzingTable(net.sourceforge.squirrel_sql.plugins.dbcopy.event.TableEvent)
435: */
436: public void analyzingTable(TableEvent e) {
437: if (pm.isCanceled()) {
438:
439: }
440: // i18n[CopyProgressMonitor.analyzingTableMessage=Analyzing table ]
441: pm
442: .setNote(getMessage("CopyProgressMonitor.analyzingTableMessage")
443: + e.getTableName());
444: pm.setProgress(e.getTableNumber());
445: }
446:
447: /* (non-Javadoc)
448: * @see net.sourceforge.squirrel_sql.plugins.dbcopy.event.CopyTableListener#tableAnalysisStarted(net.sourceforge.squirrel_sql.plugins.dbcopy.event.AnalysisEvent)
449: */
450: public void tableAnalysisStarted(AnalysisEvent e) {
451: SessionInfoProvider prov = e.getSessionInfoProvider();
452: // TODO: set the total for the progress bar.
453: pm = new ProgressMonitor(parent,
454: "Analyzing column names in tables to be copied", "", 0,
455: prov.getSourceSelectedDatabaseObjects().length);
456:
457: }
458:
459: }
|