/* * Copyright (C) 2012 Jan Pokorsky * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package cz.cas.lib.proarc.webapp.client.presenter; import com.google.gwt.event.shared.HandlerRegistration; import com.smartgwt.client.data.Criteria; import com.smartgwt.client.data.DSCallback; import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.DSResponse; import com.smartgwt.client.data.Record; import com.smartgwt.client.types.Overflow; import com.smartgwt.client.util.BooleanCallback; import com.smartgwt.client.util.SC; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.events.SubmitValuesHandler; import com.smartgwt.client.widgets.layout.VLayout; import cz.cas.lib.proarc.common.mods.custom.ModsConstants; import cz.cas.lib.proarc.common.mods.custom.ModsCutomEditorType; import cz.cas.lib.proarc.oaidublincore.DcConstants; import cz.cas.lib.proarc.webapp.client.ClientMessages; import cz.cas.lib.proarc.webapp.client.ClientUtils; import cz.cas.lib.proarc.webapp.client.action.RefreshAction.Refreshable; import cz.cas.lib.proarc.webapp.client.action.SaveAction; import cz.cas.lib.proarc.webapp.client.action.SaveAction.Savable; import cz.cas.lib.proarc.webapp.client.action.SaveAction.SaveValidation; import cz.cas.lib.proarc.webapp.client.ds.DigitalObjectDataSource.DigitalObject; import cz.cas.lib.proarc.webapp.client.ds.MetaModelDataSource; import cz.cas.lib.proarc.webapp.client.ds.MetaModelDataSource.MetaModelRecord; import cz.cas.lib.proarc.webapp.client.ds.ModsCustomDataSource; import cz.cas.lib.proarc.webapp.client.ds.ModsCustomDataSource.DescriptionMetadata; import cz.cas.lib.proarc.webapp.client.ds.ModsCustomDataSource.DescriptionSaveHandler; import cz.cas.lib.proarc.webapp.client.ds.RestConfig; import cz.cas.lib.proarc.webapp.client.event.EditorLoadEvent; import cz.cas.lib.proarc.webapp.client.widget.AbstractDatastreamEditor; import cz.cas.lib.proarc.webapp.client.widget.dc.DcEditor; import cz.cas.lib.proarc.webapp.client.widget.mods.bdm.BornDigitalForms; import cz.cas.lib.proarc.webapp.client.widget.mods.MonographForm; import cz.cas.lib.proarc.webapp.client.widget.mods.MonographUnitForm; import cz.cas.lib.proarc.webapp.client.widget.mods.NdkForms; import cz.cas.lib.proarc.webapp.client.widget.mods.PageForm; import cz.cas.lib.proarc.webapp.client.widget.mods.PeriodicalForm; import cz.cas.lib.proarc.webapp.client.widget.mods.PeriodicalIssueForm; import cz.cas.lib.proarc.webapp.client.widget.mods.PeriodicalVolumeForm; import cz.cas.lib.proarc.webapp.client.widget.mods.oldprint.OldPrintForms; import cz.cas.lib.proarc.webapp.client.widget.nsesss.NsesssV2Form; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; /** * Edits subset of MODS data. It shows different form for each dig. object model. * * @author Jan Pokorsky */ // XXX rename to DescriptionFormEditor public final class ModsCustomEditor extends AbstractDatastreamEditor implements Refreshable { private static final Logger LOG = Logger.getLogger(ModsCustomEditor.class.getName()); private final ClientMessages i18n; private final HashMap<String, DynamicForm> editorCache; private DynamicForm activeEditor; private final Canvas warning = new Canvas(); private DescriptionMetadata metadata; private final VLayout widget; private Boolean showFetchPrompt; private DigitalObject digitalObject; private String formPrefix = ""; public ModsCustomEditor(ClientMessages i18n) { this.i18n = i18n; this.editorCache = new HashMap<String, DynamicForm>(); this.widget = new VLayout(); this.widget.setOverflow(Overflow.AUTO); String wmsg = ClientUtils.format("<div class='proarcMetadataFormWarning'>%s</div>", i18n.DigitalObjectEditor_DescriptionFormEditor_FormSaveWarning_Msg()); warning.setContents(wmsg); warning.setAutoHeight(); } /** * @see #edit(DigitalObject, BooleanCallback) */ @Override public void edit(DigitalObject digitalObject) { edit(digitalObject, ClientUtils.EMPTY_BOOLEAN_CALLBACK); } /** * Loads a digital object into the given MODS custom form according to object's model. * * @param digitalObject digital object * @param loadCallback listens to load status */ public void edit(DigitalObject digitalObject, BooleanCallback loadCallback) { this.digitalObject = digitalObject; metadata = null; activeEditor = getCustomForm(digitalObject.getModel()); if (activeEditor != null) { ClientUtils.setMembers(widget, warning, activeEditor); loadCustom(activeEditor, digitalObject, loadCallback); } else { widget.setMembers(); } } @Override public void focus() { if (activeEditor != null) { activeEditor.focus(); } } /** * Validates loaded digital object. * @return values are valid */ public boolean isValidDigitalObject() { return activeEditor.valuesAreValid(false); } /** * Overrides {@link DSRequest#setShowPrompt(java.lang.Boolean)} * for the fetch operation. * <p>Disable prompt in case of a batch processing. Otherwise it blocks * the browser event queue and {@link cz.cas.lib.proarc.webapp.client.widget.ProgressTracker} * widgets might not respond. */ public void setShowFetchPrompt(Boolean showFetchPrompt) { this.showFetchPrompt = showFetchPrompt; } /** * @see #setShowFetchPrompt(java.lang.Boolean) */ public Boolean isShowFetchPrompt() { return showFetchPrompt != null ? showFetchPrompt : new DSRequest().getShowPrompt(); } @Override public void refresh() { loadCustom(activeEditor, digitalObject, ClientUtils.EMPTY_BOOLEAN_CALLBACK); } public void save(final BooleanCallback callback) { save(callback, false, SaveValidation.ASK); } /** * Stores editor content. * * @param callback notifies whether the save was successful * @param ask ask user before the save * @param strategy validation strategy * @see SaveAction#saveTask */ public void save(final BooleanCallback callback, boolean ask, SaveValidation strategy) { if (metadata == null) { callback.execute(Boolean.TRUE); return ; } SaveAction.saveTask(new Savable() { @Override public void save(BooleanCallback result) { saveImpl(result); } @Override public void validate(BooleanCallback result) { Boolean valid = activeEditor.validate(); result.execute(valid); } }, callback, ask, strategy, i18n); } private void saveImpl(final BooleanCallback callback) { // do not use customForm.getValuesAsRecord() Record r = new Record(activeEditor.getValues()); if (LOG.isLoggable(Level.FINE)) { ClientUtils.fine(LOG, "saveCustomData: %s", ClientUtils.dump(r.getJsObj())); } r = ClientUtils.normalizeData(r); metadata.setDescription(r); if (LOG.isLoggable(Level.FINE)) { ClientUtils.fine(LOG, "saveCustomRecord: %s", ClientUtils.dump(metadata.getWrapper().getJsObj())); } DescriptionSaveHandler dsh = new DescriptionSaveHandler() { @Override protected void onSave(DescriptionMetadata dm) { super.onSave(dm); if (dm != null) { metadata = dm; Record customModsRecord = dm.getDescription(); if (customModsRecord != null) { // refresh editor with server values activeEditor.editRecord(customModsRecord); } } callback.execute(true); activeEditor.focus(); } @Override protected void onConcurrencyError() { SC.ask(i18n.SaveAction_ConcurrentErrorAskReload_Msg(), new BooleanCallback() { @Override public void execute(Boolean value) { callback.execute(false); activeEditor.focus(); if (value != null && value) { refresh(); } } }); } @Override protected void onError() { super.onError(); callback.execute(false); } }; ModsCustomDataSource.getInstance().saveDescription(metadata, dsh, true); } @Override @SuppressWarnings("unchecked") public <T> T getCapability(Class<T> clazz) { T c = null; if (Refreshable.class.equals(clazz)) { c = (T) this; } return c; } @Override public Canvas[] getToolbarItems() { return new Canvas[0]; } @Override public Canvas getUI() { return widget; } @Override public HandlerRegistration addSubmitValuesHandler(SubmitValuesHandler handler) { return activeEditor.addSubmitValuesHandler(handler); } /** * Gets active custom form. * @return editor or {@code null} if unsupported */ public DynamicForm getCustomForm() { return activeEditor; } public String getFormPrefix() { return formPrefix; } /** * Sets prefix to address other than the prime form in * {@link #getCustomForm(MetaModelDataSource.MetaModelRecord)}. */ public void setFormPrefix(String formPrefix) { this.formPrefix = formPrefix; } private DynamicForm getCustomForm(MetaModelRecord model) { final String editorId = getFormPrefix() + model.getEditorId(); DynamicForm editor = editorCache.get(editorId); if (editor == null) { editor = createCustomForm(model); editorCache.put(editorId, editor); } return editor; } private DynamicForm createCustomForm(MetaModelRecord model) { String metadataFormat = model.getMetadataFormat(); DynamicForm form = null; if (ModsConstants.NS.equals(metadataFormat)) { form = new NdkForms(i18n).getForm(model); if (form == null) { form = new BornDigitalForms(i18n).getForm(model, getFormPrefix()); } if (form == null) { form = new OldPrintForms(i18n).getForm(model); } if (form == null) { // obsolete K4 forms as a fallback form = createModsForm(model.getEditorId()); } } else if (DcConstants.NS_OAIDC.equals(metadataFormat)) { form = new DcEditor(i18n, model).getForm(); } else if ("http://www.mvcr.cz/nsesss/v2".equals(metadataFormat)) { form = new NsesssV2Form(i18n, model).getForm(); } if (form == null) { ClientUtils.warning(LOG, "Uknown model editor: %s, editor: %s, format: %s", model.getId(), model.getEditorId(), metadataFormat); } return form; } private DynamicForm createModsForm(String editorId) { DynamicForm form = null; if (ModsCutomEditorType.EDITOR_PAGE.equals(editorId)) { form = new PageForm(i18n); } else if (ModsCutomEditorType.EDITOR_PERIODICAL.equals(editorId)) { form = new PeriodicalForm(i18n); } else if (ModsCutomEditorType.EDITOR_MONOGRAPH.equals(editorId)) { form = new MonographForm(i18n); } else if (ModsCutomEditorType.EDITOR_PERIODICAL_VOLUME.equals(editorId)) { form = new PeriodicalVolumeForm(i18n); } else if (ModsCutomEditorType.EDITOR_PERIODICAL_ISSUE.equals(editorId)) { form = new PeriodicalIssueForm(i18n); } else if (ModsCutomEditorType.EDITOR_MONOGRAPH_UNIT.equals(editorId)) { form = new MonographUnitForm(i18n); } return form; } private void loadCustom(final DynamicForm editor, DigitalObject dobj, final BooleanCallback loadCallback) { loadCustom(editor, dobj.getPid(), dobj.getBatchId(), dobj.getModel(), loadCallback); } private void loadCustom(final DynamicForm editor, String pid, String batchId, MetaModelRecord model, final BooleanCallback loadCallback) { metadata = null; Criteria pidCriteria = new Criteria(ModsCustomDataSource.FIELD_PID, pid); Criteria criteria = new Criteria(MetaModelDataSource.FIELD_EDITOR, model.getEditorId()); criteria.addCriteria(pidCriteria); if (batchId != null) { criteria.addCriteria(ModsCustomDataSource.FIELD_BATCHID, batchId); } ClientUtils.fine(LOG, "loadCustom pid: %s, batchId: %s, editor: %s", pid, batchId, model.getEditorId()); DSRequest request = new DSRequest(); if (showFetchPrompt != null) { request.setShowPrompt(showFetchPrompt); } ModsCustomDataSource.getInstance().fetchData(criteria, new DSCallback() { @Override public void execute(DSResponse response, Object rawData, DSRequest request) { handleFetch(response, editor, loadCallback); } }, request); } private void handleFetch(DSResponse response, DynamicForm editor, BooleanCallback loadCallback) { if (RestConfig.isStatusOk(response)) { Record[] data = response.getData(); if (LOG.isLoggable(Level.FINE)) { ClientUtils.fine(LOG, "fetch custom data: %s", ClientUtils.dump(data)); } if (data != null && data.length == 1) { Record customRecord = data[0]; DescriptionMetadata dm = new DescriptionMetadata(customRecord); Record customModsRecord = dm.getDescription(); if (customModsRecord != null) { metadata = dm; editor.editRecord(customModsRecord); editor.clearErrors(true); loadCallback.execute(Boolean.TRUE); fireEvent(new EditorLoadEvent(false)); return ; } } else { String msg = data != null && data.length > 1 ? "Unexpected data in server response!" : "No data in server response!"; SC.warn(msg); } } widget.setMembers(); loadCallback.execute(Boolean.FALSE); fireEvent(new EditorLoadEvent(true)); } }