/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE file at the root of the source * tree and available online at * * https://github.com/keeps/roda */ package org.roda.wui.client.common.actions; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import org.roda.core.data.common.RodaConstants; import org.roda.core.data.exceptions.NotFoundException; import org.roda.core.data.exceptions.RequestNotValidException; import org.roda.core.data.v2.index.select.SelectedItems; import org.roda.core.data.v2.ip.IndexedFile; import org.roda.core.data.v2.ip.IndexedRepresentation; import org.roda.wui.client.browse.BrowserService; import org.roda.wui.client.browse.PreservationEvents; import org.roda.wui.client.common.LastSelectedItemsSingleton; import org.roda.wui.client.common.LoadingAsyncCallback; import org.roda.wui.client.common.dialogs.Dialogs; import org.roda.wui.client.common.search.SearchSuggestBox; import org.roda.wui.client.planning.Planning; import org.roda.wui.client.planning.RiskIncidenceRegister; import org.roda.wui.client.process.CreateSelectedJob; import org.roda.wui.common.client.tools.HistoryUtils; import org.roda.wui.common.client.tools.RestUtils; import org.roda.wui.common.client.widgets.Toast; import com.google.gwt.core.client.GWT; import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.safehtml.shared.SafeUri; 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.FlowPanel; import com.google.gwt.user.client.ui.Widget; import config.i18n.client.ClientMessages; public class RepresentationActions extends AbstractActionable<IndexedRepresentation> { private static final RepresentationActions GENERAL_INSTANCE = new RepresentationActions(null); private static final ClientMessages messages = GWT.create(ClientMessages.class); private static final Set<RepresentationAction> POSSIBLE_ACTIONS_ON_SINGLE_REPRESENTATION = new HashSet<>( Arrays.asList(RepresentationAction.values())); private static final Set<RepresentationAction> POSSIBLE_ACTIONS_ON_MULTIPLE_REPRESENTATIONS = new HashSet<>( Arrays.asList(RepresentationAction.CHANGE_TYPE, RepresentationAction.REMOVE, RepresentationAction.NEW_PROCESS, RepresentationAction.IDENTIFY_FORMATS)); private final String aipId; private RepresentationActions(String aipId) { this.aipId = aipId; } public enum RepresentationAction implements Actionable.Action<IndexedRepresentation> { DOWNLOAD, CHANGE_TYPE, REMOVE, NEW_PROCESS, IDENTIFY_FORMATS, SHOW_EVENTS, SHOW_RISKS, UPLOAD_FILES, CREATE_FOLDER; } public static RepresentationActions get() { return GENERAL_INSTANCE; } public static RepresentationActions get(String aipId) { return new RepresentationActions(aipId); } @Override public boolean canAct(Actionable.Action<IndexedRepresentation> action, IndexedRepresentation representation) { return POSSIBLE_ACTIONS_ON_SINGLE_REPRESENTATION.contains(action); } @Override public boolean canAct(Actionable.Action<IndexedRepresentation> action, SelectedItems<IndexedRepresentation> selectedItems) { return POSSIBLE_ACTIONS_ON_MULTIPLE_REPRESENTATIONS.contains(action); } @Override public void act(Actionable.Action<IndexedRepresentation> action, IndexedRepresentation representation, AsyncCallback<ActionImpact> callback) { if (RepresentationAction.DOWNLOAD.equals(action)) { download(representation, callback); } else if (RepresentationAction.CHANGE_TYPE.equals(action)) { changeType(representation, callback); } else if (RepresentationAction.REMOVE.equals(action)) { remove(representation, callback); } else if (RepresentationAction.NEW_PROCESS.equals(action)) { newProcess(representation, callback); } else if (RepresentationAction.IDENTIFY_FORMATS.equals(action)) { identifyFormats(representation, callback); } else if (RepresentationAction.SHOW_EVENTS.equals(action)) { showEvents(representation, callback); } else if (RepresentationAction.SHOW_RISKS.equals(action)) { showRisks(representation, callback); } else if (RepresentationAction.UPLOAD_FILES.equals(action)) { uploadFiles(representation, callback); } else if (RepresentationAction.CREATE_FOLDER.equals(action)) { createFolder(representation, callback); } else { callback.onFailure(new RequestNotValidException("Unsupported action in this context: " + action)); } } /** * Act on multiple files from different representations */ @Override public void act(Actionable.Action<IndexedRepresentation> action, SelectedItems<IndexedRepresentation> selectedItems, AsyncCallback<ActionImpact> callback) { if (RepresentationAction.REMOVE.equals(action)) { remove(selectedItems, callback); } else if (RepresentationAction.CHANGE_TYPE.equals(action)) { changeType(selectedItems, callback); } else if (RepresentationAction.NEW_PROCESS.equals(action)) { newProcess(selectedItems, callback); } else if (RepresentationAction.IDENTIFY_FORMATS.equals(action)) { identifyFormats(selectedItems, callback); } else { callback.onFailure(new RequestNotValidException("Unsupported action in this context: " + action)); } } // ACTIONS public void download(IndexedRepresentation representation, final AsyncCallback<ActionImpact> callback) { SafeUri downloadUri = null; if (representation != null) { downloadUri = RestUtils.createRepresentationDownloadUri(representation.getAipId(), representation.getId()); } if (downloadUri != null) { Window.Location.assign(downloadUri.asString()); } callback.onSuccess(ActionImpact.NONE); } public void remove(final IndexedRepresentation representation, final AsyncCallback<ActionImpact> callback) { remove(objectToSelectedItems(representation), callback); } public void remove(final SelectedItems<IndexedRepresentation> selectedList, final AsyncCallback<ActionImpact> callback) { Dialogs.showConfirmDialog(messages.representationRemoveTitle(), messages.representationRemoveMessage(), messages.dialogCancel(), messages.dialogYes(), new AsyncCallback<Boolean>() { @Override public void onSuccess(Boolean confirmed) { if (confirmed) { Dialogs.showPromptDialog(messages.outcomeDetailTitle(), null, null, messages.outcomeDetailPlaceholder(), RegExp.compile(".*"), messages.cancelButton(), messages.confirmButton(), false, new AsyncCallback<String>() { @Override public void onFailure(Throwable caught) { // do nothing } @Override public void onSuccess(String details) { BrowserService.Util.getInstance().deleteRepresentation(selectedList, details, new AsyncCallback<Void>() { @Override public void onSuccess(Void result) { Timer timer = new Timer() { @Override public void run() { if (aipId != null) { HistoryUtils.openBrowse(aipId); } callback.onSuccess(ActionImpact.DESTROYED); } }; timer.schedule(RodaConstants.ACTION_TIMEOUT); } @Override public void onFailure(Throwable caught) { callback.onFailure(caught); } }); } }); } } @Override public void onFailure(Throwable caught) { // nothing to do } }); } public void changeType(final IndexedRepresentation representations, final AsyncCallback<ActionImpact> callback) { changeType(objectToSelectedItems(representations), callback); } public void changeType(final SelectedItems<IndexedRepresentation> representations, final AsyncCallback<ActionImpact> callback) { SearchSuggestBox<IndexedRepresentation> suggestBox = new SearchSuggestBox<>(IndexedRepresentation.class, RodaConstants.REPRESENTATION_TYPE, true); Dialogs.showPromptDialogSuggest(messages.changeTypeTitle(), null, messages.changeTypePlaceHolder(), messages.cancelButton(), messages.confirmButton(), suggestBox, new AsyncCallback<String>() { @Override public void onFailure(Throwable caught) { // do nothing } @Override public void onSuccess(final String newType) { Dialogs.showPromptDialog(messages.outcomeDetailTitle(), null, null, messages.outcomeDetailPlaceholder(), RegExp.compile(".*"), messages.cancelButton(), messages.confirmButton(), false, new AsyncCallback<String>() { @Override public void onFailure(Throwable caught) { // do nothing } @Override public void onSuccess(String details) { BrowserService.Util.getInstance().changeRepresentationType(representations, newType, details, new LoadingAsyncCallback<Void>() { @Override public void onSuccessImpl(Void nothing) { Toast.showInfo(messages.dialogSuccess(), messages.changeTypeSuccessful()); callback.onSuccess(ActionImpact.UPDATED); } }); } }); } }); } public void newProcess(IndexedRepresentation representation, final AsyncCallback<ActionImpact> callback) { newProcess(objectToSelectedItems(representation), callback); } public void newProcess(SelectedItems<IndexedRepresentation> selected, final AsyncCallback<ActionImpact> callback) { LastSelectedItemsSingleton selectedItems = LastSelectedItemsSingleton.getInstance(); selectedItems.setSelectedItems(selected); selectedItems.setLastHistory(HistoryUtils.getCurrentHistoryPath()); HistoryUtils.newHistory(CreateSelectedJob.RESOLVER, RodaConstants.JOB_PROCESS_ACTION); callback.onSuccess(ActionImpact.UPDATED); } public void identifyFormats(IndexedRepresentation representation, final AsyncCallback<ActionImpact> callback) { identifyFormats(objectToSelectedItems(representation), callback); } public void identifyFormats(SelectedItems<IndexedRepresentation> selected, final AsyncCallback<ActionImpact> callback) { BrowserService.Util.getInstance().createFormatIdentificationJob(selected, new AsyncCallback<Void>() { @Override public void onSuccess(Void object) { Toast.showInfo(messages.identifyingFormatsTitle(), messages.identifyingFormatsDescription()); callback.onSuccess(ActionImpact.UPDATED); } @Override public void onFailure(Throwable caught) { if (caught instanceof NotFoundException) { Toast.showError(messages.moveNoSuchObject(caught.getMessage())); } else { callback.onFailure(caught); } } }); } public void showEvents(IndexedRepresentation representation, final AsyncCallback<ActionImpact> callback) { List<String> history = new ArrayList<>(); history.add(representation.getAipId()); history.add(representation.getUUID()); HistoryUtils.newHistory(PreservationEvents.BROWSE_RESOLVER, history); callback.onSuccess(ActionImpact.NONE); } public void showRisks(IndexedRepresentation representation, final AsyncCallback<ActionImpact> callback) { List<String> history = new ArrayList<>(); history.add(RiskIncidenceRegister.RESOLVER.getHistoryToken()); history.add(representation.getAipId()); history.add(representation.getId()); HistoryUtils.newHistory(Planning.RESOLVER, history); callback.onSuccess(ActionImpact.NONE); } public void createFolder(final IndexedRepresentation representation, final AsyncCallback<ActionImpact> callback) { Dialogs.showPromptDialog(messages.createFolderTitle(), null, null, messages.createFolderPlaceholder(), RegExp.compile("^[^/]+$"), messages.cancelButton(), messages.confirmButton(), true, new AsyncCallback<String>() { @Override public void onFailure(Throwable caught) { // do nothing } @Override public void onSuccess(final String newName) { Dialogs.showPromptDialog(messages.outcomeDetailTitle(), null, null, messages.outcomeDetailPlaceholder(), RegExp.compile(".*"), messages.cancelButton(), messages.confirmButton(), false, new AsyncCallback<String>() { @Override public void onFailure(Throwable caught) { // do nothing } @Override public void onSuccess(final String details) { BrowserService.Util.getInstance().createFolder(representation.getAipId(), representation.getId(), null, newName, details, new LoadingAsyncCallback<IndexedFile>() { @Override public void onSuccessImpl(IndexedFile newFolder) { HistoryUtils.openBrowse(newFolder); callback.onSuccess(ActionImpact.UPDATED); } @Override public void onFailureImpl(Throwable caught) { if (caught instanceof NotFoundException) { Toast.showError(messages.moveNoSuchObject(caught.getMessage())); } else { callback.onFailure(caught); } } }); } }); } }); } public void uploadFiles(final IndexedRepresentation representation, final AsyncCallback<ActionImpact> callback) { Dialogs.showPromptDialog(messages.outcomeDetailTitle(), null, null, messages.outcomeDetailPlaceholder(), RegExp.compile(".*"), messages.cancelButton(), messages.confirmButton(), false, new AsyncCallback<String>() { @Override public void onFailure(Throwable caught) { // do nothing } @Override public void onSuccess(String details) { LastSelectedItemsSingleton selectedItems = LastSelectedItemsSingleton.getInstance(); selectedItems.setDetailsMessage(details); HistoryUtils.openUpload(representation); callback.onSuccess(ActionImpact.UPDATED); } }); } @Override public Widget createActionsLayout(IndexedRepresentation representation, AsyncCallback<ActionImpact> callback) { FlowPanel layout = createLayout(); // MANAGEMENT addTitle(layout, messages.representation(), representation, RepresentationAction.DOWNLOAD, RepresentationAction.CHANGE_TYPE, RepresentationAction.REMOVE); addButton(layout, messages.downloadButton(), RepresentationAction.DOWNLOAD, representation, ActionImpact.NONE, callback, "btn-download"); addButton(layout, messages.changeTypeButton(), RepresentationAction.CHANGE_TYPE, representation, ActionImpact.UPDATED, callback, "btn-edit"); addButton(layout, messages.removeButton(), RepresentationAction.REMOVE, representation, ActionImpact.DESTROYED, callback, "btn-ban"); // PRESERVATION addTitle(layout, messages.preservationTitle(), representation, RepresentationAction.NEW_PROCESS, RepresentationAction.IDENTIFY_FORMATS, RepresentationAction.SHOW_EVENTS, RepresentationAction.SHOW_RISKS); addButton(layout, messages.newProcessPreservation(), RepresentationAction.NEW_PROCESS, representation, ActionImpact.UPDATED, callback, "btn-play"); addButton(layout, messages.identifyFormatsButton(), RepresentationAction.IDENTIFY_FORMATS, representation, ActionImpact.UPDATED, callback, "btn-play"); addButton(layout, messages.preservationEvents(), RepresentationAction.SHOW_EVENTS, representation, ActionImpact.NONE, callback, "btn-play"); addButton(layout, messages.preservationRisks(), RepresentationAction.SHOW_RISKS, representation, ActionImpact.NONE, callback, "btn-play"); // Files and folders addTitle(layout, messages.sidebarFoldersFilesTitle(), representation, RepresentationAction.UPLOAD_FILES, RepresentationAction.CREATE_FOLDER); // UPLOAD_FILES, CREATE_FOLDER addButton(layout, messages.uploadFilesButton(), RepresentationAction.UPLOAD_FILES, representation, ActionImpact.UPDATED, callback, "btn-upload"); addButton(layout, messages.createFolderButton(), RepresentationAction.CREATE_FOLDER, representation, ActionImpact.UPDATED, callback, "btn-plus"); return layout; } @Override public Widget createActionsLayout(SelectedItems<IndexedRepresentation> representations, AsyncCallback<ActionImpact> callback) { FlowPanel layout = createLayout(); // MANAGEMENT addTitle(layout, messages.representation(), representations, RepresentationAction.DOWNLOAD, RepresentationAction.CHANGE_TYPE, RepresentationAction.REMOVE); addButton(layout, messages.downloadButton(), RepresentationAction.DOWNLOAD, representations, ActionImpact.NONE, callback, "btn-download"); addButton(layout, messages.changeTypeButton(), RepresentationAction.CHANGE_TYPE, representations, ActionImpact.UPDATED, callback, "btn-edit"); addButton(layout, messages.removeButton(), RepresentationAction.REMOVE, representations, ActionImpact.DESTROYED, callback, "btn-ban"); // PRESERVATION addTitle(layout, messages.preservationTitle(), representations, RepresentationAction.NEW_PROCESS, RepresentationAction.IDENTIFY_FORMATS, RepresentationAction.SHOW_EVENTS, RepresentationAction.SHOW_RISKS); addButton(layout, messages.newProcessPreservation(), RepresentationAction.NEW_PROCESS, representations, ActionImpact.UPDATED, callback, "btn-play"); addButton(layout, messages.identifyFormatsButton(), RepresentationAction.IDENTIFY_FORMATS, representations, ActionImpact.UPDATED, callback, "btn-play"); addButton(layout, messages.preservationEvents(), RepresentationAction.SHOW_EVENTS, representations, ActionImpact.NONE, callback, "btn-play"); addButton(layout, messages.preservationRisks(), RepresentationAction.SHOW_RISKS, representations, ActionImpact.NONE, callback, "btn-play"); // Files and folders addTitle(layout, messages.sidebarFoldersFilesTitle(), representations, RepresentationAction.UPLOAD_FILES, RepresentationAction.CREATE_FOLDER); // UPLOAD_FILES, CREATE_FOLDER addButton(layout, messages.uploadFilesButton(), RepresentationAction.UPLOAD_FILES, representations, ActionImpact.UPDATED, callback, "btn-upload"); addButton(layout, messages.createFolderButton(), RepresentationAction.CREATE_FOLDER, representations, ActionImpact.UPDATED, callback, "btn-plus"); return layout; } }