Java tutorial
/* * Copyright (c) 2008, SQL Power Group Inc. * * This file is part of Power*Architect. * * Power*Architect is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Power*Architect is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.architect.swingui; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.CancellationException; import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JRadioButton; import javax.swing.JTextField; import javax.swing.ListCellRenderer; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import org.apache.log4j.Logger; import ca.sqlpower.architect.ddl.DDLGenerator; import ca.sqlpower.architect.ddl.DDLUtils; import ca.sqlpower.architect.diff.CompareSQL; import ca.sqlpower.architect.swingui.CompareDMPanel.SourceOrTargetStuff.CatalogPopulator; import ca.sqlpower.architect.swingui.CompareDMPanel.SourceOrTargetStuff.SchemaPopulator; import ca.sqlpower.architect.swingui.CompareDMSettings.DatastoreType; import ca.sqlpower.architect.swingui.CompareDMSettings.SourceOrTargetSettings; import ca.sqlpower.diff.DiffChunk; import ca.sqlpower.sql.DataSourceCollection; import ca.sqlpower.sql.JDBCDataSource; import ca.sqlpower.sql.SPDataSource; import ca.sqlpower.sqlobject.SQLCatalog; import ca.sqlpower.sqlobject.SQLDatabase; import ca.sqlpower.sqlobject.SQLObject; import ca.sqlpower.sqlobject.SQLObjectException; import ca.sqlpower.sqlobject.SQLSchema; import ca.sqlpower.sqlobject.SQLTable; import ca.sqlpower.swingui.ConnectionComboBoxModel; import ca.sqlpower.swingui.ProgressWatcher; import ca.sqlpower.swingui.SPSUtils; import ca.sqlpower.swingui.SPSwingWorker; import ca.sqlpower.validation.Status; import ca.sqlpower.validation.ValidateResult; import ca.sqlpower.validation.swingui.StatusComponent; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.debug.FormDebugPanel; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; /** * The user interface for setting up the comparison between two databases, * whether they are housed in Architect project files, SQL databases, or * just the current project in the session. * <p> * This class should not actually extend JPanel.. it should have a JPanel * member instead. */ public class CompareDMPanel extends JPanel { /** * This listener helps with restoring the selected catalog and schema from the user * settings. */ private static class RestoreSettingsListener implements ListDataListener { private JComboBox box; private String selectItemName; public RestoreSettingsListener(JComboBox box, String selectItemName) { this.box = box; this.selectItemName = selectItemName; } public void intervalAdded(ListDataEvent e) { tryToSelectTheItem(e.getIndex0(), e.getIndex1()); } public void intervalRemoved(ListDataEvent e) { // don't care } public void contentsChanged(ListDataEvent e) { tryToSelectTheItem(e.getIndex0(), e.getIndex1()); } /** * Searches the combo box list data from index low to high (inclusive) and selects * the first item it finds whose name matches selectItemName. If a match * if found and selected, this listener is also removed from the list data * listener list (because it's no longer needed). * * @param low The index to start the search at * @param high One past the index to end the search at */ private void tryToSelectTheItem(int low, int high) { if (logger.isDebugEnabled()) { logger.debug("Looking for '" + selectItemName + "' from index " + low + " to " + high); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } for (int i = low; i <= high; i++) { SQLObject o = (SQLObject) box.getItemAt(i); if (o != null && o.getName().equals(selectItemName)) { box.setSelectedIndex(i); box.getModel().removeListDataListener(this); return; } } } } private static final Logger logger = Logger.getLogger(CompareDMPanel.class); private static final String OUTPUT_ENGLISH = "OUTPUT_ENGLISH"; //$NON-NLS-1$ private static final String OUTPUT_SQL = "OUTPUT_SQL"; //$NON-NLS-1$ private static final String OUTPUT_LIQUIBASE = "OUTPUT_LIQUIBASE"; //$NON-NLS-1$ public static final String DBCS_DIALOG_TITLE = Messages.getString("CompareDMPanel.dbcsDialogTitle"); //$NON-NLS-1$ private JProgressBar progressBar; private JPanel buttonPanel; private LiquibaseOptionsPanel lbOptions; /** * The list of all DDL Generators available. The items stored in this * combo box are of type <tt>Class<? extends DDLGenerator></tt>. */ private JComboBox sqlTypeDropdown; private JRadioButton sqlButton; private JRadioButton englishButton; private JRadioButton liquibaseButton; private JCheckBox showNoChanges; private JCheckBox includeIndexes; private JLabel statusLabel; /** * The status component that explains why the start compare action is disabled. * <p> * <b>Very important note</b> that you should heed carefully: CompareDMPanel * uses the SQL Power validation API in a non-standard way because it has been * retrofit over an old ad-hoc approach to validation. Do not emulate this approach * to validation in new code! */ private StatusComponent statusComponent = new StatusComponent(); private StartCompareAction startCompareAction; private SwapSourceTargetAction swapSourceTargetAction; private SourceOrTargetStuff source = new SourceOrTargetStuff(); private SourceOrTargetStuff target = new SourceOrTargetStuff(); /** * Since we can create new DB connections from this panel, we need a reference * to the session so we can retrieve the datasource collection. */ private ArchitectSwingSession session; /** * The dialog that created and contains this panel */ private JDialog parentDialog; /** * Contains all of the properties and GUI components that relate to the * source or target system. The idea is, the panel will have two instances * of this class: One for the "source" system, and the other for the * "target" system. * * <p> * Note: this class is not private because the test needs to refer to it. :( */ public class SourceOrTargetStuff { private JComboBox databaseDropdown; private JComboBox catalogDropdown; private JComboBox schemaDropdown; private JButton newConnButton; private JButton loadFileButton; private JTextField loadFilePath; /** The group for the source/target type (playpen, file, or database) */ private ButtonGroup buttonGroup = new ButtonGroup(); /** * The label for the playpen radio button. We save a reference to it because * it needs to be updated when the project's filename changes. */ private final JLabel playPenName = new JLabel(); private JRadioButton playPenRadio; private JRadioButton physicalRadio; private JRadioButton loadRadio; private JDialog newConnectionDialog; private JLabel catalogLabel; private JLabel schemaLabel; private SchemaPopulator schemaPop; private CatalogPopulator catalogPop; private boolean isSource; /** * The last database returned by getDatabase(). Never access this * directly; always use getDatabase(). */ private SQLDatabase cachedDatabase; private Action newConnectionAction = new AbstractAction( Messages.getString("CompareDMPanel.newConnectionActionName")) { //$NON-NLS-1$ public void actionPerformed(ActionEvent e) { final DataSourceCollection<JDBCDataSource> plDotIni = session.getDataSources(); final JDBCDataSource dataSource = new JDBCDataSource(plDotIni); Runnable onAccept = new Runnable() { public void run() { plDotIni.addDataSource(dataSource); databaseDropdown.setSelectedItem(dataSource); } }; ASUtils.showDbcsDialog(SPSUtils.getWindowInHierarchy(CompareDMPanel.this), dataSource, onAccept); } }; private Action chooseFileAction = new AbstractAction( Messages.getString("CompareDMPanel.chooseFileActionName")) { //$NON-NLS-1$ public void actionPerformed(ActionEvent e) { JFileChooser chooser = new JFileChooser(session.getRecentMenu().getMostRecentFile()); chooser.addChoosableFileFilter(SPSUtils.ARCHITECT_FILE_FILTER); int returnVal = chooser.showOpenDialog(CompareDMPanel.this); if (returnVal == JFileChooser.APPROVE_OPTION) { final File file = chooser.getSelectedFile(); loadFilePath.setText(file.getPath()); } } }; /** * Finds all the children of a database and puts them in the GUI. */ public class CatalogPopulator extends PopulateProgressMonitorableWorker implements ActionListener { String catalogSelect; String schemaSelect; private SQLDatabase db; public CatalogPopulator(ArchitectSwingSession session) { super(session); catalogSelect = null; schemaSelect = null; } /** * If select is a valid catalog of the database this sets a * string that will be used as a default item to select * for the catalog next time the list will be redrawn, (this * will happen only once). * * Else does nothing * * @param select The name of the item to select */ public void setDefaultCatalog(String def) { this.catalogSelect = def; } /** * If select is a valid schema of the database and there is * no catalogs for this database this sets a * string that will be used as a default item to select * for the schema next time the list will be redrawn, (this * will happen only once). * * Else does nothing * * @param select The name of the item to select */ public void setDefaultSchema(String def) { this.schemaSelect = def; } /** * Checks the datasource selected in the databaseDropdown, and * starts a worker thread to read its contents if it exists. * * <p> * Otherwise, clears out the catalog and schema dropdowns and does * not start a worker thread. */ public void actionPerformed(ActionEvent e) { startCompareAction.setEnabled(false); db = getDatabase(); if (db != null) { // disable start button (listers will reenable it when // finished) if (((JComboBox) (e.getSource())).getSelectedIndex() == 0) { startCompareAction.setEnabled(false); } new Thread(this).start(); } else { catalogDropdown.removeAllItems(); catalogDropdown.setEnabled(false); schemaDropdown.removeAllItems(); schemaDropdown.setEnabled(false); } } /** * Populates the database <tt>db</tt> which got set up in * actionPerformed(). */ @Override public void doStuff() throws Exception { try { ProgressWatcher.watchProgress(progressBar, this); db.populate(); } catch (SQLObjectException e) { logger.debug("Unexpected architect exception in ConnectionListener", e); //$NON-NLS-1$ ASUtils.showExceptionDialogNoReport(CompareDMPanel.this, Messages.getString("CompareDMPanel.unexpectedExceptionInConnectionListener"), e); //$NON-NLS-1$ } } /** * Does GUI cleanup work on the Swing EDT once the worker is done. * * <p> * This work involves: * <ul> * <li>Check which child type the database has * <li>Populate the catalog and schema boxes accordingly * <li>Enable or disable the catalog and schema boxes accordingly * </ul> */ @Override public void cleanup() throws SQLObjectException { setCleanupExceptionMessage(Messages.getString("CompareDMPanel.couldNotPopulateCatalogDropdown")); //$NON-NLS-1$ catalogDropdown.removeAllItems(); catalogDropdown.setEnabled(false); catalogLabel.setText(""); //$NON-NLS-1$ schemaLabel.setText(""); //$NON-NLS-1$ // This is either a database, a catalog, or null depending on // how db is structured SQLObject schemaParent; if (db.isCatalogContainer()) { for (SQLCatalog item : db.getChildren(SQLCatalog.class)) { // Note: if you change the way this works, also update the RestoreSettingsListener catalogDropdown.addItem(item); // did you read the note? } // check if we need to do schemas SQLCatalog cat = (SQLCatalog) catalogDropdown.getSelectedItem(); if (cat != null && cat.getNativeTerm() != null) catalogLabel.setText(cat.getNativeTerm()); schemaParent = null; if (cat == null) { // there are no catalogs (database is completely empty) catalogDropdown.setEnabled(false); } else { // there are catalogs, but they don't contain schemas catalogDropdown.setEnabled(true); } } else if (db.isSchemaContainer()) { schemaParent = db; catalogDropdown.setEnabled(false); } else { // database contains tables directly schemaParent = null; catalogDropdown.setEnabled(false); } schemaDropdown.removeAllItems(); schemaDropdown.setEnabled(false); if (schemaParent == null) { startCompareAction.setEnabled(isStartable()); } else { // need a final reference to this so we can use it in the // inner class // we only get here if the database is a schema container not // a catalog container. final SQLObject finalSchemaParent = schemaParent; new Thread(new PopulateProgressMonitorableWorker(session) { @Override public void doStuff() throws Exception { ProgressWatcher.watchProgress(progressBar, this); // this populates the schema parent (populate is not // visible here) finalSchemaParent.getChildren(); } /** * Populates the schema dropdown box from the schema * parent that doStuff() populated. * * @throws SQLObjectException */ @Override public void cleanup() throws SQLObjectException { setCleanupExceptionMessage( Messages.getString("CompareDMPanel.couldNotPopulateSchemaDropdown")); //$NON-NLS-1$ for (SQLObject item : finalSchemaParent.getChildren()) { schemaDropdown.addItem(item); } if (schemaDropdown.getItemCount() > 0) { schemaDropdown.setEnabled(true); if (((SQLSchema) (finalSchemaParent.getChild(0))).getNativeTerm() != null) schemaLabel .setText(((SQLSchema) (finalSchemaParent.getChild(0))).getNativeTerm()); } startCompareAction.setEnabled(isStartable()); //sets to the default schema, iff catalog is null logger.debug("default schema is: " + schemaSelect); //$NON-NLS-1$ if (CatalogPopulator.this.schemaSelect != null) { for (int x = 0; x < schemaDropdown.getItemCount(); x++) { SQLObject curr = (SQLObject) (schemaDropdown.getItemAt(x)); if (curr != null && curr.getName().equals(schemaSelect)) { schemaDropdown.setSelectedIndex(x); break; } } } schemaSelect = null; } }).start(); } //sets to the default catalog logger.debug("default catalog selected " + catalogSelect); //$NON-NLS-1$ if (catalogSelect != null) { for (int x = 0; x < catalogDropdown.getItemCount(); x++) { SQLObject curr = (SQLObject) (catalogDropdown.getItemAt(x)); if (curr != null && curr.getName().equals(catalogSelect)) { catalogDropdown.setSelectedIndex(x); break; } } } catalogSelect = null; } @Override protected boolean isFinishedImpl() { if (db != null) { return db.isPopulated(); } return true; } } /** * Finds all the children of a catalog and puts them in the GUI. */ public class SchemaPopulator extends PopulateProgressMonitorableWorker implements ActionListener { String select; boolean populating = false; public SchemaPopulator(ArchitectSwingSession session) { super(session); select = null; } /** * If select is a valid schema of the catalog this sets a * string that will be used as a default item to select * for the schema next time the list will be redrawn, (this * will happen only once). * * Else does nothing * * @param select The name of the item to select */ public void setDefaultSelect(String select) { this.select = select; } /** * Clears the schema dropdown, and starts a worker thread to * repopulate it (if possible). */ public void actionPerformed(ActionEvent e) { logger.debug("SCHEMA POPULATOR IS ABOUT TO START..."); //$NON-NLS-1$ schemaDropdown.removeAllItems(); schemaDropdown.setEnabled(false); SQLCatalog catToPopulate = (SQLCatalog) catalogDropdown.getSelectedItem(); if (catToPopulate != null && !populating) { populating = true; startCompareAction.setEnabled(false); Thread t = new Thread(this); t.start(); } } @Override public void doStuff() throws SQLObjectException { logger.debug("SCHEMA POPULATOR IS STARTED..."); //$NON-NLS-1$ ProgressWatcher.watchProgress(progressBar, this); SQLCatalog catToPopulate = (SQLCatalog) catalogDropdown.getSelectedItem(); catToPopulate.populate(); // this might take a while } /** * Examines the newly-populated catalog and adds its schemas to the * GUI. If the catalog doesn't contain schemas, cleanup just checks * if the comparison action is startable. * * @throws SQLObjectException */ @Override public void cleanup() throws SQLObjectException { logger.debug("SCHEMA POPULATOR IS ABOUT TO CLEAN UP..."); //$NON-NLS-1$ schemaLabel.setText(""); //$NON-NLS-1$ SQLCatalog populatedCat = (SQLCatalog) catalogDropdown.getSelectedItem(); if (populatedCat.isSchemaContainer()) { for (SQLObject item : populatedCat.getChildren()) { schemaDropdown.addItem(item); } if (schemaDropdown.getItemCount() > 0) { schemaDropdown.setEnabled(true); if (((SQLSchema) (populatedCat.getChild(0))).getNativeTerm() != null) schemaLabel.setText(((SQLSchema) (populatedCat.getChild(0))).getNativeTerm()); } } startCompareAction.setEnabled(isStartable()); //sets the default schema logger.debug("Default Schema: " + select); //$NON-NLS-1$ if (select != null) { for (int x = 0; x < schemaDropdown.getItemCount(); x++) { SQLObject curr = (SQLObject) (schemaDropdown.getItemAt(x)); if (curr != null && curr.getName().equals(select)) { schemaDropdown.setSelectedIndex(x); break; } } } select = null; populating = false; } } // -------------- Small class for monitoring populate progress ----------------- // TODO Document this class!!!! private abstract class PopulateProgressMonitorableWorker extends SPSwingWorker { public PopulateProgressMonitorableWorker(ArchitectSwingSession session) { super(session); setJobSize(null); setProgress(0); setMessage(Messages.getString("CompareDMPanel.connectingToDatabase")); //$NON-NLS-1$ } } public synchronized JDialog getNewConnectionDialog() { return newConnectionDialog; } /** * Updates the playpen name label to reflect the session's current name, * which changes when the user saves their project under a different filename. */ void updatePlayPenNameLabel() { String newPlaypenName = Messages.getString("CompareDMPanel.currentProject", session.getName()); //$NON-NLS-1$ playPenName.setText(newPlaypenName); //$NON-NLS-1$ logger.debug("Updated playpen name to " + newPlaypenName); //$NON-NLS-1$ } /** * Creates the GUI components associated with this object, and appends * them to the given builder. */ private void buildPartialUI(DefaultFormBuilder builder, boolean defaultPlayPen, SchemaPopulator schemaPop, CatalogPopulator catalogPop) { String prefix; if (defaultPlayPen == true) { prefix = "source"; //$NON-NLS-1$ } else { prefix = "target"; //$NON-NLS-1$ } this.isSource = defaultPlayPen; this.schemaPop = schemaPop; this.catalogPop = catalogPop; CellConstraints cc = new CellConstraints(); playPenRadio = new JRadioButton(); playPenRadio.setName(prefix + "PlayPenRadio"); //$NON-NLS-1$ physicalRadio = new JRadioButton(); physicalRadio.setName(prefix + "PhysicalRadio"); //$NON-NLS-1$ loadRadio = new JRadioButton(); loadRadio.setName(prefix + "LoadRadio"); //$NON-NLS-1$ buttonGroup.add(playPenRadio); buttonGroup.add(physicalRadio); buttonGroup.add(loadRadio); schemaDropdown = new JComboBox(); schemaDropdown.setEnabled(false); schemaDropdown.setName(prefix + "SchemaDropdown"); //$NON-NLS-1$ catalogDropdown = new JComboBox(); catalogDropdown.setEnabled(false); catalogDropdown.setName(prefix + "CatalogDropdown"); //$NON-NLS-1$ databaseDropdown = new JComboBox(); databaseDropdown.setName(prefix + "DatabaseDropdown"); //$NON-NLS-1$ databaseDropdown.setModel(new ConnectionComboBoxModel(session.getDataSources())); databaseDropdown.setEnabled(false); databaseDropdown.setRenderer(dataSourceRenderer); newConnButton = new JButton(); newConnButton.setName(prefix + "NewConnButton"); //$NON-NLS-1$ newConnButton.setAction(newConnectionAction); newConnectionAction.setEnabled(false); loadFilePath = new JTextField(); loadFilePath.setName(prefix + "LoadFilePath"); //$NON-NLS-1$ loadFilePath.setEnabled(false); loadFilePath.getDocument().addDocumentListener(new DocumentListener() { public void insertUpdate(DocumentEvent e) { startCompareAction.setEnabled(isStartable()); } public void removeUpdate(DocumentEvent e) { startCompareAction.setEnabled(isStartable()); } public void changedUpdate(DocumentEvent e) { startCompareAction.setEnabled(isStartable()); } }); loadFileButton = new JButton(); loadFileButton.setName(prefix + "LoadFileButton"); //$NON-NLS-1$ loadFileButton.setAction(chooseFileAction); chooseFileAction.setEnabled(false); catalogDropdown.addActionListener(schemaPop); databaseDropdown.addActionListener(catalogPop); databaseDropdown.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if (!isSource) { return; } JDBCDataSource dataSource = (JDBCDataSource) databaseDropdown.getSelectedItem(); if (dataSource != null) { String generatorClass = dataSource.getParentType().getDDLGeneratorClass(); if (generatorClass != null) { try { sqlTypeDropdown.setSelectedItem( Class.forName(generatorClass, true, CompareDMPanel.class.getClassLoader())); } catch (ClassNotFoundException ex) { logger.error("Error when finding the DDLGenerator class for the selected database!", //$NON-NLS-1$ ex); } } } } }); ActionListener listener = new OptionGroupListener(); playPenRadio.addActionListener(listener); physicalRadio.addActionListener(listener); loadRadio.addActionListener(listener); if (defaultPlayPen) { playPenRadio.doClick(); } else { physicalRadio.doClick(); } updatePlayPenNameLabel(); JLabel temp; // now give all our shiny new components to the builder builder.append(playPenRadio); builder.append(playPenName, 7); associate(playPenName, playPenRadio); builder.nextLine(); builder.append(""); // takes up blank space //$NON-NLS-1$ builder.append(physicalRadio); temp = builder.append(Messages.getString("CompareDMPanel.physicalDatabaseLabel")); //$NON-NLS-1$ associate(temp, physicalRadio); builder.append(catalogLabel = new JLabel(Messages.getString("CompareDMPanel.catalogLabel"))); //$NON-NLS-1$ builder.append(schemaLabel = new JLabel(Messages.getString("CompareDMPanel.schemaLabel"))); //$NON-NLS-1$ builder.appendRow(builder.getLineGapSpec()); builder.appendRow("pref"); //$NON-NLS-1$ builder.nextLine(2); builder.nextColumn(4); builder.append(databaseDropdown); builder.append(catalogDropdown, schemaDropdown, newConnButton); builder.nextLine(); builder.append(""); //$NON-NLS-1$ builder.append(loadRadio); temp = builder.append(Messages.getString("CompareDMPanel.fromFileLabel")); //$NON-NLS-1$ associate(temp, loadRadio); builder.nextLine(); builder.append(""); // takes up blank space //$NON-NLS-1$ builder.add(loadFilePath, cc.xyw(5, builder.getRow(), 5)); builder.nextColumn(8); builder.append(loadFileButton); builder.nextLine(); } public boolean isModelWithUUID() { return playPenRadio.isSelected() || loadRadio.isSelected(); } /** * Figures out which SQLObject holds the tables we want to compare, and * returns it. * * @throws SQLObjectException * @throws IOException * @throws IOException */ public SQLObject getObjectToCompare() throws SQLObjectException, IOException { SQLObject o; if (playPenRadio.isSelected()) { o = session.getTargetDatabase(); } else if (physicalRadio.isSelected()) { if (schemaDropdown.getSelectedItem() != null) { o = (SQLObject) schemaDropdown.getSelectedItem(); } else if (catalogDropdown.getSelectedItem() != null) { o = (SQLObject) catalogDropdown.getSelectedItem(); } else if (databaseDropdown.getSelectedItem() != null) { o = getDatabase(); } else { throw new IllegalStateException( Messages.getString("CompareDMPanel.noSchemaCatalogOrDatabaseSelected")); //$NON-NLS-1$ } } else if (loadRadio.isSelected()) { File f = new File(loadFilePath.getText()); InputStream in = new BufferedInputStream(new FileInputStream(f)); // XXX: this will take a non-trivial amount of time, so ideally would be done with a progress bar. // we might be able to use OpenProjectAction.loadAsynchronously() for this, but it would need a flag for not showing the GUI // or better yet, set o=f, and do the load itself in the compare worker, because this approach would share the progress bar with the comparison activity itself ArchitectSwingSession newSession = session.getContext().createSession(in); o = newSession.getTargetDatabase(); } else { throw new IllegalStateException(Messages.getString("CompareDMPanel.doNotKnowWhichSourceToCompare")); //$NON-NLS-1$ } return o; } /** * The public isStartable() method uses this to check source and target * readiness. * * XXX: this is really similar to the getObjectToCompare() method, * except that it doesn't try to load the file (so it runs quicker) */ private ValidateResult getStartabilityStatus() { ValidateResult result; String sourceOrTarget = isSource() ? Messages.getString("CompareDMPanel.older") : //$NON-NLS-1$ Messages.getString("CompareDMPanel.newer"); //$NON-NLS-1$ if (playPenRadio.isSelected()) { result = null; } else if (physicalRadio.isSelected()) { if (databaseDropdown.getSelectedItem() == null) { result = ValidateResult.createValidateResult(Status.FAIL, Messages.getString("CompareDMPanel.incompleteSelection", sourceOrTarget)); //$NON-NLS-1$ } else { result = null; } } else if (loadRadio.isSelected()) { if (new File(loadFilePath.getText()).canRead()) { result = null; } else { result = ValidateResult.createValidateResult(Status.FAIL, Messages.getString("CompareDMPanel.projectFileNotReadable", sourceOrTarget)); //$NON-NLS-1$ } } else { throw new IllegalStateException(Messages.getString("CompareDMPanel.noRadioButtonsSelected")); //$NON-NLS-1$ } return result; } /** * Returns the currently selected database. Only creates a new * SQLDatabase instance if necessary. */ public synchronized SQLDatabase getDatabase() { JDBCDataSource ds = (JDBCDataSource) databaseDropdown.getSelectedItem(); if (ds == null) { cachedDatabase = null; } else if (cachedDatabase == null || !cachedDatabase.getDataSource().equals(ds)) { cachedDatabase = new SQLDatabase(ds); } return cachedDatabase; } /** * This listener is used to enable/disable JComponents when one of the * database choosing options is choosen (for both source and target * selections). */ public class OptionGroupListener implements ActionListener { public void actionPerformed(ActionEvent e) { enableDisablePhysicalComps(); boolean enableLoadComps = e.getSource() == loadRadio; loadFilePath.setEnabled(enableLoadComps); loadFileButton.setEnabled(enableLoadComps); } } /** * For the special case of enabling and disabling the Physical database * Dropdown Components. */ void enableDisablePhysicalComps() { boolean enable = physicalRadio.isSelected(); databaseDropdown.setEnabled(enable); if (enable && catalogDropdown.getItemCount() > 0) { catalogDropdown.setEnabled(true); } else { catalogDropdown.setEnabled(false); } if (enable && schemaDropdown.getItemCount() > 0) { schemaDropdown.setEnabled(true); } else { schemaDropdown.setEnabled(false); } newConnectionAction.setEnabled(enable); } boolean isSource() { return isSource; } } /** * Renders list cells which have a value that is an SPDataSource. */ private ListCellRenderer dataSourceRenderer = new DataSourceRenderer(); /** * Returns true iff the comparison process can start given the current state * of the GUI form. */ private boolean isStartable() { logger.debug("isStartable is checking..."); //$NON-NLS-1$ ValidateResult result = null; if (sqlButton.isSelected() && sqlTypeDropdown.getSelectedItem() == null) { result = ValidateResult.createValidateResult(Status.FAIL, Messages.getString("CompareDMPanel.chooseSQLDialect")); //$NON-NLS-1$ } if (result == null) { result = source.getStartabilityStatus(); } if (result == null) { result = target.getStartabilityStatus(); } statusComponent.setResult(result); return result == null; } public Action getStartCompareAction() { return startCompareAction; } public Action getSwapSourceTargetAction() { return swapSourceTargetAction; } public JPanel getButtonPanel() { return buttonPanel; } public CompareDMPanel(ArchitectSwingSession session, JDialog ownerDialog) { this.session = session; this.parentDialog = ownerDialog; buildUI(target.new SchemaPopulator(session), target.new CatalogPopulator(session), source.new SchemaPopulator(session), source.new CatalogPopulator(session)); startCompareAction.setEnabled(isStartable()); addAncestorListener(playpenNameRefreshHandler); } private void buildUI(SchemaPopulator targetSchemaPop, CatalogPopulator targetCatalogPop, SchemaPopulator sourceSchemaPop, CatalogPopulator sourceCatalogPop) { progressBar = new JProgressBar(); progressBar.setIndeterminate(true); progressBar.setVisible(false); sqlTypeDropdown = new JComboBox(DDLUtils.getDDLTypes(session.getDataSources())); sqlTypeDropdown.setRenderer(new DDLGeneratorListCellRenderer()); sqlTypeDropdown.setName("sqlTypeDropDown"); //$NON-NLS-1$ OutputChoiceListener listener = new OutputChoiceListener(sqlTypeDropdown); sqlTypeDropdown.setEnabled(false); sqlTypeDropdown.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { startCompareAction.setEnabled(isStartable()); } }); sqlButton = new JRadioButton(); sqlButton.setName(OUTPUT_SQL); sqlButton.setActionCommand(OUTPUT_SQL); sqlButton.setSelected(false); sqlButton.addActionListener(listener); englishButton = new JRadioButton(); englishButton.setName("englishButton"); //$NON-NLS-1$ englishButton.setActionCommand(OUTPUT_ENGLISH); englishButton.setSelected(true); englishButton.addActionListener(listener); liquibaseButton = new JRadioButton(); liquibaseButton.setName(OUTPUT_LIQUIBASE); //$NON-NLS-1$ liquibaseButton.setActionCommand(OUTPUT_LIQUIBASE); liquibaseButton.setSelected(false); liquibaseButton.addActionListener(listener); showNoChanges = new JCheckBox(); showNoChanges.setName("showNoChanges"); //$NON-NLS-1$ includeIndexes = new JCheckBox(Messages.getString("CompareDMPanel.includeIndexes")); //$NON-NLS-1$ includeIndexes.setName("includeIndexes"); //$NON-NLS-1$ includeIndexes.setSelected(false); // Group the radio buttons. ButtonGroup outputGroup = new ButtonGroup(); outputGroup.add(sqlButton); outputGroup.add(englishButton); outputGroup.add(liquibaseButton); startCompareAction = new StartCompareAction(); startCompareAction.setEnabled(false); swapSourceTargetAction = new SwapSourceTargetAction(); swapSourceTargetAction.setEnabled(true); buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); FormLayout formLayout = new FormLayout("20dlu, 2dlu, pref, 4dlu," + // 1-4 //$NON-NLS-1$ "0:grow, 4dlu, 0:grow, 4dlu," + // 5-8 //$NON-NLS-1$ "0:grow, 4dlu, pref", // 9-11 //$NON-NLS-1$ ""); //$NON-NLS-1$ formLayout.setColumnGroups(new int[][] { { 5, 7, 9, } }); JPanel panel = logger.isDebugEnabled() ? new FormDebugPanel() : new JPanel(); DefaultFormBuilder builder = new DefaultFormBuilder(formLayout, panel); builder.setDefaultDialogBorder(); CellConstraints cc = new CellConstraints(); builder.append(statusComponent, 11); builder.nextLine(); builder.appendSeparator(Messages.getString("CompareDMPanel.olderSeparator")); //$NON-NLS-1$ builder.nextLine(); builder.append(""); // takes up blank space //$NON-NLS-1$ source.buildPartialUI(builder, true, sourceSchemaPop, sourceCatalogPop); builder.appendSeparator(Messages.getString("CompareDMPanel.newerSeparator")); //$NON-NLS-1$ builder.appendRow(builder.getLineGapSpec()); builder.appendRow("pref"); //$NON-NLS-1$ builder.nextLine(2); builder.append(""); //$NON-NLS-1$ target.buildPartialUI(builder, false, targetSchemaPop, targetCatalogPop); ActionListener radioButtonActionEnabler = new ActionListener() { public void actionPerformed(ActionEvent e) { startCompareAction.setEnabled(isStartable()); } }; source.playPenRadio.addActionListener(radioButtonActionEnabler); source.physicalRadio.addActionListener(radioButtonActionEnabler); source.loadRadio.addActionListener(radioButtonActionEnabler); target.playPenRadio.addActionListener(radioButtonActionEnabler); target.physicalRadio.addActionListener(radioButtonActionEnabler); target.loadRadio.addActionListener(radioButtonActionEnabler); JLabel temp; builder.appendSeparator(Messages.getString("CompareDMPanel.outpurFormatSeparator")); //$NON-NLS-1$ builder.appendRow(builder.getLineGapSpec()); builder.appendRow("pref"); //$NON-NLS-1$ builder.nextLine(2); builder.nextColumn(2); builder.append(sqlButton); JPanel ddlTypePanel = new JPanel(new BorderLayout(3, 3)); ddlTypePanel.add(temp = new JLabel(Messages.getString("CompareDMPanel.sqlFor")), BorderLayout.WEST); //$NON-NLS-1$ associate(temp, sqlButton); ddlTypePanel.add(sqlTypeDropdown, BorderLayout.CENTER); // ddl generator // type list ddlTypePanel.add(temp = new JLabel(Messages.getString("CompareDMPanel.makeOlderLookLikeNewer")), //$NON-NLS-1$ BorderLayout.EAST); associate(temp, sqlButton); builder.append(ddlTypePanel, 3); builder.appendRow(builder.getLineGapSpec()); builder.appendRow("pref"); //$NON-NLS-1$ builder.nextLine(2); builder.nextColumn(2); builder.append(liquibaseButton); temp = builder.append(Messages.getString("CompareDMPanel.liqubaseScript")); //$NON-NLS-1$ associate(temp, liquibaseButton); this.lbOptions = new LiquibaseOptionsPanel(); builder.appendRow("pref"); //$NON-NLS-1$ builder.nextLine(1); builder.nextColumn(2); lbOptions.getPanel().setVisible(false); builder.append(lbOptions.getPanel(), 9); builder.appendRow(builder.getLineGapSpec()); builder.appendRow("pref"); //$NON-NLS-1$ builder.nextLine(2); builder.nextColumn(2); builder.append(englishButton); temp = builder.append(Messages.getString("CompareDMPanel.englishDescriptions")); //$NON-NLS-1$ associate(temp, englishButton); builder.appendRow(builder.getLineGapSpec()); builder.appendRow("pref"); //$NON-NLS-1$ builder.nextLine(2); builder.nextColumn(2); builder.append(showNoChanges); temp = builder.append(Messages.getString("CompareDMPanel.suppressSimilarities")); //$NON-NLS-1$ associate(temp, showNoChanges); builder.append(includeIndexes); builder.nextLine(); builder.appendSeparator(Messages.getString("CompareDMPanel.status")); //$NON-NLS-1$ builder.appendRow(builder.getLineGapSpec()); builder.appendRow("pref"); //$NON-NLS-1$ builder.nextLine(2); statusLabel = new JLabel(""); //$NON-NLS-1$ builder.add(statusLabel, cc.xy(5, builder.getRow())); builder.add(progressBar, cc.xyw(7, builder.getRow(), 5)); setLayout(new BorderLayout()); add(builder.getPanel()); setPreferredSize(new Dimension(800, 600)); try { restoreSettingsFromProject(); } catch (SQLObjectException e) { logger.warn("Failed to save user CompareDM preferences!", e); //$NON-NLS-1$ } } /** * Updates the playpen name in the source and target sections whenever this * panel is shown. */ private AncestorListener playpenNameRefreshHandler = new AncestorListener() { public void ancestorAdded(AncestorEvent event) { source.updatePlayPenNameLabel(); target.updatePlayPenNameLabel(); } public void ancestorMoved(AncestorEvent event) { /* don't care */ } public void ancestorRemoved(AncestorEvent event) { /* don't care */ } }; /** * Handles disabling and enabling the "DDL Type" dropdown box and * the no-change suppression checkbox. */ public class OutputChoiceListener implements ActionListener { JComboBox cb; public OutputChoiceListener(JComboBox cb) { this.cb = cb; } public void actionPerformed(ActionEvent e) { boolean wasVisible = lbOptions.getPanel().isVisible(); if (e.getActionCommand().equals(OUTPUT_SQL)) { cb.setEnabled(true); showNoChanges.setEnabled(false); lbOptions.getPanel().setVisible(false); } else if (e.getActionCommand().equals(OUTPUT_LIQUIBASE)) { cb.setEnabled(false); showNoChanges.setEnabled(false); lbOptions.getPanel().setVisible(true); } else { cb.setEnabled(false); lbOptions.getPanel().setVisible(false); showNoChanges.setEnabled(true); } startCompareAction.setEnabled(isStartable()); if (wasVisible != lbOptions.getPanel().isVisible()) { if (CompareDMPanel.this.isVisible()) { CompareDMPanel.this.doLayout(); } } } } public class StartCompareAction extends AbstractAction { private Collection<SQLTable> sourceTables; private Collection<SQLTable> targetTables; private SPSwingWorker compareWorker; public SPSwingWorker getCompareWorker() { return compareWorker; } public StartCompareAction() { super(Messages.getString("CompareDMPanel.startCompareActionName")); //$NON-NLS-1$ } public void actionPerformed(ActionEvent e) { startCompareAction.setEnabled(false); sqlButton.setEnabled(false); englishButton.setEnabled(false); liquibaseButton.setEnabled(false); if (sqlButton.isSelected()) { sqlTypeDropdown.setEnabled(false); } else { showNoChanges.setEnabled(false); } copySettingsToProject(); // XXX: should do most or all of this work in a worker thread final CompareSQL sourceComp; final CompareSQL targetComp; final SQLObject left; final SQLObject right; try { left = source.getObjectToCompare(); if (left.getAllowedChildTypes().contains(SQLTable.class)) { sourceTables = left.getChildren(SQLTable.class); } else { sourceTables = new ArrayList<SQLTable>(); } right = target.getObjectToCompare(); if (right.getAllowedChildTypes().contains(SQLTable.class)) { targetTables = right.getChildren(SQLTable.class); } else { targetTables = new ArrayList<SQLTable>(); } boolean useUUID = source.isModelWithUUID() && target.isModelWithUUID(); sourceComp = new CompareSQL(sourceTables, targetTables, session.getCompareDMSettings().getSuppressSimilarities(), useUUID); sourceComp.setCompareIndices(includeIndexes.isSelected()); targetComp = new CompareSQL(targetTables, sourceTables, session.getCompareDMSettings().getSuppressSimilarities(), useUUID); targetComp.setCompareIndices(includeIndexes.isSelected()); } catch (SQLObjectException ex) { reenableGUIComponents(); ASUtils.showExceptionDialog(session, Messages.getString("CompareDMPanel.couldNotBeginDiffProcess"), //$NON-NLS-1$ ex); return; } catch (IOException ex) { reenableGUIComponents(); ASUtils.showExceptionDialogNoReport(CompareDMPanel.this, Messages.getString("CompareDMPanel.couldNotReadFile"), ex); //$NON-NLS-1$ logger.error("Could not read file", ex); //$NON-NLS-1$ return; } catch (RuntimeException ex) { reenableGUIComponents(); throw new RuntimeException(ex); } compareWorker = new SPSwingWorker(session) { private List<DiffChunk<SQLObject>> diff; private List<DiffChunk<SQLObject>> diff1; private String message; /** * Checks if this engine has been cancelled by another thread. If so, * throws a CancellationException. * * @throws CancellationException if this engine has been cancelled */ protected void checkCancelled() { if (isCancelled()) { throw new CancellationException("User-requested abort"); } } public void doStuff() throws SQLObjectException { try { if (source.physicalRadio.isSelected()) { message = "Refreshing older database"; logger.debug(message); source.getDatabase().refresh(); checkCancelled(); } if (target.physicalRadio.isSelected()) { message = "Refreshing newer database"; logger.debug(message); target.getDatabase().refresh(); checkCancelled(); } setJobSize(sourceComp.getJobSize() + targetComp.getJobSize()); logger.debug("Generating TableDiffs for source"); diff = sourceComp.generateTableDiffs(session); checkCancelled(); logger.debug("Generating TableDiffs for target"); diff1 = targetComp.generateTableDiffs(session); checkCancelled(); message = "Finished"; logger.debug("Finished Compare"); } catch (CancellationException e) { reenableGUIComponents(); setFinished(true); } catch (RuntimeException ex) { reenableGUIComponents(); throw new RuntimeException(ex); } } public void cleanup() { try { if (getDoStuffException() != null) { Throwable exc = getDoStuffException(); logger.error("Error in doStuff()", exc); //$NON-NLS-1$ ASUtils.showExceptionDialog(session, Messages.getString("CompareDMPanel.databaseComparisonFailed"), exc); //$NON-NLS-1$ reenableGUIComponents(); return; } logger.debug("cleanup starts"); //$NON-NLS-1$ CompareDMFormatter dmFormat = new CompareDMFormatter(session, parentDialog, session.getCompareDMSettings()); checkCancelled(); switch (session.getCompareDMSettings().getOutputFormat()) { case SQL: case LIQUIBASE: dmFormat.formatForSQLOutput(diff, diff1, left, right); break; case ENGLISH: dmFormat.formatForEnglishOutput(diff, diff1, left, right); break; default: throw new IllegalStateException("Don't know what type of output to make"); } logger.debug("cleanup finished"); //$NON-NLS-1$ } catch (CancellationException e) { setFinished(true); } finally { reenableGUIComponents(); } } @Override protected String getMessageImpl() { if (sourceComp.hasStarted() && !sourceComp.isFinished()) { return sourceComp.getMessage(); } else if (targetComp.hasStarted() && !targetComp.isFinished()) { return targetComp.getMessage(); } else { return message; } } @Override protected int getProgressImpl() { return sourceComp.getProgress() + targetComp.getProgress(); } }; ProgressWatcher pw = new ProgressWatcher(progressBar, compareWorker, statusLabel); pw.setHideLabelWhenFinished(true); pw.start(); new Thread(compareWorker).start(); } private void reenableGUIComponents() { sqlButton.setEnabled(true); englishButton.setEnabled(true); liquibaseButton.setEnabled(true); if (sqlButton.isSelected()) { sqlTypeDropdown.setEnabled(true); } else { showNoChanges.setEnabled(true); } startCompareAction.setEnabled(isStartable()); } } public SourceOrTargetStuff getSourceStuff() { return source; } public void copySettingsToProject() { CompareDMSettings s = session.getCompareDMSettings(); s.setSaveFlag(true); if (englishButton.isSelected()) { s.setOutputFormat(CompareDMSettings.OutputFormat.ENGLISH); } else if (sqlButton.isSelected()) { s.setOutputFormat(CompareDMSettings.OutputFormat.SQL); } else if (liquibaseButton.isSelected()) { s.setOutputFormat(CompareDMSettings.OutputFormat.LIQUIBASE); s.setLiquibaseSettings(lbOptions.getLiquibaseSettings()); } s.setSuppressSimilarities(showNoChanges.isSelected()); Class<? extends DDLGenerator> selectedGenerator = (Class<? extends DDLGenerator>) sqlTypeDropdown .getSelectedItem(); s.setDdlGenerator(selectedGenerator); SourceOrTargetSettings sourceSetting = s.getSourceSettings(); copySourceOrTargetSettingsToProject(sourceSetting, source); s.setSourceStuff(source); SourceOrTargetSettings targetSetting = s.getTargetSettings(); copySourceOrTargetSettingsToProject(targetSetting, target); s.setTargetStuff(target); s.setLiquibaseSettings(lbOptions.getLiquibaseSettings()); } public void copySourceOrTargetSettingsToProject(SourceOrTargetSettings setting, SourceOrTargetStuff stuff) { if (stuff.databaseDropdown.getItemCount() > 0 && stuff.databaseDropdown.getSelectedIndex() >= 0 && stuff.databaseDropdown.getSelectedItem() != null) setting.setConnectName(((SPDataSource) stuff.databaseDropdown.getSelectedItem()).getName()); else setting.setConnectName(null); if (stuff.catalogDropdown.getItemCount() > 0 && stuff.catalogDropdown.getSelectedIndex() >= 0 && stuff.catalogDropdown.getSelectedItem() != null) setting.setCatalogObject(stuff.catalogDropdown.getSelectedItem()); else setting.setCatalog(null); if (stuff.schemaDropdown.getItemCount() > 0 && stuff.schemaDropdown.getSelectedIndex() >= 0 && stuff.schemaDropdown.getSelectedItem() != null) setting.setSchemaObject(stuff.schemaDropdown.getSelectedItem()); else setting.setSchema(null); setting.setFilePath(stuff.loadFilePath.getText()); if (stuff.loadRadio.isSelected()) setting.setDatastoreType(CompareDMSettings.DatastoreType.FILE); if (stuff.physicalRadio.isSelected()) setting.setDatastoreType(CompareDMSettings.DatastoreType.DATABASE); if (stuff.playPenRadio.isSelected()) setting.setDatastoreType(CompareDMSettings.DatastoreType.PROJECT); } private void restoreSettingsFromProject() throws SQLObjectException { CompareDMSettings s = session.getCompareDMSettings(); restoreSourceOrTargetSettingsFromProject(source, s.getSourceSettings()); restoreSourceOrTargetSettingsFromProject(target, s.getTargetSettings()); lbOptions.restoreSettings(s.getLiquibaseSettings()); if (s.getOutputFormat() == CompareDMSettings.OutputFormat.ENGLISH) englishButton.doClick(); if (s.getOutputFormat() == CompareDMSettings.OutputFormat.SQL) sqlButton.doClick(); if (s.getOutputFormat() == CompareDMSettings.OutputFormat.LIQUIBASE) liquibaseButton.doClick(); showNoChanges.setSelected(s.getSuppressSimilarities()); sqlTypeDropdown.setSelectedItem(s.getDdlGenerator()); } private void restoreSourceOrTargetSettingsFromProject(SourceOrTargetStuff stuff, SourceOrTargetSettings set) throws SQLObjectException { DatastoreType rbs = set.getDatastoreType(); if (rbs == CompareDMSettings.DatastoreType.PROJECT) stuff.playPenRadio.doClick(); else if (rbs == CompareDMSettings.DatastoreType.DATABASE) stuff.physicalRadio.doClick(); else if (rbs == CompareDMSettings.DatastoreType.FILE) stuff.loadRadio.doClick(); List<? extends SPDataSource> lds = session.getContext().getConnections(); for (SPDataSource ds : lds) { if (ds.getDisplayName().equals(set.getConnectName())) { stuff.databaseDropdown.setSelectedItem(ds); if (set.getCatalog() != null) { stuff.catalogDropdown.getModel().addListDataListener( new RestoreSettingsListener(stuff.catalogDropdown, set.getCatalog())); } if (set.getSchema() != null) { stuff.schemaDropdown.getModel().addListDataListener( new RestoreSettingsListener(stuff.schemaDropdown, set.getSchema())); } if (stuff.catalogDropdown.getItemCount() == 0 && stuff.schemaDropdown.getItemCount() > 0 && set.getSchema() != null && set.getSchema().length() > 0) { for (int j = 0; j < stuff.schemaDropdown.getItemCount(); j++) { SQLObject o2 = (SQLObject) stuff.schemaDropdown.getItemAt(j); if (o2.getName().equals(set.getSchema())) { stuff.schemaDropdown.setSelectedIndex(j); break; } } } break; } } if (set.getFilePath() != null) stuff.loadFilePath.setText(set.getFilePath()); } public SourceOrTargetStuff getTargetStuff() { return target; } /** * Sets the values for the database, schema and catalog in the panel * for the source set, and set the target to look in the play pen */ public void compareCurrentWithOrig(SQLSchema schema, SQLCatalog catalog, SQLDatabase db) { //catalog may be null for some dbs (at least in Oracle) if (catalog != null) { source.catalogPop.setDefaultCatalog(catalog.getName()); } //schema can be null in a MYSQL Database if (schema != null) { //this needs to be set because if there is no catalog //then the catalog populator is responsible for the schemas source.catalogPop.setDefaultSchema(schema.getName()); source.schemaPop.setDefaultSelect(schema.getName()); } source.physicalRadio.doClick(); //selects the correct data base, this only looks at for (int x = 1; x < source.databaseDropdown.getItemCount(); x++) { SPDataSource curr = (SPDataSource) (source.databaseDropdown.getItemAt(x)); if (curr != null && curr.getName().equals(db.getName())) { source.databaseDropdown.setSelectedIndex(x); break; } } target.playPenRadio.doClick(); } /** * A simple action to swap the settings for older and newer. */ public class SwapSourceTargetAction extends AbstractAction { public SwapSourceTargetAction() { super(Messages.getString("CompareDMPanel.swapSourceTargetActionName")); //$NON-NLS-1$ } public void actionPerformed(ActionEvent e) { boolean sourcePlayPen = source.playPenRadio.isSelected(); boolean sourcePhysical = source.physicalRadio.isSelected(); String sourceLoadFilePath = source.loadFilePath.getText(); String targetLoadFilePath = target.loadFilePath.getText(); SPDataSource soDBObj = null; SQLObject soCatObj = null; SQLObject soSchemaObj = null; SPDataSource taDBObj = null; SQLObject taCatObj = null; SQLObject taSchemaObj = null; //gets the data from the drop down menus //the objects are only loaded as needed because changing an option //in the DB drop down menu if it is disabled will still enable //the catalog and or schema dropdowns if (source.physicalRadio.isSelected()) { soDBObj = (SPDataSource) source.databaseDropdown.getSelectedItem(); soCatObj = (SQLObject) source.catalogDropdown.getSelectedItem(); soSchemaObj = (SQLObject) source.schemaDropdown.getSelectedItem(); } if (target.physicalRadio.isSelected()) { taDBObj = (SPDataSource) target.databaseDropdown.getSelectedItem(); taCatObj = (SQLObject) target.catalogDropdown.getSelectedItem(); taSchemaObj = (SQLObject) target.schemaDropdown.getSelectedItem(); } target.loadFilePath.setText(sourceLoadFilePath); source.loadFilePath.setText(targetLoadFilePath); //select the db connection in the other list //then set the defaults for the catalog and schema so they //will be updated by the db connection dropdown change event if (soDBObj != null) { for (int x = 1; x < target.databaseDropdown.getItemCount(); x++) { if (target.databaseDropdown.getItemAt(x).equals(soDBObj)) { target.databaseDropdown.setSelectedIndex(x); } } } if (soCatObj != null) { target.catalogPop.setDefaultCatalog(soCatObj.getName()); } if (soSchemaObj != null) { target.catalogPop.setDefaultSchema(soSchemaObj.getName()); target.schemaPop.setDefaultSelect(soSchemaObj.getName()); } if (taDBObj != null) { for (int x = 1; x < source.databaseDropdown.getItemCount(); x++) { if (source.databaseDropdown.getItemAt(x).equals(taDBObj)) { source.databaseDropdown.setSelectedIndex(x); } } } if (taCatObj != null) { source.catalogPop.setDefaultCatalog(taCatObj.getName()); } if (taSchemaObj != null) { source.catalogPop.setDefaultSchema(taSchemaObj.getName()); source.schemaPop.setDefaultSelect(taSchemaObj.getName()); } if (target.playPenRadio.isSelected()) { source.playPenRadio.doClick(); } else if (target.physicalRadio.isSelected()) { source.physicalRadio.doClick(); } else { source.loadRadio.doClick(); } if (sourcePlayPen) { target.playPenRadio.doClick(); } else if (sourcePhysical) { target.physicalRadio.doClick(); } else { target.loadRadio.doClick(); } } } /** * Associates the given label with the given button, so that mouse * events on the label behave as if they were clicks on the button. We * need this because of the funny way the radio buttons and checkboxes * on this panel are laid out. * * @param l * The label that should be clickable like the button. * @param b * The button that should receive the label's clicks. */ private void associate(final JLabel l, final AbstractButton b) { l.addMouseListener(new MouseListener() { private void retarget(MouseEvent e) { MouseEvent newEvent = new MouseEvent(b, e.getID(), e.getWhen(), e.getModifiers(), 0, 0, e.getClickCount(), e.isPopupTrigger(), e.getButton()); b.dispatchEvent(newEvent); } public void mouseReleased(MouseEvent e) { retarget(e); } public void mousePressed(MouseEvent e) { retarget(e); } public void mouseExited(MouseEvent e) { retarget(e); } public void mouseEntered(MouseEvent e) { retarget(e); } public void mouseClicked(MouseEvent e) { retarget(e); } }); } }