001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.ui.dialogs; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProject; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsResource.CmsResourceUndoMode; 034import org.opencms.gwt.CmsVfsService; 035import org.opencms.lock.CmsLockActionRecord; 036import org.opencms.lock.CmsLockActionRecord.LockChange; 037import org.opencms.lock.CmsLockException; 038import org.opencms.lock.CmsLockUtil; 039import org.opencms.main.CmsException; 040import org.opencms.main.CmsLog; 041import org.opencms.main.OpenCms; 042import org.opencms.ui.A_CmsUI; 043import org.opencms.ui.CmsVaadinUtils; 044import org.opencms.ui.I_CmsDialogContext; 045import org.opencms.ui.components.CmsBasicDialog; 046import org.opencms.ui.components.CmsOkCancelActionHandler; 047import org.opencms.util.CmsUUID; 048import org.opencms.workplace.explorer.CmsResourceUtil; 049 050import java.util.ArrayList; 051import java.util.HashSet; 052import java.util.Set; 053 054import org.apache.commons.logging.Log; 055 056import com.vaadin.ui.Button; 057import com.vaadin.ui.Button.ClickEvent; 058import com.vaadin.ui.Button.ClickListener; 059import com.vaadin.v7.ui.CheckBox; 060import com.vaadin.v7.ui.Label; 061import com.vaadin.v7.ui.OptionGroup; 062 063/** 064 * Dialog used to change resource modification times.<p> 065 */ 066public class CmsUndoDialog extends CmsBasicDialog { 067 068 /** Logger instance for this class. */ 069 private static final Log LOG = CmsLog.getLog(CmsUndoDialog.class); 070 071 /** Serial version id. */ 072 private static final long serialVersionUID = 1L; 073 074 /** The dialog context. */ 075 protected I_CmsDialogContext m_context; 076 077 /** The Cancel button. */ 078 private Button m_cancelButton; 079 080 /** Check box to enable/disable modification of children. */ 081 private OptionGroup m_modifySubresourcesField; 082 083 /** The OK button. */ 084 private Button m_okButton; 085 086 /** Label with info text. */ 087 private Label m_infoText; 088 089 /** Label for displaying last modification date / user. */ 090 private Label m_modifiedText; 091 092 /** The date selection field. */ 093 private CheckBox m_undoMoveField; 094 095 /** 096 * Creates a new instance.<p> 097 * 098 * @param context the dialog context 099 */ 100 public CmsUndoDialog(I_CmsDialogContext context) { 101 m_context = context; 102 CmsVaadinUtils.readAndLocalizeDesign( 103 this, 104 OpenCms.getWorkplaceManager().getMessages(A_CmsUI.get().getLocale()), 105 null); 106 m_infoText.setValue( 107 CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_UNDO_CONFIRMATION_0)); 108 boolean hasFolders = false; 109 boolean hasMoved = false; 110 if (context.getResources().size() == 1) { 111 CmsResource singleRes = context.getResources().get(0); 112 CmsResourceUtil resUtil = new CmsResourceUtil(context.getCms(), singleRes); 113 String fileName = CmsResource.getName(singleRes.getRootPath()); 114 String date = CmsVfsService.formatDateTime(context.getCms(), singleRes.getDateLastModified()); 115 String user = resUtil.getUserLastModified(); 116 String key = org.opencms.workplace.commons.Messages.GUI_UNDO_LASTMODIFIED_INFO_3; 117 String message = CmsVaadinUtils.getMessageText(key, fileName, date, user); 118 m_modifiedText.setVisible(true); 119 m_modifiedText.setValue(message); 120 } 121 for (CmsResource resource : context.getResources()) { 122 if (resource.isFolder()) { 123 hasFolders = true; 124 break; 125 } else { 126 try { 127 CmsObject cms = OpenCms.initCmsObject(context.getCms()); 128 cms.getRequestContext().setCurrentProject(cms.readProject(CmsProject.ONLINE_PROJECT_ID)); 129 CmsResource onlineres = cms.readResource(resource.getStructureId()); 130 hasMoved |= !onlineres.getRootPath().equals(resource.getRootPath()); 131 } catch (CmsException e) { 132 LOG.warn(e.getLocalizedMessage(), e); 133 } 134 } 135 } 136 137 boolean multi = context.getResources().size() > 1; 138 String undoMessage = getUndoMessage(multi, hasFolders); 139 m_infoText.setValue(undoMessage); 140 m_modifySubresourcesField.setVisible(hasFolders); 141 m_modifySubresourcesField.addItem("false"); 142 m_modifySubresourcesField.setItemCaption("false", getNonRecursiveMessage(multi, hasFolders)); 143 m_modifySubresourcesField.addItem("true"); 144 m_modifySubresourcesField.setItemCaption("true", getRecursiveMessage(multi, hasFolders)); 145 m_modifySubresourcesField.setValue("false"); 146 147 m_undoMoveField.setVisible(hasFolders || hasMoved); 148 m_cancelButton.addClickListener(new ClickListener() { 149 150 private static final long serialVersionUID = 1L; 151 152 public void buttonClick(ClickEvent event) { 153 154 cancel(); 155 } 156 157 }); 158 159 m_okButton.addClickListener(new ClickListener() { 160 161 private static final long serialVersionUID = 1L; 162 163 public void buttonClick(ClickEvent event) { 164 165 undo(); 166 167 } 168 }); 169 displayResourceInfo(m_context.getResources()); 170 171 setActionHandler(new CmsOkCancelActionHandler() { 172 173 private static final long serialVersionUID = 1L; 174 175 @Override 176 protected void cancel() { 177 178 CmsUndoDialog.this.cancel(); 179 } 180 181 @Override 182 protected void ok() { 183 184 undo(); 185 } 186 }); 187 } 188 189 /** 190 * Undoes the changes.<p> 191 */ 192 protected void undo() { 193 194 try { 195 boolean recursive = Boolean.parseBoolean(m_modifySubresourcesField.getValue().toString()); 196 boolean undoMove = m_undoMoveField.getValue().booleanValue(); 197 CmsObject cms = m_context.getCms(); 198 Set<CmsUUID> updateResources = new HashSet<CmsUUID>(); 199 for (CmsResource resource : m_context.getResources()) { 200 updateResources.add(resource.getStructureId()); 201 if (undoMove) { 202 // in case a move is undone, add the former parent folder 203 updateResources.add(cms.readParentFolder(resource.getStructureId()).getStructureId()); 204 } 205 CmsLockActionRecord actionRecord = null; 206 try { 207 actionRecord = CmsLockUtil.ensureLock(m_context.getCms(), resource); 208 CmsResourceUndoMode mode = CmsResourceUndoMode.getUndoMode(undoMove, recursive); 209 cms.undoChanges(cms.getSitePath(resource), mode); 210 if (undoMove) { 211 // in case a move is undone, also add the new parent folder 212 updateResources.add(cms.readParentFolder(resource.getStructureId()).getStructureId()); 213 } 214 } finally { 215 if ((actionRecord != null) && (actionRecord.getChange() == LockChange.locked)) { 216 try { 217 m_context.getCms().unlockResource(cms.readResource(resource.getStructureId())); 218 } catch (CmsLockException e) { 219 LOG.warn(e.getLocalizedMessage(), e); 220 } 221 } 222 223 } 224 225 } 226 m_context.finish(updateResources); 227 } catch (Exception e) { 228 m_context.error(e); 229 } 230 231 } 232 233 /** 234 * Cancels the dialog.<p> 235 */ 236 void cancel() { 237 238 m_context.finish(new ArrayList<CmsUUID>()); 239 } 240 241 /** 242 * Gets the message for the non-recursive modification option.<p> 243 * 244 * @param multi true if selection contains multiple resources 245 * @param hasFolder true if selection contains a folder 246 * 247 * @return the message text 248 */ 249 String getNonRecursiveMessage(boolean multi, boolean hasFolder) { 250 251 return CmsVaadinUtils.getMessageText(key("GUI_UNDO_NONRECURSIVE_", multi, hasFolder)); 252 253 } 254 255 /** 256 * Gets the message for the recursive modification option.<p> 257 * 258 * @param multi true if selection contains multiple resources 259 * @param hasFolder true if selection contains a folder 260 * 261 * @return the message text 262 */ 263 String getRecursiveMessage(boolean multi, boolean hasFolder) { 264 265 return CmsVaadinUtils.getMessageText(key("GUI_UNDO_RECURSIVE_", multi, hasFolder)); 266 267 } 268 269 /** 270 * Gets the undo message.<p> 271 * 272 * @param multi true if selection contains multiple resources 273 * @param hasFolder true if selection contains a folder 274 * 275 * @return the message text 276 */ 277 String getUndoMessage(boolean multi, boolean hasFolder) { 278 279 return CmsVaadinUtils.getMessageText(key("GUI_UNDO_", multi, hasFolder)); 280 } 281 282 /** 283 * Generates message key for a given combination of prefix, multi/single file , and folder/ no folder.<p> 284 * 285 * @param prefix the key prefix 286 * @param multi true if we have a multi-resource selection case 287 * @param hasFolder true if the selection contains a foldr 288 * 289 * @return the message key for the given input parameters 290 */ 291 private String key(String prefix, boolean multi, boolean hasFolder) { 292 293 return prefix + (multi ? "MULTI" : "SINGLE") + "_" + (hasFolder ? "FOLDER" : "FILE") + "_0"; 294 } 295 296}