package org.gcube.portlets.widgets.mpformbuilder.client.form.generic; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.gcube.portlets.widgets.mpformbuilder.client.MetadataProfileFormBuilderService; import org.gcube.portlets.widgets.mpformbuilder.client.MetadataProfileFormBuilderServiceAsync; import org.gcube.portlets.widgets.mpformbuilder.client.events.CloseCreationFormEvent; import org.gcube.portlets.widgets.mpformbuilder.client.events.CloseCreationFormEventHandler; import org.gcube.portlets.widgets.mpformbuilder.client.events.DeleteCustomFieldEvent; import org.gcube.portlets.widgets.mpformbuilder.client.events.DeleteCustomFieldEventHandler; import org.gcube.portlets.widgets.mpformbuilder.client.form.MetaDataField; import org.gcube.portlets.widgets.mpformbuilder.client.ui.metadata.CategoryPanel; import org.gcube.portlets.widgets.mpformbuilder.client.ui.metadata.CustomFieldEntry; import org.gcube.portlets.widgets.mpformbuilder.client.ui.metadata.MetaDataFieldSkeleton; import org.gcube.portlets.widgets.mpformbuilder.client.ui.resources.AddResourceToDataset; import org.gcube.portlets.widgets.mpformbuilder.client.ui.tags.TagsPanel; import org.gcube.portlets.widgets.mpformbuilder.client.ui.twincolumnselection.TwinColumnSelectionMainPanel; import org.gcube.portlets.widgets.mpformbuilder.client.ui.utils.InfoIconsLabels; import org.gcube.portlets.widgets.mpformbuilder.shared.catalogue.OrganizationBean; import org.gcube.portlets.widgets.mpformbuilder.shared.license.LicenseBean; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.CategoryWrapper; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetaDataProfileBean; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetadataFieldWrapper; import com.github.gwtbootstrap.client.ui.AlertBlock; import com.github.gwtbootstrap.client.ui.Button; import com.github.gwtbootstrap.client.ui.ControlGroup; import com.github.gwtbootstrap.client.ui.Form; import com.github.gwtbootstrap.client.ui.Icon; import com.github.gwtbootstrap.client.ui.ListBox; import com.github.gwtbootstrap.client.ui.Paragraph; import com.github.gwtbootstrap.client.ui.Popover; import com.github.gwtbootstrap.client.ui.TabPanel; import com.github.gwtbootstrap.client.ui.constants.AlertType; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; /** * Create metadata form for ckan product. * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ public class CreateMetadataForm extends Composite{ private static EditMetadataFormUiBinder uiBinder = GWT .create(EditMetadataFormUiBinder.class); /** * The Interface EditMetadataFormUiBinder. * * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it) * * Oct 1, 2020 */ interface EditMetadataFormUiBinder extends UiBinder { } @UiField HTMLPanel createDatasetMainPanel; @UiField ControlGroup customFields; @UiField Button addCustomFieldButton; @UiField Button createButton; @UiField Button resetButton; @UiField AlertBlock infoBlock; @UiField AlertBlock onContinueAlertBlock; @UiField AlertBlock onCreateAlertBlock; @UiField VerticalPanel metadataFieldsPanel; @UiField ListBox metadataTypeListbox; @UiField Form formFirstStep; @UiField Form formThirdStep; @UiField Button continueButton; @UiField Paragraph selectedProfile; @UiField TagsPanel tagsPanel; // info panels @UiField Icon infoIconTypes; @UiField FocusPanel focusPanelTypes; @UiField Popover popoverTypes; @UiField Icon infoIconCustomFields; @UiField FocusPanel focusPanelCustomFields; @UiField Popover popoverCustomFields; @UiField ControlGroup metadataTypesControlGroup; // @UiField ControlGroup productTitleGroup; // @UiField ControlGroup maintainerControlGroup; // @UiField ControlGroup versionControlGroup; // @UiField ControlGroup organizationsGroup; // @UiField ControlGroup groupsControlGroup; private final MetadataProfileFormBuilderServiceAsync formBuilderService = GWT.create(MetadataProfileFormBuilderService.class); private static final String REGEX_TITLE_PRODUCT_SUBWORD = "[^a-zA-Z0-9_.-]"; private static final String REGEX_MAIL = "\\b[\\w.%-]+@[-.\\w]+\\.[A-Za-z]{2,4}\\b"; private static final String NONE_PROFILE = "none"; // error/info messages protected static final String ERROR_PRODUCT_CREATION = "There was an error while trying to publish your item."; protected static final String PRODUCT_CREATED_OK = "Item correctly published!"; private static final String TRYING_TO_CREATE_PRODUCT = "Trying to publish the item, please wait..."; protected static final String MISSING_PUBLISH_RIGHTS = "It seems you are not authorized to publish on catalogue. Request it to the VRE manager or the portal administrator."; // tab panel private TabPanel tabPanel; // add resource form private AddResourceToDataset resourceForm; // the licenses private List licenseBean; // event bus private HandlerManager eventBus; // added custom field entries (by the user) private List customFieldEntriesList = new ArrayList(); // the list of MetaDataField added private List listOfMetadataFields = new ArrayList(); // dataset metadata bean //private DatasetBean receivedBean; // the owner private String owner; // resource table private TwinColumnSelectionMainPanel resourcesTwinPanel; // List of opened popup'ids private List popupOpenedIds = new ArrayList(); // map of organization name title private Map nameTitleOrganizationMap = new HashMap(); private String scope; private String genericResourceSecondaryType; /** * Invoked in the most general case. * * @param scope the scope * @param genericResourceSecondaryType the generic resource secondary type * @param eventBus the event bus */ public CreateMetadataForm(String scope, String genericResourceSecondaryType, HandlerManager eventBus) { this(eventBus); this.scope = scope; this.genericResourceSecondaryType = genericResourceSecondaryType; MetadataProfileFormBuilderServiceAsync.Util.getInstance().getProfilesInTheScope(scope, genericResourceSecondaryType, new AsyncCallback>() { @Override public void onFailure(Throwable caught) { } @Override public void onSuccess(List profiles) { createDatasetFormBody(profiles); } }); } /** * Instantiates a new creates the dataset form. * * @param profiles the profiles * @param eventBus the event bus */ public CreateMetadataForm(List profiles, HandlerManager eventBus) { this(eventBus); createDatasetFormBody(profiles); } /** * Instantiates a new creates the dataset form. * * @param eventBus the event bus */ private CreateMetadataForm(HandlerManager eventBus) { initWidget(uiBinder.createAndBindUi(this)); this.eventBus = eventBus; bind(); prepareInfoIcons(); } /** * Bind on events. */ private void bind() { // when a custom field is removed, remove it from the list eventBus.addHandler(DeleteCustomFieldEvent.TYPE, new DeleteCustomFieldEventHandler() { @Override public void onRemoveEntry(DeleteCustomFieldEvent event) { customFieldEntriesList.remove(event.getRemovedEntry()); customFields.remove(event.getRemovedEntry()); } }); // on close form eventBus.addHandler(CloseCreationFormEvent.TYPE, new CloseCreationFormEventHandler() { @Override public void onClose(CloseCreationFormEvent event) { InfoIconsLabels.closeDialogBox(popupOpenedIds); } }); } /** * Creates the dataset form body. * * @param profiles the profiles */ private void createDatasetFormBody(final List profiles){ if(profiles == null){ setAlertBlock("An unknow error occurred while retrieving types, sorry", AlertType.ERROR, true); } else{ prepareMetadataList(profiles); metadataTypeListbox.setEnabled(true); } } /** * Add the items to the listbox and put data into the metadataPanel. * * @param profiles the profiles */ private void prepareMetadataList(final List profiles) { if(profiles != null && !profiles.isEmpty()){ for(MetaDataProfileBean metadataBean: profiles){ metadataTypeListbox.addItem(metadataBean.getType()); // add handler on select metadataTypeListbox.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { String selectedItemText = metadataTypeListbox.getSelectedItemText(); metadataFieldsPanel.clear(); if(selectedItemText.equals(NONE_PROFILE)){ metadataFieldsPanel.setVisible(false); //receivedBean.setChosenType(null); }else{ //receivedBean.setChosenType(selectedItemText); addFields(selectedItemText, profiles); } } }); } // // hide elements or show them if needed (groups in profiles cannot be present again in groups listbox) // if(groupsControlGroup.isVisible()){ // List groupsToHide = new ArrayList(); // for(MetaDataProfileBean profile: profiles) // groupsToHide.add(profile.getType().toString()); // // SelectElement se = groupsListbox.getElement().cast(); // // for (int i = 0; i < groupsListbox.getItemCount(); i++) { // if(groupsToHide.contains(groupsListbox.getItemText(i))){ // se.getOptions().getItem(i).getStyle().setProperty("display", "none"); // }else // se.getOptions().getItem(i).getStyle().setProperty("display", ""); // } // } // // metadataTypesControlGroup.setVisible(true); }else{ // just hide this listbox metadataTypesControlGroup.setVisible(false); metadataFieldsPanel.clear(); listOfMetadataFields.clear(); //receivedBean.setChosenType(null); } } /** * Add fields of the selected metadata profile to the widget. * * @param selectedItem the selected item * @param listProfiles the list profiles */ protected void addFields(String selectedItem, List listProfiles) { for(MetaDataProfileBean bean: listProfiles){ if(bean.getType().equals(selectedItem)){ // clear old data listOfMetadataFields.clear(); // prepare the data List fields = bean.getMetadataFields(); List categories = bean.getCategories(); GWT.log("There are " + categories.size() + " categories for profile " + bean.getTitle()); if(categories == null || categories.isEmpty()){ for (MetadataFieldWrapper field : fields) { /*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); }*/ MetaDataField fieldWidget; try { fieldWidget = new MetaDataField(field, eventBus); metadataFieldsPanel.add(fieldWidget); listOfMetadataFields.add(fieldWidget); } catch (Exception e) { GWT.log("Unable to build such widget", e); } } }else{ // create the categories, then parse the fields. Fields do not belonging to a category are put at the end for (CategoryWrapper categoryWrapper : categories) { if(categoryWrapper.getFieldsForThisCategory() != null && categoryWrapper.getFieldsForThisCategory().size() > 0){ CategoryPanel cp = new CategoryPanel(categoryWrapper.getTitle(), categoryWrapper.getDescription()); List fieldsForThisCategory = categoryWrapper.getFieldsForThisCategory(); fields.removeAll(fieldsForThisCategory); for (MetadataFieldWrapper metadataFieldWrapper : fieldsForThisCategory) { /*MetaDataFieldSkeleton fieldWidget; try { fieldWidget = new MetaDataFieldSkeleton(metadataFieldWrapper, eventBus); cp.addField(fieldWidget); listOfMetadataFields.add(fieldWidget); } catch (Exception e) { GWT.log("Unable to build such widget", e); }*/ MetaDataField fieldWidget; try { fieldWidget = new MetaDataField(metadataFieldWrapper, eventBus); cp.addField(fieldWidget); listOfMetadataFields.add(fieldWidget); } catch (Exception e) { GWT.log("Unable to build such widget", e); } } metadataFieldsPanel.add(cp); } } // add the remaining one at the end of the categories CategoryPanel extrasCategory = new CategoryPanel("Other", null); for (MetadataFieldWrapper field : fields) { /*MetaDataFieldSkeleton fieldWidget; try { fieldWidget = new MetaDataFieldSkeleton(field, eventBus); extrasCategory.addField(fieldWidget); listOfMetadataFields.add(fieldWidget); } catch (Exception e) { GWT.log("Unable to build such widget", e); }*/ MetaDataField fieldWidget; try { fieldWidget = new MetaDataField(field, eventBus); extrasCategory.addField(fieldWidget); listOfMetadataFields.add(fieldWidget); } catch (Exception e) { GWT.log("Unable to build such widget", e); } } metadataFieldsPanel.add(extrasCategory); } metadataFieldsPanel.setVisible(true); } } } /** * Adds the custom field event. * * @param e the e */ @UiHandler("addCustomFieldButton") void addCustomFieldEvent(ClickEvent e){ CustomFieldEntry toAdd = new CustomFieldEntry(eventBus, "", "", true); customFieldEntriesList.add(toAdd); customFields.add(toAdd); } /** * On continue button. * * @param e the e */ @UiHandler("continueButton") void onContinueButton(ClickEvent e){ // validate data final String errorMsg = validateDataOnContinue(); if(errorMsg != null){ alertOnContinue("Please check inserted data [" + errorMsg + "]", AlertType.ERROR); return; }else{ formThirdStep.setVisible(true); if(metadataTypeListbox.getSelectedItemText().equals(NONE_PROFILE)) selectedProfile.setText(""); else selectedProfile.setText("Selected Type is " + metadataTypeListbox.getSelectedItemText()); } } /** * After onContinue ... */ private void actionsAfterOnContinue(){ Window.alert("Called actionsAfterOnContinue"); if(metadataTypeListbox.getSelectedItemText().equals(NONE_PROFILE)) selectedProfile.setText(""); else selectedProfile.setText("Selected Type is " + metadataTypeListbox.getSelectedItemText()); } // /** // * On go back button first step. // * // * @param e the e // */ // @UiHandler("goBackButtonFirstStep") // void onGoBackButtonFirstStep(ClickEvent e){ // // Window.alert("Called onGoBackButtonFirstStep"); // //// // swap forms //// formFirstStep.setVisible(true); //// formSecondStep.setVisible(false); //// formThirdStep.setVisible(false); // // } /** * On go back button. * * @param e the e */ @UiHandler("goBackButtonSecondStep") void onGoBackButton(ClickEvent e){ Window.alert("Called onGoBackButton"); // // swap forms // if(isWorkspaceRequest){ // formFirstStep.setVisible(hideManageResources()); // formSecondStep.setVisible(!hideManageResources()); // }else{ // formFirstStep.setVisible(true); // formSecondStep.setVisible(false); // } // formThirdStep.setVisible(false); } // /** // * On continue third step. // * // * @param e the e // */ // @UiHandler("continueThirdStep") // void onContinueThirdStep(ClickEvent e){ // // Window.alert("Called onGoBackButton"); // // // swap forms //// formSecondStep.setVisible(false); //// formThirdStep.setVisible(true); // // } /** * Creates the dataset event. * * @param e the e */ @UiHandler("createButton") void createDatasetEvent(ClickEvent e){ String errorMessage = areProfileDataValid(); if(errorMessage != null){ alertOnCreate("Please check the inserted values and the mandatory fields [" + errorMessage +"]", AlertType.ERROR, true); } else{ Set tags = new HashSet(tagsPanel.getTags()); List groups = new ArrayList(); List groupsToForceCreation = new ArrayList(); Map> customFieldsMap = new HashMap>(); // prepare custom fields for (MetaDataField metaField : listOfMetadataFields) { for (MetaDataFieldSkeleton field : metaField.getListOfMetadataFields()) { List valuesForField = field.getFieldCurrentValue(); if(!valuesForField.isEmpty()){ String key = field.getFieldNameQualified(); List valuesForThisField = null; if(customFieldsMap.containsKey(key)) valuesForThisField = customFieldsMap.get(key); else valuesForThisField = new ArrayList(); valuesForThisField.addAll(valuesForField); customFieldsMap.put(key, valuesForThisField); // get also tag/group if it is the case for this field List tagsField = field.getTagFromThisField(); if(tagsField != null) tags.addAll(tagsField); List groupsTitle = field.getGroupTitleFromThisGroup(); if(groupsTitle != null){ for (String groupTitle : groupsTitle) { if(field.isGroupToForce()) groupsToForceCreation.add(new OrganizationBean(groupTitle, groupTitle, false, field.isPropagateUp())); else groups.add(new OrganizationBean(groupTitle, groupTitle, false, field.isPropagateUp())); } } } } } for(CustomFieldEntry customEntry : customFieldEntriesList){ String key = customEntry.getKey(); String value = customEntry.getValue(); if(value != null && !value.isEmpty()){ List valuesForThisField = null; if(customFieldsMap.containsKey(key)) valuesForThisField = customFieldsMap.get(key); else valuesForThisField = new ArrayList(); valuesForThisField.add(value); customFieldsMap.put(key, valuesForThisField); } } // alert alertOnCreate(TRYING_TO_CREATE_PRODUCT, AlertType.INFO, false); // invoke the create method createButton.setEnabled(false); } } /** * Prepare the info icons of all core metadata info. */ private void prepareInfoIcons() { // tags tagsPanel.prepareIcon(popupOpenedIds); // profiles (or types) InfoIconsLabels.preparePopupPanelAndPopover( InfoIconsLabels.PROFILES_INFO_ID_POPUP, InfoIconsLabels.PROFILES_INFO_TEXT, InfoIconsLabels.PROFILES_INFO_CAPTION, infoIconTypes, popoverTypes, focusPanelTypes, popupOpenedIds ); // custom fields InfoIconsLabels.preparePopupPanelAndPopover( InfoIconsLabels.CUSTOM_FIELDS_INFO_ID_POPUP, InfoIconsLabels.CUSTOM_FIELDS_INFO_TEXT, InfoIconsLabels.CUSTOM_FIELDS_INFO_CAPTION, infoIconCustomFields, popoverCustomFields, focusPanelCustomFields, popupOpenedIds ); } /** * Test if profile data are valid. * * @return the string */ private String areProfileDataValid() { for (MetaDataField metaField : listOfMetadataFields) { for (MetaDataFieldSkeleton field : metaField.getListOfMetadataFields()) { field.removeError(); String error = field.isFieldValueValid(); if(error != null){ field.showError(); return field.getFieldNameOriginal() + " is not valid. Suggestion: " + error; } } } return null; } /** * On continue show alert box and enable buttons. * * @param text the text * @param type the type */ private void alertOnContinue(String text, AlertType type){ onContinueAlertBlock.setText(text); onContinueAlertBlock.setType(type); onContinueAlertBlock.setVisible(true); continueButton.setEnabled(true); resetButton.setEnabled(true); // hide after some seconds Timer t = new Timer() { @Override public void run() { onContinueAlertBlock.setVisible(false); } }; t.schedule(4000); } /** * On continue show alert box and enable buttons. * * @param text the text * @param type the type * @param hideAfterAWhile the hide after A while */ private void alertOnCreate(String text, AlertType type, boolean hideAfterAWhile){ Window.alert("Called alertOnCreate"); // onCreateAlertBlock.setText(text); // onCreateAlertBlock.setType(type); // onCreateAlertBlock.setVisible(true); // createButton.setEnabled(true); // goBackButtonSecondStep.setEnabled(true); // // if(hideAfterAWhile){ // // hide after some seconds // Timer t = new Timer() { // // @Override // public void run() { // // onCreateAlertBlock.setVisible(false); // // } // }; // t.schedule(10000); // } } /** * Validate data. * * @return true on success, false otherwise */ private String validateDataOnContinue() { // // remove errors // productTitleGroup.setType(ControlGroupType.NONE); // maintainerControlGroup.setType(ControlGroupType.NONE); // versionControlGroup.setType(ControlGroupType.NONE); // metadataTypesControlGroup.setType(ControlGroupType.NONE); // organizationsGroup.setType(ControlGroupType.NONE); // tagsPanel.setGroupPanelType(ControlGroupType.NONE); // // String title = titleTextBox.getText().trim(); // if(title.isEmpty()){ // productTitleGroup.setType(ControlGroupType.ERROR); // return "Missing title"; // } // // // better check for the title // String[] splittedTitle = title.split(" "); // // for (String word : splittedTitle) { // String replaced = word.replaceAll(REGEX_TITLE_PRODUCT_SUBWORD, ""); // if(!replaced.equals(word)){ // productTitleGroup.setType(ControlGroupType.ERROR); // return "Please note not all characters are allowed for the title"; // } // } // // // email reg expression // String maintainerMail = maintainerEmailTextbox.getText(); // if(!maintainerMail.isEmpty() && !maintainerMail.matches(REGEX_MAIL)){ // maintainerControlGroup.setType(ControlGroupType.ERROR); // return "Not valid maintainer email"; // } // // // check if version is a number // try{ // int number = Integer.valueOf(versionTextbox.getText().trim()); // if(number <= 0) // throw new Exception(); // }catch(Exception e){ // versionControlGroup.setType(ControlGroupType.ERROR); // return "Version must be a natural number greater than zero"; // } // // // check if metadata profile is different from none and its mandatory fields have been fulfilled // if(checkSelectedMetaDataProfile()){ // metadataTypesControlGroup.setType(ControlGroupType.ERROR); // return "You must select a Type different frome none"; // } // // if(organizationsListbox.getSelectedItemText() == null){ // organizationsGroup.setType(ControlGroupType.ERROR); // return "You must select an organization in which you want to publish"; // } // // // at least one tag.. // if(tagsPanel.getTags().isEmpty()){ // tagsPanel.setGroupPanelType(ControlGroupType.ERROR); // return "Please add at least one meaningful tag for the item"; // } return null; } /** * Checks if a metadata profile has been chosen and its fields have been fulfilled. * * @return true, if successful */ private boolean checkSelectedMetaDataProfile() { return metadataTypeListbox.getSelectedItemText().equals(NONE_PROFILE) && metadataTypeListbox.getItemCount() != 1; } /** * Reset form event. * * @param e the e */ @UiHandler("resetButton") void resetFormEvent(ClickEvent e){ // delete custom fields for (CustomFieldEntry customField : customFieldEntriesList) { customField.removeFromParent(); } customFieldEntriesList.clear(); } /** * Disable dataset editable fields once the dataset has been successfully created. */ protected void disableDatasetFields() { tagsPanel.freeze(); addCustomFieldButton.setEnabled(false); metadataTypeListbox.setEnabled(false); for(CustomFieldEntry ce: customFieldEntriesList) ce.freeze(); // disable profile fields for (MetaDataField metaField : listOfMetadataFields) { for (MetaDataFieldSkeleton field : metaField.getListOfMetadataFields()) { field.freeze(); } } // freeze table of resources if(resourcesTwinPanel != null) resourcesTwinPanel.freeze(); } /** * change alert block behavior. * * @param textToShow the text to show * @param type the type * @param visible the visible */ private void setAlertBlock(String textToShow, AlertType type, boolean visible){ infoBlock.setText(textToShow); infoBlock.setType(type); infoBlock.setVisible(visible); } // /** // * On selected license change. // * // * @param c the c // */ // @UiHandler("licenseListbox") // void onSelectedLicenseChange(ChangeEvent c){ // // showLicenseUrl(); // // } /** * The body of the onSelectedLicenseChange. */ private void showLicenseUrl(){ Window.alert("Called showLicenseUrl"); } }