/* * 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.widget; import com.smartgwt.client.data.Criteria; import com.smartgwt.client.data.ResultSet; import com.smartgwt.client.data.SortSpecifier; import com.smartgwt.client.types.Alignment; import com.smartgwt.client.types.SortDirection; import com.smartgwt.client.util.BooleanCallback; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.form.ColorPicker; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.events.ColorSelectedEvent; import com.smartgwt.client.widgets.form.events.ColorSelectedHandler; import com.smartgwt.client.widgets.form.fields.SelectItem; import com.smartgwt.client.widgets.form.fields.events.ChangedEvent; import com.smartgwt.client.widgets.form.fields.events.ChangedHandler; import com.smartgwt.client.widgets.form.fields.events.DataArrivedEvent; import com.smartgwt.client.widgets.form.fields.events.DataArrivedHandler; import com.smartgwt.client.widgets.grid.ListGridRecord; import cz.cas.lib.proarc.webapp.client.ClientMessages; import cz.cas.lib.proarc.webapp.client.ClientUtils; import cz.cas.lib.proarc.webapp.client.action.AbstractAction; import cz.cas.lib.proarc.webapp.client.action.Action; import cz.cas.lib.proarc.webapp.client.action.ActionEvent; import cz.cas.lib.proarc.webapp.client.action.Actions; import cz.cas.lib.proarc.webapp.client.action.Actions.ActionSource; import cz.cas.lib.proarc.webapp.client.action.RefreshAction; import cz.cas.lib.proarc.webapp.client.action.RefreshAction.Refreshable; import cz.cas.lib.proarc.webapp.client.ds.DigitalObjectDataSource.DigitalObject; import cz.cas.lib.proarc.webapp.client.ds.MetaModelDataSource.MetaModelRecord; import cz.cas.lib.proarc.webapp.client.ds.RelationDataSource; import cz.cas.lib.proarc.webapp.client.ds.RestConfig; import cz.cas.lib.proarc.webapp.client.ds.StreamProfileDataSource; import cz.cas.lib.proarc.webapp.client.ds.StreamProfileDataSource.StreamProfile; import cz.cas.lib.proarc.webapp.shared.rest.DigitalObjectResourceApi; import java.util.ArrayList; /** * Edits data streams containing digitized multimedia content. * * @author Jan Pokorsky */ public final class MediaEditor implements DatastreamEditor, Refreshable { private static String REFRESH; private final ClientMessages i18n; private final DigitalObjectPreview doPreview; private String imgParams; private final ArrayList<Canvas> backgroundListeners = new ArrayList<Canvas>(); private Action fullAction; private AbstractAction backgroundAction; private AbstractAction uploadAction; private DigitalObject digitalObject; private SelectItem streamMenu; private boolean showRefreshButton; private final ActionSource actionSource; public MediaEditor(ClientMessages i18n) { this.i18n = i18n; this.actionSource = new ActionSource(this); doPreview = new DigitalObjectPreview(i18n); initActions(i18n); } @Override public void edit(DigitalObject digitalObject) { if (digitalObject == null) { throw new NullPointerException(); } if (this.digitalObject != null && this.digitalObject.getPid().equals(digitalObject.getPid())) { return ; } this.digitalObject = digitalObject; updateStreamMenu(digitalObject); actionSource.fireEvent(); } @Override public void focus() { // no-op } @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() { Canvas zoomer = doPreview.getPreviewZoomer(); zoomer.setWidth(100); ArrayList<Canvas> toolbar = new ArrayList<Canvas>(); if (showRefreshButton) { RefreshAction refreshAction = new RefreshAction(i18n); refreshAction.setTitle(null); toolbar.add(Actions.asIconButton(refreshAction, this)); } toolbar.add(Actions.asIconButton(fullAction, this)); toolbar.add(Actions.asIconButton(uploadAction, actionSource)); toolbar.add(Actions.asIconButton(backgroundAction, this)); toolbar.add(zoomer); toolbar.add(createStreamMenu()); return toolbar.toArray(new Canvas[toolbar.size()]); } @Override public Canvas getUI() { return doPreview.asCanvas(); } @Override public void refresh() { DigitalObject refresh = this.digitalObject; this.digitalObject = null; REFRESH = String.valueOf(System.currentTimeMillis()); edit(refresh); } public void addBackgroundColorListeners(Canvas c) { backgroundListeners.add(c); } public void setBackgroundColor(String color) { doPreview.setBackgroundColor(color); for (Canvas canvas : backgroundListeners) { canvas.setBackgroundColor(color); } } public boolean isShowRefreshButton() { return showRefreshButton; } public void setShowRefreshButton(boolean showRefreshButton) { this.showRefreshButton = showRefreshButton; } private void initActions(final ClientMessages i18n) { fullAction = new AbstractAction( i18n.DigitalObjectPreview_ViewFullAction_Title(), "[SKIN]/actions/view.png", i18n.DigitalObjectPreview_ViewFullAction_Hint()) { @Override public void performAction(ActionEvent event) { doPreview.showInWindow(getObjectTitle()); } }; backgroundAction = new AbstractAction( i18n.DigitalObjectPreview_ColorChooserAction_Title(), "[SKIN]/actions/color_swatch.png", i18n.DigitalObjectPreview_ColorChooserAction_Hint()) { @Override public void performAction(ActionEvent event) { ColorPicker picker = new ColorPicker(); picker.addColorSelectedHandler(new ColorSelectedHandler() { @Override public void onColorSelected(ColorSelectedEvent event) { setBackgroundColor(event.getColor()); } }); picker.setDefaultColor(DigitalObjectPreview.BACKGROUND_COLOR); picker.setKeepInParentRect(true); picker.show(); } }; uploadAction = new AbstractAction( i18n.DigitalObjectEditor_MediaEditor_UploaderAction_Title(), "[SKIN]/MultiUploadItem/icon_add_files.png", i18n.DigitalObjectEditor_MediaEditor_UploaderAction_Hint()) { @Override public boolean accept(ActionEvent event) { String modelId = digitalObject.getModelId(); return modelId != null && (modelId.startsWith("model:bdm") || "model:derFile".equals(modelId) || "model:desFile".equals(modelId) ); } @Override public void performAction(ActionEvent event) { UploadFile uploadFile = new UploadFile(i18n); uploadFile.showWindow(digitalObject, new BooleanCallback() { @Override public void execute(Boolean value) { if (value != null && value) { RelationDataSource.getInstance().fireRelationChange(digitalObject.getPid()); refresh(); } } }); } }; } private DynamicForm createStreamMenu() { streamMenu = new SelectItem(); streamMenu.setShowTitle(Boolean.FALSE); streamMenu.setWidth(100); streamMenu.setPickListWidth(150); streamMenu.addChangedHandler(new ChangedHandler() { @Override public void onChanged(ChangedEvent event) { showStream(); } }); streamMenu.setAutoFetchData(Boolean.FALSE); streamMenu.setOptionDataSource(StreamProfileDataSource.getInstance()); SortSpecifier sort = new SortSpecifier(StreamProfileDataSource.FIELD_ORDER, SortDirection.ASCENDING); streamMenu.setPickListSort(new SortSpecifier[] {sort}); streamMenu.setDisplayField(StreamProfileDataSource.FIELD_LABEL); streamMenu.setValueField(StreamProfileDataSource.FIELD_ID); streamMenu.addDataArrivedHandler(new DataArrivedHandler() { @Override public void onDataArrived(DataArrivedEvent event) { updateStreamMenu(event.getData(), streamMenu); } }); DynamicForm form = new DynamicForm(); form.setFields(streamMenu); form.setLayoutAlign(Alignment.CENTER); return form; } private void updateStreamMenu(DigitalObject dobj) { Criteria streamMenuFilter = dobj.toCriteria(); streamMenu.setPickListCriteria(streamMenuFilter); streamMenu.fetchData(); } private void updateStreamMenu(ResultSet data, SelectItem view) { ListGridRecord lastViewSelection = view.getSelectedRecord(); Boolean contains = lastViewSelection == null ? false : data.contains(lastViewSelection); if (!contains) { String dsId = data.isEmpty() ? null : data.get(0).getAttribute(StreamProfileDataSource.FIELD_ID); view.setValue(dsId); } showStream(); } private void showStream() { StreamProfile stream = StreamProfile.get(streamMenu.getSelectedRecord()); if (stream != null) { StringBuilder sb = new StringBuilder(); sb.append(DigitalObjectResourceApi.DIGITALOBJECT_PID).append('=') .append(digitalObject.getPid()) .append('&').append(DigitalObjectResourceApi.DISSEMINATION_DATASTREAM) .append('=').append(stream.getId()); String batchId = digitalObject.getBatchId(); if (batchId != null) { sb.append('&').append(DigitalObjectResourceApi.BATCHID_PARAM).append('=').append(batchId); } if (REFRESH != null) { sb.append('&').append(REFRESH); } imgParams = sb.toString(); String previewUrl = buildResourceUrl(RestConfig.URL_DIGOBJECT_DISSEMINATION, imgParams); doPreview.show(previewUrl, stream.getMime()); } else { doPreview.show(null); } } private String getObjectTitle() { String label = digitalObject.getRecord().getAttribute(DigitalObjectResourceApi.MEMBERS_ITEM_LABEL); MetaModelRecord model = digitalObject.getModel(); String modelName = null; if (model != null) { modelName = model.getDisplayName(); } StringBuilder sb = new StringBuilder(); sb.append(i18n.DigitalObjectPreview_Window_Title()); if (modelName != null) { sb.append(" - ").append(modelName); } if (label != null) { sb.append(": ").append(label); } return sb.toString(); } /** * * @param datastreamUrl data stream URL * @param objectParams PID and batch ID as URL parameters * @return URL */ private static String buildResourceUrl(String datastreamUrl, String objectParams) { String url = ClientUtils.format("%s?%s", datastreamUrl, objectParams); return url; } }