blob: 3c2abe3ebbc621ef45364cbfb88443d5a571be45 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2009 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0, which accompanies this distribution
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.jpa.ui.internal.wizards;
import java.util.EventListener;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.jpt.common.utility.internal.ListenerList;
import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable;
import org.eclipse.jpt.jpa.core.JpaProject;
import org.eclipse.jpt.jpa.db.ConnectionAdapter;
import org.eclipse.jpt.jpa.db.ConnectionListener;
import org.eclipse.jpt.jpa.db.ConnectionProfile;
import org.eclipse.jpt.jpa.db.Schema;
import org.eclipse.jpt.jpa.db.SchemaContainer;
import org.eclipse.jpt.jpa.ui.internal.JpaHelpContextIds;
import org.eclipse.jpt.jpa.ui.internal.JptUiMessages;
import org.eclipse.jpt.jpa.ui.internal.properties.JpaProjectPropertiesPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
/**
* Most of the behavior is in DatabaseGroup....
*
* We open the wizard page with the JPA project's connection profile and
* default schema selected (if possible), but then the selections are driven
* by the user. If the user re-selects the JPA project's connection profile,
* we will pre-select the project's default schema if possible.
*/
public class DatabaseSchemaWizardPage extends WizardPage {
final JpaProject jpaProject;
private final ListenerList<Listener> listenerList = new ListenerList<Listener>(Listener.class);
private DatabaseGroup databaseGroup;
public DatabaseSchemaWizardPage(JpaProject jpaProject) {
super("Database Schema"); //$NON-NLS-1$
if (jpaProject == null) {
throw new NullPointerException();
}
this.jpaProject = jpaProject;
this.setTitle(JptUiMessages.DatabaseSchemaWizardPage_title);
this.setMessage(JptUiMessages.DatabaseSchemaWizardPage_desc);
}
public void createControl(Composite parent) {
this.setPageComplete(false);
this.setControl(this.buildTopLevelControl(parent));
}
private Control buildTopLevelControl(Composite parent) {
Composite composite = new Composite(parent, SWT.NULL);
composite.setLayout(new GridLayout());
this.databaseGroup = new DatabaseGroup(composite);
Dialog.applyDialogFont(parent);
PlatformUI.getWorkbench().getHelpSystem().setHelp(composite, JpaHelpContextIds.PROPERTIES_JAVA_PERSISTENCE_CONNECTION);
return composite;
}
public ConnectionProfile getJpaProjectConnectionProfile() {
return this.jpaProject.getConnectionProfile();
}
public Schema getSelectedSchema() {
return this.databaseGroup.getSelectedSchema();
}
@Override
public void dispose() {
this.databaseGroup.dispose();
super.dispose();
}
// ********** listeners **********
public void addListener(Listener listener) {
this.listenerList.add(listener);
}
public void removeListener(Listener listener) {
this.listenerList.remove(listener);
}
void fireSchemaChanged(Schema schema) {
this.setPageComplete(schema != null);
for (Listener listener : this.listenerList.getListeners()) {
listener.selectedSchemaChanged(schema);
}
}
// ********** listener interface **********
/**
* Allows clients to listen for changes to the selected connection profile
* and schema.
*/
public interface Listener extends EventListener {
void selectedSchemaChanged(Schema schema);
}
// ********** database group **********
/**
* schema combo-box
* add project connection link
* reconnect link
*/
class DatabaseGroup {
// these are kept in synch with the selection
private Schema selectedSchema;
private final Combo schemaComboBox;
private final Link reconnectLink;
private Link addJpaProjectConnectionLink;
private final ConnectionListener connectionListener;
// ********** construction **********
DatabaseGroup(Composite composite) {
super();
Group group = new Group(composite, SWT.NONE);
group.setLayout(new GridLayout(2, false)); // false = do not make columns equal width
group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
group.setText(JptUiMessages.DatabaseSchemaWizardPage_schemaSettings);
// TODO PlatformUI.getWorkbench().getHelpSystem().setHelp(this.group, JpaHelpContextIds.XXX);
// schema combo-box
this.buildLabel(group, 1, JptUiMessages.DatabaseSchemaWizardPage_schema);
this.schemaComboBox = this.buildComboBox(group, this.buildSchemaComboBoxSelectionListener());
String message = (this.projectHasAConnection()) ?
JptUiMessages.DatabaseSchemaWizardPage_schemaInfo :
JptUiMessages.DatabaseSchemaWizardPage_connectionInfo;
this.buildLabel(group, 2, message);
// add project's connection link
if( ! this.projectHasAConnection()) {
this.addJpaProjectConnectionLink = this.buildLink(group,
JptUiMessages.DatabaseSchemaWizardPage_addConnectionToProject,
this.buildAddJpaProjectConnectionLinkListener());
}
// reconnect link
this.reconnectLink = this.buildLink(group, JptUiMessages.DatabaseSchemaWizardPage_connectLink, this.buildReconnectLinkSelectionListener());
this.reconnectLink.setEnabled(true);
this.selectedSchema = this.getDefaultSchema();
if (this.selectedSchema != null) {
DatabaseSchemaWizardPage.this.fireSchemaChanged(this.selectedSchema);
}
this.connectionListener = this.buildConnectionListener();
this.addJpaProjectConnectionProfileListener(this.connectionListener);
this.updateSchemaComboBox();
this.updateReconnectLink();
}
// ********** intra-wizard methods **********
Schema getSelectedSchema() {
return this.selectedSchema;
}
void dispose() {
if(this.projectHasAConnection()) {
this.getJpaProjectConnectionProfile().removeConnectionListener(this.connectionListener);
}
}
// ********** internal methods **********
void addJpaProjectConnectionListener() {
this.addJpaProjectConnectionProfileListener(this.connectionListener);
}
private void addJpaProjectConnectionProfileListener(ConnectionListener listener) {
if(this.projectHasAConnection()) {
this.getJpaProjectConnectionProfile().addConnectionListener(listener);
}
}
private boolean projectHasAConnection() {
return this.getJpaProjectConnectionProfile() != null;
}
/**
* this can return null;
* called at start-up and when the selected connection profile changes
*/
private ConnectionProfile getJpaProjectConnectionProfile() {
return DatabaseSchemaWizardPage.this.jpaProject.getConnectionProfile();
}
/**
* this can return null;
* called at start-up and when the selected connection profile changes
*/
private Schema getDefaultSchema() {
return DatabaseSchemaWizardPage.this.jpaProject.getDefaultDbSchema();
}
private SchemaContainer getDefaultSchemaContainer() {
return DatabaseSchemaWizardPage.this.jpaProject.getDefaultDbSchemaContainer();
}
/**
* called at start-up and when the selected connection profile changes
*/
private void updateReconnectLink() {
this.reconnectLink.setEnabled(this.reconnectLinkCanBeEnabled());
}
void updateAddJpaProjectConnectionLink() {
this.addJpaProjectConnectionLink.setEnabled(this.addJpaProjectConnectionLinkCanBeEnabled());
}
private boolean reconnectLinkCanBeEnabled() {
if(this.projectHasAConnection()) {
return this.getJpaProjectConnectionProfile().isInactive();
}
return false;
}
private boolean addJpaProjectConnectionLinkCanBeEnabled() {
return ! this.projectHasAConnection();
}
/**
* the schema combo-box is updated at start-up and
* when the selected connection profile changes
*/
private void updateSchemaComboBox() {
this.schemaComboBox.removeAll();
for (String name : this.getSchemaNames()) {
this.schemaComboBox.add(name);
}
// the current schema *should* be in the current connection profile
if (this.selectedSchema != null) {
this.schemaComboBox.select(this.schemaComboBox.indexOf(this.selectedSchema.getName()));
}
}
private Iterable<String> getSchemaNames() {
SchemaContainer sc = this.getDefaultSchemaContainer();
// use schema *names* since the combo-box is read-only
return (sc != null) ? sc.getSortedSchemaNames() : EmptyIterable.<String>instance();
}
// ********** listener callbacks **********
void selectedSchemaChanged() {
Schema old = this.selectedSchema;
this.selectedSchema = this.getDefaultSchemaContainer().getSchemaNamed(this.schemaComboBox.getText());
if (this.selectedSchema != old) {
DatabaseSchemaWizardPage.this.fireSchemaChanged(this.selectedSchema);
}
}
void reconnect() {
this.getJpaProjectConnectionProfile().connect();
// everything should be synchronized when we get the resulting open event
}
/**
* called when
* - a connection is set to the Jpa project
* - the connection was opened
* - the connection was closed (never happens?)
* we need to update the schema stuff and the reconnect link
*/
void connectionChanged() {
Schema old = this.selectedSchema;
this.selectedSchema = this.getDefaultSchema();
if (this.selectedSchema != old) {
DatabaseSchemaWizardPage.this.fireSchemaChanged(this.selectedSchema);
}
this.updateSchemaComboBox();
this.updateReconnectLink();
}
// ********** listeners **********
private SelectionListener buildSchemaComboBoxSelectionListener() {
return new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent event) {
// nothing special for "default" (double-click?)
this.widgetSelected(event);
}
public void widgetSelected(SelectionEvent event) {
DatabaseGroup.this.selectedSchemaChanged();
}
@Override
public String toString() {
return "DatabaseSchemaWizardPage schema combo-box selection listener"; //$NON-NLS-1$
}
};
}
private SelectionListener buildReconnectLinkSelectionListener() {
return new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
DatabaseGroup.this.reconnect();
}
@Override
public String toString() {
return "DatabaseSchemaWizardPage reconnect link selection listener"; //$NON-NLS-1$
}
};
}
private ConnectionListener buildConnectionListener() {
return new ConnectionAdapter() {
@Override
public void opened(ConnectionProfile cp) {
this.connectionChanged();
}
@Override // this probably won't ever get called...
public void closed(ConnectionProfile cp) {
this.connectionChanged();
}
private void connectionChanged() {
Display.getDefault().asyncExec(
new Runnable() {
public void run() {
DatabaseGroup.this.connectionChanged();
}
}
);
}
@Override
public String toString() {
return "DatabaseSchemaWizardPage connection listener"; //$NON-NLS-1$
}
};
}
private SelectionListener buildAddJpaProjectConnectionLinkListener() {
return new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
DatabaseGroup.this.promptToConfigJpaProjectConnection();
DatabaseGroup.this.addJpaProjectConnectionListener();
DatabaseGroup.this.updateAddJpaProjectConnectionLink();
DatabaseGroup.this.connectionChanged();
}
@Override
public String toString() {
return "DatabaseSchemaWizardPage AddProjectConnection link selection listener"; //$NON-NLS-1$
}
};
}
void promptToConfigJpaProjectConnection() {
PreferenceDialog dialog =
PreferencesUtil.createPropertyDialogOn(
getShell(), DatabaseSchemaWizardPage.this.jpaProject.getProject(),
JpaProjectPropertiesPage.PROP_ID,
null,
null);
dialog.open();
}
// ********** UI components **********
/**
* build and return a label
*/
private Label buildLabel(Composite parent, int span, String text) {
Label label = new Label(parent, SWT.NONE);
label.setText(text);
GridData gd = new GridData();
gd.horizontalSpan = span;
label.setLayoutData(gd);
return label;
}
/**
* build and return a combo-box
*/
private Combo buildComboBox(Composite parent, SelectionListener listener) {
Combo combo = new Combo(parent, SWT.BORDER | SWT.READ_ONLY);
combo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
combo.addSelectionListener(listener);
return combo;
}
/**
* build and return a link
*/
private Link buildLink(Composite parent, String text, SelectionListener listener) {
Link link = new Link(parent, SWT.NONE);
GridData data = new GridData(GridData.END, GridData.CENTER, false, false);
data.horizontalSpan = 2;
link.setLayoutData(data);
link.setText(text);
link.addSelectionListener(listener);
return link;
}
}
}