/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.webservice.ui.wizard;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.ViewForm;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.help.IWorkbenchHelpSystem;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.I18nUtil;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.ui.common.util.UiUtil;
import org.teiid.designer.ui.common.util.WidgetFactory;
import org.teiid.designer.ui.common.wizard.AbstractWizardPage;
import org.teiid.designer.webservice.IWebServiceModelBuilder;
import org.teiid.designer.webservice.IWebServiceXsdResource;
import org.teiid.designer.webservice.NonResolvableXSDSchema;
import org.teiid.designer.webservice.ui.IInternalUiConstants;
import org.teiid.designer.webservice.ui.util.WebServiceUiUtil;
/**
* @since 8.0
*/
public class SchemaLocationPage extends AbstractWizardPage
implements IInternalUiConstants, IInternalUiConstants.HelpContexts, IInternalUiConstants.Images {
/** Properties key prefix. */
static final String PREFIX = I18nUtil.getPropertyPrefix(SchemaLocationPage.class);
/** Column headers for the table. */
private static final String[] TBL_HDRS;
/** Index of the error column in the table. */
static final int ERROR_COLUMN;
/** Index of the namespace column in the table. */
static final int NAMESPACE_COLUMN;
/** Index of the source file column in the table. */
static final int SOURCE_FILE_COLUMN;
/** Index of the target path column in the table. */
static final int TARGET_PATH_COLUMN;
/**
* Utility to get localized text from properties file.
*
* @param theKey the key whose localized value is being requested
* @return the localized text
* @since 4.2
*/
private static String getString( String theKey ) {
return UTIL.getString(new StringBuffer().append(PREFIX).append(theKey).toString());
}
static {
// set column indexes
ERROR_COLUMN = 0;
NAMESPACE_COLUMN = 1;
SOURCE_FILE_COLUMN = 2;
TARGET_PATH_COLUMN = 3;
// set column headers
TBL_HDRS = new String[4];
TBL_HDRS[ERROR_COLUMN] = ""; //$NON-NLS-1$
TBL_HDRS[NAMESPACE_COLUMN] = getString("table.column.namespace"); //$NON-NLS-1$
TBL_HDRS[SOURCE_FILE_COLUMN] = getString("table.column.sourceFile"); //$NON-NLS-1$
TBL_HDRS[TARGET_PATH_COLUMN] = getString("table.column.targetPath"); //$NON-NLS-1$
}
/** The model builder. */
private IWebServiceModelBuilder builder;
/** Action to show/hide editor. */
private IAction showEditorAction;
private SchemaLocationEditor editor;
private CLabel lblStatusMsg;
private TableViewer viewer;
private ViewForm viewForm;
public SchemaLocationPage( IWebServiceModelBuilder theBuilder ) {
super(SchemaLocationPage.class.getSimpleName(), getString("title")); //$NON-NLS-1$
this.builder = theBuilder;
setImageDescriptor(WebServiceUiUtil.getImageDescriptor(NEW_MODEL_BANNER));
}
/**
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
* @since 4.2
*/
@Override
public void createControl( Composite theParent ) {
//
// Create main container
//
Composite pnlMain = WidgetFactory.createPanel(theParent, SWT.NONE, GridData.FILL_BOTH);
setControl(pnlMain);
IWorkbenchHelpSystem helpSystem = UiUtil.getWorkbench().getHelpSystem();
helpSystem.setHelp(pnlMain, SCHEMA_LOCATION_PAGE);
//
// pnlMain contents
//
// target models view form
this.viewForm = WidgetFactory.createViewForm(pnlMain, SWT.BORDER, GridData.FILL_BOTH, 1);
this.viewForm.setTopLeft(WidgetFactory.createLabel(this.viewForm, getString("label.viewForm"))); //$NON-NLS-1$
createTablePanelContents(this.viewForm);
createTableActions(WidgetFactory.createViewFormToolBar(this.viewForm));
// editor view form
this.editor = new SchemaLocationEditor(pnlMain, this.builder);
this.editor.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
this.editor.addListener(new Listener() {
@Override
public void handleEvent( Event theEvent ) {
processEditorEvent(theEvent);
}
});
}
private void createTableActions( IToolBarManager theToolBarMgr ) {
this.showEditorAction = new Action("", IAction.AS_RADIO_BUTTON) { //$NON-NLS-1$
@Override
public void run() {
showEditor(!getEditor().isVisible());
}
};
this.showEditorAction.setImageDescriptor(WebServiceUiUtil.getImageDescriptor(SCHEMA_EDITOR));
this.showEditorAction.setToolTipText(getString("button.showEditor.tip")); //$NON-NLS-1$
this.showEditorAction.setChecked(true);
theToolBarMgr.add(this.showEditorAction);
theToolBarMgr.update(true);
}
private void createTablePanelContents( ViewForm theViewForm ) {
Composite pnl = WidgetFactory.createPanel(theViewForm, SWT.NONE, GridData.FILL_BOTH);
theViewForm.setContent(pnl);
int style = SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION;
Table tbl = new Table(pnl, style);
tbl.setLayout(new GridLayout());
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gd.heightHint = tbl.getItemHeight() * 8;
gd.widthHint = 450;
tbl.setLayoutData(gd);
this.viewer = new TableViewer(tbl);
this.viewer.setContentProvider(new TableContentProvider());
this.viewer.setLabelProvider(new TableLabelProvider());
this.viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged( SelectionChangedEvent theEvent ) {
handleRowSelected();
}
});
this.viewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick( DoubleClickEvent theEvent ) {
handleDoubleClick();
}
});
tbl.setHeaderVisible(true);
tbl.setLinesVisible(true);
// create columns
for (int i = 0; i < TBL_HDRS.length; i++) {
TableColumn col = new TableColumn(tbl, SWT.LEFT);
col.setText(TBL_HDRS[i]);
col.pack();
if (i == ERROR_COLUMN) {
col.setResizable(false);
col.setImage(WebServiceUiUtil.getImage(PROBLEM_INDICATOR));
}
}
// label showing selected unit's status message
this.lblStatusMsg = WidgetFactory.createLabel(pnl, GridData.HORIZONTAL_ALIGN_FILL);
}
/**
* Convenience method to give inner classes access to the builder.
*
* @return the builder
* @since 4.2
*/
IWebServiceModelBuilder getBuilder() {
return this.builder;
}
/**
* Override to replace the NewModelWizard settings with the section devoted to the Web Service Model Wizard.
*
* @see org.eclipse.jface.wizard.WizardPage#getDialogSettings()
* @since 4.2
*/
@Override
protected IDialogSettings getDialogSettings() {
IDialogSettings settings = super.getDialogSettings();
if (settings != null) {
// get the right section of the NewModelWizard settings
IDialogSettings temp = settings.getSection(DIALOG_SETTINGS_SECTION);
if (temp == null) {
settings = settings.addNewSection(DIALOG_SETTINGS_SECTION);
} else {
settings = temp;
}
}
return settings;
}
SchemaLocationEditor getEditor() {
return this.editor;
}
void handleDoubleClick() {
if (!getEditor().isVisible()) {
showEditor(true);
}
}
void handleRowSelected() {
// if uncommitted changes exist in editor offer to save prior to setting new editor input
handleUnsavedEditor();
// process new selection
IStructuredSelection selection = (IStructuredSelection)this.viewer.getSelection();
// enable/disable editor related controls
boolean doEdit = !selection.isEmpty();
this.editor.setEnabled(doEdit);
// load/clear editor based on selection
if (doEdit) {
this.editor.setInput(selection.toList());
} else {
this.editor.clear();
}
updateStatusLabel();
updatePageStatus();
}
void handleUnsavedEditor() {
if (this.editor.isDirty() && this.editor.canSave()) {
String msg = null;
List editorInput = this.editor.getInput();
if (editorInput.size() == 1) {
IWebServiceXsdResource xsd = (IWebServiceXsdResource)editorInput.get(0);
msg = UTIL.getString(PREFIX + "dialog.dirtyEditor.oneFile.msg", new Object[] {xsd.getTargetNamespace()}); //$NON-NLS-1$
} else {
msg = getString("dialog.dirtyEditor.multipleFiles.msg"); //$NON-NLS-1$
}
if (MessageDialog.openQuestion(getShell(), getString("dialog.dirtyEditor.title"), msg)) { //$NON-NLS-1$
this.editor.save();
}
}
}
private void packTableColumns() {
Table tbl = this.viewer.getTable();
for (int i = 0; i < TBL_HDRS.length; i++) {
tbl.getColumn(i).pack();
}
}
void processEditorEvent( Event theEvent ) {
if (theEvent.type == SchemaLocationEditor.CLOSED) {
// editor is already closed but calling this method sets the button state to match
// and layouts the container
showEditor(false);
} else {
// editor was saved
// refresh each row that was edited. will always have rows selected.
// can't use the currently selected rows in the viewer for this as they have already changed.
List editorInput = this.editor.getInput();
for (int size = editorInput.size(), i = 0; i < size; i++) {
this.viewer.refresh(editorInput.get(0), true);
}
packTableColumns();
// update statuses
updatePageStatus();
updateStatusLabel();
}
}
/**
* @see org.eclipse.jface.dialogs.IDialogPage#setVisible(boolean)
*/
@Override
public void setVisible( boolean theShowFlag ) {
// gets the editor and table initialized along with the page status
// and makes sure they're are no unsaved changes in the editor
handleRowSelected();
if (theShowFlag) {
this.editor.setDialogSettings(getDialogSettings());
this.viewer.setInput(this);
packTableColumns();
// set focus so that the help context will be correct
this.viewer.getControl().setFocus();
} else {
this.editor.clear();
}
super.setVisible(theShowFlag);
}
void showEditor( boolean theShowFlag ) {
this.showEditorAction.setChecked(theShowFlag);
this.editor.setVisible(theShowFlag);
this.editor.getParent().layout(true);
}
private void updatePageStatus() {
// loop through to determine current status
boolean enable = true;
int severity = IStatus.OK;
String msgId = null;
Collection xsdResources = null;
boolean requiredStart = ModelerCore.startTxn(false, false, "Get XSD Destinations", this); //$NON-NLS-1$
boolean succeeded = false;
try {
xsdResources = this.builder.getXsdDestinations();
succeeded = true;
} finally {
// If we start txn, commit it
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
if ((xsdResources == null) || xsdResources.isEmpty()) {
msgId = "page.msg.noXsdResources"; //$NON-NLS-1$
enable = false;
} else {
Iterator itr = xsdResources.iterator();
while (itr.hasNext()) {
IWebServiceXsdResource xsd = (IWebServiceXsdResource)itr.next();
IStatus status = xsd.isValid();
if (status.getSeverity() > severity) {
severity = status.getSeverity();
if (severity == IStatus.ERROR) {
break;
}
}
}
switch (severity) {
case IStatus.ERROR: {
msgId = "page.msg.error"; //$NON-NLS-1$
break;
}
case IStatus.WARNING: {
msgId = "page.msg.warning"; //$NON-NLS-1$
break;
}
case IStatus.INFO: {
msgId = "page.msg.info"; //$NON-NLS-1$
break;
}
default: {
msgId = "page.msg.ok"; //$NON-NLS-1$
break;
}
}
}
// enable table
this.viewer.getControl().setEnabled(enable);
// set page status
String msg = getString(msgId);
if (severity == IStatus.ERROR) {
setMessage(msg, IStatus.ERROR);
setPageComplete(false);
} else {
setMessage(msg, severity);
setPageComplete(true);
}
}
private void updateStatusLabel() {
IStructuredSelection selection = (IStructuredSelection)this.viewer.getSelection();
Image image = null;
String text = ""; //$NON-NLS-1$
if (selection.size() == 1) {
IWebServiceXsdResource xsd = (IWebServiceXsdResource)selection.getFirstElement();
IStatus status = xsd.isValid();
if (!status.isOK()) {
image = WebServiceUiUtil.getStatusImage(status);
text = status.getMessage();
}
}
this.lblStatusMsg.setImage(image);
this.lblStatusMsg.setText(text);
}
/**
* Determines if the current file location was created from a url originally by looking for the value in the mapping of files
* to urls built in the <code>WebServiceSelectionPage</code>.
*
* @param schemaLocation
* @return location (Original Url or the actual file location)
*/
String getUrlValue( String schemaLocation ) {
Object location = null;
Map urlMap = getBuilder().getUrlMap();
// Remove preceding backslash from schemaLocation
String substringLocation = schemaLocation.substring(1);
if (urlMap != null) {
location = urlMap.get(substringLocation);
}
return location == null ? schemaLocation : location.toString();
}
/**
* Formats source location for display
*
* @param schemaLocation
* @return location
*/
String formatLocation( String schemaLocation ) {
String location = schemaLocation;
// Strip off the file schema if present.
if (location.indexOf("file:/") > -1) { //$NON-NLS-1$
location = location.substring(6);
}
return location;
}
class TableContentProvider implements IStructuredContentProvider {
/**
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
* @since 4.1
*/
@Override
public void dispose() {
}
/**
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
* @since 4.1
*/
@Override
public Object[] getElements( Object theInputElement ) {
Collection xsdResources = getBuilder().getXsdDestinations();
return (xsdResources == null) ? Collections.EMPTY_LIST.toArray() : xsdResources.toArray();
}
/**
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object,
* java.lang.Object)
* @since 4.1
*/
@Override
public void inputChanged( Viewer theViewer,
Object theOldInput,
Object theNewInput ) {
}
}
class TableLabelProvider extends LabelProvider implements ITableLabelProvider {
/**
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
* @since 4.1
*/
@Override
public Image getColumnImage( Object theElement,
int theColumnIndex ) {
Image result = null;
if (theElement instanceof IWebServiceXsdResource) {
if (theColumnIndex == ERROR_COLUMN) {
IStatus status = ((IWebServiceXsdResource)theElement).isValid();
result = WebServiceUiUtil.getStatusImage(status);
}
} else {
// should not happen
CoreArgCheck.isTrue(false, UTIL.getString(PREFIX + "msg.unknownObjectType", //$NON-NLS-1$
new Object[] {theElement.getClass().getName()}));
}
return result;
}
/**
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
* @since 4.1
*/
@Override
public String getColumnText( Object theElement,
int theIndex ) {
String result = null;
if (theElement instanceof IWebServiceXsdResource) {
IWebServiceXsdResource xsd = (IWebServiceXsdResource)theElement;
if (theIndex == ERROR_COLUMN) {
result = ""; //$NON-NLS-1$
} else if (theIndex == NAMESPACE_COLUMN) {
result = xsd.getTargetNamespace();
} else if (theIndex == SOURCE_FILE_COLUMN) {
// Defect 23072 - handle NonResolvable schemas
if (xsd.getSchema() instanceof NonResolvableXSDSchema) {
NonResolvableXSDSchema nrSchema = (NonResolvableXSDSchema)xsd.getSchema();
String schemaLoc = nrSchema.getSchemaLocation();
if (schemaLoc != null) {
result = formatLocation(schemaLoc);
} else {
result = nrSchema.getUri() != null ? nrSchema.getUri().toString() : null;
}
// If this is a standalone schema file, xsd.getSchema().getSchemaLocation() will return a
// non-null value. If this is schema imbedded in a WSDL file, xsd.getOriginalPath() will return
// the correct value which we will use to see if there is a corresponding url value in the urlMap.
} else {
String schemaLoc = xsd.getSchema().getSchemaLocation();
result = schemaLoc != null ? formatLocation(schemaLoc) : getUrlValue(xsd.getOriginalPath());
}
} else if (theIndex == TARGET_PATH_COLUMN) {
result = xsd.getDestinationPath().makeRelative().toOSString();
} else {
// should not happen
CoreArgCheck.isTrue(false, UTIL.getString(PREFIX + "msg.unknownTableColumn", //$NON-NLS-1$
new Object[] {Integer.toString(theIndex)}));
}
} else {
// should not happen
CoreArgCheck.isTrue(false, UTIL.getString(PREFIX + "msg.unknownObjectType", //$NON-NLS-1$
new Object[] {theElement.getClass().getName()}));
}
return result;
}
}
}