001: /*
002: * TableDefinitionPanel.java
003: *
004: * Copyright (C) 2002, 2003, 2004, 2005, 2006 Takis Diakoumis
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021:
022: package org.executequery.gui.table;
023:
024: import java.awt.GridBagConstraints;
025: import java.awt.GridBagLayout;
026: import java.awt.Insets;
027: import java.awt.Point;
028: import java.awt.event.ActionEvent;
029: import java.awt.event.FocusListener;
030: import java.awt.event.KeyAdapter;
031: import java.awt.event.KeyEvent;
032: import java.awt.event.MouseEvent;
033: import java.awt.event.MouseListener;
034:
035: import java.util.Vector;
036:
037: import javax.swing.DefaultCellEditor;
038: import javax.swing.JPanel;
039: import javax.swing.JScrollPane;
040: import javax.swing.JTable;
041: import javax.swing.SwingUtilities;
042: import javax.swing.event.ChangeEvent;
043: import javax.swing.event.TableModelEvent;
044: import javax.swing.event.TableModelListener;
045: import javax.swing.table.TableCellEditor;
046: import javax.swing.table.TableColumnModel;
047: import javax.swing.table.TableModel;
048: import org.executequery.GUIUtilities;
049: import org.underworldlabs.swing.print.AbstractPrintableTableModel;
050: import org.executequery.gui.browser.ColumnData;
051: import org.executequery.components.table.BrowsingCellEditor;
052: import org.executequery.gui.DefaultTable;
053: import org.executequery.util.Log;
054: import org.underworldlabs.swing.table.NumberCellEditor;
055: import org.underworldlabs.swing.table.StringCellEditor;
056:
057: /* ----------------------------------------------------------
058: * CVS NOTE: Changes to the CVS repository prior to the
059: * release of version 3.0.0beta1 has meant a
060: * resetting of CVS revision numbers.
061: * ----------------------------------------------------------
062: */
063:
064: /**
065: *
066: * @author Takis Diakoumis
067: * @version $Revision: 1.7 $
068: * @date $Date: 2006/07/16 15:46:54 $
069: */
070: public abstract class TableDefinitionPanel extends JPanel implements
071: TableModelListener {
072:
073: /** The table containing all column descriptions */
074: protected DatabaseTable table;
075:
076: /** The table's _model */
077: protected CreateTableModel _model;
078:
079: /** The cell editor for the column names */
080: protected static StringCellEditor colNameEditor;
081:
082: /** The cell editor for the column size */
083: protected NumberCellEditor sizeEditor;
084:
085: /** The cell editor for the column scale */
086: protected NumberCellEditor scaleEditor;
087:
088: /** The cell editor for the datatype column */
089: //protected ComboBoxCellEditor comboCell;
090: /** The cell editor for the datatype column */
091: protected DataTypeSelectionTableCell dataTypeCell;
092:
093: /** The <code>Vector</code> of <code>ColumnData</code> objects */
094: protected Vector<ColumnData> tableVector;
095:
096: /** The literal 'PK' */
097: private static final String PRIMARY = "PK";
098:
099: /** The literal 'FK' */
100: private static final String FOREIGN = "FK";
101:
102: /** The literal 'FK' */
103: private static final String PRIMARY_AND_FOREIGN = "PKFK";
104:
105: /** An empty String literal */
106: private static final String EMPTY = " ";
107:
108: protected boolean editing;
109:
110: /** the available data types */
111: private String[] dataTypes;
112:
113: public TableDefinitionPanel() {
114: this (true, null);
115: }
116:
117: public TableDefinitionPanel(boolean editing, String[] dataTypes) {
118: super (new GridBagLayout());
119: this .editing = editing;
120: this .dataTypes = dataTypes;
121:
122: try {
123: jbInit();
124: } catch (Exception e) {
125: //e.printStackTrace();
126: }
127:
128: }
129:
130: private void jbInit() throws Exception {
131: // set the table model to use
132: _model = new CreateTableModel();
133: table = new DatabaseTable(_model);
134:
135: TableColumnModel tcm = table.getColumnModel();
136: tcm.getColumn(0).setPreferredWidth(25);
137: //tcm.getColumn(0).setMinWidth(25);
138: tcm.getColumn(0).setMaxWidth(25);
139: tcm.getColumn(1).setPreferredWidth(200);
140: tcm.getColumn(2).setPreferredWidth(130);
141: tcm.getColumn(3).setPreferredWidth(50);
142: tcm.getColumn(4).setPreferredWidth(50);
143: //tcm.getColumn(5).setPreferredWidth(60);
144: tcm.getColumn(5).setPreferredWidth(70);
145: tcm.getColumn(5).setMaxWidth(70);
146:
147: tcm.getColumn(0).setCellRenderer(new KeyCellRenderer());
148:
149: // add the editors if editing
150: if (editing) {
151: colNameEditor = new StringCellEditor();
152: DefaultCellEditor colStrEditor = new DefaultCellEditor(
153: colNameEditor) {
154: public Object getCellEditorValue() {
155: return colNameEditor.getValue();
156: }
157: };
158: tcm.getColumn(1).setCellEditor(colStrEditor);
159: //tcm.getColumn(5).setCellEditor(colStrEditor);
160:
161: scaleEditor = new NumberCellEditor();
162: DefaultCellEditor scEditor = new DefaultCellEditor(
163: scaleEditor) {
164: public Object getCellEditorValue() {
165: return scaleEditor.getStringValue();
166: }
167: };
168:
169: sizeEditor = new NumberCellEditor();
170: DefaultCellEditor szEditor = new DefaultCellEditor(
171: sizeEditor) {
172: public Object getCellEditorValue() {
173: return sizeEditor.getStringValue();
174: }
175: };
176: tcm.getColumn(3).setCellEditor(szEditor);
177: tcm.getColumn(4).setCellEditor(scEditor);
178:
179: dataTypeCell = new DataTypeSelectionTableCell();
180: tcm.getColumn(2).setCellRenderer(dataTypeCell);
181: tcm.getColumn(2).setCellEditor(dataTypeCell);
182:
183: // create the key listener to notify changes
184: KeyAdapter valueKeyListener = new KeyAdapter() {
185: public void keyReleased(KeyEvent e) {
186: String value = null;
187: Object object = e.getSource();
188: if (object == colNameEditor) {
189: value = colNameEditor.getValue();
190: } else if (object == sizeEditor) {
191: value = sizeEditor.getEditorValue();
192: } else if (object == scaleEditor) {
193: value = scaleEditor.getEditorValue();
194: } else if (object == dataTypeCell.getComponent()) {
195: value = dataTypeCell.getEditorValue();
196: }
197: tableChanged(table.getEditingColumn(), table
198: .getEditingRow(), value);
199: }
200: };
201: colNameEditor.addKeyListener(valueKeyListener);
202: dataTypeCell.addKeyListener(valueKeyListener);
203: sizeEditor.addKeyListener(valueKeyListener);
204: scaleEditor.addKeyListener(valueKeyListener);
205:
206: _model.addTableModelListener(this );
207: }
208:
209: //setPreferredSize(new Dimension(460, 150));
210: //setPreferredSize(new Dimension(500, 150));
211: add(new JScrollPane(table), new GridBagConstraints(1, 1, 1, 1,
212: 1.0, 1.0, GridBagConstraints.SOUTHEAST,
213: GridBagConstraints.BOTH, new Insets(2, 2, 2, 2), 0, 0));
214:
215: }
216:
217: public void setColumnDataArray(ColumnData[] cda) {
218: _model.setColumnDataArray(cda);
219: }
220:
221: public void setColumnDataArray(ColumnData[] cda, String[] dataTypes) {
222: _model.setColumnDataArray(cda);
223: this .dataTypes = dataTypes;
224: /*
225: if (dataTypes != null) {
226: comboCell.setSelectionValues(dataTypes);
227: }
228: */
229: }
230:
231: /**
232: * Sets the available data types to the values specified.
233: *
234: * @param the data type values
235: */
236: public void setDataTypes(String[] dataTypes) {
237: this .dataTypes = dataTypes;
238: /*
239: if (dataTypes != null) {
240: comboCell.setSelectionValues(dataTypes);
241: }
242: */
243: }
244:
245: public void tableChanged(TableModelEvent e) {
246: //Log.debug("tableChanged");
247: int row = table.getEditingRow();
248: if (row == -1) {
249: return;
250: }
251: tableChanged(table.getEditingColumn(), row, null);
252: }
253:
254: /**
255: * Fires that a table cell value has changed as specified.
256: *
257: * @param col - the column index
258: * @param row - the row index
259: * @param value - the current value
260: */
261: public abstract void tableChanged(int col, int row, String value);
262:
263: /** <p>Adds all the column definition lines to
264: * the SQL text buffer for display.
265: *
266: * @param the current row being edited
267: */
268: public abstract void addColumnLines(int row);
269:
270: /** <p>Moves the selected column up one row within
271: * the table moving the column above the selection
272: * below the selection.
273: */
274: public void moveColumnUp() {
275: int selection = table.getSelectedRow();
276: if (selection == -1 || selection == 0) {
277: return;
278: }
279:
280: table.editingStopped(null);
281: if (table.isEditing()) {
282: table.removeEditor();
283: }
284:
285: int newPostn = selection - 1;
286: ColumnData move = tableVector.elementAt(selection);
287: tableVector.removeElementAt(selection);
288: tableVector.add(newPostn, move);
289: table.setRowSelectionInterval(newPostn, newPostn);
290: _model.fireTableRowsUpdated(newPostn, selection);
291: addColumnLines(-1);
292: }
293:
294: public void tableEditingStopped(ChangeEvent e) {
295: table.editingStopped(e);
296: }
297:
298: public int getEditingRow() {
299: return table.getEditingRow();
300: }
301:
302: public void setEditingRow(int newEditingRow) {
303: table.setEditingRow(newEditingRow);
304: }
305:
306: public int getSelectedRow() {
307: return table.getSelectedRow();
308: }
309:
310: public int getEditingColumn() {
311: return table.getEditingColumn();
312: }
313:
314: public void addTableFocusListener(FocusListener listener) {
315: table.addFocusListener(listener);
316: }
317:
318: /** <p>Propogates the call to <code>removeEditor()</code>
319: * on the table displaying the data. */
320: public void removeEditor() {
321: table.removeEditor();
322: }
323:
324: /** <p>Propogates the call to <code>isEditing()</code>
325: * on the table displaying the data.
326: *
327: * @return if a data edit is in progress on the table
328: */
329: public boolean isEditing() {
330: return table.isEditing();
331: }
332:
333: /** <p>Returns the table displaying the
334: * column data.
335: *
336: * @return the table displaying the data
337: */
338: public JTable getTable() {
339: return table;
340: }
341:
342: /** <p>Moves the selected column down one row within
343: * the table moving the column below the selection
344: * above the selection. */
345: public void moveColumnDown() {
346: int selection = table.getSelectedRow();
347: if (selection == -1 || selection == tableVector.size() - 1) {
348: return;
349: }
350:
351: table.editingStopped(null);
352: if (table.isEditing()) {
353: table.removeEditor();
354: }
355:
356: int newPostn = selection + 1;
357: ColumnData move = tableVector.elementAt(selection);
358: tableVector.removeElementAt(selection);
359: tableVector.add(newPostn, move);
360: table.setRowSelectionInterval(newPostn, newPostn);
361: _model.fireTableRowsUpdated(selection, newPostn);
362: addColumnLines(-1);
363: }
364:
365: /** <p>Inserts a new column before the selected
366: * column moving the selected column down one row. */
367: public void insertBefore() {
368: fireEditingStopped();
369:
370: if (table.isEditing()) {
371: table.removeEditor();
372: }
373:
374: int selection = table.getSelectedRow();
375: if (selection == -1) {
376: return;
377: } else {
378: tableVector.insertElementAt(new ColumnData(), selection);
379: }
380:
381: _model.fireTableRowsInserted(
382: selection == 0 ? 0 : selection - 1, selection == 0 ? 1
383: : selection);
384:
385: table.setRowSelectionInterval(selection, selection);
386: table.setColumnSelectionInterval(1, 1);
387:
388: table.setEditingRow(selection);
389: table.setEditingColumn(1);
390:
391: }
392:
393: public void fireEditingStopped() {
394: table.editingStopped(null);
395: if (table.isEditing()) {
396: table.removeEditor();
397: }
398: }
399:
400: /** <p>Deletes the selected row from the table.
401: * This will also modify the SQL generated text. */
402: public void deleteRow() {
403: table.editingStopped(null);
404: if (table.isEditing()) {
405: table.removeEditor();
406: }
407:
408: int selection = table.getSelectedRow();
409: if (selection == -1 || tableVector.size() == 0) {
410: return;
411: }
412:
413: tableVector.removeElementAt(selection);
414: _model.fireTableRowsDeleted(selection, selection);
415:
416: if (tableVector.size() == 0) {
417: tableVector.addElement(new ColumnData(true));
418: _model.fireTableRowsInserted(0, 0);
419: }
420:
421: addColumnLines(-1);
422: }
423:
424: public void addMouseListener() {
425: table.addMouseListener();
426: }
427:
428: /** <p>Inserts a new column after the selected
429: * column moving the selected column up one row. */
430: public void insertAfter() {
431: fireEditingStopped();
432: int selection = table.getSelectedRow();
433: int newRow = selection + 1;
434:
435: if (selection == -1) {
436: return;
437: } else if (selection == tableVector.size()) {
438: tableVector.add(new ColumnData());
439: } else {
440: tableVector.add(newRow, new ColumnData());
441: }
442:
443: _model.fireTableRowsInserted(selection, newRow);
444: table.setRowSelectionInterval(newRow, newRow);
445: table.setColumnSelectionInterval(1, 1);
446:
447: table.setEditingRow(newRow);
448: table.setEditingColumn(1);
449: ((DefaultCellEditor) table.getCellEditor(newRow, 1))
450: .getComponent().requestFocus();
451: }
452:
453: public TableCellEditor getCellEditor(int row, int col) {
454: return table.getCellEditor(row, col);
455: }
456:
457: public void setEditingColumn(int col) {
458: table.setEditingColumn(col);
459: }
460:
461: public void setRowSelectionInterval(int row) {
462: table.setRowSelectionInterval(row, row);
463: }
464:
465: public void setColumnSelectionInterval(int col) {
466: table.setColumnSelectionInterval(col, col);
467: }
468:
469: public void setTableColumnData(ColumnData[] cda) {
470: tableVector = new Vector(cda.length);
471: for (int i = 0; i < cda.length; i++) {
472: tableVector.add(cda[i]);
473: }
474: _model.fireTableDataChanged();
475: addColumnLines(-1);
476: }
477:
478: public ColumnData[] getTableColumnData() {
479: int v_size = tableVector.size();
480: ColumnData[] cda = new ColumnData[v_size];
481:
482: for (int i = 0; i < v_size; i++) {
483: cda[i] = tableVector.elementAt(i);
484: }
485: return cda;
486: }
487:
488: public abstract String getSQLText();
489:
490: public Vector getTableColumnDataVector() {
491: return tableVector;
492: }
493:
494: /**
495: * The table view display.
496: */
497: private class DatabaseTable extends DefaultTable implements
498: MouseListener {
499:
500: public DatabaseTable(TableModel _model) {
501: super (_model);
502: //setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
503: getTableHeader().setReorderingAllowed(false);
504: setRowHeight(20);
505: setCellSelectionEnabled(true);
506: setColumnSelectionAllowed(false);
507: setRowSelectionAllowed(false);
508: setSurrendersFocusOnKeystroke(true);
509: }
510:
511: public void addMouseListener() {
512: addMouseListener(this );
513: }
514:
515: public void mouseClicked(MouseEvent e) {
516: int mouseX = e.getX();
517: int mouseY = e.getY();
518:
519: int col = columnAtPoint(new Point(mouseX, mouseY));
520: if (col != 0) {
521: return;
522: }
523:
524: ColumnData[] cda = getTableColumnData();
525: int row = rowAtPoint(new Point(mouseX, mouseY));
526: for (int i = 0; i < cda.length; i++) {
527: if (i == row && !cda[i].isPrimaryKey()) {
528: cda[i].setPrimaryKey(true);
529: } else {
530: cda[i].setPrimaryKey(false);
531: }
532: }
533:
534: _model.fireTableRowsUpdated(0, cda.length);
535: addColumnLines(-1);
536: }
537:
538: public void mouseEntered(MouseEvent e) {
539: }
540:
541: public void mouseExited(MouseEvent e) {
542: }
543:
544: public void mousePressed(MouseEvent e) {
545: }
546:
547: public void mouseReleased(MouseEvent e) {
548: }
549:
550: } // class DatabaseTable
551:
552: /**
553: * The table's model.
554: */
555: protected class CreateTableModel extends
556: AbstractPrintableTableModel {
557:
558: protected String[] header = { EMPTY, "Name", "Datatype",
559: "Size", "Scale", "Required" };
560:
561: public CreateTableModel() {
562: tableVector = new Vector<ColumnData>();
563: tableVector.addElement(new ColumnData());
564: }
565:
566: public CreateTableModel(Vector<ColumnData> data) {
567: tableVector = data;
568: }
569:
570: public void setColumnDataArray(ColumnData[] cda) {
571:
572: if (cda != null) {
573: if (tableVector == null) {
574: tableVector = new Vector<ColumnData>(cda.length);
575: } else {
576: tableVector.clear();
577: }
578:
579: for (int i = 0; i < cda.length; i++) {
580: tableVector.add(cda[i]);
581: }
582: } else {
583: tableVector.clear();
584: }
585:
586: fireTableDataChanged();
587: }
588:
589: public int getColumnCount() {
590: return header.length;
591: }
592:
593: public int getRowCount() {
594: return tableVector.size();
595: }
596:
597: /**
598: * Returns the printable value at the specified row and column.
599: *
600: * @param row - the row index
601: * @param col - the column index
602: * @return the value to print
603: */
604: public String getPrintValueAt(int row, int col) {
605: if (col > 0) {
606: Object value = getValueAt(row, col);
607: if (value != null) {
608: return value.toString();
609: }
610: return EMPTY;
611: } else {
612: ColumnData cd = tableVector.elementAt(row);
613: if (cd.isPrimaryKey()) {
614: if (cd.isForeignKey()) {
615: return "PFK";
616: }
617: return "PK";
618: } else if (cd.isForeignKey()) {
619: return "FK";
620: }
621: return EMPTY;
622: }
623: }
624:
625: public Object getValueAt(int row, int col) {
626:
627: if (row >= tableVector.size()) {
628: return null;
629: }
630:
631: ColumnData cd = tableVector.elementAt(row);
632:
633: switch (col) {
634:
635: case 0:
636: return cd;
637: case 1:
638: return cd.getColumnName();
639:
640: case 2:
641: return cd.getColumnType();
642:
643: case 3:
644: return new Integer(cd.getColumnSize());
645:
646: case 4:
647: return new Integer(cd.getColumnScale());
648:
649: // case 5:
650: // return cd.getDefaultValue();
651:
652: case 5:
653: return new Boolean(cd.isRequired());
654:
655: default:
656: return null;
657:
658: }
659: }
660:
661: public void setValueAt(Object value, int row, int col) {
662: ColumnData cd = tableVector.elementAt(row);
663:
664: //Log.debug("setValueAt [row: "+row+" col: "+col+" value: "+value+"]");
665:
666: switch (col) {
667: case 0:
668: if (cd.isPrimaryKey()) {
669: cd.setKeyType(PRIMARY);
670: } else if (cd.isForeignKey()) {
671: cd.setKeyType(FOREIGN);
672: } else {
673: cd.setKeyType(null);
674: }
675: break;
676: case 1:
677: cd.setColumnName((String) value);
678: break;
679: case 2:
680: cd.setColumnType((String) value);
681: break;
682: case 3:
683: cd.setColumnSize(Integer.parseInt((String) value));
684: break;
685: case 4:
686: cd.setColumnScale(Integer.parseInt((String) value));
687: break;
688: // case 5:
689: // cd.setDefaultValue((String)value);
690: // break;
691: case 5:
692: cd
693: .setColumnRequired(((Boolean) value)
694: .booleanValue() ? 0 : 1);
695: break;
696: }
697:
698: fireTableRowsUpdated(row, row);
699: }
700:
701: public boolean isCellEditable(int row, int col) {
702: return editing && col != 0;
703: }
704:
705: public String getColumnName(int col) {
706: return header[col];
707: }
708:
709: public Class getColumnClass(int col) {
710: if (col == 5) {
711: return Boolean.class;
712: } else if (col == 3 || col == 4) {
713: return Integer.class;
714: } else {
715: return String.class;
716: }
717: }
718:
719: public void addNewRow() {
720: ColumnData cd = tableVector.lastElement();
721: if (!cd.isNewColumn()) {
722: tableVector.addElement(new ColumnData(true));
723: }
724:
725: }
726:
727: } // class CreateTableModel
728:
729: private class DataTypeSelectionTableCell extends BrowsingCellEditor
730: implements DataTypeSelectionListener {
731:
732: private int lastEditingRow;
733: private int lastEditingColumn;
734:
735: public DataTypeSelectionTableCell() {
736: }
737:
738: public void actionPerformed(ActionEvent e) {
739: // store the current edit row and column
740: lastEditingRow = table.getEditingRow();
741: lastEditingColumn = table.getEditingColumn();
742:
743: fireEditingStopped();
744: if (dataTypes == null || dataTypes.length == 0) {
745: GUIUtilities
746: .displayWarningMessage("Data type values are not available");
747: return;
748: }
749:
750: SwingUtilities.invokeLater(new Runnable() {
751: public void run() {
752: new DataTypesDialog(GUIUtilities.getParentFrame(),
753: DataTypeSelectionTableCell.this , dataTypes);
754: }
755: });
756: }
757:
758: /**
759: * Called when the selction is cancelled.
760: */
761: public void dataTypeSelectionCancelled() {
762: fireEditingCanceled();
763: }
764:
765: /**
766: * Called when a data type has been selected.
767: *
768: * @param the data type value string
769: */
770: public void dataTypeSelected(String dataType) {
771: //setDelegateValue(dataType);
772: if (lastEditingRow != -1 && lastEditingColumn != -1) {
773: _model.setValueAt(dataType, lastEditingRow,
774: lastEditingColumn);
775: tableChanged(lastEditingColumn, lastEditingRow,
776: dataType);
777: }
778: fireEditingStopped();
779:
780: // reset row and column values
781: lastEditingRow = -1;
782: lastEditingColumn = -1;
783: }
784:
785: } // class DataTypeSelectionTableCell
786:
787: }
|