From c393e798b203d7e5963f50d91d2c156204a597f4 Mon Sep 17 00:00:00 2001 From: Costantino Perciante Date: Wed, 14 Sep 2016 14:29:52 +0000 Subject: [PATCH] Added support for new metadata (https://wiki.gcube-system.org/gcube/GCube_Data_Catalogue#Metadata_Profile_v.2_.28coming_soon.29) git-svn-id: http://svn.d4science-ii.research-infrastructures.eu/gcube/trunk/portlets/widgets/ckan-metadata-publisher-widget@131355 82a268e6-3cf1-43bd-a215-b396298e98cf --- pom.xml | 7 +- .../client/CKanMetadataPublisher.java | 106 ++- .../client/CKanPublisherService.java | 1 - .../client/ui/CreateDatasetForm.java | 37 +- .../client/ui/MetaDataFieldSkeleton.java | 667 +++++++++++++++--- .../client/ui/MetaDataFieldSkeleton.ui.xml | 2 +- .../server/utils/Utils.java | 2 +- .../shared/DataType.java | 4 +- .../shared/MetadataFieldWrapper.java | 16 +- 9 files changed, 725 insertions(+), 117 deletions(-) diff --git a/pom.xml b/pom.xml index bf222cd..230aa61 100644 --- a/pom.xml +++ b/pom.xml @@ -115,11 +115,6 @@ portal-service provided - - org.gcube.applicationsupportlayer - accesslogger - - org.gcube.applicationsupportlayer aslcore @@ -163,7 +158,7 @@ org.gcube.core common-scope-maps - compile + provided diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanMetadataPublisher.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanMetadataPublisher.java index 3969410..2fccaf9 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanMetadataPublisher.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanMetadataPublisher.java @@ -1,17 +1,30 @@ package org.gcube.portlets.widgets.ckandatapublisherwidget.client; -import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.CreateDatasetForm; +import java.util.ArrayList; +import java.util.List; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.CreateDatasetForm; +import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.MetaDataFieldSkeleton; +import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DataType; +import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.MetadataFieldWrapper; + +import com.github.gwtbootstrap.client.ui.Button; import com.google.gwt.core.client.EntryPoint; -import com.google.gwt.core.client.GWT; +import com.google.gwt.core.shared.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.shared.HandlerManager; +import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.VerticalPanel; /** * Entry point classes define onModuleLoad(). */ public class CKanMetadataPublisher implements EntryPoint { + private HandlerManager eventBus = new HandlerManager(null); + /** * This is the entry point method. */ @@ -19,17 +32,100 @@ public class CKanMetadataPublisher implements EntryPoint { // remove comment to the below line for testing the widget //startExample(); + //testMetadata(); + + } + + @SuppressWarnings("unused") + private void testMetadata() { + + VerticalPanel panel = new VerticalPanel(); + panel.setWidth("95%"); + RootPanel.get("ckan-metadata-publisher-div").add(panel); + + // prepare the data + List fields = new ArrayList(); + + // checkbox + //fields.add(new MetadataFieldWrapper("CheckBox", true, DataType.Boolean, "false", "Checkbox example", null, null)); + + // number + //fields.add(new MetadataFieldWrapper("Number", true, DataType.Number, "52", "Number example", null, null)); + + // other number + //fields.add(new MetadataFieldWrapper("Number2", true, DataType.Number, null, "Number example 2", null, "[0-9]+")); + + // other number + //fields.add(new MetadataFieldWrapper("Number3", false, DataType.Number, null, "Number example 3", null, "[0-9]+")); + + // text area + //fields.add(new MetadataFieldWrapper("Text Area", false, DataType.Text, "This is the default value", "Text Area", null, "^#\\w+\\.$")); + + // textbox + //fields.add(new MetadataFieldWrapper("TextBox", true, DataType.String, null, "TextBox", null, "^#\\w+\\.$")); + + // listbox + //fields.add(new MetadataFieldWrapper("ListBox", true, DataType.String, "prova4", "ListBox", Arrays.asList("prova1", "prova2", "prova3"), null)); + + // single date + //fields.add(new MetadataFieldWrapper("Single date", true, DataType.Time, null, "Single date", null, null)); + + // single date + //fields.add(new MetadataFieldWrapper("Single date 2", false, DataType.Time, "2045-12-01 18:20", "Single date 2", null, null)); + + // time interval + //fields.add(new MetadataFieldWrapper("Time interval 1", false, DataType.Time_Interval, null, "Time interval 1", null, null)); + + // time interval + //fields.add(new MetadataFieldWrapper("Time interval 2", true, DataType.Time_Interval, null, "Time interval 2", null, null)); + + // time interval + //fields.add(new MetadataFieldWrapper("Time intervals 2", true, DataType.Time_Interval, null, "Time intervals 2", null, null)); + + // time interval lists + fields.add(new MetadataFieldWrapper("Time intervals 2", false, DataType.Times_ListOf, null, "Time intervals 2", null, null)); + + final ArrayList widgetsList = new ArrayList(); + for (MetadataFieldWrapper metadataFieldWrapper : fields) { + MetaDataFieldSkeleton widget; + try { + widget = new MetaDataFieldSkeleton(metadataFieldWrapper, eventBus); + widgetsList.add(widget); + panel.add(widget); + } catch (Exception e) { + GWT.log("Error!", e); + } + } + + Button validator = new Button("Validate"); + panel.add(validator); + + validator.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + + for (MetaDataFieldSkeleton field : widgetsList) { + String error = field.isFieldValueValid(); + if(error != null){ + Window.alert(field.getFieldName() + " is not valid. Suggestion: " + error); + }else + { + Window.alert("No ERROR: " + field.getFieldCurrentValue() + " and without missing " + field.getTimeIntervalOrTimeListWithoutMissing()); + } + + } + } + }); } - private final CKanPublisherServiceAsync ckanServices = GWT.create(CKanPublisherService.class); @SuppressWarnings("unused") private void startExample() { String idFolderWorkspace = "d3a37eb9-1589-4c95-a9d0-c473a02d4f0f"; - String owner = "costantino.perciante"; - HandlerManager eventBus = new HandlerManager(null); + String owner = "costantino.perciante"; RootPanel.get("ckan-metadata-publisher-div").add(new CreateDatasetForm(idFolderWorkspace ,owner, eventBus)); } diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherService.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherService.java index eb9e6ec..bc98054 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherService.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/CKanPublisherService.java @@ -59,5 +59,4 @@ public interface CKanPublisherService extends RemoteService { * @return true on success, false otherwise */ boolean deleteResourceFromDataset(ResourceBeanWrapper resource); - } diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/CreateDatasetForm.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/CreateDatasetForm.java index 520cd63..217b959 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/CreateDatasetForm.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/CreateDatasetForm.java @@ -17,6 +17,7 @@ import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.DeleteCu import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.DeleteCustomFieldEventHandler; import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.utils.GcubeDialogExtended; import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.utils.InfoIconsLabels; +import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DataType; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetMetadataBean; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.LicensesBean; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.MetaDataProfileBean; @@ -320,7 +321,7 @@ public class CreateDatasetForm extends Composite{ alertNoResources.setType(AlertType.WARNING); alertNoResources.setVisible(true); - + } } @@ -544,11 +545,15 @@ public class CreateDatasetForm extends Composite{ listOfMetadataFields.clear(); for (MetadataFieldWrapper field : fields) { - MetaDataFieldSkeleton fieldWidget = new MetaDataFieldSkeleton(field, eventBus); - metadataFieldsPanel.add(fieldWidget); - listOfMetadataFields.add(fieldWidget); + MetaDataFieldSkeleton fieldWidget; + try { + fieldWidget = new MetaDataFieldSkeleton(field, eventBus); + metadataFieldsPanel.add(fieldWidget); + listOfMetadataFields.add(fieldWidget); + } catch (Exception e) { + GWT.log("Unable to build such widget", e); + } } - metadataFieldsPanel.setVisible(true); } } @@ -604,14 +609,14 @@ public class CreateDatasetForm extends Composite{ // check what to do if(isWorkspaceRequest){ - // we need to show the page to handle resources one by one from the workspace - formFirstStep.setVisible(false); - formSecondStep.setVisible(true); - formThirdStep.setVisible(false); + // we need to show the page to handle resources one by one from the workspace + formFirstStep.setVisible(false); + formSecondStep.setVisible(true); + formThirdStep.setVisible(false); - // add the resources to the container panel - if(workspaceResourcesContainer.getWidget() == null) - workspaceResourcesContainer.add(resourcesTable); + // add the resources to the container panel + if(workspaceResourcesContainer.getWidget() == null) + workspaceResourcesContainer.add(resourcesTable); }else{ @@ -719,8 +724,14 @@ public class CreateDatasetForm extends Composite{ // prepare custom fields for (MetaDataFieldSkeleton field : listOfMetadataFields) { + + MetadataFieldWrapper originalField = field.getField(); + + String value = originalField.getType().equals(DataType.Time_Interval) || originalField.getType().equals(DataType.Times_ListOf) ? + field.getTimeIntervalOrTimeListWithoutMissing() : field.getFieldCurrentValue(); - customFieldsMap.put(field.getFieldName(), field.getFieldCurrentValue()); + if(!value.isEmpty()) + customFieldsMap.put(field.getFieldName(), field.getFieldCurrentValue()); } diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/MetaDataFieldSkeleton.java b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/MetaDataFieldSkeleton.java index 1f1aec9..d07bc7f 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/MetaDataFieldSkeleton.java +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/MetaDataFieldSkeleton.java @@ -1,5 +1,6 @@ package org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui; +import java.util.Date; import java.util.List; import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.CloseCreationFormEvent; @@ -7,6 +8,7 @@ import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.CloseCre import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.utils.GcubeDialogExtended; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.MetadataFieldWrapper; +import com.github.gwtbootstrap.client.ui.Button; import com.github.gwtbootstrap.client.ui.CheckBox; import com.github.gwtbootstrap.client.ui.ControlLabel; import com.github.gwtbootstrap.client.ui.Controls; @@ -15,16 +17,20 @@ import com.github.gwtbootstrap.client.ui.ListBox; import com.github.gwtbootstrap.client.ui.Popover; import com.github.gwtbootstrap.client.ui.TextArea; import com.github.gwtbootstrap.client.ui.TextBox; +import com.github.gwtbootstrap.client.ui.constants.IconType; import com.github.gwtbootstrap.datetimepicker.client.ui.DateTimeBox; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.SpanElement; import com.google.gwt.dom.client.Style.Cursor; import com.google.gwt.dom.client.Style.Display; +import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.logical.shared.ResizeEvent; import com.google.gwt.event.logical.shared.ResizeHandler; import com.google.gwt.event.shared.HandlerManager; +import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; @@ -34,6 +40,7 @@ import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; public class MetaDataFieldSkeleton extends Composite{ @@ -55,19 +62,45 @@ public class MetaDataFieldSkeleton extends Composite{ @UiField Icon infoIcon; @UiField FocusPanel focusPanelIconContainer; - // the element that holds the value (it could be a checkbox, textbox or listbox, textarea, calendar) + private static final String REGEX_IS_NUMBER = "[0-9]+[.]?[0-9]+"; + + // the element that holds the value (it could be a checkbox, textbox or listbox, textarea, calendar, two calendars, more calendars) private Widget holder; // the field this object represents private MetadataFieldWrapper field; - + // the dialog box for this metadata private GcubeDialogExtended dialog; // save event bus reference private HandlerManager eventBus; - public MetaDataFieldSkeleton(MetadataFieldWrapper field, HandlerManager eventBus) { + // the date formatter(s) to use + private DateTimeFormat format1 = DateTimeFormat.getFormat("yyyy-MM-dd"); + private DateTimeFormat format2 = DateTimeFormat.getFormat("yyyy-MM-dd hh:mm"); + + // labels + private static final String INSERT_TIME_INSTANT_LABEL = "Insert a time instant"; + private static final String INSERT_TIME_START_LABEL = "Insert a start time instant"; + private static final String INSERT_TIME_END_LABEL = "Insert an end time instant"; + + // errors + private static final String MANDATORY_ATTRIBUTE_MISSING = "a mandatory attribute cannot be empty"; + private static final String MALFORMED_ATTRIBUTE = " the inserted value has a wrong format"; + private static final String ADD_NEW_TIME_RANGE = "Add a new Time Range"; + private static final String DELETE_TIME_RANGE = "Delete this Time Range"; + + // missing range value + public static final String MISSING_RANGE_VALUE = "missing"; + private static final String INSERT_MISSING_VALUE = " one or more range values missing"; + private static final String INSERT_MISSING_VALUE_MANDATORY = " one or more range values missing in mandatory field(s)"; + + // time range separator + public static final String RANGE_SEPARATOR_START_END = "/"; + public static final String RANGE_SEPARATOR = ","; + + public MetaDataFieldSkeleton(final MetadataFieldWrapper field, HandlerManager eventBus) throws Exception{ initWidget(uiBinder.createAndBindUi(this)); // prepare information @@ -79,17 +112,6 @@ public class MetaDataFieldSkeleton extends Composite{ // bind bind(); - // add custom css properties - controls.addStyleName("form-controls-custom"); - controlLabel.addStyleName("form-control-label-custom"); - - // save the name - name.setInnerText(field.getFieldName() + ":"); - - // check if it is mandatory - if(!field.getMandatory()) - mandatorySymbol.getStyle().setDisplay(Display.NONE); - switch(field.getType()){ case Boolean : @@ -97,27 +119,162 @@ public class MetaDataFieldSkeleton extends Composite{ // its a checkbox holder = new CheckBox(); - if(field.getDefaulValue() != null) - ((CheckBox)holder).setValue(Boolean.valueOf(field.getDefaulValue())); + if(field.getDefaultValue() != null) + ((CheckBox)holder).setValue(Boolean.valueOf(field.getDefaultValue())); break; case Text: holder = new TextArea(); - if(field.getDefaulValue() != null) - ((TextArea)holder).setText(field.getDefaulValue()); + if(field.getDefaultValue() != null) + ((TextArea)holder).setText(field.getDefaultValue()); break; - case Date: + case Time: holder = new DateTimeBox(); - if(field.getDefaulValue() != null) - ((DateTimeBox)holder).setFormat(field.getValidator()); - else // the default one - ((DateTimeBox)holder).setFormat("yyyy/mm/dd hh:ii"); + ((DateTimeBox)holder).setAutoClose(true); + ((DateTimeBox)holder).setPlaceholder(INSERT_TIME_INSTANT_LABEL); + + // check the formatter to be used + DateTimeFormat formatter = checkFormatterToUse(field.getDefaultValue()); + ((DateTimeBox)holder).setFormat(formatter.getPattern()); + + if(field.getDefaultValue() != null && !field.getDefaultValue().isEmpty()) + ((DateTimeBox)holder).setValue(formatter.parse(field.getDefaultValue())); + else + ((DateTimeBox)holder).setValue(null); + + break; + + case Time_Interval: + + holder = new FlowPanel(); + + DateTimeFormat formatterTimeInterval = checkFormatterToUse(field.getDefaultValue()); + + // start and end range date + DateTimeBox start = new DateTimeBox(); + DateTimeBox end = new DateTimeBox(); + start.setWidth("40%"); + start.getElement().getStyle().setMarginRight(10, Unit.PCT); + end.setWidth("40%"); + + // add two calendars + ((FlowPanel)holder).add(start); + ((FlowPanel)holder).add(end); + + start.setFormat(formatterTimeInterval.getPattern()); + end.setFormat(formatterTimeInterval.getPattern()); + + start.setPlaceholder(INSERT_TIME_START_LABEL); + end.setPlaceholder(INSERT_TIME_END_LABEL); + + if(field.getDefaultValue() != null && !field.getDefaultValue().isEmpty()){ + Date parsedTime = formatterTimeInterval.parse(field.getDefaultValue()); + start.setValue(parsedTime); + end.setValue(parsedTime); + }else{ + start.setValue(null); + end.setValue(null); + } + + break; + + case Times_ListOf: + + holder = new FlowPanel(); + + // start and end range date + final VerticalPanel containerRanges = new VerticalPanel(); + containerRanges.setWidth("100%"); + FlowPanel panelFirstRange = new FlowPanel(); + DateTimeBox startFirstRange = new DateTimeBox(); + DateTimeBox endFirstRange = new DateTimeBox(); + startFirstRange.setPlaceholder(INSERT_TIME_START_LABEL); + endFirstRange.setPlaceholder(INSERT_TIME_END_LABEL); + startFirstRange.setWidth("40%"); + startFirstRange.getElement().getStyle().setMarginRight(10, Unit.PCT); + endFirstRange.setWidth("40%"); + + final DateTimeFormat formatterTimeIntervalList = checkFormatterToUse(field.getDefaultValue()); + + startFirstRange.setFormat(formatterTimeIntervalList.getPattern()); + endFirstRange.setFormat(formatterTimeIntervalList.getPattern()); + + if(field.getDefaultValue() != null && !field.getDefaultValue().isEmpty()){ + Date formattedDefaultValueListOf = formatterTimeIntervalList.parse(field.getDefaultValue()); + startFirstRange.setValue(formattedDefaultValueListOf); + endFirstRange.setValue(formattedDefaultValueListOf); + }else{ + startFirstRange.setValue(null); + endFirstRange.setValue(null); + } + + // Add more button + Button addRangeButton = new Button(); + addRangeButton.setIcon(IconType.PLUS_SIGN); + addRangeButton.setTitle(ADD_NEW_TIME_RANGE); + + addRangeButton.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + + final FlowPanel newRange = new FlowPanel(); + DateTimeBox startNewRange = new DateTimeBox(); + DateTimeBox endNewRange = new DateTimeBox(); + + startNewRange.setWidth("40%"); + startNewRange.getElement().getStyle().setMarginRight(10, Unit.PCT); + endNewRange.setWidth("40%"); + endNewRange.getElement().getStyle().setMarginRight(2, Unit.PCT); + + startNewRange.setFormat(formatterTimeIntervalList.getPattern()); + endNewRange.setFormat(formatterTimeIntervalList.getPattern()); + + startNewRange.setPlaceholder(INSERT_TIME_START_LABEL); + endNewRange.setPlaceholder(INSERT_TIME_END_LABEL); + + if(field.getDefaultValue() != null && !field.getDefaultValue().isEmpty()){ + startNewRange.setValue(formatterTimeIntervalList.parse(field.getDefaultValue())); + endNewRange.setValue(formatterTimeIntervalList.parse(field.getDefaultValue())); + }else{ + startNewRange.setValue(null); + endNewRange.setValue(null); + } + + // delete button + Button deleteRangeButton = new Button("", IconType.MINUS_SIGN, new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + + newRange.removeFromParent(); + + } + }); + deleteRangeButton.setTitle(DELETE_TIME_RANGE); + + newRange.add(startNewRange); + newRange.add(endNewRange); + newRange.add(deleteRangeButton); + containerRanges.add(newRange); + + } + }); + + // add calendars and plus sign + panelFirstRange.add(startFirstRange); + panelFirstRange.add(endFirstRange); + containerRanges.add(panelFirstRange); + + // add the vertical panel first, then the button + ((FlowPanel)holder).add(containerRanges); + ((FlowPanel)holder).add(addRangeButton); break; @@ -125,8 +282,8 @@ public class MetaDataFieldSkeleton extends Composite{ holder = new TextBox(); - if(field.getDefaulValue() != null) - ((TextBox)holder).setText(field.getDefaulValue()); + if(field.getDefaultValue() != null) + ((TextBox)holder).setText(field.getDefaultValue()); break; @@ -138,8 +295,8 @@ public class MetaDataFieldSkeleton extends Composite{ // textbox holder = new TextBox(); - if(field.getDefaulValue() != null) - ((TextBox)holder).setText(field.getDefaulValue()); + if(field.getDefaultValue() != null) + ((TextBox)holder).setText(field.getDefaultValue()); }else{ @@ -163,8 +320,8 @@ public class MetaDataFieldSkeleton extends Composite{ } // set default value - if(field.getDefaulValue() != null) - ((ListBox)holder).setSelectedValue(field.getDefaulValue()); + if(field.getDefaultValue() != null) + ((ListBox)holder).setSelectedValue(field.getDefaultValue()); // check if multiple selection is allowed ((ListBox)holder).setMultipleSelect(field.isMultiSelection()); @@ -177,6 +334,17 @@ public class MetaDataFieldSkeleton extends Composite{ } + // add custom css properties + controls.addStyleName("form-controls-custom"); + controlLabel.addStyleName("form-control-label-custom"); + + // save the name + name.setInnerText(field.getFieldName() + ":"); + + // check if it is mandatory + if(!field.getMandatory()) + mandatorySymbol.getStyle().setDisplay(Display.NONE); + // add to the elementPanel elementPanel.add(holder); @@ -211,6 +379,25 @@ public class MetaDataFieldSkeleton extends Composite{ } + /** + * Check if we need to use format1 or format2 + * @param defaultValue + * @return format2 is returned as default + */ + private DateTimeFormat checkFormatterToUse(String defaultValue) { + if(defaultValue == null || defaultValue.isEmpty()) + return format2; + else{ + try{ + format1.parse(defaultValue); + return format1; + }catch(Exception e){ + GWT.log("Unable to parse default value with format 1", e); + return format2; + } + } + } + /** * Bind on events */ @@ -248,79 +435,284 @@ public class MetaDataFieldSkeleton extends Composite{ } /** - * Check if this field has a valid values + * Check if this field has valid values * @return a string with the occurred error on error, null otherwise */ public String isFieldValueValid(){ - if(field.getMandatory()){ + switch(field.getType()){ + + case Boolean : + + // nothing to validate + return null; + + case Text: + + String textAreaValue = getFieldCurrentValue(); + + if(field.getMandatory()){ + + if(!textAreaValue.trim().isEmpty()) + if(field.getValidator() == null || field.getValidator().isEmpty()) + return null; // no further check + else return checkValidator(textAreaValue, field.getValidator()) ? null : MALFORMED_ATTRIBUTE; + else return MANDATORY_ATTRIBUTE_MISSING; + + }else{ + + if(textAreaValue.trim().isEmpty()) + return null; + + else return checkValidator(textAreaValue, field.getValidator()) ? null : MALFORMED_ATTRIBUTE; + + } + + case Time: + + String dateValue = getFieldCurrentValue(); + + if(field.getMandatory()){ + if(dateValue == null || dateValue.isEmpty()) + return MANDATORY_ATTRIBUTE_MISSING; + } + return null; + + + case Time_Interval: + + String dateValueInterval = getFieldCurrentValue(); + + if(field.getMandatory()){ + if(dateValueInterval.contains(MISSING_RANGE_VALUE)) + return INSERT_MISSING_VALUE_MANDATORY; // there cannot be "missing" values here + else + return null; + }else{ + + String[] values = dateValueInterval.split(RANGE_SEPARATOR_START_END); + + if(values.length == 1) + return null; // same instants + else{ + + if(values[0].equals(values[1]) && values[0].equals(MISSING_RANGE_VALUE)) + return null; // missing/missing + + if(!values[0].equals(MISSING_RANGE_VALUE) && !values[1].equals(MISSING_RANGE_VALUE)) + return null; + + return INSERT_MISSING_VALUE; + } + + } + + case Times_ListOf: + + String dateValuesInterval = getFieldCurrentValue(); + + if(field.getMandatory()){ + if(dateValuesInterval.contains(MISSING_RANGE_VALUE)) // there cannot be "missing" values here + return INSERT_MISSING_VALUE_MANDATORY; + else + return null; + }else{ + + String[] values = dateValuesInterval.split(RANGE_SEPARATOR); + + for (int i = 0; i < values.length; i++) { + + String[] splitSingleRange = values[i].split(RANGE_SEPARATOR_START_END); + + if(splitSingleRange.length == 1) + continue; // same instants + else{ + + if(splitSingleRange[0].equals(splitSingleRange[1]) && splitSingleRange[0].equals(MISSING_RANGE_VALUE)) + continue; // missing/missing, it's ok + + if(!splitSingleRange[0].equals(MISSING_RANGE_VALUE) && !splitSingleRange[1].equals(MISSING_RANGE_VALUE)) // value/value is ok too + continue; + + return INSERT_MISSING_VALUE; // something like missing/x or x/missing + } + } + + return null; + } + + case Number: + + String numberValue = ((TextBox)holder).getValue(); + + if(field.getMandatory()){ + + if(!numberValue.trim().isEmpty()) + if(field.getValidator() == null || field.getValidator().isEmpty()) + return checkValidator(numberValue, REGEX_IS_NUMBER) ? null : MALFORMED_ATTRIBUTE; + else return checkValidator(numberValue, field.getValidator()) ? null : MALFORMED_ATTRIBUTE; + else return " a mandatory attribute cannot be empty"; + + }else{ + + if(numberValue.trim().isEmpty()) + return null; + else { + String validatorToUse = field.getValidator() == null || field.getValidator().isEmpty() ? REGEX_IS_NUMBER : field.getValidator(); + return checkValidator(numberValue, validatorToUse) ? null : MALFORMED_ATTRIBUTE; + } + } + + case String: + + // just handle the case of textbox if(holder.getClass().equals(TextBox.class)){ - if(!getFieldCurrentValue().isEmpty()) - if(field.getValidator() == null || field.getValidator().isEmpty()) + String textBoxValue = getFieldCurrentValue(); + if(field.getMandatory()){ + if(!textBoxValue.trim().isEmpty()) + if(field.getValidator() == null || field.getValidator().isEmpty()) + return null; // no further check + else return checkValidator(textBoxValue, field.getValidator()) ? null : MALFORMED_ATTRIBUTE; + else return " a mandatory attribute cannot be empty"; + + }else{ + if(textBoxValue.trim().isEmpty()) return null; - else return checkValidator(holder, field) ? null : " the inserted value has a wrong format"; - else - return " a mandatory attribute cannot be empty"; + else return checkValidator(textBoxValue, field.getValidator()) ? null : MALFORMED_ATTRIBUTE; + } + } + else return null; - }else - return null; - - }else{ - - if(holder.getClass().equals(TextBox.class) && getFieldCurrentValue().isEmpty()) - return null; - - return checkValidator(holder, field) ? null : " please select a different value for this field"; + default: return null; } } - private boolean checkValidator(Widget holder, MetadataFieldWrapper field){ - - String validator = field.getValidator(); - + /** + * Check if value matches validator (regex). In case validator is null, true is returned. + * @param value + * @param validator + * @return true if validator is null OR value.matches(reges), false otherwise + */ + private boolean checkValidator(String value, String validator) { if(validator == null || validator.isEmpty()) return true; - else if(holder.getClass().equals(TextBox.class)){ - return getFieldCurrentValue().matches(field.getValidator().trim()); - }else - return true; - + else return value.matches(validator); } /** * Returns the current value of the field (in case of multiselection Listbox returns - * the values separated by column) + * the values separated by column ','). In case of TimeInterval or TimeList see getTimeIntervalOrTimeListWithoutMissing() * @return */ public String getFieldCurrentValue(){ - String value = ""; + String toReturn = ""; - // we validate only listbox and textbox - if(holder.getClass().equals(ListBox.class)){ + switch(field.getType()){ - boolean first = true; + case Boolean : - for(int i = 0; i < ((ListBox)holder).getItemCount(); i++){ - if(((ListBox)holder).isItemSelected(i)){ - value += first ? ((ListBox)holder).getItemText(i) : ", " + ((ListBox)holder).getItemText(i); - first = false; - } + toReturn = ((CheckBox)holder).getValue().toString(); + break; + + case Text: + + toReturn = ((TextArea)holder).getText(); + break; + + case Time: + + Date date = ((DateTimeBox)holder).getValue(); + if(date == null) + return null; + else{ + DateTimeFormat formatter = checkFormatterToUse(field.getDefaultValue()); + return formatter.format(date); } - // if it was not mandatory but there was no choice, returning empty string - if(!field.getMandatory()) - if(value.equals("Select " + field.getFieldName())) - return ""; - } - else if(holder.getClass().equals(TextBox.class)) - value = ((TextBox)holder).getText(); - else - value = ((CheckBox)holder).getValue().toString(); + case Time_Interval: - return value; + DateTimeBox init = (DateTimeBox)((FlowPanel)holder).getWidget(0); + DateTimeBox end = (DateTimeBox)((FlowPanel)holder).getWidget(1); + + Date initDate = init.getValue(); + Date endDate = end.getValue(); + + DateTimeFormat formatter = checkFormatterToUse(field.getDefaultValue()); + + String initDateAsString = initDate == null ? MISSING_RANGE_VALUE : formatter.format(initDate); + String endDateAsString = endDate == null ? MISSING_RANGE_VALUE : formatter.format(endDate); + + if(initDateAsString.equals(endDateAsString) && !initDateAsString.equals(MISSING_RANGE_VALUE)) + toReturn = formatter.format(initDate); // an instant + else + toReturn = initDateAsString + RANGE_SEPARATOR_START_END + endDateAsString; + + GWT.log("Time_Interval " + toReturn); + + break; + + case Times_ListOf: + + // get container + VerticalPanel containerRanges = (VerticalPanel)((FlowPanel)holder).getWidget(0); + + // get its children count + int values = containerRanges.getWidgetCount(); + + for (int i = 0; i < values; i++) { + + // get FlowPanel panel + FlowPanel line = (FlowPanel)containerRanges.getWidget(i); + DateTimeBox initRangeInLine = (DateTimeBox)line.getWidget(0); + DateTimeBox endRangeInLine = (DateTimeBox)line.getWidget(1); + DateTimeFormat formatterRange = checkFormatterToUse(field.getDefaultValue()); + String initRangeAsString = initRangeInLine.getValue() == null ? MISSING_RANGE_VALUE : formatterRange.format(initRangeInLine.getValue()); + String endRangeAsString = endRangeInLine.getValue() == null ? MISSING_RANGE_VALUE : formatterRange.format(endRangeInLine.getValue()); + + if(initRangeAsString.equals(endRangeAsString) && !endRangeAsString.equals(MISSING_RANGE_VALUE)) + toReturn += (i == 0) ? initRangeAsString : + RANGE_SEPARATOR + initRangeAsString; // an instant + else + toReturn += (i == 0) ? initRangeAsString + RANGE_SEPARATOR_START_END + endRangeAsString : + RANGE_SEPARATOR + initRangeAsString + RANGE_SEPARATOR_START_END + endRangeAsString; + + } + + break; + + case Number: + case String: + + if(holder.getClass().equals(TextBox.class)) + toReturn = ((TextBox)holder).getText(); + else{// listbox case + + boolean first = true; + + // handle multiselected case + for(int i = 0; i < ((ListBox)holder).getItemCount(); i++){ + if(((ListBox)holder).isItemSelected(i)){ + toReturn += first ? ((ListBox)holder).getItemText(i) : ", " + ((ListBox)holder).getItemText(i); + first = false; + } + } + + // if it was not mandatory but there was no choice, returning empty string + if(!field.getMandatory()) + if(toReturn.equals("Select " + field.getFieldName())) + toReturn = ""; + } + + break; + + default: break; + + } + + return toReturn; } /** @@ -338,12 +730,125 @@ public class MetaDataFieldSkeleton extends Composite{ */ public void freeze() { - if(holder.getClass().equals(ListBox.class)) - ((ListBox)holder).setEnabled(false); - else if(holder.getClass().equals(TextBox.class)) - ((TextBox)holder).setEnabled(false); - else - ((CheckBox)holder).setEnabled(false); + switch(field.getType()){ + case Boolean : + + ((CheckBox)holder).setEnabled(false); + break; + + case Text: + + ((TextArea)holder).setEnabled(false); + break; + + case Time: + + ((DateTimeBox)holder).setEnabled(false); + break; + + case Time_Interval: + + ((DateTimeBox)((FlowPanel)holder).getWidget(0)).setEnabled(false); + ((DateTimeBox)((FlowPanel)holder).getWidget(1)).setEnabled(false); + break; + + case Times_ListOf: + + // get container + VerticalPanel containerRanges = (VerticalPanel)((FlowPanel)holder).getWidget(0); + + // freeze the button too + ((Button)((FlowPanel)holder).getWidget(1)).setEnabled(false); + + // get its children count + int values = containerRanges.getWidgetCount(); + + for (int i = 0; i < values; i++) { + + // get FlowPanel panel + FlowPanel line = (FlowPanel)containerRanges.getWidget(i); + ((DateTimeBox)line.getWidget(0)).setEnabled(false); + ((DateTimeBox)line.getWidget(1)).setEnabled(false); + + } + + break; + + case Number: + + ((TextBox)holder).setEnabled(false); + break; + + case String: + + if(holder.getClass().equals(ListBox.class)) + ((ListBox)holder).setEnabled(false); + else + ((TextBox)holder).setEnabled(false); + break; + + default: break; + + } } -} + + /** + * Use it to retrieve TimeInterval or TimeListOf after isValidField() invocation returned true (and only for these types!) + * @return + */ + public String getTimeIntervalOrTimeListWithoutMissing(){ + + String currentValue = getFieldCurrentValue(); + + switch(field.getType()){ + + case Time_Interval: + + String tempCurrentValue = currentValue.replaceAll(MISSING_RANGE_VALUE, "").replaceAll(RANGE_SEPARATOR_START_END, ""); + if(tempCurrentValue.trim().equals("")) + return ""; + else + return currentValue; + + case Times_ListOf: + + String toReturn = ""; + + String[] values = currentValue.split(RANGE_SEPARATOR); + + for (int i = 0; i < values.length; i++) { + + String[] splitSingleRange = values[i].split(RANGE_SEPARATOR_START_END); + + if(splitSingleRange.length == 1) + toReturn += splitSingleRange + RANGE_SEPARATOR; // same instants + else{ + + if(splitSingleRange[0].equals(splitSingleRange[1]) && splitSingleRange[0].equals(MISSING_RANGE_VALUE)) + continue; // missing/missing, it's ok + + if(!splitSingleRange[0].equals(MISSING_RANGE_VALUE) && !splitSingleRange[1].equals(MISSING_RANGE_VALUE)) // value/value is ok too + toReturn += splitSingleRange[0] + RANGE_SEPARATOR_START_END + splitSingleRange[1] + RANGE_SEPARATOR; + } + } + + if(toReturn.endsWith(RANGE_SEPARATOR)) + toReturn = toReturn.substring(0, toReturn.length() - 1); + + return toReturn; + + default: return null; + + } + } + + /** + * Get the original MetadataFieldWrapper object + * @return + */ + public MetadataFieldWrapper getField() { + return field; + } + +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/MetaDataFieldSkeleton.ui.xml b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/MetaDataFieldSkeleton.ui.xml index ace5151..6458c26 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/MetaDataFieldSkeleton.ui.xml +++ b/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/client/ui/MetaDataFieldSkeleton.ui.xml @@ -32,7 +32,7 @@ - + vocabulary; private boolean multiSelection; @@ -40,13 +40,13 @@ public class MetadataFieldWrapper implements Serializable{ */ public MetadataFieldWrapper( String fieldName, Boolean mandatory, DataType type, - String defaulValue, String note, List vocabulary, + String defaultValue, String note, List vocabulary, String validator) { super(); this.fieldName = fieldName; this.mandatory = mandatory; this.type = type; - this.defaulValue = defaulValue; + this.defaultValue = defaultValue; this.note = note; this.vocabulary = vocabulary; this.validator = validator; @@ -77,9 +77,9 @@ public class MetadataFieldWrapper implements Serializable{ * * @return the defaulValue */ - public String getDefaulValue() { + public String getDefaultValue() { - return defaulValue; + return defaultValue; } /** @@ -137,9 +137,9 @@ public class MetadataFieldWrapper implements Serializable{ * * @param defaulValue the defaulValue to set */ - public void setDefaulValue(String defaulValue) { + public void setDefaultValue(String defaultValue) { - this.defaulValue = defaulValue; + this.defaultValue = defaultValue; } /** @@ -191,7 +191,7 @@ public class MetadataFieldWrapper implements Serializable{ @Override public String toString() { return "MetadataFieldWrapper [fieldName=" + fieldName + ", mandatory=" - + mandatory + ", type=" + type + ", defaulValue=" + defaulValue + + mandatory + ", type=" + type + ", defaultValue=" + defaultValue + ", note=" + note + ", vocabulary=" + vocabulary + ", multiSelection=" + multiSelection + ", validator=" + validator + "]";