/******************************************************************************* * Copyright (c) 2010 SAP AG. * 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: * Emil Simeonov - initial API and implementation. * Dimitar Donchev - initial API and implementation. * Dimitar Tenev - initial API and implementation. * Nevena Manova - initial API and implementation. * Georgi Konstantinov - initial API and implementation. *******************************************************************************/ package org.eclipse.wst.sse.sieditor.ui.v2.sections; import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CCombo; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.graphics.FontMetrics; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.wst.sse.sieditor.model.xsd.api.IFacet; import org.eclipse.wst.sse.sieditor.model.xsd.api.ISimpleType; import org.eclipse.wst.sse.sieditor.model.xsd.api.ISimpleType.Whitespace; import org.eclipse.wst.sse.sieditor.ui.Activator; import org.eclipse.wst.sse.sieditor.ui.i18n.Messages; import org.eclipse.wst.sse.sieditor.ui.v2.UIConstants; import org.eclipse.wst.sse.sieditor.ui.v2.common.CarriageReturnListener; import org.eclipse.wst.sse.sieditor.ui.v2.common.LabeledControl; import org.eclipse.wst.sse.sieditor.ui.v2.dt.IConstraintsController; import org.eclipse.wst.sse.sieditor.ui.v2.sections.elements.ElementNodeDetailsController; import org.eclipse.wst.sse.sieditor.ui.v2.sections.tables.FacetTable; import org.eclipse.wst.sse.sieditor.ui.v2.sections.tables.editing.EnumsTableEditingSupport; import org.eclipse.wst.sse.sieditor.ui.v2.sections.tables.editing.PatternsTableEditingSupport; import org.eclipse.xsd.XSDPackage; public class SimpleTypeConstraintsSection extends AbstractDetailsPageSection implements ModifyListener, FocusListener { private final ElementNodeDetailsController detailsController; protected TableViewer patternsTableViewer; protected TableViewer enumsTableViewer; protected LabeledControl<Text> lengthControl; protected LabeledControl<Text> minLengthControl; protected LabeledControl<Text> maxLengthControl; protected LabeledControl<Text> minInclusiveControl; protected LabeledControl<Text> maxInclusiveControl; protected LabeledControl<Text> minExclusiveControl; protected LabeledControl<Text> maxExclusiveControl; protected LabeledControl<Text> totalDigitsControl; protected LabeledControl<Text> fractionDigitsControl; protected LabeledControl<CCombo> whitespaceControl; protected LabeledControl<Composite> patternsControl; protected FacetTable patternsControl_facetTable; protected LabeledControl<Composite> enumsControl; protected FacetTable enumsControl_facetTable; protected WhitespaceComboItem[] whitespaceComboItems; protected Label unresolvedLabel; public SimpleTypeConstraintsSection(final ElementNodeDetailsController detailsController, final FormToolkit toolkit, final IManagedForm managedForm) { super(detailsController.getFormPageController(), toolkit, managedForm); this.detailsController = detailsController; whitespaceComboItems = new WhitespaceComboItem[] { new WhitespaceComboItem(null, Messages.SimpleTypeConstraintsSection_NOT_SPECIFIED_WHITESPACE), new WhitespaceComboItem(Whitespace.COLLAPSE, Messages.SimpleTypeConstraintsSection_collapse), new WhitespaceComboItem(Whitespace.PRESERVE, Messages.SimpleTypeConstraintsSection_preserve), new WhitespaceComboItem(Whitespace.REPLACE, Messages.SimpleTypeConstraintsSection_replace), }; } @Override public void createContents(final Composite parent) { final FormToolkit toolkit = getToolkit(); control = createSection(parent, Messages.SimpleTypeConstraintsSection_constraints); final Composite clientComposite = toolkit.createComposite(control); control.setClient(clientComposite); setCompositeLayout(clientComposite); createControls(toolkit, clientComposite); toolkit.paintBordersFor(clientComposite); } @Override public void refresh() { boolean applicable = detailsController.isConstraintsSectionApplicable(); IConstraintsController constraintsController = null; boolean lengthVisible = false; boolean minMaxVisible = false; boolean minMaxInclusiveVisible = false; boolean minMaxExclusiveVisible = false; boolean totalDigitsVisible = false; boolean fractionDigitsVisible = false; boolean whitespaceVisible = false; boolean patternsVisible = false; boolean enumsVisible = false; // even if the constraints section is applicable, if no facet is // applicable then the section would be empty, so we hide it. // it happens when the base type is unresolved if (applicable) { constraintsController = detailsController.getConstraintsController(); lengthVisible = constraintsController.isLengthVisible(); minMaxVisible = constraintsController.isMinMaxVisible(); minMaxExclusiveVisible = constraintsController.isMinMaxExclusiveVisible(); minMaxInclusiveVisible = constraintsController.isMinMaxInclusiveVisible(); totalDigitsVisible = constraintsController.isTotalDigitsVisible(); fractionDigitsVisible = constraintsController.isFractionDigitsVisible(); whitespaceVisible = constraintsController.isWhitespaceVisible(); patternsVisible = constraintsController.isPatternsVisible(); enumsVisible = constraintsController.isEnumsVisible(); applicable = lengthVisible || minMaxVisible || minMaxInclusiveVisible || minMaxExclusiveVisible || totalDigitsVisible || fractionDigitsVisible || whitespaceVisible || patternsVisible || enumsVisible; } setVisible(applicable); if (!applicable) { return; } boolean changed = false; final boolean constraintSectionEditable = constraintsController.isEditable(); final boolean enabled = constraintSectionEditable && isEditable(); // changed = showUnresolvableMessage(!resolvable)? true : changed; if (lengthVisible) { updateTextControl(lengthControl, constraintsController.getLength()); lengthControl.getControl().setEnabled(enabled); getProblemDecorator().bind(XSDPackage.Literals.XSD_LENGTH_FACET__VALUE, lengthControl); } changed = lengthControl.setVisible(lengthVisible) ? true : changed; if (minMaxVisible) { updateTextControl(minLengthControl, constraintsController.getMinLength()); updateTextControl(maxLengthControl, constraintsController.getMaxLength()); minLengthControl.getControl().setEnabled(enabled); getProblemDecorator().bind(XSDPackage.Literals.XSD_MIN_LENGTH_FACET__VALUE, minLengthControl); maxLengthControl.getControl().setEnabled(enabled); getProblemDecorator().bind(XSDPackage.Literals.XSD_MAX_LENGTH_FACET__VALUE, maxLengthControl); } changed = minLengthControl.setVisible(minMaxVisible) ? true : changed; changed = maxLengthControl.setVisible(minMaxVisible) ? true : changed; if (minMaxExclusiveVisible) { updateTextControl(minExclusiveControl, constraintsController.getMinExclusive()); updateTextControl(maxExclusiveControl, constraintsController.getMaxExclusive()); minExclusiveControl.getControl().setEnabled(enabled); maxExclusiveControl.getControl().setEnabled(enabled); getProblemDecorator().bind(XSDPackage.Literals.XSD_MIN_FACET__EXCLUSIVE, minExclusiveControl); getProblemDecorator().bind(XSDPackage.Literals.XSD_MAX_FACET__EXCLUSIVE, maxExclusiveControl); } if(minMaxInclusiveVisible){ updateTextControl(minInclusiveControl, constraintsController.getMinInclusive()); updateTextControl(maxInclusiveControl, constraintsController.getMaxInclusive()); minInclusiveControl.getControl().setEnabled(enabled); maxInclusiveControl.getControl().setEnabled(enabled); getProblemDecorator().bind(XSDPackage.Literals.XSD_MIN_FACET__INCLUSIVE, minInclusiveControl); getProblemDecorator().bind(XSDPackage.Literals.XSD_MAX_FACET__INCLUSIVE, maxInclusiveControl); } changed = minInclusiveControl.setVisible(minMaxInclusiveVisible) ? true : changed; changed = maxInclusiveControl.setVisible(minMaxInclusiveVisible) ? true : changed; changed = minExclusiveControl.setVisible(minMaxExclusiveVisible) ? true : changed; changed = maxExclusiveControl.setVisible(minMaxExclusiveVisible) ? true : changed; if (totalDigitsVisible) { updateTextControl(totalDigitsControl, constraintsController.getTotalDigits()); totalDigitsControl.getControl().setEnabled(enabled); getProblemDecorator().bind(XSDPackage.Literals.XSD_TOTAL_DIGITS_FACET__VALUE, totalDigitsControl); } changed = totalDigitsControl.setVisible(totalDigitsVisible) ? true : changed; if (fractionDigitsVisible) { updateTextControl(fractionDigitsControl, constraintsController.getFractionDigits()); fractionDigitsControl.getControl().setEnabled(enabled); } changed = fractionDigitsControl.setVisible(fractionDigitsVisible) ? true : changed; int horizontalSpan = 1; if (totalDigitsVisible && !fractionDigitsVisible) { horizontalSpan = 3; } final GridData totalDigitsGridData = (GridData) totalDigitsControl.getControl().getLayoutData(); if (totalDigitsGridData.horizontalSpan != horizontalSpan) { totalDigitsGridData.horizontalSpan = horizontalSpan; changed = true; } if (whitespaceVisible) { final Whitespace whitespace = constraintsController.getWhitespace(); for (int ndx = 0; ndx < whitespaceComboItems.length; ndx++) { final WhitespaceComboItem item = whitespaceComboItems[ndx]; if (item.whitespace == whitespace) { whitespaceControl.getControl().setText(item.label); } } whitespaceControl.setEnabled(enabled); getProblemDecorator().bind(XSDPackage.Literals.XSD_WHITE_SPACE_FACET__VALUE, whitespaceControl); } changed = whitespaceControl.setVisible(whitespaceVisible) ? true : changed; if (patternsVisible) { patternsTableViewer.setInput(constraintsController.getType()); patternsControl.setEnabled(enabled); patternsControl_facetTable.setEnabled(enabled); } changed = patternsControl.setVisible(patternsVisible) ? true : changed; if (enumsVisible) { enumsTableViewer.setInput(constraintsController.getType()); enumsControl.setEnabled(enabled); enumsControl_facetTable.setEnabled(enabled); getProblemDecorator().bind(XSDPackage.Literals.XSD_ENUMERATION_FACET__VALUE, enumsControl); } changed = enumsControl.setVisible(enumsVisible) ? true : changed; if (changed) { redrawSection(); } getProblemDecorator().updateDecorations(); } // private boolean showUnresolvableMessage(final boolean visible) { // // do nothing // return false; // // if (unresolvedLabel.getVisible() != visible) { // // unresolvedLabel.setVisible(!visible); // // Object layoutData = unresolvedLabel.getLayoutData(); // // if (layoutData instanceof GridData) { // // ((GridData) layoutData).exclude = !visible; // // } // // return true; // // } // // return false; // } public void modifyText(final ModifyEvent e) { // TODO Auto-generated method stub } public void focusGained(final FocusEvent e) { // TODO Auto-generated method stub } public void focusLost(final FocusEvent e) { final Object source = e.getSource(); final boolean updated = true; final IConstraintsController constraintsController = detailsController.getConstraintsController(); if (source == lengthControl.getControl()) { constraintsController.setLength(lengthControl.getControl().getText()); } else if (source == minLengthControl.getControl()) { constraintsController.setMinLength(minLengthControl.getControl().getText()); } else if (source == maxLengthControl.getControl()) { constraintsController.setMaxLength(maxLengthControl.getControl().getText()); } else if (source == minInclusiveControl.getControl()) { constraintsController.setMinInclusive(minInclusiveControl.getControl().getText()); } else if (source == maxInclusiveControl.getControl()) { constraintsController.setMaxInclusive(maxInclusiveControl.getControl().getText()); } else if (source == minExclusiveControl.getControl()) { constraintsController.setMinExclusive(minExclusiveControl.getControl().getText()); } else if (source == maxExclusiveControl.getControl()) { constraintsController.setMaxExclusive(maxExclusiveControl.getControl().getText()); } else if (source == whitespaceControl.getControl()) { constraintsController.setWhitespace(getSelectedWhitespace()); } else if (source == totalDigitsControl.getControl()) { constraintsController.setTotalDigits(totalDigitsControl.getControl().getText()); } else if (source == fractionDigitsControl.getControl()) { constraintsController.setFractionDigits(fractionDigitsControl.getControl().getText()); } if (updated) { // setDirty(source, false); dirtyStateChanged(); } } @Override protected int getColumnsCount() { return 4; } private void createControls(final FormToolkit toolkit, final Composite clientComposite) { final TextControlsCreator textControlsCreator = new TextControlsCreator(toolkit, clientComposite, this); createStringControls(textControlsCreator); createDigitsControls(textControlsCreator); createWhiteSpaceControl(toolkit, clientComposite); createPatternsControl(toolkit, clientComposite); createEnumsControl(toolkit, clientComposite); } /** * Utility method. Creates the string constraint section controls * * @param textControlsCreator */ private void createStringControls(final TextControlsCreator textControlsCreator) { lengthControl = textControlsCreator.create(Messages.SimpleTypeConstraintsSection_length, false, true); minLengthControl = textControlsCreator.create(Messages.SimpleTypeConstraintsSection_min_length, false, false); maxLengthControl = textControlsCreator.create(Messages.SimpleTypeConstraintsSection_max_length, true, false); } /** * Utility method. Creates the digit constraint section controls * * @param textControlsCreator */ private void createDigitsControls(final TextControlsCreator textControlsCreator) { minInclusiveControl = textControlsCreator.create(Messages.SimpleTypeConstraintsSection_min_inclusive, false, false); maxInclusiveControl = textControlsCreator.create(Messages.SimpleTypeConstraintsSection_max_inclusive, true, false); minExclusiveControl = textControlsCreator.create(Messages.SimpleTypeConstraintsSection_min_exclusive, false, false); maxExclusiveControl = textControlsCreator.create(Messages.SimpleTypeConstraintsSection_max_exclusive, true, false); totalDigitsControl = textControlsCreator.create(Messages.SimpleTypeConstraintsSection_total_digits, false, false); fractionDigitsControl = textControlsCreator.create(Messages.SimpleTypeConstraintsSection_fraction_digits, true, false); } /** * Utility method. Creates the whitespace constraint section controls * * @param toolkit * @param clientComposite */ private void createWhiteSpaceControl(final FormToolkit toolkit, final Composite clientComposite) { whitespaceControl = new LabeledControl<CCombo>(toolkit, clientComposite, Messages.SimpleTypeConstraintsSection_whitespace); whitespaceControl.setControl(Activator.getDefault().createCCombo(toolkit, clientComposite, SWT.DROP_DOWN | SWT.FLAT | SWT.READ_ONLY)); final CCombo whitespaceCombo = whitespaceControl.getControl(); for (final WhitespaceComboItem item : whitespaceComboItems) { whitespaceCombo.add(item.label); } whitespaceCombo.addFocusListener(this); whitespaceCombo.addKeyListener(CarriageReturnListener.getInstance()); GridDataFactory.swtDefaults().grab(true, false).align(SWT.LEFT, SWT.CENTER).span(3, 1).applyTo(whitespaceCombo); } /** * Utility method. Creates the patterns constraint section controls * * @param toolkit * @param clientComposite */ private void createPatternsControl(final FormToolkit toolkit, final Composite clientComposite) { patternsControl = new LabeledControl<Composite>(toolkit, clientComposite, Messages.SimpleTypeConstraintsSection_patterns); patternsControl.setControl(new Composite(clientComposite, SWT.NONE)); final Composite patternsComposite = patternsControl.getControl(); patternsControl_facetTable = new FacetTable(toolkit, patternsComposite, new PatternsTableContentProvider(), new FacetsTableLabelProvider()); patternsControl_facetTable.setEditingSupport(new PatternsTableEditingSupport(patternsControl_facetTable.getTableViewer(), detailsController)); patternsControl_facetTable.setAddHandler(new FacetTable.AddHandler() { public boolean addElement() { final InputDialog dlg = getInputDialog(null, Messages.SimpleTypeConstraintsSection_add_pattern_dlg_title, Messages.SimpleTypeConstraintsSection_add_pattern_dlg_msg, null, createDefaultInputValidator()); final int result = dlg.open(); if (result == Window.OK) { final String value = dlg.getValue().trim(); detailsController.getConstraintsController().addPattern(value); return true; } return false; } }); patternsControl_facetTable.setRemoveHandler(new FacetTable.RemoveHandler() { public void removeElement(final Object toRemove) { if (toRemove instanceof IFacet) { detailsController.getConstraintsController().deletePattern((IFacet) toRemove); } } }); patternsTableViewer = patternsControl_facetTable.getTableViewer(); GridDataFactory.swtDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).span(3, 1).applyTo( patternsControl.getControl()); } /** * Utility method. Creates the enumeration constraint section controls * * @param toolkit * @param clientComposite */ private void createEnumsControl(final FormToolkit toolkit, final Composite clientComposite) { enumsControl = new LabeledControl<Composite>(toolkit, clientComposite, Messages.SimpleTypeConstraintsSection_enums); enumsControl.setControl(new Composite(clientComposite, SWT.NONE)); final Composite enumsComposite = enumsControl.getControl(); enumsControl_facetTable = new FacetTable(toolkit, enumsComposite, new EnumsTableContentProvider(), new FacetsTableLabelProvider()); enumsControl_facetTable.setEditingSupport(new EnumsTableEditingSupport(enumsControl_facetTable.getTableViewer(), detailsController)); enumsControl_facetTable.setAddHandler(new FacetTable.AddHandler() { public boolean addElement() { final InputDialog dlg = getInputDialog(null, Messages.SimpleTypeConstraintsSection_add_enum_dlg_title, Messages.SimpleTypeConstraintsSection_add_enum_dlg_msg, null, createDefaultInputValidator()); final int result = dlg.open(); if (result == Window.OK) { final String value = dlg.getValue().trim(); detailsController.getConstraintsController().addEnum(value); return true; } return false; } }); enumsControl_facetTable.setRemoveHandler(new FacetTable.RemoveHandler() { public void removeElement(final Object toRemove) { final IStructuredSelection selection = (IStructuredSelection) enumsTableViewer.getSelection(); final Object element = selection.getFirstElement(); if (element instanceof IFacet) { detailsController.getConstraintsController().deleteEnum((IFacet) element); } } }); enumsTableViewer = enumsControl_facetTable.getTableViewer(); GridDataFactory.swtDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).span(3, 1).applyTo(enumsControl.getControl()); } @Override public boolean isStale() { return getModelObject() == null ? false : true; } protected InputDialog getInputDialog(final Shell parentShell, final String dialogTitle, final String dialogMessage, final String initialValue, final IInputValidator validator) { return new InputDialog(parentShell, dialogTitle, dialogMessage, initialValue, validator); } /** * Utility method. Creates default input validator - empty strings are * treated as invalid input * * @return the created input validator */ private IInputValidator createDefaultInputValidator() { return new IInputValidator() { @Override public String isValid(final String newText) { if (newText.trim().isEmpty()) { // input invalid - return "error" message return ""; //$NON-NLS-1$ } return null; } }; } private Whitespace getSelectedWhitespace() { final String text = whitespaceControl.getControl().getText(); for (final WhitespaceComboItem item : whitespaceComboItems) { if (item.label.equals(text)) { return item.whitespace; } } return null; } private void updateTextControl(final LabeledControl<Text> control, final String value) { final Text text = control.getControl(); text.setText(value); } private static class WhitespaceComboItem { private final Whitespace whitespace; private final String label; WhitespaceComboItem(final Whitespace whitespace, final String label) { this.whitespace = whitespace; this.label = label; } @Override public String toString() { return label; } } private static class TextControlsCreator { private final FormToolkit toolkit; private final Composite clientComposite; private final Point textDimensions; private final FocusListener focusListener; public TextControlsCreator(final FormToolkit toolkit, final Composite clientComposite, final FocusListener focusListener) { this.toolkit = toolkit; this.clientComposite = clientComposite; this.focusListener = focusListener; textDimensions = calculateTextDimensions(clientComposite); } public LabeledControl<Text> create(final String label, final boolean hasLeftIndent, final boolean spanRow) { // Length final LabeledControl<Text> labeledControl = new LabeledControl<Text>(toolkit, clientComposite, label); final Text text = toolkit.createText(clientComposite, UIConstants.EMPTY_STRING, SWT.SINGLE | SWT.RIGHT); labeledControl.setControl(text); labeledControl.getControl().addFocusListener(focusListener); labeledControl.getControl().addKeyListener(CarriageReturnListener.getInstance()); if (hasLeftIndent) { GridDataFactory.swtDefaults().indent(20, 0).applyTo(labeledControl.getLabel()); } final GridDataFactory textGDF = GridDataFactory.swtDefaults(); textGDF.hint(textDimensions); if (spanRow) { textGDF.grab(true, false).align(SWT.BEGINNING, SWT.CENTER).span(3, 1); } textGDF.applyTo(text); return labeledControl; } private Point calculateTextDimensions(final Composite parent) { final Text text = new Text(parent, SWT.BORDER); final int columns = 10; final GC gc = new GC(text); final FontMetrics fm = gc.getFontMetrics(); final int width = columns * fm.getAverageCharWidth(); final int height = fm.getHeight(); gc.dispose(); text.dispose(); return new Point(width, height); } } private class PatternsTableContentProvider implements IStructuredContentProvider { public Object[] getElements(final Object inputElement) { if (inputElement instanceof ISimpleType) { final IConstraintsController constraintsController = detailsController.getConstraintsController(); return constraintsController.getPatterns(); } return null; } public void dispose() { } public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) { } } private class EnumsTableContentProvider extends PatternsTableContentProvider { @Override public Object[] getElements(final Object inputElement) { if (inputElement instanceof ISimpleType) { final IConstraintsController constraintsController = detailsController.getConstraintsController(); return constraintsController.getEnums(); } return null; } } private static class FacetsTableLabelProvider extends LabelProvider { @Override public String getText(final Object element) { return ((IFacet) element).getValue(); } } }