/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.mappingsplugin.ui.db;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.swing.Action;
import javax.swing.ComboBoxModel;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import org.eclipse.persistence.tools.workbench.framework.action.AbstractFrameworkAction;
import org.eclipse.persistence.tools.workbench.framework.action.FrameworkAction;
import org.eclipse.persistence.tools.workbench.framework.context.WorkbenchContextHolder;
import org.eclipse.persistence.tools.workbench.framework.resources.ResourceRepository;
import org.eclipse.persistence.tools.workbench.framework.ui.dialog.NewNameDialog;
import org.eclipse.persistence.tools.workbench.framework.ui.view.ScrollablePropertiesPage;
import org.eclipse.persistence.tools.workbench.framework.uitools.SwingComponentFactory;
import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWColumn;
import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWReference;
import org.eclipse.persistence.tools.workbench.mappingsmodel.db.MWTable;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.common.cell.TableCellRendererAdapter;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.project.relational.RelationalProjectComponentFactory;
import org.eclipse.persistence.tools.workbench.uitools.app.CollectionAspectAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.CollectionValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.ItemPropertyListValueModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.ListValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.PropertyAspectAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.PropertyValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.SimplePropertyValueModel;
import org.eclipse.persistence.tools.workbench.uitools.app.SortedListValueModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.ValuePropertyPropertyValueModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.ColumnAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.ComboBoxModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.ListModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.ObjectListSelectionModel;
import org.eclipse.persistence.tools.workbench.uitools.app.swing.TableModelAdapter;
import org.eclipse.persistence.tools.workbench.uitools.cell.AdaptableListCellRenderer;
import org.eclipse.persistence.tools.workbench.uitools.cell.CheckBoxTableCellRenderer;
import org.eclipse.persistence.tools.workbench.uitools.cell.ComboBoxTableCellRenderer;
import org.eclipse.persistence.tools.workbench.uitools.cell.TableCellEditorAdapter;
import org.eclipse.persistence.tools.workbench.utility.CollectionTools;
public class ReferencesPropertiesPage extends ScrollablePropertiesPage {
private ListValueModel targetTablesHolder;
ListValueModel sortedReferencesAdapter;
private TableModel tableModel;
private ObjectListSelectionModel rowSelectionModel;
private PropertyValueModel selectedReferenceHolder;
private Action removeAction;
private Action renameAction;
JTable table;
public ReferencesPropertiesPage(PropertyValueModel tableNodeHolder, WorkbenchContextHolder contextHolder) {
super(tableNodeHolder, contextHolder);
}
protected void initialize(PropertyValueModel nodeHolder) {
super.initialize(nodeHolder);
this.targetTablesHolder = RelationalProjectComponentFactory.buildExtendedTablesHolder(getSelectionHolder());
this.sortedReferencesAdapter = buildSortedReferencesAdapter();
this.tableModel = buildTableModel();
this.selectedReferenceHolder = buildSelectedReferenceHolder();
this.rowSelectionModel = buildRowSelectionModel();
getSelectionHolder().addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (ReferencesPropertiesPage.this.table.isEditing()) {
ReferencesPropertiesPage.this.table.getCellEditor().cancelCellEditing();
}
if (ReferencesPropertiesPage.this.sortedReferencesAdapter.size() > 0) {
setSelectedReference((MWReference) ReferencesPropertiesPage.this.sortedReferencesAdapter.getItem(0));
}
}
});
}
protected String helpTopicId() {
return "table.references";
}
private ListValueModel buildSortedReferencesAdapter() {
return new SortedListValueModelAdapter(this.buildReferenceNameAdapter());
}
// the list will need to be re-sorted if a name changes
private ListValueModel buildReferenceNameAdapter() {
return new ItemPropertyListValueModelAdapter(this.buildReferencesAdapter(), MWColumn.NAME_PROPERTY);
}
private CollectionValueModel buildReferencesAdapter() {
return new CollectionAspectAdapter(getSelectionHolder(), MWTable.REFERENCES_COLLECTION) {
protected Iterator getValueFromSubject() {
return ((MWTable) this.subject).references();
}
protected int sizeFromSubject() {
return ((MWTable) this.subject).referencesSize();
}
};
}
private TableModel buildTableModel() {
return new TableModelAdapter(this.sortedReferencesAdapter, this.buildColumnAdapter());
}
private ColumnAdapter buildColumnAdapter() {
return new ReferencesColumnAdapter(resourceRepository());
}
private PropertyValueModel buildSelectedReferenceHolder() {
return new SimplePropertyValueModel(null);
}
private ObjectListSelectionModel buildRowSelectionModel() {
ObjectListSelectionModel model = new ObjectListSelectionModel(new ListModelAdapter(this.sortedReferencesAdapter));
model.addListSelectionListener(this.buildRowSelectionListener());
model.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
return model;
}
private ListSelectionListener buildRowSelectionListener() {
return new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if ( ! e.getValueIsAdjusting()) {
ReferencesPropertiesPage.this.rowSelectionChanged();
}
}
};
}
void rowSelectionChanged() {
Object selection = this.rowSelectionModel.getSelectedValue();
this.selectedReferenceHolder.setValue(selection);
boolean referenceSelected = (selection != null);
this.removeAction.setEnabled(referenceSelected);
this.renameAction.setEnabled(referenceSelected);
}
protected Component buildPage() {
JPanel mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
// Create the button panel first
JPanel buttonPanel = buildButtonPanel();
constraints.gridx = 1;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 0;
constraints.weighty = 0;
constraints.fill = GridBagConstraints.NONE;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.insets = new Insets(5, 5, 5, 5);
mainPanel.add(buttonPanel, constraints);
this.table = this.buildTable();
JScrollPane scrollPane = new JScrollPane(this.table);
scrollPane.getViewport().setPreferredSize(new Dimension(50,50));
scrollPane.getViewport().setBackground(this.table.getBackground());
constraints.gridx = 0;
constraints.gridy = 0;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weightx = 1;
constraints.weighty = 1;
constraints.fill = GridBagConstraints.BOTH;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.insets = new Insets(5, 5, 5, 0);
mainPanel.add(scrollPane, constraints);
ColumnPairsPanel fieldAssociationPage = buildFieldAssociationsPanel();
addHelpTopicId(fieldAssociationPage, helpTopicId() + ".associations");
constraints.gridx = 0;
constraints.gridy = 1;
constraints.gridwidth = 2;
constraints.gridheight = 1;
constraints.weightx = 1;
constraints.weighty = 1;
constraints.fill = GridBagConstraints.BOTH;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.insets = new Insets(5,5,5,5);
mainPanel.add(fieldAssociationPage, constraints);
addPaneForAlignment(fieldAssociationPage);
addHelpTopicId(mainPanel, helpTopicId());
return mainPanel;
}
private JTable buildTable() {
JTable t = SwingComponentFactory.buildTable(this.tableModel, this.rowSelectionModel);
t.getTableHeader().setReorderingAllowed(false);
int rowHeight = 20; // start with minimum of 20
// target table column (combo-box)
TableColumn column = t.getColumnModel().getColumn(ReferencesColumnAdapter.TARGET_TABLE_COLUMN);
ComboBoxTableCellRenderer targetTableRenderer = this.buildTargetTableComboBoxRenderer();
column.setCellRenderer(targetTableRenderer);
column.setCellEditor(new TableCellEditorAdapter(this.buildTargetTableComboBoxRenderer()));
rowHeight = Math.max(rowHeight, targetTableRenderer.getPreferredHeight());
// on database column (check box)
column = t.getColumnModel().getColumn(ReferencesColumnAdapter.ON_DATABASE_COLUMN);
CheckBoxTableCellRenderer onDatabaseRenderer = new CheckBoxTableCellRenderer();
column.setCellRenderer(onDatabaseRenderer);
column.setCellEditor(new TableCellEditorAdapter(new CheckBoxTableCellRenderer()));
rowHeight = Math.max(rowHeight, onDatabaseRenderer.getPreferredHeight());
t.setRowHeight(rowHeight);
return t;
}
private JPanel buildButtonPanel() {
JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 0, 5));
JButton button = this.buildAddButton();
buttonPanel.add(button);
addAlignRight(button);
button = this.buildRemoveButton();
buttonPanel.add(button);
addAlignRight(button);
button = this.buildRenameButton();
buttonPanel.add(button);
addAlignRight(button);
return buttonPanel;
}
private ColumnPairsPanel buildFieldAssociationsPanel() {
return new ColumnPairsPanel(getWorkbenchContextHolder(), this.selectedReferenceHolder);
}
// ********** add **********
private JButton buildAddButton() {
return new JButton(this.buildAddAction());
}
private Action buildAddAction() {
FrameworkAction action = new AbstractFrameworkAction(getApplicationContext()) {
protected void initialize() {
initializeText("ADD_REFERENCE_BUTTON_TEXT");
initializeMnemonic("ADD_REFERENCE_BUTTON_TEXT");
}
public void actionPerformed(ActionEvent event) {
ReferencesPropertiesPage.this.addReference();
}
};
action.setEnabled(true);
return action;
}
void addReference() {
if (this.table.isEditing()) {
this.table.getCellEditor().stopCellEditing();
}
List targetTables = new ArrayList(this.table().getDatabase().tablesSize());
CollectionTools.addAll(targetTables, this.table().getDatabase().tables());
CollectionTools.sort(targetTables);
NewTableReferenceDialog dialog =
NewTableReferenceDialog.buildReferenceDialogDisallowSourceTableSelection(
this.getWorkbenchContext(),
Collections.singletonList(this.selection()),
targetTables
);
dialog.setSourceTable(this.table());
dialog.setTargetTable((MWTable) targetTables.get(0)); // there will always be at least one table in the list
dialog.show();
if (dialog.wasCanceled()) {
return;
}
MWReference reference = table().addReference(dialog.getReferenceName(), dialog.getTargetTable());
reference.setOnDatabase(dialog.isOnDatabase());
setSelectedReference(reference);
}
// ********** remove **********
private JButton buildRemoveButton() {
return new JButton(this.buildRemoveAction());
}
private Action buildRemoveAction() {
this.removeAction = new AbstractFrameworkAction(getApplicationContext()) {
protected void initialize() {
initializeText("REMOVE_REFERENCE_BUTTON_TEXT");
initializeMnemonic("REMOVE_REFERENCE_BUTTON_TEXT");
}
public void actionPerformed(ActionEvent event) {
ReferencesPropertiesPage.this.removeReference();
}
};
this.removeAction.setEnabled(false);
return this.removeAction;
}
void removeReference() {
if (this.table.isEditing()) {
this.table.getCellEditor().stopCellEditing();
}
int option = JOptionPane.showConfirmDialog(getWorkbenchContext().getCurrentWindow(),
resourceRepository().getString("REMOVE_REFERENCES_WARNING_DIALOG.message"),
resourceRepository().getString("REMOVE_REFERENCES_WARNING_DIALOG.title"),
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (option == JOptionPane.YES_OPTION) {
MWReference reference = this.selectedReference();
if (reference != null) {
this.table().removeReference(reference);
}
}
}
// ********** rename **********
private JButton buildRenameButton() {
return new JButton(this.buildRenameAction());
}
private Action buildRenameAction() {
this.renameAction = new AbstractFrameworkAction(getApplicationContext()) {
protected void initialize() {
initializeText("RENAME_REFERENCE_BUTTON_TEXT");
initializeMnemonic("RENAME_REFERENCE_BUTTON_TEXT");
}
public void actionPerformed(ActionEvent event) {
ReferencesPropertiesPage.this.renameReference();
}
};
this.renameAction.setEnabled(false);
return this.renameAction;
}
void renameReference() {
MWReference reference = this.selectedReference();
if (reference != null) {
String name = this.getReferenceNameFromUser(reference.getName(), "RENAME_REFERENCE_DIALOG");
if (name != null) {
reference.setName(name);
this.setSelectedReference(reference);
}
}
}
// ********** new name dialog **********
private String getReferenceNameFromUser(String originalName, String messageKey) {
NewNameDialog dialog = this.buildNewNameDialog(originalName, messageKey);
dialog.show();
return (dialog.wasConfirmed()) ? dialog.getNewName() : null;
}
private NewNameDialog buildNewNameDialog(String originalName, String messageKey) {
NewNameDialog.Builder builder = new NewNameDialog.Builder();
builder.setExistingNames(this.table().referenceNames());
builder.setOriginalName(originalName);
builder.setTextFieldDescription(resourceRepository().getString(messageKey + ".message"));
builder.setTitle(resourceRepository().getString(messageKey + ".title"));
builder.setHelpTopicId("dialog.referenceRename");
return builder.buildDialog(getWorkbenchContext());
}
// **********target table (for cell editor) **********
private ComboBoxTableCellRenderer buildTargetTableComboBoxRenderer() {
return new ComboBoxTableCellRenderer(this.buildTargetTableComboBoxModel(), this.buildTargetTableListCellRenderer());
}
private ComboBoxModel buildTargetTableComboBoxModel() {
return new ComboBoxModelAdapter(this.targetTablesHolder, new SimplePropertyValueModel());
}
private ListCellRenderer buildTargetTableListCellRenderer() {
return new AdaptableListCellRenderer(new TableCellRendererAdapter(this.resourceRepository()));
}
// ********** queries **********
private MWReference selectedReference() {
if (this.rowSelectionModel.isSelectionEmpty()) {
return null;
}
return (MWReference) this.rowSelectionModel.getSelectedValue();
}
void setSelectedReference(MWReference reference) {
this.rowSelectionModel.setSelectedValue(reference);
}
private MWTable table() {
return (MWTable) getSelectionHolder().getValue();
}
// ********** classes **********
public static class ReferencesColumnAdapter implements ColumnAdapter {
private ResourceRepository resourceRepository;
public static final int COLUMN_COUNT = 3;
public static final int REFERENCE_NAME_COLUMN = 0;
public static final int TARGET_TABLE_COLUMN = 1;
public static final int ON_DATABASE_COLUMN = 2;
private static final String[] COLUMN_NAME_KEYS = new String[] {
"REFERENCE_NAME_COLUMN_HEADER",
"TARGET_TABLE_COLUMN_HEADER",
"ON_DATABASE_COLUMN_HEADER",
};
protected ReferencesColumnAdapter(ResourceRepository repository) {
super();
this.resourceRepository = repository;
}
public int getColumnCount() {
return COLUMN_COUNT;
}
public String getColumnName(int index) {
return this.resourceRepository.getString(COLUMN_NAME_KEYS[index]);
}
public Class getColumnClass(int index) {
switch (index) {
case REFERENCE_NAME_COLUMN: return Object.class;
case TARGET_TABLE_COLUMN: return Object.class;
case ON_DATABASE_COLUMN: return Boolean.class;
default: return Object.class;
}
}
public boolean isColumnEditable(int index) {
return index != REFERENCE_NAME_COLUMN;
}
public PropertyValueModel[] cellModels(Object subject) {
MWReference reference = (MWReference) subject;
PropertyValueModel[] result = new PropertyValueModel[COLUMN_COUNT];
result[REFERENCE_NAME_COLUMN] = this.buildReferenceNameAdapter(reference);
result[TARGET_TABLE_COLUMN] = this.buildTargetTableAdapter(reference);
result[ON_DATABASE_COLUMN] = this.buildOnDatabaseAdapter(reference);
return result;
}
private PropertyValueModel buildReferenceNameAdapter(MWReference reference) {
return new PropertyAspectAdapter(MWReference.NAME_PROPERTY, reference) {
protected Object getValueFromSubject() {
return ((MWReference) this.subject).getName();
}
protected void setValueOnSubject(Object value) {
((MWReference) this.subject).setName((String) value);
}
};
}
private PropertyValueModel buildTargetTableAdapter(MWReference reference) {
PropertyValueModel propertyValueModel = new PropertyAspectAdapter(MWReference.TARGET_TABLE_PROPERTY, reference) {
protected Object getValueFromSubject() {
return ((MWReference) this.subject).getTargetTable();
}
protected void setValueOnSubject(Object value) {
((MWReference) this.subject).setTargetTable((MWTable) value);
}
};
return new ValuePropertyPropertyValueModelAdapter(propertyValueModel, MWTable.QUALIFIED_NAME_PROPERTY);
}
private PropertyValueModel buildOnDatabaseAdapter(MWReference reference) {
return new PropertyAspectAdapter(MWReference.ON_DATABASE_PROPERTY, reference) {
protected Object getValueFromSubject() {
return Boolean.valueOf(((MWReference) this.subject).isOnDatabase());
}
protected void setValueOnSubject(Object value) {
((MWReference) this.subject).setOnDatabase(((Boolean) value).booleanValue());
}
};
}
}
}