/* * 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.modelgenerator.wsdl.ui.wizards; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TreeExpansionEvent; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.model.WorkbenchLabelProvider; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.core.designer.util.I18nUtil; import org.teiid.core.designer.util.FileUtils; import org.teiid.designer.modelgenerator.wsdl.model.Binding; import org.teiid.designer.modelgenerator.wsdl.model.Fault; import org.teiid.designer.modelgenerator.wsdl.model.Message; import org.teiid.designer.modelgenerator.wsdl.model.Model; import org.teiid.designer.modelgenerator.wsdl.model.ModelGenerationException; import org.teiid.designer.modelgenerator.wsdl.model.Operation; import org.teiid.designer.modelgenerator.wsdl.model.Port; import org.teiid.designer.modelgenerator.wsdl.model.Service; import org.teiid.designer.modelgenerator.wsdl.model.WSDLElement; import org.teiid.designer.modelgenerator.wsdl.ui.ModelGeneratorWsdlUiConstants; import org.teiid.designer.modelgenerator.wsdl.ui.util.ModelGeneratorWsdlUiUtil; import org.teiid.designer.ui.common.util.WidgetFactory; import org.teiid.designer.ui.common.util.WidgetUtil; import org.teiid.designer.ui.common.util.WizardUtil; import org.teiid.designer.ui.common.widget.DefaultTreeViewerController; import org.teiid.designer.ui.common.wizard.AbstractWizardPage; /** * WSDL Operations Selection page. This page of the WSDL to Relational Importer is used to select the operations in the source * wsdl that will be used to generate the relational entities. * * @since 8.0 */ public class SelectWsdlOperationsPage extends AbstractWizardPage implements Listener, FileUtils.Constants, CoreStringUtil.Constants, ModelGeneratorWsdlUiConstants, ModelGeneratorWsdlUiConstants.Images { /** Used as a prefix to properties file keys. */ private static final String PREFIX = I18nUtil.getPropertyPrefix(SelectWsdlOperationsPage.class); /** <code>IDialogSetting</code>s key for saved dialog height. */ private static final String DIALOG_HEIGHT = "dialogHeight"; //$NON-NLS-1$ /** <code>IDialogSetting</code>s key for saved dialog width. */ private static final String DIALOG_WIDTH = "dialogWidth"; //$NON-NLS-1$ /** <code>IDialogSetting</code>s key for saved dialog X position. */ private static final String DIALOG_X = "dialogX"; //$NON-NLS-1$ /** <code>IDialogSetting</code>s key for saved dialog Y position. */ private static final String DIALOG_Y = "dialogY"; //$NON-NLS-1$ /** The checkbox treeViewer */ private TreeViewer treeViewer; private Tree tree; boolean treeExpanded = false; private CheckboxTreeController controller; /** Buttons for tree selection */ private Button selectAllButton; private Button deselectAllButton; /** Text area for display of selection details */ private Text detailsTextBox; /** The import manager. */ WSDLImportWizardManager importManager; /** The WSDL model representation */ Model wsdlModel = null; private boolean initializing = false; /** * Constructs the page with the provided import manager * * @param theImportManager the import manager object */ public SelectWsdlOperationsPage( WSDLImportWizardManager theImportManager ) { super(SelectWsdlOperationsPage.class.getSimpleName(), getString("title")); //$NON-NLS-1$ this.importManager = theImportManager; this.importManager.setSelectedOperations(new ArrayList()); setImageDescriptor(ModelGeneratorWsdlUiUtil.getImageDescriptor(NEW_MODEL_BANNER)); } /** * Event handler * * @param event the Event */ @Override public void handleEvent( Event event ) { if (!initializing) { boolean validate = false; // Tree node selected if (event.widget == this.tree) { updateTreeSelectionDetails(); } // SelectAll button selected if (event.widget == this.selectAllButton) { setAllNodesSelected(true); } // DeselectAll button selected if (event.widget == this.deselectAllButton) { setAllNodesSelected(false); } if (validate) { setPageStatus(); } } } void updateTreeSelectionDetails() { TreeItem[] selections = this.tree.getSelection(); if (selections != null && selections.length > 0) { TreeItem selectedItem = selections[0]; updateSelectionDetailsArea(selectedItem.getData()); } } /** * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) * @since 4.2 */ @Override public void createControl( Composite theParent ) { final int COLUMNS = 1; Composite pnlMain = WidgetFactory.createPanel(theParent, SWT.NONE, GridData.FILL_BOTH); GridLayout layout = new GridLayout(COLUMNS, false); pnlMain.setLayout(layout); setControl(pnlMain); SashForm splitter = new SashForm(pnlMain, SWT.VERTICAL); GridData gid = new GridData(); gid.grabExcessHorizontalSpace = gid.grabExcessVerticalSpace = true; gid.horizontalAlignment = gid.verticalAlignment = GridData.FILL; splitter.setLayoutData(gid); createCheckboxTreeComposite(splitter, getString("checkboxTreeGroup.title")); //$NON-NLS-1$ createDetailsComposite(splitter); splitter.setWeights(new int[] {70, 30}); restoreState(); } /** * create the checkbox tree Composite * * @param parent the parent composite * @param title the group title */ private void createCheckboxTreeComposite( Composite parent, String title ) { Composite checkBoxTreeComposite = WidgetFactory.createPanel(parent, SWT.NONE, GridData.FILL_BOTH); GridLayout layout = new GridLayout(1, false); checkBoxTreeComposite.setLayout(layout); // -------------------------- // Group for checkbox tree // -------------------------- Group group = WidgetFactory.createGroup(checkBoxTreeComposite, title, GridData.FILL_BOTH, 1, 2); // ---------------------------- // TreeViewer // ---------------------------- this.controller = new CheckboxTreeController(); this.treeViewer = WidgetFactory.createTreeViewer(group, SWT.SINGLE | SWT.CHECK, GridData.FILL_BOTH, controller); this.tree = this.treeViewer.getTree(); tree.addListener(SWT.Selection, this); tree.setLayoutData(new GridData(GridData.FILL_BOTH)); this.treeViewer.setContentProvider(new CheckboxTreeContentProvider()); this.treeViewer.setLabelProvider(new CheckboxTreeLabelProvider()); this.treeViewer.setInput(null); // ---------------------------- // Select/DeSelect Buttons // ---------------------------- Composite buttonComposite = WidgetFactory.createPanel(group, SWT.NONE, GridData.FILL_VERTICAL); layout = new GridLayout(1, false); buttonComposite.setLayout(layout); this.selectAllButton = WidgetFactory.createButton(buttonComposite, getString("selectAllButton.text"), GridData.FILL_HORIZONTAL); //$NON-NLS-1$ this.selectAllButton.setToolTipText(getString("selectAllButton.tipText")); //$NON-NLS-1$ this.deselectAllButton = WidgetFactory.createButton(buttonComposite, getString("deselectAllButton.text"), GridData.FILL_HORIZONTAL); //$NON-NLS-1$ this.deselectAllButton.setToolTipText(getString("deselectAllButton.tipText")); //$NON-NLS-1$ this.selectAllButton.addListener(SWT.Selection, this); this.deselectAllButton.addListener(SWT.Selection, this); } /** * create the selection details text Composite * * @param parent the parent composite */ private void createDetailsComposite( Composite parent ) { Composite detailsComposite = WidgetFactory.createPanel(parent, SWT.NONE, GridData.FILL_BOTH); GridLayout layout = new GridLayout(1, false); detailsComposite.setLayout(layout); // Have to remove WidgetFactory.createLabel since it breaks 4.3.3 // at runtime due to a change to the return type to a type that // does not exist in 4.3.3 //WidgetFactory.createLabel(detailsComposite, SWT.NONE, getString("detailsTextbox.title")); //$NON-NLS-1$ CLabel theLabel = new CLabel(detailsComposite, SWT.NONE); theLabel.setText(getString("detailsTextbox.title")); //$NON-NLS-1$ final GridData gridData = new GridData(SWT.NONE); gridData.horizontalSpan = 1; theLabel.setLayoutData(gridData); this.detailsTextBox = WidgetFactory.createTextBox(detailsComposite, SWT.NONE, GridData.FILL_BOTH); detailsTextBox.setEditable(false); } /** * update method for selection details area */ private void updateSelectionDetailsArea( Object selectedObject ) { StringBuffer sb = new StringBuffer(); if (selectedObject instanceof Service) { Service theService = (Service)selectedObject; sb.append(theService.getName() + " [Service]\n"); //$NON-NLS-1$ sb.append("id: " + theService.getId()); //$NON-NLS-1$ } else if (selectedObject instanceof Port) { Port thePort = (Port)selectedObject; sb.append(thePort.getName() + " [Port]\n"); //$NON-NLS-1$ sb.append("id: " + thePort.getId()); //$NON-NLS-1$ } else if (selectedObject instanceof Binding) { addBindingDetails((Binding)selectedObject, sb); } else if (selectedObject instanceof Operation) { addOperationDetails((Operation)selectedObject, sb); } else if (selectedObject instanceof Message) { Message theMessage = (Message)selectedObject; sb.append(theMessage.getName() + " [Message]\n"); //$NON-NLS-1$ sb.append("id: " + theMessage.getId()); //$NON-NLS-1$ } this.detailsTextBox.setText(sb.toString()); } private void addBindingDetails( Binding binding, StringBuffer sb ) { sb.append(binding.getName() + " [Binding]\n"); //$NON-NLS-1$ sb.append("id: \t\t" + binding.getId() + '\n'); //$NON-NLS-1$ sb.append("uri: \t" + binding.getTransportURI() + '\n'); //$NON-NLS-1$ sb.append("style: \t" + binding.getStyle()); //$NON-NLS-1$ } private void addOperationDetails( Operation operation, StringBuffer sb ) { sb.append(operation.getName() + " [Operation]\n"); //$NON-NLS-1$ sb.append("id: \t\t\t\t\t" + operation.getId() + '\n'); //$NON-NLS-1$ sb.append("input message: \t" + operation.getInputMessage().getName() + '\n'); //$NON-NLS-1$ String outputMsg = "<none>"; //$NON-NLS-1$ if( operation.getOutputMessage() != null ) { outputMsg = operation.getOutputMessage().getName(); } sb.append("output message: \t" + outputMsg + '\n'); //$NON-NLS-1$ Fault[] faults = operation.getFaults(); sb.append("fault names: \t\t"); //$NON-NLS-1$ if (faults == null || faults.length == 0) { sb.append("none"); //$NON-NLS-1$ } else { for (int i = 0; i < faults.length; i++) { Fault theFault = faults[i]; sb.append(theFault.getName()); if (i != faults.length - 1) { sb.append(", "); //$NON-NLS-1$ } } } // -------------------------------------------------------- // Add Problem Messages // -------------------------------------------------------- if (!operation.canModel()) { String[] errorMsgs = operation.getProblemMessages(); for (int i = 0; i < errorMsgs.length; i++) { sb.append('\n'); sb.append(errorMsgs[i]); } } } /** * @see org.eclipse.jface.dialogs.IDialogPage#dispose() * @since 4.2 */ @Override public void dispose() { saveState(); } /** * 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; } /** * Utility to get localized text from properties file. * * @param theKey the key whose localized value is being requested * @return the localized text */ private static String getString( String theKey ) { return UTIL.getString(new StringBuffer().append(PREFIX).append(theKey).toString()); } /** * Restores dialog size and position of the last time wizard ran. * * @since 4.2 */ private void restoreState() { IDialogSettings settings = getDialogSettings(); if (settings != null) { Shell shell = getContainer().getShell(); if (shell != null) { try { int x = settings.getInt(DIALOG_X); int y = settings.getInt(DIALOG_Y); int width = settings.getInt(DIALOG_WIDTH); int height = settings.getInt(DIALOG_HEIGHT); shell.setBounds(x, y, width, height); } catch (NumberFormatException theException) { // getInt(String) throws exception if not found. // just means no settings exist yet. } } } } /** * Persists dialog size and position. * * @since 4.2 */ private void saveState() { IDialogSettings settings = getDialogSettings(); if (settings != null) { Shell shell = getContainer().getShell(); if (shell != null) { Rectangle r = shell.getBounds(); settings.put(DIALOG_X, r.x); settings.put(DIALOG_Y, r.y); settings.put(DIALOG_WIDTH, r.width); settings.put(DIALOG_HEIGHT, r.height); } } } /** * Sets the wizard page status message. * * @since 4.2 */ void setPageStatus() { // Determine if any of the operations are checked boolean hasSelections = this.importManager.getSelectedOperations().size() > 0; if (!hasSelections) { WizardUtil.setPageComplete(this, getString("noSelections.msg"), IMessageProvider.ERROR); //$NON-NLS-1$ return; } WizardUtil.setPageComplete(this); getContainer().updateButtons(); } @Override public void setVisible( boolean isVisible ) { if (isVisible) { try { this.wsdlModel = this.importManager.getWSDLModel(); } catch (ModelGenerationException e) { this.wsdlModel = null; Status exStatus = new Status(IStatus.ERROR, PLUGIN_ID, 0, getString("dialog.wsdlParseError.msg"), e); //$NON-NLS-1$ Shell shell = this.getShell(); ErrorDialog.openError(shell, null, getString("dialog.wsdlParseError.title"), exStatus); //$NON-NLS-1$ } this.treeViewer.setInput(this.wsdlModel); this.importManager.setSelectedOperations(new ArrayList()); this.treeViewer.expandToLevel(4); setAllNodesSelected(true); setPageStatus(); } super.setVisible(isVisible); } private void setAllNodesSelected( boolean bSelected ) { // System.out.println("[CompareTreePanel.setAllNodesSelected] bSelected: " + bSelected ); //$NON-NLS-1$ TreeItem[] items = tree.getItems(); for (int i = 0; i < items.length; i++) { setAllSelected(items[i], bSelected); } } private void setAllSelected( final TreeItem item, final boolean checked ) { WidgetUtil.setChecked(item, checked, false, this.controller); // Apply same checked state to any children final TreeItem[] children = item.getItems(); for (int ndx = 0; ndx < children.length; ndx++) { setAllSelected(children[ndx], checked); } } /** * Determine if the object has a 'valid' operation underneath it's heirarchy. Valid operation has 'canModel' set to true. */ boolean hasValidOperation( Object object ) { boolean hasValid = false; if (object instanceof Model) { Object[] services = ((Model)object).getServices(); for (int i = 0; i < services.length; i++) { if (hasValidOperation(services[i])) { hasValid = true; break; } } } else if (object instanceof Service) { Object[] ports = ((Service)object).getPorts(); for (int i = 0; i < ports.length; i++) { if (hasValidOperation(ports[i])) { hasValid = true; break; } } } else if (object instanceof Port) { Object binding = ((Port)object).getBinding(); if (hasValidOperation(binding)) { hasValid = true; } } else if (object instanceof Binding) { Object[] operations = ((Binding)object).getOperations(); for (int i = 0; i < operations.length; i++) { if (hasValidOperation(operations[i])) { hasValid = true; break; } } } else if (object instanceof Operation) { hasValid = ((Operation)object).canModel(); } return hasValid; } class CheckboxTreeLabelProvider extends LabelProvider { private final Image SERVICE_ICON_IMG = ModelGeneratorWsdlUiUtil.getImage(SERVICE_ICON); private final Image PORT_ICON_IMG = ModelGeneratorWsdlUiUtil.getImage(PORT_ICON); private final Image OPERATION_ICON_IMG = ModelGeneratorWsdlUiUtil.getImage(OPERATION_ICON); private final Image BINDING_ICON_IMG = ModelGeneratorWsdlUiUtil.getImage(BINDING_ICON); final WorkbenchLabelProvider workbenchProvider = new WorkbenchLabelProvider(); @Override public Image getImage( final Object node ) { if (node instanceof Service) { return SERVICE_ICON_IMG; } else if (node instanceof Port) { return PORT_ICON_IMG; } else if (node instanceof Operation) { return OPERATION_ICON_IMG; } else if (node instanceof Binding) { return BINDING_ICON_IMG; } return null; } @Override public String getText( final Object node ) { if (node instanceof Model) { return "theModel"; //$NON-NLS-1$ } else if (node instanceof WSDLElement) { return ((WSDLElement)node).getName(); } return "unknownElement"; //$NON-NLS-1$ } } class CheckboxTreeContentProvider implements ITreeContentProvider { @Override public void dispose() { } @Override public Object[] getChildren( final Object node ) { if (wsdlModel != null) { if (node instanceof Model) { return ((Model)node).getServices(); } else if (node instanceof Service) { return ((Service)node).getPorts(); } else if (node instanceof Port) { return new Object[] {((Port)node).getBinding()}; } else if (node instanceof Binding) { return ((Binding)node).getOperations(); } } return EMPTY_STRING_ARRAY; } @Override public Object[] getElements( final Object inputElement ) { return getChildren(inputElement); } @Override public Object getParent( final Object node ) { if (wsdlModel != null) { if (node instanceof Model) { return null; } else if (node instanceof Service) { return null; } else if (node instanceof Port) { return ((Port)node).getService(); } else if (node instanceof Binding) { return ((Binding)node).getPort(); } else if (node instanceof Operation) { return ((Operation)node).getBinding(); } } return null; } @Override public boolean hasChildren( final Object node ) { if (wsdlModel != null) { if (node instanceof Model) { return (((Model)node).getServices().length > 0); } else if (node instanceof Service) { return (((Service)node).getPorts().length > 0); } else if (node instanceof Port) { return ((Port)node).getBinding() != null; } else if (node instanceof Binding) { return (((Binding)node).getOperations().length > 0); } } return false; } @Override public void inputChanged( final Viewer viewer, final Object oldInput, final Object newInput ) { } } class CheckboxTreeController extends DefaultTreeViewerController { /** * @see org.teiid.designer.ui.common.widget.DefaultTreeViewerController#checkedStateToggled(org.eclipse.swt.widgets.TreeItem) */ @Override public void checkedStateToggled( TreeItem item ) { } /** * @see org.teiid.designer.ui.common.widget.ITreeViewerController#isItemCheckable(org.eclipse.swt.widgets.TreeItem) */ @Override public boolean isItemCheckable( final TreeItem item ) { final Object node = item.getData(); if (node instanceof Service || node instanceof Binding || node instanceof Port || node instanceof Operation) { return hasValidOperation(node); } return false; } /** * @see org.teiid.designer.ui.common.widget.ITreeViewerController#update(org.eclipse.swt.widgets.TreeItem, boolean) * @since 4.0 */ @Override public void update( final TreeItem item, final boolean selected ) { Object dataObj = item.getData(); if (dataObj != null) { final boolean checked = !WidgetUtil.isUnchecked(item); if (isItemCheckable(item)) { item.setChecked(checked); } item.setGrayed(WidgetUtil.isPartiallyChecked(item)); if (selected) { updateChildren(item, checked); for (TreeItem parent = item.getParentItem(); parent != null; parent = parent.getParentItem()) { int state = PARTIALLY_CHECKED; final TreeItem[] children = parent.getItems(); for (int ndx = children.length; --ndx >= 0;) { final TreeItem child = children[ndx]; if (WidgetUtil.isPartiallyChecked(child)) { state = PARTIALLY_CHECKED; break; } final int childState = WidgetUtil.getCheckedState(child); if (state == PARTIALLY_CHECKED) { state = childState; } else if (state != childState) { state = PARTIALLY_CHECKED; break; } } if (state != WidgetUtil.getCheckedState(parent)) { WidgetUtil.setCheckedState(parent, state, false, this); } } } if (dataObj instanceof Operation && hasValidOperation(dataObj)) { updateCheckedOperations((Operation)dataObj, checked); } if (!isItemCheckable(item)) { item.setGrayed(true); item.setChecked(false); } else { item.setGrayed(false); } } } private void updateCheckedOperations( Operation operation, boolean checked ) { List<Operation> selectedOperations = importManager.getSelectedOperations(); if (checked && operation.canModel() && !selectedOperations.contains(operation)) { selectedOperations.add(operation); importManager.setSelectedOperations(selectedOperations); setPageStatus(); } else if (!checked && selectedOperations.contains(operation)) { selectedOperations.remove(operation); importManager.setSelectedOperations(selectedOperations); setPageStatus(); } } /** * @since 4.0 */ private void updateChildren( final TreeItem item, final boolean checked ) { final TreeItem[] children = item.getItems(); for (int ndx = children.length; --ndx >= 0;) { final TreeItem child = children[ndx]; if (child.getData() != null) { updateChildren(child, checked); WidgetUtil.setChecked(child, checked, false, this); } } } /** * @see org.teiid.designer.ui.common.widget.ITreeViewerController#itemExpanded(org.eclipse.jface.viewers.TreeExpansionEvent) * @since 4.0 */ @Override public void itemExpanded( final TreeExpansionEvent event ) { if (treeExpanded) { super.itemExpanded(event); } else { if( ((TreeViewer)event.getTreeViewer()).getTree().getSelection().length > 0 ) { final TreeItem item = ((TreeViewer)event.getTreeViewer()).getTree().getSelection()[0]; if (item.getData() != null) { updateChildren(item, false); } treeExpanded = true; } } updateTreeSelectionDetails(); } @Override public void itemCollapsed( final TreeExpansionEvent event ) { super.itemCollapsed(event); updateTreeSelectionDetails(); } } }