001: /*
002: * Copyright (C) 2007 Rob Manning
003: * manningr@users.sourceforge.net
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library 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 GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; 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.dbdiff.gui;
020:
021: import java.awt.BorderLayout;
022: import java.awt.Color;
023: import java.awt.Component;
024: import java.awt.Container;
025: import java.awt.Font;
026: import java.awt.GridLayout;
027: import java.util.List;
028:
029: import javax.swing.JLabel;
030: import javax.swing.JPanel;
031: import javax.swing.JScrollPane;
032: import javax.swing.JTable;
033: import javax.swing.JTextField;
034: import javax.swing.border.EmptyBorder;
035: import javax.swing.table.DefaultTableCellRenderer;
036: import javax.swing.table.DefaultTableColumnModel;
037: import javax.swing.table.DefaultTableModel;
038: import javax.swing.table.TableColumn;
039: import javax.swing.table.TableColumnModel;
040: import javax.swing.table.TableModel;
041:
042: import net.sourceforge.squirrel_sql.fw.gui.ButtonTableHeader;
043: import net.sourceforge.squirrel_sql.fw.sql.JDBCTypeMapper;
044: import net.sourceforge.squirrel_sql.fw.util.StringManager;
045: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
046: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
047: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
048: import net.sourceforge.squirrel_sql.plugins.dbdiff.ColumnDifference;
049:
050: import org.jdesktop.layout.GroupLayout;
051:
052: /**
053: *
054: * @author manningr
055: */
056: public class ColumnDiffDialog extends javax.swing.JDialog {
057:
058: private static final long serialVersionUID = 1856729976997357397L;
059:
060: private static StringManager s_stringMgr = StringManagerFactory
061: .getStringManager(ColumnDiffDialog.class);
062:
063: /** Logger for this class. */
064: private final static ILogger s_log = LoggerController
065: .createLogger(ColumnDiffDialog.class);
066:
067: interface i18n {
068: // i18n[ColumnDiffDialog.sessionLabelPrefix=Session]
069: String SESSION_LABEL_PREFIX = s_stringMgr
070: .getString("ColumnDiffDialog.sessionLabelPrefix");
071:
072: //i18n[ColumnDiffDialog.missingLabel=Missing]
073: String MISSING_LABEL = s_stringMgr
074: .getString("ColumnDiffDialog.missingLabel");
075: }
076:
077: private javax.swing.JPanel jPanel1;
078: private javax.swing.JPanel jPanel2;
079: private javax.swing.JScrollPane jScrollPane1;
080: private javax.swing.JTabbedPane jTabbedPane1;
081: private javax.swing.JTable diffTable;
082:
083: // The header for the scrollable part which presents column differences
084: private ButtonTableHeader _tableHeader;
085:
086: private JTable corner = null;
087:
088: private JPanel infoPanel;
089: private JPanel diffPanel;
090: private JLabel session1Label;
091: private JLabel session2Label;
092:
093: private JTable _rowHeader;
094: private List<ColumnDifference> _tableDiffs;
095:
096: private static final Color differenceColor = new Color(255, 166,
097: 166);
098:
099: private static final Color missingColor = new Color(255, 230, 0);
100:
101: private int rowHeaderColumnMinimumWidth = 120;
102:
103: public ColumnDiffDialog(java.awt.Frame parent, boolean modal) {
104: super (parent, modal);
105: initComponents();
106: postInit();
107: super .setLocationRelativeTo(parent);
108: super .setTitle("Table/Column Differences");
109: }
110:
111: public void setColumnDifferences(List<ColumnDifference> diffs) {
112: if (diffs == null) {
113: throw new IllegalArgumentException("diffs cannot be null");
114: }
115: DiffTableModel model = new DiffTableModel(diffs);
116: diffTable.setModel(model);
117: _tableDiffs = diffs;
118:
119: RowHeaderTableModel rowheaderModel = new RowHeaderTableModel(
120: diffs);
121:
122: _rowHeader.setModel(rowheaderModel);
123:
124: TableColumnModel rowHeaderTableColModel = _rowHeader
125: .getColumnModel();
126: TableColumn rowHeaderTableCol1 = rowHeaderTableColModel
127: .getColumn(0);
128: TableColumn rowHeaderTableCol2 = rowHeaderTableColModel
129: .getColumn(1);
130:
131: TableColumnModel cornerTableColModel = corner.getColumnModel();
132: TableColumn cornerTableCol1 = cornerTableColModel.getColumn(0);
133: TableColumn cornerTableCol2 = cornerTableColModel.getColumn(1);
134:
135: int column1MinWidth = getLongestColumnDifferenceTableName(diffs) * 3;
136: System.out.println("column1MinWidth: " + column1MinWidth);
137: int column2MinWidth = getLongestColumnDifferenceColumnName(diffs) * 7;
138: System.out.println("column2MinWidth: " + column2MinWidth);
139: rowHeaderTableCol1.setMinWidth(column1MinWidth);
140: rowHeaderTableCol2.setMinWidth(column2MinWidth);
141: cornerTableCol1.setMinWidth(column1MinWidth);
142: cornerTableCol2.setMinWidth(column2MinWidth);
143:
144: // These don't appear to work.
145: // rowHeaderTableCol1.setResizable(true);
146: // rowHeaderTableCol2.setResizable(true);
147: // cornerTableCol1.setResizable(true);
148: // cornerTableCol2.setResizable(true);
149:
150: //corner.validate();
151:
152: super .pack();
153: }
154:
155: public void setSession1Label(String label) {
156: if (label == null) {
157: throw new IllegalArgumentException("label cannot be null");
158: }
159: session1Label.setText(getSessionLabel(1, label));
160: }
161:
162: public void setSession2Label(String label) {
163: if (label == null) {
164: throw new IllegalArgumentException("label cannot be null");
165: }
166: session2Label.setText(getSessionLabel(2, label));
167: }
168:
169: private int getLongestColumnDifferenceTableName(
170: List<ColumnDifference> diffs) {
171: int result = 0;
172: for (ColumnDifference diff : diffs) {
173: int length = diff.getTableName().length();
174: if (result < length) {
175: result = length;
176: }
177: }
178: return result;
179: }
180:
181: private int getLongestColumnDifferenceColumnName(
182: List<ColumnDifference> diffs) {
183: int result = 0;
184: for (ColumnDifference diff : diffs) {
185: int length = diff.getColumnName().length();
186: if (result < length) {
187: result = length;
188: }
189: }
190: return result;
191: }
192:
193: private String getSessionLabel(int sessionNum, String label) {
194: StringBuilder result = new StringBuilder();
195: result.append(i18n.SESSION_LABEL_PREFIX);
196: result.append(sessionNum);
197: result.append(" : ");
198: result.append(label);
199: return result.toString();
200: }
201:
202: private void initComponents() {
203: jTabbedPane1 = new javax.swing.JTabbedPane();
204: jPanel1 = new javax.swing.JPanel();
205: jPanel1.setBackground(Color.lightGray);
206: jScrollPane1 = new javax.swing.JScrollPane();
207: diffTable = new javax.swing.JTable();
208: jPanel2 = new javax.swing.JPanel();
209:
210: setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
211: diffTable.setModel(new DefaultTableModel(new Object[][] {
212: { null, null, null, null, null, null, null, null },
213: { null, null, null, null, null, null, null, null },
214: { null, null, null, null, null, null, null, null },
215: { null, null, null, null, null, null, null, null } },
216: new String[] { i18n.SESSION_LABEL_PREFIX + "1 Type",
217: i18n.SESSION_LABEL_PREFIX + "2 Type",
218: i18n.SESSION_LABEL_PREFIX + "1 Length",
219: i18n.SESSION_LABEL_PREFIX + "2 Length",
220: i18n.SESSION_LABEL_PREFIX + "1 Null",
221: i18n.SESSION_LABEL_PREFIX + "2 Null",
222: i18n.SESSION_LABEL_PREFIX + "1 Remarks",
223: i18n.SESSION_LABEL_PREFIX + "2 Remarks", }) {
224: private static final long serialVersionUID = -8971846055387133384L;
225:
226: boolean[] canEdit = new boolean[] { false, false, false,
227: false, false, false, false, false };
228:
229: public boolean isCellEditable(int rowIndex, int columnIndex) {
230: return canEdit[columnIndex];
231: }
232: });
233: diffTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
234: diffTable.setDefaultRenderer(Object.class,
235: new DiffCellRenderer());
236: jScrollPane1.setViewportView(diffTable);
237:
238: GroupLayout jPanel1Layout = new GroupLayout(jPanel1);
239: jPanel1.setLayout(jPanel1Layout);
240: jPanel1Layout.setHorizontalGroup(jPanel1Layout
241: .createParallelGroup(GroupLayout.LEADING).add(
242: jScrollPane1, GroupLayout.DEFAULT_SIZE, 395,
243: Short.MAX_VALUE));
244: jPanel1Layout.setVerticalGroup(jPanel1Layout
245: .createParallelGroup(GroupLayout.LEADING).add(
246: jScrollPane1, GroupLayout.DEFAULT_SIZE, 264,
247: Short.MAX_VALUE));
248: jTabbedPane1.addTab("Columns", jPanel1);
249:
250: GroupLayout jPanel2Layout = new GroupLayout(jPanel2);
251: jPanel2.setLayout(jPanel2Layout);
252: jPanel2Layout.setHorizontalGroup(jPanel2Layout
253: .createParallelGroup(GroupLayout.LEADING).add(0, 395,
254: Short.MAX_VALUE));
255: jPanel2Layout.setVerticalGroup(jPanel2Layout
256: .createParallelGroup(GroupLayout.LEADING).add(0, 264,
257: Short.MAX_VALUE));
258: jTabbedPane1.addTab("Constraints", jPanel2);
259:
260: Container contentPane = getContentPane();
261: contentPane.setLayout(new BorderLayout());
262: infoPanel = new JPanel();
263: infoPanel.setBorder(new EmptyBorder(5, 10, 5, 0));
264: infoPanel.setLayout(new GridLayout(2, 1));
265: session1Label = new JLabel(i18n.SESSION_LABEL_PREFIX + "1: ");
266: session2Label = new JLabel(i18n.SESSION_LABEL_PREFIX + "2: ");
267: infoPanel.add(session1Label);
268: infoPanel.add(session2Label);
269:
270: diffPanel = new JPanel();
271:
272: GroupLayout layout = new GroupLayout(diffPanel);
273: diffPanel.setLayout(layout);
274: layout.setHorizontalGroup(layout.createParallelGroup(
275: GroupLayout.LEADING).add(jTabbedPane1,
276: GroupLayout.DEFAULT_SIZE, 600, Short.MAX_VALUE));
277: layout.setVerticalGroup(layout.createParallelGroup(
278: GroupLayout.LEADING).add(
279: layout.createSequentialGroup().add(jTabbedPane1,
280: GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
281: .addContainerGap()));
282:
283: contentPane.add(BorderLayout.NORTH, infoPanel);
284: contentPane.add(BorderLayout.CENTER, diffPanel);
285:
286: }
287:
288: private void postInit() {
289: _rowHeader = getRowHeader();
290: _rowHeader.setBackground(new Color(238, 238, 238));
291: JPanel panel = new JPanel();
292: panel.setLayout(new BorderLayout());
293: panel.add(_rowHeader, BorderLayout.CENTER);
294: jScrollPane1.setRowHeaderView(panel);
295: //jScrollPane1.setRowHeaderView(_rowHeader);
296:
297: _tableHeader = new ButtonTableHeader();
298: _tableHeader.setTable(diffTable);
299: diffTable.setTableHeader(_tableHeader);
300: _tableHeader.initColWidths();
301: _tableHeader.setColumnModel(diffTable.getColumnModel());
302: //_tableHeader.adoptAllColWidths(true);
303: //_tableHeader.initColWidths();
304:
305: corner = new JTable(new CornerTableModel());
306: corner.setRowHeight(25);
307:
308: corner.setBackground(Color.lightGray);
309: corner.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
310: corner.setFont(corner.getFont().deriveFont(Font.BOLD));
311: //corner.createDefaultColumnsFromModel();
312:
313: // This is weird - if I don't set this the column header doesn't line up
314: // with the column contents.
315: corner.getColumnModel().getColumn(0).setMinWidth(200);
316:
317: DefaultTableCellRenderer tcrColumn = new DefaultTableCellRenderer();
318: tcrColumn.setHorizontalAlignment(JTextField.CENTER);
319: corner.getColumnModel().getColumn(0).setCellRenderer(tcrColumn);
320: corner.getColumnModel().getColumn(1).setCellRenderer(tcrColumn);
321:
322: JPanel cornerPanel = new JPanel();
323: cornerPanel.setLayout(new BorderLayout());
324: cornerPanel.add(corner, BorderLayout.CENTER);
325:
326: jScrollPane1.setCorner(JScrollPane.UPPER_LEFT_CORNER,
327: cornerPanel);
328: //jScrollPane1.setCorner(JScrollPane.UPPER_LEFT_CORNER, corner);
329:
330: }
331:
332: private JTable getRowHeader() {
333: //result.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
334: /*
335: TableModel tm =
336: new DefaultTableModel(new String [] { "Table", "Column" }, 4) {
337:
338: private static final long serialVersionUID = -8826914717673025881L;
339:
340: public boolean isCellEditable(int rowIndex, int columnIndex) {
341: return false;
342: }
343: };
344: */
345: TableModel tm = new RowHeaderTableModel();
346: TableColumnModel tcm = getTableColumnModel(rowHeaderColumnMinimumWidth);
347: JTable result = new JTable(tm, tcm);
348: result.createDefaultColumnsFromModel();
349: return result;
350: }
351:
352: private TableColumnModel getTableColumnModel(final int minWidth) {
353: TableColumnModel result = new DefaultTableColumnModel() {
354: private static final long serialVersionUID = 1L;
355:
356: public void addColumn(TableColumn tc) {
357: tc.setResizable(true);
358: tc.setMinWidth(minWidth);
359: super .addColumn(tc);
360: }
361: };
362: return result;
363: }
364:
365: private static class DiffTableModel extends DefaultTableModel {
366:
367: private static final long serialVersionUID = 6563983121243062913L;
368:
369: private List<ColumnDifference> _diffs;
370:
371: String[] columnHeadings = new String[] {
372: i18n.SESSION_LABEL_PREFIX + "1 Type",
373: i18n.SESSION_LABEL_PREFIX + "2 Type",
374: i18n.SESSION_LABEL_PREFIX + "1 Length",
375: i18n.SESSION_LABEL_PREFIX + "2 Length",
376: i18n.SESSION_LABEL_PREFIX + "1 Null",
377: i18n.SESSION_LABEL_PREFIX + "2 Null",
378: i18n.SESSION_LABEL_PREFIX + "1 Remarks",
379: i18n.SESSION_LABEL_PREFIX + "2 Remarks"
380:
381: };
382:
383: public DiffTableModel(List<ColumnDifference> diffs) {
384: _diffs = diffs;
385: }
386:
387: /* (non-Javadoc)
388: * @see javax.swing.table.DefaultTableModel#getColumnCount()
389: */
390: @Override
391: public int getColumnCount() {
392: return columnHeadings.length;
393: }
394:
395: /* (non-Javadoc)
396: * @see javax.swing.table.DefaultTableModel#getColumnName(int)
397: */
398: @Override
399: public String getColumnName(int column) {
400: return columnHeadings[column];
401: }
402:
403: /* (non-Javadoc)
404: * @see javax.swing.table.DefaultTableModel#getRowCount()
405: */
406: @Override
407: public int getRowCount() {
408: if (_diffs == null) {
409: return 0;
410: }
411: return _diffs.size();
412: }
413:
414: /* (non-Javadoc)
415: * @see javax.swing.table.DefaultTableModel#getValueAt(int, int)
416: */
417: @Override
418: public Object getValueAt(int row, int column) {
419: if (_diffs == null) {
420: System.err.println("_diffs is null");
421: return "";
422: }
423: if (row >= _diffs.size()) {
424: s_log.error("specified row (" + row
425: + ") equals or exceeds " + "_diffs size("
426: + _diffs.size() + ")");
427: return "";
428: }
429: ColumnDifference diff = _diffs.get(row);
430: if (!diff.isCol1Exists() || !diff.isCol2Exists()) {
431: if (!diff.isCol1Exists() && column % 2 == 0) {
432: return i18n.MISSING_LABEL;
433: }
434: if (!diff.isCol2Exists() && column % 2 == 1) {
435: return i18n.MISSING_LABEL;
436: }
437: }
438: Object result = null;
439: switch (column) {
440: case 0:
441: result = JDBCTypeMapper.getJdbcTypeName(diff
442: .getCol1Type());
443: break;
444: case 1:
445: result = JDBCTypeMapper.getJdbcTypeName(diff
446: .getCol2Type());
447: break;
448: case 2:
449: result = diff.getCol1Length();
450: break;
451: case 3:
452: result = diff.getCol2Length();
453: break;
454: case 4:
455: result = diff.col1AllowsNull();
456: break;
457: case 5:
458: result = diff.col2AllowsNull();
459: break;
460: case 6:
461: result = diff.getCol1Remarks();
462: break;
463: case 7:
464: result = diff.getCol2Remarks();
465: break;
466: default:
467: System.err.println("Unknown column: " + column);
468: }
469: return result;
470: }
471: }
472:
473: private static class CornerTableColumnModel extends
474: DefaultTableColumnModel {
475:
476: }
477:
478: private static class CornerTableModel extends DefaultTableModel {
479:
480: private static final long serialVersionUID = 1L;
481:
482: /**
483: * @see javax.swing.table.DefaultTableModel#getColumnCount()
484: */
485: @Override
486: public int getColumnCount() {
487: return 2;
488: }
489:
490: /**
491: * @see javax.swing.table.DefaultTableModel#getColumnName(int)
492: */
493: @Override
494: public String getColumnName(int column) {
495: if (column == 0) {
496: return "Table";
497: }
498: return "Column";
499: }
500:
501: /**
502: * @see javax.swing.table.DefaultTableModel#getRowCount()
503: */
504: @Override
505: public int getRowCount() {
506: return 1;
507: }
508:
509: /**
510: * @see javax.swing.table.DefaultTableModel#getValueAt(int, int)
511: */
512: @Override
513: public Object getValueAt(int row, int column) {
514: if (column == 0) {
515: return "Table";
516: }
517: return "Column";
518: }
519:
520: /**
521: * @see javax.swing.table.DefaultTableModel#isCellEditable(int, int)
522: */
523: @Override
524: public boolean isCellEditable(int row, int column) {
525: return false;
526: }
527:
528: }
529:
530: /**
531: * This class forms the vertical "header" that contains the first two
532: * columns in our table and is used to display the table and column name
533: * being diff'd for a particular row.
534: */
535: private static class RowHeaderTableModel extends DefaultTableModel {
536:
537: private static final long serialVersionUID = 9015962292222867195L;
538:
539: private List<ColumnDifference> _diffs;
540:
541: private RowHeaderTableModel() {
542: //throw new IllegalStateException("Wrong constructor");
543: }
544:
545: public RowHeaderTableModel(List<ColumnDifference> diffs) {
546: if (diffs == null) {
547: throw new IllegalArgumentException(
548: "diffs cannot be null");
549: }
550: _diffs = diffs;
551: }
552:
553: /* (non-Javadoc)
554: * @see javax.swing.table.DefaultTableModel#getColumnCount()
555: */
556: @Override
557: public int getColumnCount() {
558: return 2;
559: }
560:
561: /* (non-Javadoc)
562: * @see javax.swing.table.DefaultTableModel#getColumnName(int)
563: */
564: @Override
565: public String getColumnName(int column) {
566: if (column == 0) {
567: return "Table";
568: }
569: if (column == 1) {
570: return "Column";
571: }
572: throw new IllegalArgumentException("Invalid column: "
573: + column);
574: }
575:
576: /* (non-Javadoc)
577: * @see javax.swing.table.DefaultTableModel#getRowCount()
578: */
579: @Override
580: public int getRowCount() {
581: if (_diffs == null) {
582: return 0;
583: }
584: return _diffs.size();
585: }
586:
587: /* (non-Javadoc)
588: * @see javax.swing.table.DefaultTableModel#getValueAt(int, int)
589: */
590: @Override
591: public Object getValueAt(int row, int column) {
592: ColumnDifference diff = _diffs.get(row);
593: if (column == 0) {
594: return diff.getTableName();
595: }
596: if (column == 1) {
597: return diff.getColumnName();
598: }
599: throw new IllegalArgumentException("Invalid column: "
600: + column);
601: }
602:
603: /* (non-Javadoc)
604: * @see javax.swing.table.DefaultTableModel#isCellEditable(int, int)
605: */
606: @Override
607: public boolean isCellEditable(int row, int column) {
608: return false;
609: }
610: }
611:
612: private class DiffCellRenderer extends DefaultTableCellRenderer {
613:
614: private static final long serialVersionUID = -3678335726720196633L;
615:
616: private Color originalCellBGColor = Color.white;
617:
618: @Override
619: public Component getTableCellRendererComponent(JTable table,
620: Object value, boolean isSelected, boolean hasFocus,
621: int row, int column) {
622:
623: Component label = super .getTableCellRendererComponent(
624: table, value, isSelected, hasFocus, row, column);
625:
626: if (_tableDiffs == null) {
627: return label;
628: }
629: ColumnDifference diff = _tableDiffs.get(row);
630:
631: if (!diff.isCol1Exists() || !diff.isCol2Exists()) {
632: setMissing(label, value);
633: return label;
634: }
635:
636: switch (column) {
637: case 0:
638: case 1:
639: if (!diff.typesEqual()) {
640: setHighlighted(label, value);
641: } else {
642: setNormal(label);
643: }
644: break;
645: case 2:
646: case 3:
647: if (!diff.lengthsEqual()) {
648: setHighlighted(label, value);
649: } else {
650: setNormal(label);
651: }
652: break;
653: case 4:
654: case 5:
655: if (!diff.nullableEqual()) {
656: setHighlighted(label, value);
657: } else {
658: setNormal(label);
659: }
660: break;
661: case 6:
662: case 7:
663: if (!diff.remarksEqual()) {
664: setHighlighted(label, value);
665: } else {
666: setNormal(label);
667: }
668: break;
669: default:
670: System.err.println("Unknown column: " + column);
671: }
672: return label;
673: }
674:
675: private void setMissing(Component label, Object value) {
676: if (value != null && value.toString() != null
677: && value.toString().equals(i18n.MISSING_LABEL)) {
678: label.setBackground(missingColor);
679: label.setForeground(Color.BLACK);
680: label.setFont(label.getFont().deriveFont(Font.ITALIC));
681: } else {
682: setNormal(label);
683: }
684: }
685:
686: private void setHighlighted(Component label, Object value) {
687: label.setBackground(differenceColor);
688: label.setFont(label.getFont().deriveFont(Font.ITALIC));
689: label.setForeground(Color.BLACK);
690: }
691:
692: private void setNormal(Component label) {
693: label.setBackground(originalCellBGColor);
694: label.setForeground(Color.BLACK);
695: label.setFont(label.getFont().deriveFont(Font.PLAIN));
696: }
697:
698: }
699: }
|