/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.core.commons.modules.bc; import static java.util.Arrays.asList; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.controllers.linkchooser.FileLinkChooserController; import org.olat.core.commons.controllers.linkchooser.LinkChooserController; import org.olat.core.commons.controllers.linkchooser.URLChoosenEvent; import org.olat.core.commons.modules.bc.commands.FolderCommand; import org.olat.core.commons.modules.bc.commands.FolderCommandStatus; import org.olat.core.commons.modules.bc.components.FolderComponent; import org.olat.core.commons.modules.bc.meta.MetaInfo; import org.olat.core.commons.modules.bc.meta.MetaInfoFactory; import org.olat.core.commons.modules.bc.version.RevisionListController; import org.olat.core.commons.modules.bc.version.VersionCommentController; import org.olat.core.commons.modules.bc.vfs.OlatRootFileImpl; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.modal.ButtonClickedEvent; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Roles; import org.olat.core.logging.activity.CoreLoggingResourceable; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.FileUtils; import org.olat.core.util.Util; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.vfs.VFSLockManager; import org.olat.core.util.vfs.VFSManager; import org.olat.core.util.vfs.version.Versionable; import org.olat.core.util.vfs.version.Versions; /** * * Description:<br> * TODO: srosse Class Description for FileCopyController * * <P> * Initial Date: 18 mars 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public class FileCopyController extends LinkChooserController { private final FolderComponent folderComponent; private DialogBoxController lockedFileDialog; private DialogBoxController overwriteDialog; private RevisionListController revisionListCtr; private CloseableModalController revisionListDialogBox; private VersionCommentController commentVersionCtr; private CloseableModalController commentVersionDialogBox; private VersionCommentController unlockCtr; private CloseableModalController unlockDialogBox; private VFSLeaf newFile; private VFSLeaf sourceLeaf; private VFSLeaf existingVFSItem; private String renamedFilename; private final VFSLockManager vfsLockManager; public FileCopyController(UserRequest ureq, WindowControl wControl, VFSContainer rootDir, FolderComponent folderComponent) { super(ureq, wControl, rootDir, null, null, null, false, "", null, true); this.folderComponent = folderComponent; vfsLockManager = CoreSpringFactory.getImpl(VFSLockManager.class); } @Override //this is a hack to overwrite the package used by the BasicController protected VelocityContainer createVelocityContainer(String page) { Translator fallbackTranslator = Util.createPackageTranslator(FileCopyController.class, getLocale()); setTranslator(Util.createPackageTranslator(LinkChooserController.class, getLocale(), fallbackTranslator)); velocity_root = Util.getPackageVelocityRoot(LinkChooserController.class); return super.createVelocityContainer(page); } @Override public void event(UserRequest ureq, Controller source, Event event) { if(source instanceof FileLinkChooserController) { if (event == Event.DONE_EVENT || event == Event.CANCELLED_EVENT){ fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED); } else if (event instanceof URLChoosenEvent) { URLChoosenEvent choosenEvent = (URLChoosenEvent)event; String url = choosenEvent.getURL(); if(url.indexOf("://") < 0) { VFSContainer cContainer = folderComponent.getExternContainerForCopy(); VFSItem item = cContainer.resolve(url); if(item instanceof VFSLeaf) { sourceLeaf = (VFSLeaf)item; String filename = sourceLeaf.getName(); VFSContainer tContainer = folderComponent.getCurrentContainer(); newFile = tContainer.createChildLeaf(filename); if(newFile == null) { existingVFSItem = (VFSLeaf)tContainer.resolve(filename); fileAlreadyExists(ureq); } else { finishUpload(ureq); } } else { fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED); } } else { fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED); } } } else if (source == overwriteDialog) { if (event instanceof ButtonClickedEvent) { ButtonClickedEvent buttonClickedEvent = (ButtonClickedEvent) event; if (buttonClickedEvent.getPosition() == 0) { //ok if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) { //new version String relPath = null; if(existingVFSItem instanceof OlatRootFileImpl) { relPath = ((OlatRootFileImpl)existingVFSItem).getRelPath(); } int maxNumOfRevisions = FolderConfig.versionsAllowed(relPath); if(maxNumOfRevisions == 0) { //someone play with the configuration // Overwrite... String fileName = existingVFSItem.getName(); existingVFSItem.delete(); newFile = folderComponent.getCurrentContainer().createChildLeaf(fileName); // ... and notify listeners. finishUpload(ureq); } else { removeAsListenerAndDispose(commentVersionCtr); boolean locked = vfsLockManager.isLocked(existingVFSItem); commentVersionCtr = new VersionCommentController(ureq,getWindowControl(), locked, true); listenTo(commentVersionCtr); removeAsListenerAndDispose(commentVersionDialogBox); commentVersionDialogBox = new CloseableModalController(getWindowControl(), translate("save"), commentVersionCtr.getInitialComponent()); listenTo(commentVersionDialogBox); commentVersionDialogBox.activate(); } } else { //if the file is locked, ask for unlocking it if(vfsLockManager.isLocked(existingVFSItem)) { removeAsListenerAndDispose(unlockCtr); unlockCtr = new VersionCommentController(ureq,getWindowControl(), true, false); listenTo(unlockCtr); removeAsListenerAndDispose(unlockDialogBox); unlockDialogBox = new CloseableModalController(getWindowControl(), translate("ok"), unlockCtr.getInitialComponent()); listenTo(unlockDialogBox); unlockDialogBox.activate(); } else { // Overwrite... String fileName = existingVFSItem.getName(); existingVFSItem.delete(); newFile = folderComponent.getCurrentContainer().createChildLeaf(fileName); // ... and notify listeners. finishUpload(ureq); } } } else if (buttonClickedEvent.getPosition() == 1) { //not ok //make newFile with the proposition of filename newFile = folderComponent.getCurrentContainer().createChildLeaf(renamedFilename); // ... and notify listeners. finishUpload(ureq); } else if (buttonClickedEvent.getPosition() == 2) { // cancel //cancel -> do nothing } else { throw new RuntimeException("Unknown button number " + buttonClickedEvent.getPosition()); } } } else if (source == lockedFileDialog) { if (event instanceof ButtonClickedEvent) { ButtonClickedEvent buttonClickedEvent = (ButtonClickedEvent) event; switch(buttonClickedEvent.getPosition()) { case 0: { // ... and notify listeners. newFile = existingVFSItem; finishUpload(ureq); break; } case 1: {//cancel fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED); break; } default: throw new RuntimeException("Unknown button number " + buttonClickedEvent.getPosition()); } } } else if (source == commentVersionCtr) { String comment = commentVersionCtr.getComment(); Roles roles = ureq.getUserSession().getRoles(); boolean locked = vfsLockManager.isLocked(existingVFSItem); if(locked && !commentVersionCtr.keepLocked()) { vfsLockManager.unlock(existingVFSItem, getIdentity(), roles); } commentVersionDialogBox.deactivate(); if(revisionListDialogBox != null) { revisionListDialogBox.deactivate(); } //ok, new version of the file Versionable existingVersionableItem = (Versionable)existingVFSItem; boolean ok = existingVersionableItem.getVersions().addVersion(ureq.getIdentity(), comment, sourceLeaf.getInputStream()); if(ok) { newFile = existingVFSItem; } finishSuccessfullUpload(existingVFSItem.getName(), ureq); } else if (source == unlockCtr) { // Overwrite... if(!unlockCtr.keepLocked()) { vfsLockManager.unlock(existingVFSItem, getIdentity(), ureq.getUserSession().getRoles()); } unlockDialogBox.deactivate(); newFile = existingVFSItem; // ... and notify listeners. finishSuccessfullUpload(existingVFSItem.getName(), ureq); } else if (source == revisionListCtr) { if(FolderCommandStatus.STATUS_CANCELED == revisionListCtr.getStatus()) { revisionListDialogBox.deactivate(); //don't want to delete revisions fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED); } else { if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) { revisionListDialogBox.deactivate(); Versionable versionable = (Versionable)existingVFSItem; Versions versions = versionable.getVersions(); int maxNumOfRevisions = FolderConfig.versionsAllowed(null); if(maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) { removeAsListenerAndDispose(commentVersionCtr); boolean locked = vfsLockManager.isLocked(existingVFSItem); commentVersionCtr = new VersionCommentController(ureq,getWindowControl(), locked, true); listenTo(commentVersionCtr); removeAsListenerAndDispose(commentVersionDialogBox); commentVersionDialogBox = new CloseableModalController(getWindowControl(), translate("save"), commentVersionCtr.getInitialComponent()); listenTo(commentVersionDialogBox); commentVersionDialogBox.activate(); } else { removeAsListenerAndDispose(revisionListCtr); revisionListCtr = new RevisionListController(ureq,getWindowControl(),versionable, false); listenTo(revisionListCtr); removeAsListenerAndDispose(revisionListDialogBox); revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent()); listenTo(revisionListDialogBox); revisionListDialogBox.activate(); } } } } } private void finishUpload(UserRequest ureq) { VFSManager.copyContent(sourceLeaf, newFile); finishSuccessfullUpload(newFile.getName(), ureq); } private void finishSuccessfullUpload(String fileName, UserRequest ureq) { VFSContainer currentContainer = folderComponent.getCurrentContainer(); VFSItem item = currentContainer.resolve(fileName); if (item instanceof OlatRootFileImpl) { OlatRootFileImpl relPathItem = (OlatRootFileImpl) item; // create meta data MetaInfo meta = CoreSpringFactory.getImpl(MetaInfoFactory.class).createMetaInfoFor(relPathItem); meta.setAuthor(ureq.getIdentity()); meta.clearThumbnails();//if overwrite an older file meta.write(); } ThreadLocalUserActivityLogger.log(FolderLoggingAction.FILE_COPIED, getClass(), CoreLoggingResourceable.wrapUploadFile(fileName)); // Notify listeners about upload fireEvent(ureq, new FolderEvent(FolderEvent.NEW_FILE_EVENT, newFile.getName())); fireEvent(ureq, FolderCommand.FOLDERCOMMAND_FINISHED); } private void fileAlreadyExists(UserRequest ureq) { renamedFilename = proposedRenamedFilename(existingVFSItem); boolean locked = vfsLockManager.isLockedForMe(existingVFSItem, getIdentity(), ureq.getUserSession().getRoles()); if (locked) { //the file is locked and cannot be overwritten removeAsListenerAndDispose(lockedFileDialog); lockedFileDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.lockedFile.title"), translate("ul.lockedFile.text", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); listenTo(lockedFileDialog); lockedFileDialog.activate(); } else if (existingVFSItem instanceof Versionable && ((Versionable)existingVFSItem).getVersions().isVersioned()) { Versionable versionable = (Versionable)existingVFSItem; Versions versions = versionable.getVersions(); String relPath = null; if(existingVFSItem instanceof OlatRootFileImpl) { relPath = ((OlatRootFileImpl)existingVFSItem).getRelPath(); } int maxNumOfRevisions = FolderConfig.versionsAllowed(relPath); if(maxNumOfRevisions == 0) { //it's possible if someone change the configuration // let calling method decide what to do. removeAsListenerAndDispose(overwriteDialog); overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.overwrite.threeoptions.title"), translate("ul.overwrite.threeoptions.text", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.overwrite"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); listenTo(overwriteDialog); overwriteDialog.activate(); } else if(versions.getRevisions().isEmpty() || maxNumOfRevisions < 0 || maxNumOfRevisions > versions.getRevisions().size()) { // let calling method decide what to do. removeAsListenerAndDispose(overwriteDialog); overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.overwrite.threeoptions.title"), translate("ul.versionoroverwrite", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.newVersion"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); listenTo(overwriteDialog); overwriteDialog.activate(); } else { String title = translate("ul.tooManyRevisions.title", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size())}); String description = translate("ul.tooManyRevisions.description", new String[]{Integer.toString(maxNumOfRevisions), Integer.toString(versions.getRevisions().size())}); removeAsListenerAndDispose(revisionListCtr); revisionListCtr = new RevisionListController(ureq, getWindowControl(), versionable, null, description, false); listenTo(revisionListCtr); removeAsListenerAndDispose(revisionListDialogBox); revisionListDialogBox = new CloseableModalController(getWindowControl(), translate("delete"), revisionListCtr.getInitialComponent(), true, title); listenTo(revisionListDialogBox); revisionListDialogBox.activate(); } } else { // let calling method decide what to do. // for this, we put a list with "existing name" and "new name" overwriteDialog = DialogBoxUIFactory.createGenericDialog(ureq, getWindowControl(), translate("ul.overwrite.threeoptions.title"), translate("ul.overwrite.threeoptions.text", new String[] {existingVFSItem.getName(), renamedFilename} ), asList(translate("ul.overwrite.threeoptions.overwrite"), translate("ul.overwrite.threeoptions.rename", renamedFilename), translate("ul.overwrite.threeoptions.cancel"))); listenTo(overwriteDialog); overwriteDialog.activate(); } } private String proposedRenamedFilename(VFSLeaf file) { String currentName = file.getName(); for(int i=1; i<999; i++) { String proposition = FileUtils.appendNumberAtTheEndOfFilename(currentName, i); VFSItem item = folderComponent.getCurrentContainer().resolve(proposition); if(item == null) { return proposition; } } return null; } }