001: /*
002: * TableDefinitionPanel.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.dbobjects;
013:
014: import java.awt.BorderLayout;
015: import java.awt.Component;
016: import java.awt.Frame;
017: import java.awt.GridBagConstraints;
018: import java.awt.GridBagLayout;
019: import java.awt.Insets;
020: import java.awt.Window;
021: import java.awt.event.ActionEvent;
022: import java.awt.event.ActionListener;
023: import java.sql.SQLException;
024: import java.util.ArrayList;
025: import java.util.List;
026: import javax.swing.JLabel;
027: import javax.swing.JPanel;
028: import javax.swing.SwingUtilities;
029: import javax.swing.event.ListSelectionEvent;
030: import javax.swing.event.ListSelectionListener;
031: import javax.swing.table.TableColumn;
032: import javax.swing.table.TableColumnModel;
033: import workbench.db.ColumnDropper;
034: import workbench.db.ColumnIdentifier;
035: import workbench.db.DbMetadata;
036: import workbench.db.DbObject;
037: import workbench.db.TableIdentifier;
038: import workbench.db.WbConnection;
039: import workbench.gui.WbSwingUtilities;
040: import workbench.gui.actions.DropDbObjectAction;
041: import workbench.gui.actions.ReloadAction;
042: import workbench.gui.actions.WbAction;
043: import workbench.gui.components.DataStoreTableModel;
044: import workbench.gui.components.QuickFilterPanel;
045: import workbench.gui.components.WbScrollPane;
046: import workbench.gui.components.WbTable;
047: import workbench.gui.renderer.RendererFactory;
048: import workbench.gui.sql.ExecuteSqlDialog;
049: import workbench.interfaces.Reloadable;
050: import workbench.interfaces.Resettable;
051: import workbench.log.LogMgr;
052: import workbench.resource.ResourceMgr;
053: import workbench.storage.DataStore;
054: import workbench.util.ExceptionUtil;
055: import workbench.util.WbThread;
056:
057: /**
058: * A panel to display the table definition information inside the DbExplorer.
059: *
060: * @see workbench.db.DbMetadata#getTableDefinition(TableIdentifier)
061: *
062: * @author support@sql-workbench.net
063: */
064: public class TableDefinitionPanel extends JPanel implements Reloadable,
065: ActionListener, ListSelectionListener, Resettable, DbObjectList {
066: public static final String INDEX_PROP = "index";
067: private WbTable tableDefinition;
068: private JLabel tableNameLabel;
069: private QuickFilterPanel columnFilter;
070: private WbAction createIndexAction;
071: private TableIdentifier currentTable;
072: private WbConnection dbConnection;
073: private WbAction reloadAction;
074: private DropDbObjectAction dropColumnsAction;
075: private JPanel toolbar;
076: private boolean busy;
077:
078: public TableDefinitionPanel() {
079: this .tableDefinition = new WbTable(true, false, false);
080: this .tableDefinition.setAdjustToColumnLabel(false);
081: this .tableDefinition.setSelectOnRightButtonClick(true);
082: this .tableDefinition.getExportAction().setEnabled(true);
083:
084: this .reloadAction = new ReloadAction(this );
085: this .reloadAction.setEnabled(false);
086: this .reloadAction.addToInputMap(this .tableDefinition);
087:
088: toolbar = new JPanel(new GridBagLayout());
089:
090: String[] cols = new String[] { "COLUMN_NAME", "DATA_TYPE",
091: "PK", "NULLABLE", "DEFAULT", "REMARKS", "JAVA_TYPE" };
092: columnFilter = new QuickFilterPanel(this .tableDefinition, cols,
093: true, "columnlist");
094: columnFilter.addToToolbar(reloadAction, 0);
095: GridBagConstraints cc = new GridBagConstraints();
096:
097: cc.anchor = GridBagConstraints.WEST;
098: cc.fill = GridBagConstraints.HORIZONTAL;
099: cc.gridx = 0;
100: cc.weightx = 0.0;
101: cc.ipadx = 0;
102: cc.ipady = 0;
103: cc.insets = new Insets(0, 0, 0, 5);
104: toolbar.add(columnFilter, cc);
105:
106: JLabel l = new JLabel(ResourceMgr.getString("LblTable") + ":");
107: cc.fill = GridBagConstraints.NONE;
108: cc.gridx++;
109: cc.weightx = 0.0;
110: cc.insets = new Insets(0, 5, 0, 5);
111: toolbar.add(l, cc);
112:
113: //Font std = Settings.getInstance().getStandardLabelFont();
114: //Font bold = std.deriveFont(Font.BOLD);
115: tableNameLabel = new JLabel();
116: //tableNameLabel.setFont(bold);
117: cc.gridx++;
118: cc.weightx = 0.0;
119: cc.fill = GridBagConstraints.NONE;
120: cc.insets = new Insets(0, 0, 0, 0);
121: toolbar.add(tableNameLabel, cc);
122:
123: cc.gridx++;
124: cc.weightx = 1.0;
125: cc.fill = GridBagConstraints.HORIZONTAL;
126: toolbar.add(new JPanel(), cc);
127:
128: WbScrollPane scroll = new WbScrollPane(this .tableDefinition);
129: this .setLayout(new BorderLayout());
130: this .add(toolbar, BorderLayout.NORTH);
131: this .add(scroll, BorderLayout.CENTER);
132:
133: this .createIndexAction = new WbAction(this , "create-index");
134: this .createIndexAction.setEnabled(false);
135: this .createIndexAction.initMenuDefinition("MnuTxtCreateIndex");
136:
137: this .tableDefinition.getSelectionModel()
138: .addListSelectionListener(this );
139: this .tableDefinition.addPopupAction(this .createIndexAction,
140: true);
141: }
142:
143: protected void fireIndexChanged(String indexName) {
144: firePropertyChange(INDEX_PROP, null, indexName);
145: }
146:
147: public void showFocusBorder() {
148: this .tableDefinition.showFocusBorder();
149: }
150:
151: private final Object busyLock = new Object();
152:
153: public boolean isBusy() {
154: synchronized (this .busyLock) {
155: return busy;
156: }
157: }
158:
159: private void setBusy(boolean flag) {
160: synchronized (this .busyLock) {
161: busy = flag;
162: }
163: }
164:
165: /**
166: * Retrieve the definition of the given table.
167: */
168: public void retrieve(TableIdentifier table) throws SQLException {
169: this .currentTable = table;
170: this .tableDefinition.reset();
171: retrieveTableDefinition();
172: }
173:
174: protected void retrieveTableDefinition() throws SQLException {
175: if (this .isBusy())
176: return;
177:
178: synchronized (this .dbConnection) {
179: try {
180: WbSwingUtilities.invoke(new Runnable() {
181: public void run() {
182: reloadAction.setEnabled(false);
183: String msg = "<html>"
184: + ResourceMgr
185: .getString("TxtRetrieveTableDef")
186: + " <b>" + currentTable.getTableName()
187: + "</b></html>";
188: tableNameLabel.setText(msg);
189: }
190: });
191: DbMetadata meta = this .dbConnection.getMetadata();
192: DataStore def = meta
193: .getTableDefinition(this .currentTable);
194: final DataStoreTableModel model = new DataStoreTableModel(
195: def);
196: WbSwingUtilities.invoke(new Runnable() {
197: public void run() {
198: applyTableModel(model);
199: }
200: });
201: } catch (SQLException e) {
202: tableNameLabel.setText(ExceptionUtil.getDisplay(e));
203: throw e;
204: } finally {
205: reloadAction.setEnabled(true);
206: setBusy(false);
207: }
208: }
209: }
210:
211: protected void applyTableModel(DataStoreTableModel model) {
212: tableDefinition
213: .setPrintHeader(this .currentTable.getTableName());
214: tableDefinition.setAutoCreateColumnsFromModel(true);
215: tableDefinition.setModel(model, true);
216: tableDefinition.adjustOrOptimizeColumns();
217:
218: // remove the last three columns if we are not displaying a SEQUENCE
219: // these columns are "SCALE/SIZE", "PRECISION" and "POSITION"
220: // they don't need to be displayed as this is "included" in the
221: // displayed (DBMS) data type already
222: if (!"SEQUENCE".equalsIgnoreCase(this .currentTable.getType())) {
223: TableColumnModel colmod = tableDefinition.getColumnModel();
224:
225: // Assign the correct renderer to display java.sql.Types values
226: TableColumn col = colmod
227: .getColumn(DbMetadata.COLUMN_IDX_TABLE_DEFINITION_JAVA_SQL_TYPE);
228: col.setCellRenderer(RendererFactory.getSqlTypeRenderer());
229:
230: try {
231: if (colmod.getColumnCount() == DbMetadata.TABLE_DEFINITION_COLS.length) {
232: for (int i = 0; i < 3; i++) {
233: col = colmod
234: .getColumn(colmod.getColumnCount() - 1);
235: colmod.removeColumn(col);
236: }
237: }
238: } catch (Throwable e) {
239: LogMgr.logError(
240: "TableDefinitionPanel.applyTableModel()",
241: "Error when applying the table model", e);
242: }
243: }
244: tableNameLabel.setText("<html><b>"
245: + currentTable.getTableName() + "</b></html>");
246: }
247:
248: public void reset() {
249: this .currentTable = null;
250: this .tableDefinition.reset();
251: reloadAction.setEnabled(false);
252: }
253:
254: private DropDbObjectAction getDropColumnAction() {
255: if (this .dropColumnsAction == null) {
256: dropColumnsAction = new DropDbObjectAction(
257: "MnuTxtDropColumn", this , tableDefinition
258: .getSelectionModel(), this );
259: dropColumnsAction.setDropper(new ColumnDropper());
260: }
261: return dropColumnsAction;
262: }
263:
264: public void setConnection(WbConnection conn) {
265: this .dbConnection = conn;
266: this .createIndexAction.setEnabled(this .dbConnection != null);
267: this .reloadAction.setEnabled(this .dbConnection != null);
268: if (dbConnection != null
269: && dbConnection.getDbSettings().canDropType("column")) {
270: DropDbObjectAction action = getDropColumnAction();
271: action.setAvailable(true);
272: this .tableDefinition.addPopupAction(action, false);
273: } else if (this .dropColumnsAction != null) {
274: dropColumnsAction.setAvailable(false);
275: }
276: }
277:
278: public void reload() {
279: if (this .currentTable == null)
280: return;
281: if (this .dbConnection == null)
282: return;
283:
284: this .tableDefinition.reset();
285:
286: WbThread t = new WbThread("TableDefinition Retrieve") {
287: public void run() {
288: try {
289: retrieveTableDefinition();
290: } catch (SQLException ex) {
291: LogMgr.logError("TableDefinitionPanel.reload()",
292: "Error loading table definition", ex);
293: }
294: }
295: };
296: t.start();
297: }
298:
299: public void actionPerformed(ActionEvent e) {
300: if (e.getSource() == this .createIndexAction) {
301: createIndex();
302: }
303: }
304:
305: public List<DbObject> getSelectedObjects() {
306: if (this .tableDefinition.getSelectedRowCount() <= 0)
307: return null;
308: int rows[] = this .tableDefinition.getSelectedRows();
309:
310: List<DbObject> columns = new ArrayList<DbObject>(rows.length);
311:
312: for (int i = 0; i < rows.length; i++) {
313: String column = this .tableDefinition.getValueAsString(
314: rows[i],
315: DbMetadata.COLUMN_IDX_TABLE_DEFINITION_COL_NAME);
316: columns.add(new ColumnIdentifier(column));
317: }
318: return columns;
319: }
320:
321: public Component getComponent() {
322: return this ;
323: }
324:
325: public WbConnection getConnection() {
326: return this .dbConnection;
327: }
328:
329: public TableIdentifier getObjectTable() {
330: return this .currentTable;
331: }
332:
333: protected void createIndex() {
334: if (this .tableDefinition.getSelectedRowCount() <= 0)
335: return;
336: int rows[] = this .tableDefinition.getSelectedRows();
337: int count = rows.length;
338: String[] columns = new String[count];
339: String indexName = ResourceMgr.getString("TxtNewIndexName");
340: //String indexName = WbSwingUtilities.getUserInput(this, msg, defaultName);
341: if (indexName == null || indexName.trim().length() == 0)
342: return;
343:
344: for (int i = 0; i < count; i++) {
345: columns[i] = this .tableDefinition.getValueAsString(rows[i],
346: DbMetadata.COLUMN_IDX_TABLE_DEFINITION_COL_NAME)
347: .toLowerCase();
348: }
349: String sql = this .dbConnection.getMetadata().buildIndexSource(
350: this .currentTable, indexName, false, columns);
351: String title = ResourceMgr
352: .getString("TxtWindowTitleCreateIndex");
353: Window parent = SwingUtilities.getWindowAncestor(this );
354: Frame owner = null;
355: if (parent != null && parent instanceof Frame) {
356: owner = (Frame) parent;
357: }
358: ExecuteSqlDialog dialog = new ExecuteSqlDialog(owner, title,
359: sql, indexName, this .dbConnection);
360: dialog.setStartButtonText(ResourceMgr
361: .getString("TxtCreateIndex"));
362: dialog.setVisible(true);
363: fireIndexChanged(indexName);
364: }
365:
366: /**
367: * Invoked when the selection in the table list has changed
368: */
369: public void valueChanged(ListSelectionEvent e) {
370: if (e.getValueIsAdjusting())
371: return;
372: if (e.getSource() == this .tableDefinition.getSelectionModel()) {
373: boolean rowsSelected = (this .tableDefinition
374: .getSelectedRowCount() > 0);
375: this .createIndexAction.setEnabled(rowsSelected);
376: }
377: }
378:
379: public String getSelectForTable() {
380: int colCount = this .tableDefinition.getRowCount();
381: if (colCount == 0)
382: return null;
383:
384: StringBuilder sql = new StringBuilder(colCount * 80);
385:
386: sql.append("SELECT ");
387: DbMetadata meta = this .dbConnection.getMetadata();
388: for (int i = 0; i < colCount; i++) {
389: String column = this .tableDefinition.getValueAsString(i,
390: DbMetadata.COLUMN_IDX_TABLE_DEFINITION_COL_NAME);
391: column = meta.quoteObjectname(column);
392: if (i > 0 && i < colCount)
393: sql.append(",\n");
394: if (i > 0)
395: sql.append(" ");
396: sql.append(column);
397: }
398: sql.append("\nFROM ");
399: sql.append(this .currentTable
400: .getTableExpression(this .dbConnection));
401: return sql.toString();
402: }
403:
404: public int getRowCount() {
405: return this .tableDefinition.getRowCount();
406: }
407:
408: public DataStore getDataStore() {
409: return this .tableDefinition.getDataStore();
410: }
411:
412: public void restoreSettings() {
413: this .columnFilter.restoreSettings();
414: }
415:
416: public void saveSettings() {
417: this.columnFilter.saveSettings();
418: }
419: }
|