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.FontOpenCms; 045import org.opencms.ui.I_CmsDialogContext; 046import org.opencms.ui.components.CmsBasicDialog; 047import org.opencms.ui.components.CmsOkCancelActionHandler; 048import org.opencms.util.CmsUUID; 049import org.opencms.workplace.explorer.CmsResourceUtil; 050 051import java.util.ArrayList; 052import java.util.HashSet; 053import java.util.Set; 054 055import org.apache.commons.logging.Log; 056 057import com.vaadin.ui.Button; 058import com.vaadin.ui.Button.ClickEvent; 059import com.vaadin.ui.Button.ClickListener; 060import com.vaadin.v7.shared.ui.label.ContentMode; 061import com.vaadin.v7.ui.CheckBox; 062import com.vaadin.v7.ui.Label; 063import com.vaadin.v7.ui.OptionGroup; 064import com.vaadin.v7.ui.VerticalLayout; 065 066/** 067 * Dialog used to change resource modification times.<p> 068 */ 069public class CmsUndoDialog extends CmsBasicDialog { 070 071 /** Logger instance for this class. */ 072 private static final Log LOG = CmsLog.getLog(CmsUndoDialog.class); 073 074 /** Serial version id. */ 075 private static final long serialVersionUID = 1L; 076 077 /** The dialog context. */ 078 protected I_CmsDialogContext m_context; 079 080 /** The Cancel button. */ 081 private Button m_cancelButton; 082 083 /** Check box to enable/disable modification of children. */ 084 private OptionGroup m_modifySubresourcesField; 085 086 /** The OK button. */ 087 private Button m_okButton; 088 089 /** Label with info text. */ 090 private Label m_infoText; 091 092 /** Label for displaying last modification date / user. */ 093 private Label m_modifiedText; 094 095 /** The date selection field. */ 096 private CheckBox m_undoMoveField; 097 098 /** The lock warning to display if sub-resources are locked. */ 099 private VerticalLayout m_lockWarning; 100 101 /** The warning icon */ 102 private Label m_icon; 103 104 /** 105 * Creates a new instance.<p> 106 * 107 * @param context the dialog context 108 * @param hasBlockingLocksOnSubResources flag, indicating if there are blocking locks on sub-resources 109 */ 110 public CmsUndoDialog(I_CmsDialogContext context, boolean hasBlockingLocksOnSubResources) { 111 112 m_context = context; 113 CmsVaadinUtils.readAndLocalizeDesign( 114 this, 115 OpenCms.getWorkplaceManager().getMessages(A_CmsUI.get().getLocale()), 116 null); 117 m_infoText.setValue( 118 CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_UNDO_CONFIRMATION_0)); 119 boolean hasFolders = false; 120 boolean hasMoved = false; 121 if (context.getResources().size() == 1) { 122 CmsResource singleRes = context.getResources().get(0); 123 CmsResourceUtil resUtil = new CmsResourceUtil(context.getCms(), singleRes); 124 String fileName = CmsResource.getName(singleRes.getRootPath()); 125 String date = CmsVfsService.formatDateTime(context.getCms(), singleRes.getDateLastModified()); 126 String user = resUtil.getUserLastModified(); 127 String key = org.opencms.workplace.commons.Messages.GUI_UNDO_LASTMODIFIED_INFO_3; 128 String message = CmsVaadinUtils.getMessageText(key, fileName, date, user); 129 m_modifiedText.setVisible(true); 130 m_modifiedText.setValue(message); 131 } 132 for (CmsResource resource : context.getResources()) { 133 if (resource.isFolder()) { 134 hasFolders = true; 135 break; 136 } else { 137 try { 138 CmsObject cms = OpenCms.initCmsObject(context.getCms()); 139 cms.getRequestContext().setCurrentProject(cms.readProject(CmsProject.ONLINE_PROJECT_ID)); 140 CmsResource onlineres = cms.readResource(resource.getStructureId()); 141 hasMoved |= !onlineres.getRootPath().equals(resource.getRootPath()); 142 } catch (CmsException e) { 143 LOG.warn(e.getLocalizedMessage(), e); 144 } 145 } 146 } 147 148 boolean multi = context.getResources().size() > 1; 149 String undoMessage = getUndoMessage(multi, hasFolders); 150 m_infoText.setValue(undoMessage); 151 m_modifySubresourcesField.setVisible(hasFolders); 152 m_modifySubresourcesField.addItem("false"); 153 m_modifySubresourcesField.setItemCaption("false", getNonRecursiveMessage(multi, hasFolders)); 154 m_modifySubresourcesField.addItem("true"); 155 m_modifySubresourcesField.setItemCaption("true", getRecursiveMessage(multi, hasFolders)); 156 m_modifySubresourcesField.setValue("false"); 157 158 m_undoMoveField.setVisible(hasFolders || hasMoved); 159 if (hasBlockingLocksOnSubResources) { 160 m_modifySubresourcesField.setItemEnabled("true", false); 161 m_undoMoveField.setEnabled(false); 162 m_icon.setContentMode(ContentMode.HTML); 163 m_icon.setValue(FontOpenCms.WARNING.getHtml()); 164 m_lockWarning.setVisible(true); 165 } 166 167 m_cancelButton.addClickListener(new ClickListener() { 168 169 private static final long serialVersionUID = 1L; 170 171 public void buttonClick(ClickEvent event) { 172 173 cancel(); 174 } 175 176 }); 177 178 m_okButton.addClickListener(new ClickListener() { 179 180 private static final long serialVersionUID = 1L; 181 182 public void buttonClick(ClickEvent event) { 183 184 undo(); 185 186 } 187 }); 188 displayResourceInfo(m_context.getResources()); 189 190 setActionHandler(new CmsOkCancelActionHandler() { 191 192 private static final long serialVersionUID = 1L; 193 194 @Override 195 protected void cancel() { 196 197 CmsUndoDialog.this.cancel(); 198 } 199 200 @Override 201 protected void ok() { 202 203 undo(); 204 } 205 }); 206 } 207 208 /** 209 * Undoes the changes.<p> 210 */ 211 protected void undo() { 212 213 try { 214 boolean recursive = Boolean.parseBoolean(m_modifySubresourcesField.getValue().toString()); 215 boolean undoMove = m_undoMoveField.getValue().booleanValue(); 216 CmsObject cms = m_context.getCms(); 217 Set<CmsUUID> updateResources = new HashSet<CmsUUID>(); 218 for (CmsResource resource : m_context.getResources()) { 219 updateResources.add(resource.getStructureId()); 220 if (undoMove) { 221 // in case a move is undone, add the former parent folder 222 updateResources.add(cms.readParentFolder(resource.getStructureId()).getStructureId()); 223 } 224 CmsLockActionRecord actionRecord = null; 225 try { 226 actionRecord = CmsLockUtil.ensureLock( 227 m_context.getCms(), 228 resource, 229 !(resource.isFile() || recursive || undoMove)); 230 CmsResourceUndoMode mode = CmsResourceUndoMode.getUndoMode(undoMove, recursive); 231 cms.undoChanges(cms.getSitePath(resource), mode); 232 if (undoMove) { 233 // in case a move is undone, also add the new parent folder 234 updateResources.add(cms.readParentFolder(resource.getStructureId()).getStructureId()); 235 } 236 } finally { 237 if ((actionRecord != null) && (actionRecord.getChange() == LockChange.locked)) { 238 try { 239 m_context.getCms().unlockResource(cms.readResource(resource.getStructureId())); 240 } catch (CmsLockException e) { 241 LOG.warn(e.getLocalizedMessage(), e); 242 } 243 } 244 245 } 246 247 } 248 m_context.finish(updateResources); 249 } catch (Exception e) { 250 m_context.error(e); 251 } 252 253 } 254 255 /** 256 * Cancels the dialog.<p> 257 */ 258 void cancel() { 259 260 m_context.finish(new ArrayList<CmsUUID>()); 261 } 262 263 /** 264 * Gets the message for the non-recursive modification option.<p> 265 * 266 * @param multi true if selection contains multiple resources 267 * @param hasFolder true if selection contains a folder 268 * 269 * @return the message text 270 */ 271 String getNonRecursiveMessage(boolean multi, boolean hasFolder) { 272 273 return CmsVaadinUtils.getMessageText(key("GUI_UNDO_NONRECURSIVE_", multi, hasFolder)); 274 275 } 276 277 /** 278 * Gets the message for the recursive modification option.<p> 279 * 280 * @param multi true if selection contains multiple resources 281 * @param hasFolder true if selection contains a folder 282 * 283 * @return the message text 284 */ 285 String getRecursiveMessage(boolean multi, boolean hasFolder) { 286 287 return CmsVaadinUtils.getMessageText(key("GUI_UNDO_RECURSIVE_", multi, hasFolder)); 288 289 } 290 291 /** 292 * Gets the undo message.<p> 293 * 294 * @param multi true if selection contains multiple resources 295 * @param hasFolder true if selection contains a folder 296 * 297 * @return the message text 298 */ 299 String getUndoMessage(boolean multi, boolean hasFolder) { 300 301 return CmsVaadinUtils.getMessageText(key("GUI_UNDO_", multi, hasFolder)); 302 } 303 304 /** 305 * Generates message key for a given combination of prefix, multi/single file , and folder/ no folder.<p> 306 * 307 * @param prefix the key prefix 308 * @param multi true if we have a multi-resource selection case 309 * @param hasFolder true if the selection contains a foldr 310 * 311 * @return the message key for the given input parameters 312 */ 313 private String key(String prefix, boolean multi, boolean hasFolder) { 314 315 return prefix + (multi ? "MULTI" : "SINGLE") + "_" + (hasFolder ? "FOLDER" : "FILE") + "_0"; 316 } 317 318}