package org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.gcube.portlets.user.gcubewidgets.client.elements.Span; import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService; import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherServiceAsync; import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.DeleteCustomFieldEvent; import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.DeleteCustomFieldEventHandler; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetMetadataBean; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.LicensesBean; import com.github.gwtbootstrap.client.ui.AlertBlock; import com.github.gwtbootstrap.client.ui.Button; import com.github.gwtbootstrap.client.ui.CheckBox; import com.github.gwtbootstrap.client.ui.ControlGroup; import com.github.gwtbootstrap.client.ui.ListBox; import com.github.gwtbootstrap.client.ui.Tab; import com.github.gwtbootstrap.client.ui.TabPanel; import com.github.gwtbootstrap.client.ui.TextArea; import com.github.gwtbootstrap.client.ui.TextBox; import com.github.gwtbootstrap.client.ui.base.ListItem; import com.github.gwtbootstrap.client.ui.constants.AlertType; import com.github.gwtbootstrap.client.ui.resources.Bootstrap.Tabs; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyDownEvent; 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.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; /** * Edit metadata form for ckan dataset. * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ public class EditMetadataForm extends Composite{ /** * Create a remote service proxy to talk to the server-side ckan service. */ private final CKanPublisherServiceAsync ckanServices = GWT.create(CKanPublisherService.class); private static EditMetadataFormUiBinder uiBinder = GWT .create(EditMetadataFormUiBinder.class); interface EditMetadataFormUiBinder extends UiBinder { } @UiField TextBox titleTextBox; @UiField TextArea descriptionTextarea; @UiField TextBox tagsEnterTextBox; @UiField FlowPanel tagsPanel; @UiField ListBox licenseListbox; @UiField ListBox visibilityListbox; @UiField ListBox organizationsListbox; @UiField TextBox versionTextbox; @UiField TextBox authorTextbox; @UiField TextBox authorEmailTextbox; @UiField TextBox maintainerTextbox; @UiField TextBox maintainerEmailTextbox; @UiField ControlGroup customFields; @UiField Button addCustomFieldButton; @UiField CheckBox addResourcesCheckBox; @UiField ControlGroup resourcesControlGroup; @UiField Button createButton; @UiField Button addResourcesButton; @UiField Button resetButton; @UiField AlertBlock infoBlock; @UiField AlertBlock onCreateAlertBlock; @UiField VerticalPanel resourcesPanel; // tab panel private TabPanel tabPanel; // add resource form AddResourceToDataset resourceForm; // tags list private List tagsList = new ArrayList(); // the licenses private LicensesBean licenseBean; // event bus private final HandlerManager eventBus = new HandlerManager(null); // added custom field entries List customFieldEntriesList = new ArrayList(); // dataset metadata bean private DatasetMetadataBean receivedBean; // the owner private String owner; /** * Invoked in the most general case * @param owner */ public EditMetadataForm(String owner) { initWidget(uiBinder.createAndBindUi(this)); this.owner = owner; // bind on events bind(); // set info block setAlertBlock("Retrieving information, please wait...", AlertType.INFO, true); // disable create button createButton.setEnabled(false); resetButton.setEnabled(false); // get back the licenses and the metadata information ckanServices.getDatasetBean(null, owner, new AsyncCallback() { @Override public void onSuccess(DatasetMetadataBean bean) { if(bean != null){ // save it receivedBean = bean; // fill the form versionTextbox.setText(String.valueOf(bean.getVersion())); authorTextbox.setText(bean.getAuthor()); authorEmailTextbox.setText(bean.getAuthorEmail()); maintainerTextbox.setText(bean.getMaintainer()); maintainerEmailTextbox.setText(bean.getMaintainerEmail()); // set organizations List organizations = bean.getOrganizationList(); for (String organization : organizations) { organizationsListbox.addItem(organization); } // try to retrieve the licenses setAlertBlock("Retrieving licenses, please wait...", AlertType.INFO, true); ckanServices.getLicenses(new AsyncCallback() { @Override public void onSuccess(LicensesBean lBean) { if(lBean != null && !lBean.getLicenses().isEmpty()){ licenseBean = lBean; // fill the listbox for(String license: licenseBean.getLicenses()){ licenseListbox.addItem(license); } // everything went ok setAlertBlock("", AlertType.ERROR, false); createButton.setEnabled(true); resetButton.setEnabled(true); }else{ setAlertBlock("Error while retrieving licenses, try to refresh the page", AlertType.ERROR, true); } } @Override public void onFailure(Throwable caught) { setAlertBlock("Error while retrieving licenses, try to refresh the page", AlertType.ERROR, true); } }); }else{ setAlertBlock("Error while retrieving information, try to refresh the page", AlertType.ERROR, true); } } @Override public void onFailure(Throwable caught) { setAlertBlock("Error while retrieving information, try to refresh the page", AlertType.ERROR, true); } }); // hide the Add resources checkbox resourcesControlGroup.setVisible(false); } /** * Invoked when the workspace is used. * @param idFolderWorkspace * @param owner */ public EditMetadataForm(String idFolderWorkspace, String owner) { initWidget(uiBinder.createAndBindUi(this)); this.owner = owner; // bind on events bind(); // set info block setAlertBlock("Retrieving information, please wait...", AlertType.INFO, true); // disable create button createButton.setEnabled(false); resetButton.setEnabled(false); // get back the licenses and the metadata information from the workspace ckanServices.getDatasetBean(idFolderWorkspace, owner, new AsyncCallback() { @Override public void onSuccess(DatasetMetadataBean bean) { if(bean != null){ // save it receivedBean = bean; // fill the form titleTextBox.setText(bean.getTitle()); descriptionTextarea.setText(bean.getDescription()); versionTextbox.setText(String.valueOf(bean.getVersion())); authorTextbox.setText(bean.getAuthor()); authorEmailTextbox.setText(bean.getAuthorEmail()); maintainerTextbox.setText(bean.getMaintainer()); maintainerEmailTextbox.setText(bean.getMaintainerEmail()); // set organizations List organizations = bean.getOrganizationList(); for (String organization : organizations) { organizationsListbox.addItem(organization); } // retrieve custom fields Map customFieldsMap = bean.getCustomFields(); GWT.log("Custom fields is " + customFieldsMap); if(customFieldsMap != null){ // get the keys and put them as tags Iterator> iteratorOverCustomField = customFieldsMap.entrySet().iterator(); while (iteratorOverCustomField.hasNext()) { Map.Entry entry = (Map.Entry) iteratorOverCustomField .next(); // these are fixed key, variable value custom fields CustomFieldEntry toAdd = new CustomFieldEntry(eventBus, entry.getKey(), entry.getValue(), false); customFieldEntriesList.add(toAdd); customFields.add(toAdd); // add as tag addTagElement(entry.getKey()); } } // try to retrieve the licenses setAlertBlock("Retrieving licenses, please wait...", AlertType.INFO, true); ckanServices.getLicenses(new AsyncCallback() { @Override public void onSuccess(LicensesBean lBean) { if(lBean != null && !lBean.getLicenses().isEmpty()){ licenseBean = lBean; // fill the listbox for(String license: licenseBean.getLicenses()){ licenseListbox.addItem(license); } // everything went ok setAlertBlock("", AlertType.ERROR, false); createButton.setEnabled(true); resetButton.setEnabled(true); }else{ setAlertBlock("Error while retrieving licenses, try to refresh the page", AlertType.ERROR, true); } } @Override public void onFailure(Throwable caught) { setAlertBlock("Error while retrieving licenses, try to refresh the page", AlertType.ERROR, true); } }); }else{ setAlertBlock("Error while retrieving information, try to refresh the page", AlertType.ERROR, true); } } @Override public void onFailure(Throwable caught) { setAlertBlock("Error while retrieving information, try to refresh the page", AlertType.ERROR, true); } }); } /** * 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()); } }); } @UiHandler("addCustomFieldButton") void addCustomFieldEvent(ClickEvent e){ CustomFieldEntry toAdd = new CustomFieldEntry(eventBus, "", "", true); customFieldEntriesList.add(toAdd); customFields.add(toAdd); } @UiHandler("createButton") void createDatasetEvent(ClickEvent e){ // validate data TODO boolean areDataValid = validateData(); // Collect current data and send them to the server if(areDataValid){ String title = titleTextBox.getValue(); String description = descriptionTextarea.getText(); String selectedLicense = licenseListbox.getSelectedItemText(); String visibility = visibilityListbox.getSelectedItemText(); long version = Long.valueOf(versionTextbox.getValue()); String author = authorTextbox.getValue(); String authorEmail = authorEmailTextbox.getValue(); String maintainer = maintainerTextbox.getValue(); String maintainerEmail = maintainerEmailTextbox.getValue(); String chosenOrganization = organizationsListbox.getSelectedItemText(); boolean addResources = addResourcesCheckBox.getValue(); // fill the bean receivedBean.setAuthor(author); receivedBean.setAuthorEmail(authorEmail); receivedBean.setDescription(description); receivedBean.setLicense(selectedLicense); receivedBean.setMaintainer(maintainer); receivedBean.setMaintainerEmail(maintainerEmail); receivedBean.setVersion(version); receivedBean.setVisibility(visibility.equals("Public")); receivedBean.setTitle(title); receivedBean.setTags(tagsList); receivedBean.setSelectedOrganization(chosenOrganization); receivedBean.setAddResources(addResources); Map customFieldsMap = new HashMap(); // prepare custom fields for(CustomFieldEntry customEntry : customFieldEntriesList){ String key = customEntry.getKey(); String value = customEntry.getValue(); customFieldsMap.put(key, value); } receivedBean.setCustomFields(customFieldsMap); // invoke the create method createButton.setEnabled(false); resetButton.setEnabled(false); onCreateAlertBlock.setText("Trying to create dataset, please wait"); onCreateAlertBlock.setVisible(true); ckanServices.createCKanDataset(receivedBean, new AsyncCallback() { @Override public void onSuccess(final String datasetId) { if(datasetId != null){ alertOnCreate("Dataset correctly created!", AlertType.SUCCESS); // disable dataset fields disableDatasetFields(); // if we are in the "general case" we need to show a form for adding resources if(!resourcesControlGroup.isVisible()){ createButton.setVisible(false); resetButton.setVisible(false); // show the add resources button addResourcesButton.setVisible(true); addResourcesButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { // hide the button addResourcesButton.setVisible(false); // TabPanel tabPanel = new TabPanel(Tabs.ABOVE); tabPanel.setWidth("100%"); // add the form resourceForm = new AddResourceToDataset(eventBus, datasetId, owner); // tab for the form Tab formContainer = new Tab(); formContainer.add(resourceForm); formContainer.setHeading("Add New Resource"); tabPanel.add(formContainer); // tab for the added resources Tab addedResources = new Tab(); addedResources.add(new AddedResourcesSummary(eventBus)); addedResources.setHeading("Added Resource"); tabPanel.add(addedResources); // add tabs to resources panel tabPanel.selectTab(0); resourcesPanel.add(tabPanel); resourcesPanel.setVisible(true); } }); } }else{ alertOnCreate("Unable to create this dataset, please retry later", AlertType.ERROR); } } @Override public void onFailure(Throwable caught) { alertOnCreate("Unable to create this dataset, please retry later", AlertType.ERROR); } }); } } /** * On create show alert box and enable buttons * @param text * @param type */ private void alertOnCreate(String text, AlertType type){ onCreateAlertBlock.setText(text); onCreateAlertBlock.setType(type); onCreateAlertBlock.setVisible(true); createButton.setEnabled(true); resetButton.setEnabled(true); // hide after some seconds Timer t = new Timer() { @Override public void run() { onCreateAlertBlock.setVisible(false); } }; t.schedule(2000); } /** * Validate data * @return true on success */ private boolean validateData() { // TODO return true; } @UiHandler("resetButton") void resetFormEvent(ClickEvent e){ // reset main fields titleTextBox.setText(""); descriptionTextarea.setText(""); versionTextbox.setText(""); authorTextbox.setText(""); authorEmailTextbox.setText(""); maintainerTextbox.setText(""); maintainerEmailTextbox.setText(""); removeTags(); // delete custom fields for (CustomFieldEntry customField : customFieldEntriesList) { customField.removeFromParent(); } customFieldEntriesList.clear(); } /** * Disable dataset editable fields */ protected void disableDatasetFields() { titleTextBox.setEnabled(false); descriptionTextarea.setEnabled(false); versionTextbox.setEnabled(false); authorTextbox.setEnabled(false); authorEmailTextbox.setEnabled(false); maintainerTextbox.setEnabled(false); maintainerEmailTextbox.setEnabled(false); visibilityListbox.setEnabled(false); tagsEnterTextBox.setEnabled(false); licenseListbox.setEnabled(false); organizationsListbox.setEnabled(false); addCustomFieldButton.setEnabled(false); } /** * change alert block behavior. * @param textToShow * @param type * @param visible */ private void setAlertBlock(String textToShow, AlertType type, boolean visible){ infoBlock.setText(textToShow); infoBlock.setType(type); infoBlock.setVisible(visible); } @UiHandler("tagsEnterTextBox") void onAddTag(KeyDownEvent event){ if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { if (!"".equals(tagsEnterTextBox.getValue().trim())) { addTagElement(tagsEnterTextBox); } } } /** * Add the tag as an element */ private void addTagElement(TextBox itemBox){ if (itemBox.getValue() != null && !"".equals(itemBox.getValue().trim())) { if(tagsList.contains(itemBox.getValue())) return; final String value = itemBox.getValue(); final ListItem displayItem = new ListItem(); displayItem.setStyleName("tag-style"); Span p = new Span(itemBox.getValue()); Span span = new Span("x"); span.setTitle("Remove this tag"); span.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { removeListItem(displayItem, value); } }); span.setStyleName("tag-style-x"); displayItem.add(p); displayItem.add(span); itemBox.setValue(""); itemBox.setFocus(true); tagsPanel.add(displayItem); tagsList.add(value); } } /** * Add the tag as an element */ private void addTagElement(final String tag){ if(tagsList.contains(tag)) return; final ListItem displayItem = new ListItem(); displayItem.setStyleName("tag-style"); Span p = new Span(tag); Span span = new Span("x"); span.setTitle("Remove this tag"); span.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { removeListItem(displayItem, tag); } }); span.setStyleName("tag-style-x"); displayItem.add(p); displayItem.add(span); tagsPanel.add(displayItem); tagsList.add(tag); } /** * Remove a tag from the list * @param displayItem */ private void removeListItem(ListItem displayItem, String value) { GWT.log("Removing: " + displayItem.getWidget(0).getElement().getInnerHTML(), null); tagsList.remove(value); tagsPanel.remove(displayItem); } /** * Remove all inserted tags */ private void removeTags(){ tagsList.clear(); tagsPanel.clear(); } }