diff options
author | Benjamin Muskalla | 2012-04-29 16:18:23 +0000 |
---|---|---|
committer | Gerrit Code Review @ Eclipse.org | 2013-12-17 22:02:56 +0000 |
commit | 461cb61c85d4f7872c0faf5b9174d999bfcc98f5 (patch) | |
tree | c36be495374ed35a321c65beb44e6adc45f06f70 | |
parent | 20324679c2367c793f27095c4ac89ebe7b725bf4 (diff) | |
download | org.eclipse.mylyn.tasks-461cb61c85d4f7872c0faf5b9174d999bfcc98f5.tar.gz org.eclipse.mylyn.tasks-461cb61c85d4f7872c0faf5b9174d999bfcc98f5.tar.xz org.eclipse.mylyn.tasks-461cb61c85d4f7872c0faf5b9174d999bfcc98f5.zip |
NEW - bug 378032: provide support for required attributes
https://bugs.eclipse.org/bugs/show_bug.cgi?id=378032
Change-Id: Ib3cfcb8c8cb489fab5afbb0565f6da0643ab4b97
Signed-off-by: Benjamin Muskalla <benjamin.muskalla@tasktop.com>
10 files changed, 346 insertions, 3 deletions
diff --git a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaTaskDataHandler.java b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaTaskDataHandler.java index b50cca6da..ba1f3f4dd 100644 --- a/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaTaskDataHandler.java +++ b/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaTaskDataHandler.java @@ -546,6 +546,7 @@ public class BugzillaTaskDataHandler extends AbstractTaskDataHandler { createAttribute(taskData, BugzillaAttribute.SHORT_DESC); TaskAttribute attributeVersion = createAttribute(taskData, BugzillaAttribute.VERSION); + attributeVersion.getMetaData().setRequired(true); optionValues = repositoryConfiguration.getProductOptionValues(BugzillaAttribute.VERSION, productAttribute.getValue()); Collections.sort(optionValues); @@ -557,6 +558,7 @@ public class BugzillaTaskDataHandler extends AbstractTaskDataHandler { } TaskAttribute attributeComponent = createAttribute(taskData, BugzillaAttribute.COMPONENT); + attributeComponent.getMetaData().setRequired(true); optionValues = repositoryConfiguration.getProductOptionValues(BugzillaAttribute.COMPONENT, productAttribute.getValue()); Collections.sort(optionValues); @@ -607,6 +609,7 @@ public class BugzillaTaskDataHandler extends AbstractTaskDataHandler { } TaskAttribute attributeOPSYS = createAttribute(taskData, BugzillaAttribute.OP_SYS); + attributeOPSYS.getMetaData().setRequired(true); optionValues = repositoryConfiguration.getOptionValues(BugzillaAttribute.OP_SYS); for (String option : optionValues) { attributeOPSYS.putOption(option, option); @@ -617,6 +620,7 @@ public class BugzillaTaskDataHandler extends AbstractTaskDataHandler { } TaskAttribute attributePriority = createAttribute(taskData, BugzillaAttribute.PRIORITY); + attributePriority.getMetaData().setRequired(true); optionValues = repositoryConfiguration.getOptionValues(BugzillaAttribute.PRIORITY); for (String option : optionValues) { attributePriority.putOption(option, option); @@ -627,6 +631,7 @@ public class BugzillaTaskDataHandler extends AbstractTaskDataHandler { } TaskAttribute attributeSeverity = createAttribute(taskData, BugzillaAttribute.BUG_SEVERITY); + attributeSeverity.getMetaData().setRequired(true); optionValues = repositoryConfiguration.getOptionValues(BugzillaAttribute.BUG_SEVERITY); for (String option : optionValues) { attributeSeverity.putOption(option, option); diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttribute.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttribute.java index 12f96bbc6..0f555f39a 100644 --- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttribute.java +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttribute.java @@ -149,6 +149,11 @@ public final class TaskAttribute { public static final String META_READ_ONLY = "task.meta.readOnly"; //$NON-NLS-1$ /** + * @since 3.8 + */ + public static final String META_REQUIRED = "task.meta.required"; //$NON-NLS-1$ + + /** * @since 3.6 */ public static final String COMMENT_ISPRIVATE = "task.common.comment.isprivate"; //$NON-NLS-1$ diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttributeMetaData.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttributeMetaData.java index 7518b411b..ee3b0f599 100644 --- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttributeMetaData.java +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttributeMetaData.java @@ -40,6 +40,7 @@ public class TaskAttributeMetaData { setKind(null); setReadOnly(true); setType(TaskAttribute.TYPE_SHORT_TEXT); + setRequired(false); // only for test // putValue(TaskAttribute.META_DESCRIPTION, "Tooltip Defaul Text"); //$NON-NLS-1$ return this; @@ -98,6 +99,14 @@ public class TaskAttributeMetaData { return Boolean.parseBoolean(taskAttribute.getMetaDatum(TaskAttribute.META_READ_ONLY)); } + /** + * @since 3.11 + * @see TaskAttribute#META_REQUIRED + */ + public boolean isRequired() { + return Boolean.parseBoolean(taskAttribute.getMetaDatum(TaskAttribute.META_REQUIRED)); + } + public TaskAttributeMetaData putValue(String key, String value) { taskAttribute.putMetaDatum(key, value); return this; @@ -173,4 +182,14 @@ public class TaskAttributeMetaData { return this; } + /** + * @since 3.11 + * @see TaskAttribute#META_REQUIRED + * @return this + */ + public TaskAttributeMetaData setRequired(boolean value) { + taskAttribute.putMetaDatum(TaskAttribute.META_REQUIRED, Boolean.toString(value)); + return this; + } + } diff --git a/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/AllTasksTests.java b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/AllTasksTests.java index 1c4070d98..88730ef7f 100644 --- a/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/AllTasksTests.java +++ b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/AllTasksTests.java @@ -23,6 +23,7 @@ import org.eclipse.mylyn.tasks.tests.core.PriorityLevelTest; import org.eclipse.mylyn.tasks.tests.core.RepositoryClientManagerTest; import org.eclipse.mylyn.tasks.tests.core.RepositoryConnectorContributorTest; import org.eclipse.mylyn.tasks.tests.core.SynchronizeTasksJobTest; +import org.eclipse.mylyn.tasks.tests.core.TaskAttributeMetaDataTest; import org.eclipse.mylyn.tasks.tests.core.TaskInitializationDataTest; import org.eclipse.mylyn.tasks.tests.core.TaskListUnmatchedContainerTest; import org.eclipse.mylyn.tasks.tests.core.TaskRepositoryLocationTest; @@ -33,6 +34,7 @@ import org.eclipse.mylyn.tasks.tests.data.TaskDataDiffTest; import org.eclipse.mylyn.tasks.tests.data.TaskDataExternalizerTest; import org.eclipse.mylyn.tasks.tests.data.Xml11InputStreamTest; import org.eclipse.mylyn.tasks.tests.ui.AbstractRepositoryConnectorUiTest; +import org.eclipse.mylyn.tasks.tests.ui.AttributeEditorTest; import org.eclipse.mylyn.tasks.tests.ui.MultipleTaskHyperlinkDetectorTest; import org.eclipse.mylyn.tasks.tests.ui.ScheduledTaskContainerTest; import org.eclipse.mylyn.tasks.tests.ui.TaskAttachmentPropertyTesterTest; @@ -150,6 +152,8 @@ public class AllTasksTests { suite.addTestSuite(TaskAttributeTest.class); suite.addTestSuite(TaskAttributeMapperTest.class); suite.addTestSuite(SupportHandlerManagerTest.class); + suite.addTestSuite(TaskAttributeMetaDataTest.class); + suite.addTestSuite(AttributeEditorTest.class); suite.addTestSuite(RepositoryClientManagerTest.class); suite.addTestSuite(AbstractRepositoryConnectorUiTest.class); suite.addTestSuite(SynchronizeTasksJobTest.class); diff --git a/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/core/TaskAttributeMetaDataTest.java b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/core/TaskAttributeMetaDataTest.java new file mode 100644 index 000000000..a63364ff9 --- /dev/null +++ b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/core/TaskAttributeMetaDataTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2012 Tasktop Technologies and others. + * 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: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.tasks.tests.core; + +import junit.framework.TestCase; + +import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper; +import org.eclipse.mylyn.tasks.core.data.TaskData; +import org.eclipse.mylyn.tasks.tests.connector.MockRepositoryConnector; + +/** + * @author Benjamin Muskalla + */ +public class TaskAttributeMetaDataTest extends TestCase { + + private TaskData data; + + @Override + protected void setUp() throws Exception { + TaskRepository taskRepository = new TaskRepository("kind", "url"); + data = new TaskData(new TaskAttributeMapper(taskRepository), MockRepositoryConnector.CONNECTOR_KIND, + MockRepositoryConnector.REPOSITORY_URL, "taskid"); + } + + public void testInitialRequiredAttribute() { + TaskAttribute attribute = new TaskAttribute(data.getRoot(), "attributeId"); + boolean required = attribute.getMetaData().isRequired(); + assertFalse(required); + } + + public void testLifecycleRequiredAttribute() { + TaskAttribute attribute = new TaskAttribute(data.getRoot(), "attributeId"); + attribute.getMetaData().setRequired(true); + assertTrue(attribute.getMetaData().isRequired()); + attribute.getMetaData().setRequired(false); + assertFalse(attribute.getMetaData().isRequired()); + } + +} diff --git a/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/ui/AttributeEditorTest.java b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/ui/AttributeEditorTest.java new file mode 100644 index 000000000..77f3a15a1 --- /dev/null +++ b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/ui/AttributeEditorTest.java @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright (c) 2012 Tasktop Technologies and others. + * 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: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.tasks.tests.ui; + +import junit.framework.TestCase; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.mylyn.commons.workbench.WorkbenchUtil; +import org.eclipse.mylyn.internal.tasks.core.data.TaskDataState; +import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; +import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper; +import org.eclipse.mylyn.tasks.core.data.TaskData; +import org.eclipse.mylyn.tasks.core.data.TaskDataModel; +import org.eclipse.mylyn.tasks.tests.connector.MockRepositoryConnector; +import org.eclipse.mylyn.tasks.tests.connector.MockTask; +import org.eclipse.mylyn.tasks.ui.editors.AbstractAttributeEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.forms.widgets.FormToolkit; + +/** + * @author Benjamin Muskalla + */ +public class AttributeEditorTest extends TestCase { + + private class MockAttributeEditor extends AbstractAttributeEditor { + + private MockAttributeEditor(TaskDataModel manager, TaskAttribute taskAttribute) throws CoreException { + super(manager, taskAttribute); + setControl(new Shell()); + } + + @Override + public void createControl(Composite parent, FormToolkit toolkit) { + // ignore + } + + @Override + public boolean isRequired() { + return super.isRequired(); + } + + @Override + public void refresh() { + // ignore + } + + @Override + public Label getLabelControl() { + return new Label(new Shell(), SWT.NONE); + } + + @Override + protected boolean shouldAutoRefresh() { + return true; + } + } + + private TaskRepository repository; + + private TaskData taskData; + + private TaskDataModel manager; + + @Override + protected void setUp() throws Exception { + repository = new TaskRepository(MockRepositoryConnector.CONNECTOR_KIND, MockRepositoryConnector.REPOSITORY_URL); + TasksUiPlugin.getRepositoryManager().addRepository(repository); + + taskData = new TaskData(new TaskAttributeMapper(repository), MockRepositoryConnector.CONNECTOR_KIND, + MockRepositoryConnector.REPOSITORY_URL, "1"); + + manager = createManager(); + } + + public void testDetermineNotRequired() throws Exception { + TaskAttribute attribute = new TaskAttribute(taskData.getRoot(), "not.required.field"); + MockAttributeEditor editor = new MockAttributeEditor(manager, attribute); + assertFalse(editor.isRequired()); + attribute.setValue(""); + assertFalse(editor.isRequired()); + attribute.setValue("abc"); + assertFalse(editor.isRequired()); + } + + public void testDetermineRequired() throws Exception { + TaskAttribute attribute = new TaskAttribute(taskData.getRoot(), "a.required.field"); + attribute.getMetaData().setRequired(true); + MockAttributeEditor editor = new MockAttributeEditor(manager, attribute); + assertTrue(editor.isRequired()); + attribute.setValue(""); + assertTrue(editor.isRequired()); + attribute.setValue("abc"); + assertFalse(editor.isRequired()); + } + + public void testDecorateRequired() throws Exception { + final StringBuilder eventLog = new StringBuilder(); + TaskAttribute attribute = new TaskAttribute(taskData.getRoot(), "a.required.field"); + MockAttributeEditor editor = new MockAttributeEditor(manager, attribute) { + @Override + protected void decorateRequired() { + eventLog.append("decorateRequired"); + } + + }; + + assertEquals("", eventLog.toString()); + Color someColor = WorkbenchUtil.getShell().getDisplay().getSystemColor(SWT.COLOR_CYAN); + editor.decorate(someColor); + assertEquals("", eventLog.toString()); + + attribute.getMetaData().setRequired(true); + editor.decorate(someColor); + assertEquals("decorateRequired", eventLog.toString()); + eventLog.setLength(0); + + attribute.getMetaData().setRequired(false); + editor.decorate(someColor); + assertEquals("", eventLog.toString()); + } + + public void testDecorateRequiredOnChange() throws Exception { + final StringBuilder eventLog = new StringBuilder(); + TaskAttribute attribute = new TaskAttribute(taskData.getRoot(), "a.required.field"); + MockAttributeEditor editor = new MockAttributeEditor(manager, attribute) { + + @Override + protected void decorateRequired() { + eventLog.append("decorateRequired"); + } + + @Override + public boolean isRequired() { + eventLog.append("asked"); + return super.isRequired(); + } + + }; + + assertEquals("", eventLog.toString()); + Color someColor = WorkbenchUtil.getShell().getDisplay().getSystemColor(SWT.COLOR_CYAN); + + attribute.getMetaData().setRequired(true); + editor.decorate(someColor); + assertEquals("askeddecorateRequired", eventLog.toString()); + eventLog.setLength(0); + + attribute.setValue("someValue"); + manager.attributeChanged(attribute); + + assertEquals("asked", eventLog.toString()); + } + + public void testDecorateRequiredReal() throws Exception { + TaskAttribute attribute = new TaskAttribute(taskData.getRoot(), "a.required.field"); + MockAttributeEditor editor = new MockAttributeEditor(manager, attribute); + + Color someColor = WorkbenchUtil.getShell().getDisplay().getSystemColor(SWT.COLOR_CYAN); + + attribute.getMetaData().setRequired(true); + editor.decorate(someColor); + + attribute.getMetaData().setRequired(false); + manager.attributeChanged(attribute); + } + + public void testNoDecorateWithoutLabel() throws Exception { + TaskAttribute attribute = new TaskAttribute(taskData.getRoot(), "a.required.field"); + MockAttributeEditor editor = new MockAttributeEditor(manager, attribute) { + @Override + public Label getLabelControl() { + return null; + } + }; + + Color someColor = WorkbenchUtil.getShell().getDisplay().getSystemColor(SWT.COLOR_CYAN); + + attribute.getMetaData().setRequired(true); + editor.decorate(someColor); + + attribute.getMetaData().setRequired(false); + manager.attributeChanged(attribute); + } + + private TaskDataModel createManager() throws Exception { + MockTask task = new MockTask("taskId"); + TaskDataState state = new TaskDataState("kind", "url", "taskId"); + state.setEditsData(taskData); + state.setLocalTaskData(taskData); + TaskDataModel manager = new TaskDataModel(repository, task, state); + return manager; + } + +} diff --git a/org.eclipse.mylyn.tasks.ui/icons/ovr16/overlay-required.gif b/org.eclipse.mylyn.tasks.ui/icons/ovr16/overlay-required.gif Binary files differnew file mode 100644 index 000000000..1b17af928 --- /dev/null +++ b/org.eclipse.mylyn.tasks.ui/icons/ovr16/overlay-required.gif diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/Messages.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/Messages.java index 49597de80..5cf42dbf3 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/Messages.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/Messages.java @@ -25,6 +25,8 @@ public class Messages extends NLS { NLS.initializeMessages(BUNDLE_NAME, Messages.class); } + public static String AbstractAttributeEditor_AttributeIsRequired; + public static String AbstractReplyToCommentAction_Reply; public static String AttachmentSizeFormatter_0_bytes; diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/messages.properties b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/messages.properties index cb12598c9..0586ac69e 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/messages.properties +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/messages.properties @@ -8,6 +8,7 @@ # Contributors: # Tasktop Technologies - initial API and implementation ############################################################################### +AbstractAttributeEditor_AttributeIsRequired=This attribute is required AbstractReplyToCommentAction_Reply=Reply AttachmentSizeFormatter_0_bytes=0 bytes diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/editors/AbstractAttributeEditor.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/editors/AbstractAttributeEditor.java index 38291ebdd..f68a8a97a 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/editors/AbstractAttributeEditor.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/editors/AbstractAttributeEditor.java @@ -11,16 +11,22 @@ package org.eclipse.mylyn.tasks.ui.editors; +import org.apache.commons.lang.StringUtils; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.action.LegacyActionTools; +import org.eclipse.jface.fieldassist.ControlDecoration; +import org.eclipse.jface.fieldassist.FieldDecorationRegistry; +import org.eclipse.mylyn.internal.tasks.ui.editors.Messages; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper; import org.eclipse.mylyn.tasks.core.data.TaskDataModel; import org.eclipse.mylyn.tasks.core.data.TaskDataModelEvent; import org.eclipse.mylyn.tasks.core.data.TaskDataModelListener; +import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; @@ -66,10 +72,13 @@ public abstract class AbstractAttributeEditor { private final TaskDataModelListener modelListener = new TaskDataModelListener() { @Override public void attributeChanged(TaskDataModelEvent event) { - if (shouldAutoRefresh() && getTaskAttribute().equals(event.getTaskAttribute())) { + if (getTaskAttribute().equals(event.getTaskAttribute())) { try { - refreshInProgress = true; - refresh(); + if (shouldAutoRefresh()) { + refreshInProgress = true; + refresh(); + } + updateRequiredDecoration(); } catch (UnsupportedOperationException e) { } finally { refreshInProgress = false; @@ -84,6 +93,8 @@ public abstract class AbstractAttributeEditor { } }; + private ControlDecoration decoration; + /** * @since 3.0 */ @@ -233,10 +244,47 @@ public abstract class AbstractAttributeEditor { if (manager.hasOutgoingChanges(getTaskAttribute())) { decorateOutgoing(color); } + updateRequiredDecoration(); + } + } + + private void updateRequiredDecoration() { + if (getLabelControl() != null && isRequired()) { + decorateRequired(); + } else if (decoration != null) { + decoration.hide(); + decoration.dispose(); } } /** + * @since 3.11 + */ + protected void decorateRequired() { + decoration = new ControlDecoration(getLabelControl(), SWT.TOP | SWT.RIGHT); + decoration.setDescriptionText(Messages.AbstractAttributeEditor_AttributeIsRequired); + decoration.setMarginWidth(0); + Image image = FieldDecorationRegistry.getDefault() + .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR) + .getImage(); + decoration.setImage(image); + getLabelControl().addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent e) { + decoration.dispose(); + } + }); + } + + /** + * @since 3.11 + */ + protected boolean isRequired() { + boolean isRequired = getTaskAttribute().getMetaData().isRequired(); + boolean hasValue = !StringUtils.isEmpty(getTaskAttribute().getValue()); + return isRequired && !hasValue; + } + + /** * @since 3.0 */ protected void decorateOutgoing(Color color) { |