/* * Copyright (c) 2008, SQL Power Group Inc. * * This file is part of SQL Power Library. * * SQL Power Library 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. * * SQL Power Library 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.swingui.db; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ListModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.undo.UndoManager; import org.apache.log4j.Logger; import ca.sqlpower.sql.DataSourceCollection; import ca.sqlpower.sql.JDBCDataSource; import ca.sqlpower.sql.JDBCDataSourceType; import ca.sqlpower.swingui.AddRemoveIcon; import ca.sqlpower.swingui.DataEntryPanel; import ca.sqlpower.swingui.DataEntryPanelBuilder; import ca.sqlpower.swingui.Messages; import ca.sqlpower.swingui.SPDataSourceTypeListCellRenderer; import ca.sqlpower.swingui.SPSUtils; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.layout.FormLayout; public class DataSourceTypeEditor implements DataEntryPanel { private static final Logger logger = Logger.getLogger(DataSourceTypeEditor.class); /** * The panel that this editor's GUI lives in. */ private final JPanel panel; private final DataSourceCollection<JDBCDataSource> dataSourceCollection; /** * The list of data source types. */ private final JList dsTypeList; /** * Button for adding a new data source type. */ private final JButton addDsTypeButton; /** * Button for deleting the selected data source type. */ private final JButton removeDsTypeButton; /** * The panel that edits the currently-selected data source type. */ private final DataSourceTypeEditorPanel dsTypePanel; /** * An undo manager for DS types. */ private final UndoManager undoManager = new UndoManager(); /** * The model for the list of data source types in this editor. */ private DefaultListModel dsTypeListModel; /** * If true, then this editor will not try to save settings locally. It assumes that they will be sent to a server. */ private final boolean enterprise; /** * Creates a multi-tabbed panel with facilities for configuring all the * database types defined in a particular data source collection. * * @param collection * The data source collection to edit. * @param owner The Window that should own any dialogs created within the editor GUI. * @see DefaultDataSourceTypeDialogFactory for a more out-of-the-box setup */ public DataSourceTypeEditor(DataSourceCollection<JDBCDataSource> dataSourceCollection, final Window owner, boolean enterprise) { this.dataSourceCollection = dataSourceCollection; this.enterprise = enterprise; dsTypeListModel = new DefaultListModel(); dataSourceCollection.addUndoableEditListener(undoManager); for (JDBCDataSourceType type : dataSourceCollection.getDataSourceTypes()) { dsTypeListModel.addElement(type); type.addUndoableEditListener(undoManager); } dsTypeList = new JList(dsTypeListModel); dsTypeList.setCellRenderer(new SPDataSourceTypeListCellRenderer()); addDsTypeButton = new JButton(new AddRemoveIcon(AddRemoveIcon.Type.ADD)); addDsTypeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final NewDataSourceTypePanel copyPropertiesPanel = new NewDataSourceTypePanel(DataSourceTypeEditor.this, DataSourceTypeEditor.this.dataSourceCollection); final JDialog d = DataEntryPanelBuilder.createDataEntryPanelDialog( copyPropertiesPanel, owner, "Copy Properties", DataEntryPanelBuilder.OK_BUTTON_LABEL); d.pack(); d.setLocationRelativeTo(owner); d.setVisible(true); } }); removeDsTypeButton = new JButton(new AddRemoveIcon(AddRemoveIcon.Type.REMOVE)); removeDsTypeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { removeSelectedDsType(); } }); removeDsTypeButton.setEnabled(false); dsTypePanel = new DataSourceTypeEditorPanel(dataSourceCollection, owner); dsTypeList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { JDBCDataSourceType dst = (JDBCDataSourceType) dsTypeList.getSelectedValue(); switchToDsType(dst); } // remove button enabled when a datasource has been selected removeDsTypeButton.setEnabled(dsTypeList.getSelectedIndex() != -1); } }); panel = createPanel(); } /** * Creates a multi-tabbed panel with facilities for configuring all the * database types defined in a particular data source collection. * * @param collection * The data source collection to edit. * @param owner The Window that should own any dialogs created within the editor GUI. * @see DefaultDataSourceTypeDialogFactory for a more out-of-the-box setup */ public DataSourceTypeEditor(DataSourceCollection<JDBCDataSource> dataSourceCollection, final Window owner) { this(dataSourceCollection, owner, false); } /** * Removes the selected data source type from the list. If there is * no selected type, does nothing. */ private void removeSelectedDsType() { JDBCDataSourceType type = (JDBCDataSourceType) dsTypeList.getSelectedValue(); if (type != null) { ((DefaultListModel) dsTypeList.getModel()).removeElement(type); dataSourceCollection.removeDataSourceType(type); } } public void addDsType(JDBCDataSourceType type) { if (type == null) { throw new NullPointerException("Don't add null data source types, silly!"); //$NON-NLS-1$ } dataSourceCollection.addDataSourceType(type); ((DefaultListModel) dsTypeList.getModel()).addElement(type); dsTypeList.setSelectedValue(type, true); } /** * Creates the panel layout. Requires that the GUI components have already * been created. Does not fill in any values into the components. See * {@link #switchToDsType()} for that. */ private JPanel createPanel() { FormLayout layout = new FormLayout("fill:max(60dlu;pref), 6dlu, pref:grow", "pref, 6dlu, pref:grow, 3dlu, pref"); //$NON-NLS-1$ //$NON-NLS-2$ DefaultFormBuilder fb = new DefaultFormBuilder(layout); fb.setDefaultDialogBorder(); JComponent addRemoveBar = new JPanel(new FlowLayout(FlowLayout.LEFT)); addRemoveBar.add(addDsTypeButton); addRemoveBar.add(removeDsTypeButton); JScrollPane dsTypePane = new JScrollPane(dsTypeList); //Setting the preferred size to 0 so the add/remove bar and the default size //set the width of the column and not the max type name width. dsTypePane.setPreferredSize(new Dimension(0, 0)); fb.add(dsTypePane, "1, 1, 1, 3"); //$NON-NLS-1$ fb.add(addRemoveBar, "1, 5"); //$NON-NLS-1$ fb.add(dsTypePanel.getPanel(), "3, 1"); //$NON-NLS-1$ return fb.getPanel(); } /** * Returns this editor's GUI. */ public JPanel getPanel() { return panel; } /** * Copies all the data source types and their properties back to the * DataSourceCollection we're editing. */ public boolean applyChanges() { logger.debug("Applying changes to all data source types"); //$NON-NLS-1$ applyCurrentChanges(); ListModel lm = dsTypeList.getModel(); for (int i = 0; i < lm.getSize(); i++) { JDBCDataSourceType dst = (JDBCDataSourceType) lm.getElementAt(i); dataSourceCollection.mergeDataSourceType(dst); } if (!enterprise) { try { dataSourceCollection.write(); } catch (IOException ex) { SPSUtils.showExceptionDialogNoReport(panel, Messages.getString("DataSourceTypeEditor.errorSavingToPlDotIni"), ex); //$NON-NLS-1$ } } undoManager.discardAllEdits(); return true; } /** * This method is a no-op implementation, since all we have to do to discard the * changes is not copy them back to the model. */ public void discardChanges() { logger.debug("Discarding changes to all data source types."); int undoCount = 0; while (undoManager.canUndo()) { undoCount++; undoManager.undo(); } logger.debug("There were " + undoCount + " changes."); dsTypePanel.discardChanges(); dsTypeListModel.clear(); for (JDBCDataSourceType type : dataSourceCollection.getDataSourceTypes()) { dsTypeListModel.addElement(type); } } /** * Call this to disconnect the editor from the DS types. */ public void cleanup() { for (JDBCDataSourceType type : dataSourceCollection.getDataSourceTypes()) { type.removeUndoableEditListener(undoManager); } dataSourceCollection.removeUndoableEditListener(undoManager); } /** * Causes this editor to set up all its GUI components to edit the given data source type. * Null is an acceptable value, and means to make no DS Type the current type. */ public void switchToDsType(JDBCDataSourceType dst) { applyCurrentChanges(); dsTypeList.setSelectedValue(dst, true); dsTypePanel.editDsType(dst); } private void applyCurrentChanges() { dsTypePanel.applyChanges(); } public void addTab(String title, DataSourceTypeEditorTabPanel dataEntryPanel) { dsTypePanel.addTab(title, dataEntryPanel); } public boolean hasUnsavedChanges() { return undoManager.canUndo(); } }