001: /*
002: * The contents of this file are subject to the Mozilla Public License
003: * Version 1.1 (the "License"); you may not use this file except in
004: * compliance with the License. You may obtain a copy of the License at
005: * http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
009: * License for the specific language governing rights and limitations
010: * under the License.
011: *
012: * The Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
013: *
014: * The Initial Developer of the Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
015: * Portions created by Mark A. Kobold are Copyright (C) 2000-2007. All Rights Reserved.
016: *
017: * Contributor(s):
018: * Mark A. Kobold [mkobold <at> isqlviewer <dot> com].
019: *
020: * If you didn't download this code from the following link, you should check
021: * if you aren't using an obsolete version: http://www.isqlviewer.com
022: */
023: package org.isqlviewer.ui;
024:
025: import java.awt.Frame;
026: import java.awt.GridBagConstraints;
027: import java.awt.GridBagLayout;
028: import java.awt.event.ActionEvent;
029: import java.awt.event.ActionListener;
030: import java.sql.ResultSet;
031: import java.sql.SQLException;
032: import java.sql.SQLWarning;
033: import java.sql.Statement;
034: import java.text.MessageFormat;
035: import java.util.Properties;
036: import java.util.concurrent.atomic.AtomicBoolean;
037: import java.util.prefs.Preferences;
038:
039: import javax.swing.BoundedRangeModel;
040: import javax.swing.Box;
041: import javax.swing.Icon;
042: import javax.swing.JButton;
043: import javax.swing.JComponent;
044: import javax.swing.JLabel;
045: import javax.swing.JMenuBar;
046: import javax.swing.JPanel;
047: import javax.swing.JProgressBar;
048:
049: import org.apache.log4j.Logger;
050: import org.isqlviewer.sql.ResultSetRenderer;
051: import org.isqlviewer.swing.EnhancedTabbedPane;
052: import org.isqlviewer.swing.SwingUtilities;
053: import org.isqlviewer.swing.WizardPanel;
054: import org.isqlviewer.swing.action.SwingEventManager;
055: import org.isqlviewer.swing.table.EnhancedTableModel;
056: import org.isqlviewer.swing.table.ResultSetTableModel;
057: import org.isqlviewer.util.IsqlToolkit;
058: import org.isqlviewer.util.LocalMessages;
059:
060: /**
061: * Resultset handler that translate query results into tables within an EnhancedTabbedPane.
062: * <p>
063: *
064: * @author Mark A. Kobold <mkobold at isqlviewer dot com>
065: * @version 1.0
066: */
067: public class TabbedResultsetRenderer implements ResultSetRenderer {
068:
069: private static final long serialVersionUID = 1199835121337623550L;
070: private static final String BUNDLE_NAME = "org.isqlviewer.ui.ResourceBundle";
071: private LocalMessages messages = new LocalMessages(BUNDLE_NAME);
072:
073: private Preferences preferences = Preferences.userRoot().node(
074: IsqlToolkit.getRootPreferencesNode());
075: private MessageFormat choiceNodeFormat = new MessageFormat(
076: "string-substitutions/{0}");
077: private AtomicBoolean isCancelled = new AtomicBoolean(false);
078:
079: private Properties currentSubstitutions = new Properties();
080: private BusyQueryIndicator eyeCandy = null;
081: private EnhancedTabbedPane tabbedPane = null;
082:
083: public TabbedResultsetRenderer(EnhancedTabbedPane container) {
084:
085: if (container == null) {
086: throw new NullPointerException();
087: }
088: this .tabbedPane = container;
089: }
090:
091: public void initialize() {
092:
093: synchronized (isCancelled) {
094: isCancelled.set(false);
095: }
096: currentSubstitutions.clear();
097: JPanel componentView = new JPanel();
098: eyeCandy = new BusyQueryIndicator(isCancelled);
099: eyeCandy.doLayout(componentView, null, null);
100: int index = tabbedPane.getTabCount();
101: tabbedPane.addTab("", SwingUtilities.loadIconResource(
102: "busy_animation", 16), componentView);
103: tabbedPane.setClosableTab(index, false);
104: }
105:
106: public void statementInitialized(String stmtID, Statement statement) {
107:
108: synchronized (isCancelled) {
109: isCancelled.set(false);
110: }
111: eyeCandy
112: .updateStatus(messages.format(
113: "TabbedResultsetRenderer.statement_initalized",
114: stmtID));
115: eyeCandy.setStatement(statement);
116: }
117:
118: public void handleSQLException(SQLException error) {
119:
120: ThrowableView view = new ThrowableView(error, "");
121: JPanel parentComponent = new JPanel();
122: view.doLayout(parentComponent, null, null);
123: String tabText = "ERROR";
124: Icon tabIcon = SwingUtilities.loadIconResource("fatal_error",
125: 16);
126: JComponent componentView = eyeCandy.getComponentView();
127: int index = tabbedPane.indexOfComponent(componentView);
128: if (index < 0) {
129: tabbedPane.addTab("error", componentView);
130: index = tabbedPane.indexOfComponent(componentView);
131: }
132: tabbedPane.setToolTipTextAt(index, "ERROR");
133: tabbedPane.setTitleAt(index, tabText);
134: tabbedPane.setComponentAt(index, parentComponent);
135: tabbedPane.setClosableTab(index, true);
136: tabbedPane.setIconAt(index, tabIcon);
137: tabbedPane.setSelectedIndex(index);
138: }
139:
140: public long processResultSet(String stmtID, ResultSet set,
141: String nativeSQL, int count) {
142:
143: eyeCandy.updateStatus(messages.format(
144: "TabbedResultsetRenderer.process_resultset", stmtID));
145: try {
146: ResultSetTableModel model = new ResultSetTableModel();
147: model.setResults(set, this );
148: eyeCandy.setQueryData(model);
149: return model.getTrueRowCount();
150: } catch (SQLException error) {
151: handleSQLException(error);
152: }
153: return -1;
154: }
155:
156: public void recieveResultsetWarnings(ResultSet set,
157: SQLWarning warnings) {
158:
159: eyeCandy.updateStatus(messages
160: .format("TabbedResultsetRenderer.resultset_warnings"));
161: }
162:
163: public void recieveStatementWarnings(Statement stmt,
164: SQLWarning warnings) {
165:
166: eyeCandy.updateStatus(messages
167: .format("TabbedResultsetRenderer.statement_warnings"));
168: }
169:
170: public void processRowUpdates(String stmtID, int updateCount,
171: String nativeSQL) {
172:
173: eyeCandy.updateStatus(messages.format(
174: "TabbedResultsetRenderer.row_updates", Integer
175: .toString(updateCount)));
176: Logger logger = IsqlToolkit.getApplicationLogger();
177: logger.info(messages.format(
178: "tabbedresultsetrenderer.rows_affected", new Integer(
179: updateCount)));
180: }
181:
182: public void finalizeStatement(String stmtID) {
183:
184: eyeCandy.updateStatus(messages.format(
185: "TabbedResultsetRenderer.finalize_statement", stmtID));
186:
187: String html = "";
188: EnhancedTableModel resultSet = eyeCandy.getQueryData();
189: JComponent componentView = eyeCandy.getComponentView();
190: if (resultSet != null) {
191: String str = "";
192: Icon ico = null;
193: str = "Resultset";
194: ico = SwingUtilities.loadIconResource("table", 16);
195: int index = tabbedPane.indexOfComponent(componentView);
196: if (index < 0) {
197: tabbedPane.addTab("", componentView);
198: index = tabbedPane.indexOfComponent(componentView);
199: }
200: DataGrid dataGrid = new DataGrid();
201: componentView.removeAll();
202: dataGrid.doLayout(componentView, null, null);
203: dataGrid.setModel(eyeCandy.getQueryData());
204: tabbedPane.setToolTipTextAt(index, html);
205: tabbedPane.setTitleAt(index, str);
206: tabbedPane.setComponentAt(index, componentView);
207: tabbedPane.setClosableTab(index, true);
208: tabbedPane.setIconAt(index, ico);
209: tabbedPane.setSelectedIndex(index);
210: } else {
211: int index = tabbedPane.indexOfComponent(componentView);
212: if (index >= 0) {
213: tabbedPane.removeTabAt(index);
214: }
215: }
216: tabbedPane.invalidate();
217: eyeCandy.destroy();
218: }
219:
220: public void processGeneratedKeys(String stmtID, ResultSet keys,
221: String nativeSQL) {
222:
223: eyeCandy.updateStatus(messages.format(
224: "TabbedResultsetRenderer.processing_generated_keys",
225: stmtID));
226: processResultSet(stmtID, keys, nativeSQL, Integer.MIN_VALUE);
227: }
228:
229: public boolean supportsGeneratedKeys() {
230:
231: return true;
232: }
233:
234: public boolean supportsUpdateableResultSets() {
235:
236: return false;
237: }
238:
239: public boolean isCancelled() {
240:
241: return isCancelled.get();
242: }
243:
244: public String substituteVariable(String variableName) {
245:
246: eyeCandy
247: .updateStatus(messages
248: .format("TabbedResultsetRenderer.processing_variable_substitutions"));
249: String normalized = variableName.toLowerCase().trim();
250: normalized = normalized.replace('.', '-');
251: String existingInput = currentSubstitutions
252: .getProperty(normalized);
253: if (existingInput != null) {
254: return existingInput;
255: }
256:
257: Object[] arguments = new Object[] { normalized };
258: Preferences previousChoices = preferences.node(choiceNodeFormat
259: .format(arguments));
260: Frame frameOwner = (Frame) javax.swing.SwingUtilities
261: .getAncestorOfClass(Frame.class, tabbedPane);
262: VariableSubstitutor substitutor = new VariableSubstitutor(
263: frameOwner, variableName, previousChoices);
264: substitutor.setVisible(true);
265: String selection = substitutor.getSubstitution();
266: if (selection != null) {
267: long existing = previousChoices.getLong(selection, 0);
268: previousChoices.putLong(selection, existing++);
269: currentSubstitutions.put(normalized, selection);
270: }
271: return selection;
272: }
273:
274: public EnhancedTabbedPane getTabbedPane() {
275:
276: return tabbedPane;
277: }
278:
279: private static class BusyQueryIndicator extends
280: AbstractApplicationView implements ActionListener {
281:
282: private JProgressBar progressBar = null;
283: private JButton cancelButton = null;
284: private JLabel statusLabel = null;
285: private AtomicBoolean isCancelled = null;
286: private EnhancedTableModel queryData = null;
287: private JComponent componentView = null;
288: private Statement statement = null;
289: private LocalMessages msgs = new LocalMessages(BUNDLE_NAME);
290:
291: public BusyQueryIndicator(AtomicBoolean isCancelled) {
292:
293: this .isCancelled = isCancelled;
294: }
295:
296: public void destroy() {
297:
298: progressBar = null;
299: cancelButton = null;
300: statusLabel = null;
301: isCancelled = null;
302: queryData = null;
303: componentView = null;
304: statement = null;
305: }
306:
307: public void setStatement(Statement statement) {
308:
309: this .statement = statement;
310: }
311:
312: public void updateStatus(String text) {
313:
314: statusLabel.setText(text);
315: BoundedRangeModel model = progressBar.getModel();
316: model.setValue(model.getValue() + 1);
317: }
318:
319: public void configureMenubar(JMenuBar menuBar) {
320:
321: }
322:
323: public void disposeView(Preferences preferences) {
324:
325: }
326:
327: public void doLayout(JComponent parentComponent,
328: Preferences preferences, SwingEventManager eventManager) {
329:
330: Object obj = null;
331:
332: this .componentView = parentComponent;
333: JPanel container = new JPanel(new GridBagLayout());
334: parentComponent.setLayout(new WizardPanel.Layout());
335: parentComponent.add(container);
336:
337: obj = constrain(1, 1, 1, 1, 1.0, 0.0,
338: GridBagConstraints.CENTER,
339: GridBagConstraints.HORIZONTAL);
340: progressBar = new JProgressBar(JProgressBar.HORIZONTAL, 1,
341: 6);
342: container.add(progressBar, obj);
343:
344: statusLabel = new JLabel(SwingUtilities.loadIconResource(
345: "information", 16));
346: obj = constrain(1, 2, 2, 1, 1.0, 0.0,
347: GridBagConstraints.CENTER,
348: GridBagConstraints.HORIZONTAL);
349: container.add(statusLabel, obj);
350:
351: cancelButton = new JButton(
352: msgs
353: .format("TabbedResultsetRenderer.cancel_button.text"));
354: cancelButton
355: .setToolTipText(msgs
356: .format("TabbedResultsetRenderer.cancel_button.tip"));
357: cancelButton.addActionListener(this );
358: obj = constrain(2, 1, 1, 1, 0.0, 0.0,
359: GridBagConstraints.CENTER, GridBagConstraints.NONE);
360: container.add(cancelButton, obj);
361:
362: obj = constrain(1, 3, 1, 1, 0.0, 1.0,
363: GridBagConstraints.CENTER,
364: GridBagConstraints.VERTICAL);
365: container.add(Box.createVerticalGlue(), obj);
366:
367: obj = constrain(1, 0, 1, 1, 0.0, 1.0,
368: GridBagConstraints.CENTER,
369: GridBagConstraints.VERTICAL);
370: container.add(Box.createVerticalGlue(), obj);
371: }
372:
373: public void initializeView() {
374:
375: }
376:
377: public void actionPerformed(ActionEvent e) {
378:
379: synchronized (isCancelled) {
380: isCancelled.set(true);
381: if (statement != null) {
382: try {
383: statement.cancel();
384: } catch (SQLException error) {
385: Logger logger = IsqlToolkit
386: .getApplicationLogger();
387: String text = msgs
388: .format("TabbedResultsetRenderer.statement_cancel_failed");
389: logger.warn(text, error);
390: }
391: }
392: }
393: cancelButton.setEnabled(false);
394: }
395:
396: public EnhancedTableModel getQueryData() {
397:
398: return queryData;
399: }
400:
401: public void setQueryData(EnhancedTableModel queryData) {
402:
403: this .queryData = queryData;
404: }
405:
406: public JComponent getComponentView() {
407:
408: return componentView;
409: }
410: }
411: }
|