diff --git a/plugins/org.jboss.tools.openshift.common.ui/src/org/jboss/tools/openshift/internal/common/ui/utils/TableViewerBuilder.java b/plugins/org.jboss.tools.openshift.common.ui/src/org/jboss/tools/openshift/internal/common/ui/utils/TableViewerBuilder.java index 7df9f939fd..e7c28586f0 100644 --- a/plugins/org.jboss.tools.openshift.common.ui/src/org/jboss/tools/openshift/internal/common/ui/utils/TableViewerBuilder.java +++ b/plugins/org.jboss.tools.openshift.common.ui/src/org/jboss/tools/openshift/internal/common/ui/utils/TableViewerBuilder.java @@ -10,6 +10,7 @@ ******************************************************************************/ package org.jboss.tools.openshift.internal.common.ui.utils; +import org.eclipse.core.runtime.Assert; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; @@ -66,6 +67,10 @@ public ColumnBuilder column(IColumnLabelProvider columnLabelProvider) { return new ColumnBuilder().labelProvider(columnLabelProvider); } + public ColumnBuilder column(CellLabelProvider cellLabelProvider) { + return new ColumnBuilder().labelProvider(cellLabelProvider); + } + public TableViewer buildViewer() { return viewer; } @@ -74,6 +79,7 @@ public class ColumnBuilder { private int alignement; private IColumnLabelProvider columnLabelProvider; + private CellLabelProvider cellLabelProvider; private ICellToolTipProvider cellToolTipProvider; private String name; private int weight; @@ -87,6 +93,11 @@ public ColumnBuilder labelProvider(IColumnLabelProvider labelProvider) { return this; } + public ColumnBuilder labelProvider(CellLabelProvider labelProvider) { + this.cellLabelProvider = labelProvider; + return this; + } + public ColumnBuilder cellToolTipProvider(ICellToolTipProvider cellToolTipProvider) { this.cellToolTipProvider = cellToolTipProvider; return this; @@ -118,36 +129,53 @@ public TableViewerBuilder buildColumn() { } TableViewerColumn column = new TableViewerColumn(viewer, alignement); column.getColumn().setText(name); - column.setLabelProvider(new CellLabelProvider() { + setLabelAndTooltipProviders(columnLabelProvider, cellLabelProvider, cellToolTipProvider, column); + tableLayout.setColumnData(column.getColumn(), new ColumnWeightData(weight, minWidth, true)); + return TableViewerBuilder.this; + } - @Override - public void update(ViewerCell cell) { - @SuppressWarnings("unchecked") - String cellValue = columnLabelProvider.getValue((E) cell.getElement()); - cell.setText(cellValue); - } - - @SuppressWarnings("unchecked") - @Override - public String getToolTipText(Object object) { - if(cellToolTipProvider != null) { - return cellToolTipProvider.getToolTipText((E) object); + private void setLabelAndTooltipProviders( + final IColumnLabelProvider labelProvider, final CellLabelProvider cellLabelProvider, final ICellToolTipProvider tooltipProvider, TableViewerColumn column) { + Assert.isLegal(labelProvider != null + || cellLabelProvider != null + , "set either IColumnLabelProvider or CellLabelProvider"); + Assert.isLegal((cellLabelProvider != null && tooltipProvider == null) + || cellLabelProvider == null + , "cannot use ITooltipProvider with with CellLabelProvider"); + if (labelProvider != null) { + column.setLabelProvider(new CellLabelProvider() { + + @Override + public void update(ViewerCell cell) { + if (labelProvider != null) { + String cellValue = labelProvider.getValue((E) cell.getElement()); + cell.setText(cellValue); + } } - return super.getToolTipText(object); - }; - - @SuppressWarnings("unchecked") - @Override - public int getToolTipDisplayDelayTime(Object element) { - if(cellToolTipProvider != null) { - return cellToolTipProvider.getToolTipDisplayDelayTime((E) element); + + @SuppressWarnings("unchecked") + @Override + public String getToolTipText(Object object) { + if (tooltipProvider != null) { + return tooltipProvider.getToolTipText((E) object); + } else { + return super.getToolTipText(object); + } + }; + + @SuppressWarnings("unchecked") + @Override + public int getToolTipDisplayDelayTime(Object element) { + if (tooltipProvider != null) { + return tooltipProvider.getToolTipDisplayDelayTime((E) element); + } else { + return super.getToolTipDisplayDelayTime(element); + } } - return super.getToolTipDisplayDelayTime(element); - } - - }); - tableLayout.setColumnData(column.getColumn(), new ColumnWeightData(weight, minWidth, true)); - return TableViewerBuilder.this; + }); + } else { + column.setLabelProvider(cellLabelProvider); + } } } diff --git a/plugins/org.jboss.tools.openshift.common.ui/src/org/jboss/tools/openshift/internal/common/ui/utils/TableViewerCellDecorationManager.java b/plugins/org.jboss.tools.openshift.common.ui/src/org/jboss/tools/openshift/internal/common/ui/utils/TableViewerCellDecorationManager.java new file mode 100644 index 0000000000..44d7ef6d37 --- /dev/null +++ b/plugins/org.jboss.tools.openshift.common.ui/src/org/jboss/tools/openshift/internal/common/ui/utils/TableViewerCellDecorationManager.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2015 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is 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: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package org.jboss.tools.openshift.internal.common.ui.utils; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.TableEditor; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; + +/** + * A manager that controls image based decorations for table viewer cells. + * + * @author Andre Dietisheim + */ +public class TableViewerCellDecorationManager { + + private Image image; + private Table table; + + /** + * @param table + * the table to handle cell decorations for + * @param image + * the image to show as decoration + */ + public TableViewerCellDecorationManager(Table table, Image image) { + this.image = image; + this.table = table; + } + + private Map decorationByItem = new HashMap(); + + public void show(ViewerCell cell) { + Control decoration = createDecoration(image, table); + TableEditor editor = decorationByItem.get((TableItem) cell.getItem()); + if (editor == null) { + editor = createTableEditor(image, table); + decorationByItem.put((TableItem) cell.getItem(), editor); + } + editor.setEditor(decoration, (TableItem) cell.getItem(), cell.getColumnIndex()); + } + + public void hide(ViewerCell cell) { + TableEditor editor = decorationByItem.get((TableItem) cell.getItem()); + if (editor != null) { + Control decoration = editor.getEditor(); + if (decoration != null) { + decoration.dispose(); + } + editor.setEditor(null); + } + } + + private Control createDecoration(Image image, Table table) { + Label validationDecoration = new Label(table, SWT.None); + validationDecoration.setImage(image); + return validationDecoration; + } + + private TableEditor createTableEditor(Image image, Table table) { + TableEditor tableEditor = new TableEditor(table); + tableEditor.grabHorizontal = false; + tableEditor.grabVertical = false; + Rectangle bounds = image.getBounds(); + tableEditor.minimumHeight = bounds.height; + tableEditor.minimumWidth = bounds.width; + tableEditor.verticalAlignment = SWT.BEGINNING; + tableEditor.horizontalAlignment = SWT.LEFT; + + return tableEditor; + } +} diff --git a/plugins/org.jboss.tools.openshift.ui/src/org/jboss/tools/openshift/internal/ui/wizard/newapp/TemplateParameterColumnLabelProvider.java b/plugins/org.jboss.tools.openshift.ui/src/org/jboss/tools/openshift/internal/ui/wizard/newapp/TemplateParameterValueColumnLabelProvider.java similarity index 92% rename from plugins/org.jboss.tools.openshift.ui/src/org/jboss/tools/openshift/internal/ui/wizard/newapp/TemplateParameterColumnLabelProvider.java rename to plugins/org.jboss.tools.openshift.ui/src/org/jboss/tools/openshift/internal/ui/wizard/newapp/TemplateParameterValueColumnLabelProvider.java index 0c0c310ada..ab5448fcd1 100644 --- a/plugins/org.jboss.tools.openshift.ui/src/org/jboss/tools/openshift/internal/ui/wizard/newapp/TemplateParameterColumnLabelProvider.java +++ b/plugins/org.jboss.tools.openshift.ui/src/org/jboss/tools/openshift/internal/ui/wizard/newapp/TemplateParameterValueColumnLabelProvider.java @@ -18,7 +18,7 @@ * A column provider for template parameters * @author jeff.cantrill */ -public class TemplateParameterColumnLabelProvider implements IColumnLabelProvider{ +public class TemplateParameterValueColumnLabelProvider implements IColumnLabelProvider{ protected static final String GENERATED = "(generated)"; diff --git a/plugins/org.jboss.tools.openshift.ui/src/org/jboss/tools/openshift/internal/ui/wizard/newapp/TemplateParametersPage.java b/plugins/org.jboss.tools.openshift.ui/src/org/jboss/tools/openshift/internal/ui/wizard/newapp/TemplateParametersPage.java index 219fbeaa97..5de5985e00 100644 --- a/plugins/org.jboss.tools.openshift.ui/src/org/jboss/tools/openshift/internal/ui/wizard/newapp/TemplateParametersPage.java +++ b/plugins/org.jboss.tools.openshift.ui/src/org/jboss/tools/openshift/internal/ui/wizard/newapp/TemplateParametersPage.java @@ -8,20 +8,34 @@ ******************************************************************************/ package org.jboss.tools.openshift.internal.ui.wizard.newapp; +import static org.apache.commons.lang.StringUtils.defaultIfBlank; +import static org.apache.commons.lang.StringUtils.isNotBlank; + +import java.util.Iterator; + import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.beans.BeanProperties; +import org.eclipse.core.databinding.observable.map.ObservableMap; +import org.eclipse.core.databinding.observable.map.WritableMap; +import org.eclipse.core.databinding.validation.MultiValidator; +import org.eclipse.core.databinding.validation.ValidationStatus; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.databinding.swt.WidgetProperties; import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; import org.eclipse.jface.databinding.viewers.ViewerProperties; import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.fieldassist.FieldDecorationRegistry; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.wizard.IWizard; import org.eclipse.osgi.util.NLS; @@ -29,15 +43,17 @@ import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Table; import org.jboss.tools.common.ui.databinding.ValueBindingBuilder; +import org.jboss.tools.openshift.common.core.utils.StringUtils; import org.jboss.tools.openshift.internal.common.ui.databinding.IsNotNull2BooleanConverter; import org.jboss.tools.openshift.internal.common.ui.utils.TableViewerBuilder; -import org.jboss.tools.openshift.internal.common.ui.utils.TableViewerBuilder.ICellToolTipProvider; -import org.jboss.tools.openshift.internal.common.ui.utils.TableViewerBuilder.IColumnLabelProvider; +import org.jboss.tools.openshift.internal.common.ui.utils.TableViewerCellDecorationManager; import org.jboss.tools.openshift.internal.common.ui.wizard.AbstractOpenShiftWizardPage; import com.openshift.restclient.model.template.IParameter; @@ -74,13 +90,12 @@ protected void doCreateControls(Composite container, DataBindingContext dbc) { .numColumns(2).margins(6, 6).applyTo(templateParametersGroup); Composite tableContainer = new Composite(templateParametersGroup, SWT.NONE); - this.viewer = createTable(tableContainer); + this.viewer = createTable(tableContainer, dbc); GridDataFactory.fillDefaults() .span(1, 5).align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(tableContainer); ValueBindingBuilder.bind(ViewerProperties.singleSelection().observe(viewer)) .to(BeanProperties.value(ITemplateParametersPageModel.PROPERTY_SELECTED_PARAMETER).observe(model)) .in(dbc); - viewer.setContentProvider(new ObservableListContentProvider()); viewer.setInput(BeanProperties.list( ITemplateParametersPageModel.PROPERTY_PARAMETERS).observe(model)); @@ -92,10 +107,10 @@ public void doubleClick(DoubleClickEvent event) { openEditDialog(param); } }); - + Button editExistingButton = new Button(templateParametersGroup, SWT.PUSH); GridDataFactory.fillDefaults() - .align(SWT.FILL, SWT.FILL).applyTo(editExistingButton); + .align(SWT.FILL, SWT.FILL).hint(100, SWT.DEFAULT).applyTo(editExistingButton); editExistingButton.setText("Edit"); editExistingButton.addSelectionListener(onEdit()); ValueBindingBuilder @@ -110,39 +125,116 @@ public void doubleClick(DoubleClickEvent event) { .align(SWT.FILL, SWT.FILL).applyTo(resetButton); resetButton.setText("Reset"); resetButton.addSelectionListener(onReset()); + + Label requiredExplanationLabel = new Label(templateParametersGroup, SWT.None); + requiredExplanationLabel.setText("* = value required, edit or double click to change them."); + GridDataFactory.fillDefaults() + .grab(true, false).align(SWT.FILL, SWT.FILL).span(2,1).applyTo(requiredExplanationLabel); } - public static TableViewer createTable(Composite tableContainer) { - Table table = + public static TableViewer createTable(final Composite tableContainer, DataBindingContext dbc) { + final Table table = new Table(tableContainer, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL); table.setLinesVisible(true); table.setHeaderVisible(true); - ICellToolTipProvider cellToolTipProvider = new ICellToolTipProvider() { - - @Override - public String getToolTipText(IParameter object) { - return object.getDescription(); - } - - @Override - public int getToolTipDisplayDelayTime(IParameter object) { - return 0; - } - }; + Image decorationImage = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR).getImage(); + final ObservableMap cellsValidationStatusObservable = new WritableMap(String.class, IStatus.class); + final TableViewerCellDecorationManager decorations = new TableViewerCellDecorationManager(table, decorationImage); TableViewer viewer = new TableViewerBuilder(table, tableContainer) .contentProvider(new ArrayContentProvider()) - .column(new IColumnLabelProvider() { - @Override - public String getValue(IParameter variable) { - return variable.getName(); - } - }) - .cellToolTipProvider(cellToolTipProvider) - .name("Name").align(SWT.LEFT).weight(2).minWidth(100).buildColumn() - .column(new TemplateParameterColumnLabelProvider()) - .cellToolTipProvider(cellToolTipProvider) - .name("Value").align(SWT.LEFT).weight(2).minWidth(100).buildColumn() - .buildViewer(); + .column(new CellLabelProvider() { + + @Override + public void update(ViewerCell cell) { + Assert.isLegal(cell.getElement() instanceof IParameter, "cell element is not a IParameter"); + + IParameter parameter = (IParameter) cell.getElement(); + String label = parameter.getName(); + if (parameter.isRequired()) { + label = markRequired(label); + } + cell.setText(label); + } + + private String markRequired(String label) { + return label += " *"; + } + + @Override + public String getToolTipText(Object object) { + Assert.isLegal(object instanceof IParameter, "cell element is not a IParameter"); + + return ((IParameter) object).getDescription(); + } + + @Override + public int getToolTipDisplayDelayTime(Object object) { + return 0; + } + }) + .name("Name") + .align(SWT.LEFT) + .weight(2) + .minWidth(100) + .buildColumn() + .column(new CellLabelProvider() { + + @Override + public void update(ViewerCell cell) { + Assert.isLegal(cell.getElement() instanceof IParameter, "cell element is not a IParameter"); + + final IParameter parameter = (IParameter) cell.getElement(); + String label = getLabel(parameter); + cell.setText(label); + + IStatus validationStatus = validate(parameter); + cellsValidationStatusObservable.put(parameter.getName(), validationStatus); + if(validationStatus.isOK()) { + decorations.hide(cell); + } else { + decorations.show(cell); + } + } + + private IStatus validate(IParameter parameter) { + if (parameter.isRequired()) { + if (StringUtils.isEmpty(parameter.getValue()) + && StringUtils.isEmpty(parameter.getGeneratorName())) { + return ValidationStatus.error(NLS.bind("Parameter {0} is required, please provide a value.", parameter.getName())); + }; + } + return ValidationStatus.ok(); + } + + private String getLabel(IParameter parameter) { + boolean hasGenerator = isNotBlank(parameter.getGeneratorName()); + boolean hasValue = isNotBlank(parameter.getValue()); + if(hasGenerator) { + return hasValue ? parameter.getValue() : "(generated)"; + } + return defaultIfBlank(parameter.getValue(), ""); + } + + @Override + public String getToolTipText(Object object) { + Assert.isLegal(object instanceof IParameter, "cell element is not a IParameter"); + + return ((IParameter) object).getDescription(); + } + + @Override + public int getToolTipDisplayDelayTime(Object object) { + return 0; + } + + }) + .name("Value") + .align(SWT.LEFT) + .weight(2) + .minWidth(100) + .buildColumn() + .buildViewer(); + viewer.setComparator(new ViewerComparator() { @Override @@ -153,9 +245,24 @@ public int compare(Viewer viewer, Object e1, Object e2) { } }); + viewer.setContentProvider(new ObservableListContentProvider()); + dbc.addValidationStatusProvider(new MultiValidator() { + + @Override + protected IStatus validate() { + for (Iterator iterator = (Iterator) cellsValidationStatusObservable.values().iterator(); iterator.hasNext(); ) { + IStatus cellValidationStatus = iterator.next(); + if (cellValidationStatus != null + && !cellValidationStatus.isOK()) { + return cellValidationStatus; + } + } + return ValidationStatus.ok(); + } + }); return viewer; } - + private SelectionListener onEdit() { return new SelectionAdapter() { @Override @@ -167,7 +274,9 @@ public void widgetSelected(SelectionEvent e) { } private void openEditDialog(final IParameter param) { - InputDialog dialog = new InputDialog(getShell(), "Edit Template Parameter", NLS.bind("Enter a value for {0}.\n{1}", param.getName(), param.getDescription()), param.getValue(), null) ; + InputDialog dialog = new InputDialog(getShell(), + "Edit Template Parameter", + NLS.bind("Enter a value for {0}.\n{1}", param.getName(), param.getDescription()), param.getValue(), null) ; if(InputDialog.OK == dialog.open()){ model.updateParameterValue(param, dialog.getValue()); viewer.refresh(); diff --git a/tests/org.jboss.tools.openshift.test/src/org/jboss/tools/openshift/test/ui/application/TemplateParameterColumnLabelProviderTest.java b/tests/org.jboss.tools.openshift.test/src/org/jboss/tools/openshift/test/ui/application/TemplateParameterColumnLabelProviderTest.java index b68adf4852..48d7b59fbc 100644 --- a/tests/org.jboss.tools.openshift.test/src/org/jboss/tools/openshift/test/ui/application/TemplateParameterColumnLabelProviderTest.java +++ b/tests/org.jboss.tools.openshift.test/src/org/jboss/tools/openshift/test/ui/application/TemplateParameterColumnLabelProviderTest.java @@ -11,7 +11,7 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; -import org.jboss.tools.openshift.internal.ui.wizard.newapp.TemplateParameterColumnLabelProvider; +import org.jboss.tools.openshift.internal.ui.wizard.newapp.TemplateParameterValueColumnLabelProvider; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -27,7 +27,7 @@ public class TemplateParameterColumnLabelProviderTest { @Mock private IParameter param; - private TemplateParameterColumnLabelProvider provider = new TemplateParameterColumnLabelProvider(); + private TemplateParameterValueColumnLabelProvider provider = new TemplateParameterValueColumnLabelProvider(); @Test public void parametersWithBlankValueAndNoGeneratorShouldReturnBlank() {