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.apps.linkvalidation; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsResource; 032import org.opencms.main.CmsException; 033import org.opencms.main.CmsLog; 034import org.opencms.main.OpenCms; 035import org.opencms.ui.A_CmsUI; 036import org.opencms.ui.CmsVaadinUtils; 037import org.opencms.ui.FontOpenCms; 038import org.opencms.ui.apps.A_CmsWorkplaceApp; 039import org.opencms.ui.apps.CmsFileExplorer; 040import org.opencms.ui.apps.Messages; 041import org.opencms.ui.components.CmsBasicDialog; 042import org.opencms.ui.components.CmsBasicDialog.DialogWidth; 043import org.opencms.ui.components.CmsFileTable; 044import org.opencms.ui.components.CmsResourceTableProperty; 045import org.opencms.ui.components.CmsToolBar; 046import org.opencms.ui.dialogs.CmsDeleteDialog; 047import org.opencms.util.CmsStringUtil; 048import org.opencms.util.CmsUUID; 049 050import java.util.ArrayList; 051import java.util.Collections; 052import java.util.LinkedHashMap; 053import java.util.List; 054import java.util.Map; 055 056import org.apache.commons.logging.Log; 057 058import com.google.common.collect.Multimap; 059import com.vaadin.server.Sizeable.Unit; 060import com.vaadin.shared.MouseEventDetails.MouseButton; 061import com.vaadin.ui.Button; 062import com.vaadin.ui.Button.ClickEvent; 063import com.vaadin.ui.Button.ClickListener; 064import com.vaadin.ui.Component; 065import com.vaadin.ui.HorizontalSplitPanel; 066import com.vaadin.ui.Window; 067import com.vaadin.v7.event.ItemClickEvent; 068import com.vaadin.v7.event.ItemClickEvent.ItemClickListener; 069import com.vaadin.v7.ui.VerticalLayout; 070 071/** 072 * App to check relations of resources in folder to other folder.<p> 073 */ 074public class CmsLinkInFolderValidationApp extends A_CmsWorkplaceApp implements I_CmsUpdatableComponent { 075 076 /** 077 * Validator.<p> 078 */ 079 public class InFolderValidator extends A_CmsLinkValidator { 080 081 /**Resource which would be broken, if considered resoures would be deleted. */ 082 Multimap<CmsResource, CmsResource> brokenResources; 083 084 /** 085 * @see org.opencms.ui.apps.linkvalidation.A_CmsLinkValidator#failedResources(java.util.List) 086 */ 087 @Override 088 public List<CmsResource> failedResources(List<String> resources) { 089 090 try { 091 CmsObject cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject()); 092 cms.getRequestContext().setSiteRoot(""); 093 List<CmsResource> res = new ArrayList<CmsResource>(); 094 for (String resource : resources) { 095 if (cms.existsResource(resource)) { 096 res.add(cms.readResource(resource)); 097 } 098 } 099 100 brokenResources = CmsDeleteDialog.getBrokenLinks( 101 cms, 102 res, 103 false, 104 CmsVaadinUtils.isButtonPressed(m_revertButton)); 105 return new ArrayList<CmsResource>(brokenResources.keySet()); 106 } catch (CmsException e) { 107 return new ArrayList<CmsResource>(); 108 } 109 } 110 111 /** 112 * @see org.opencms.ui.apps.linkvalidation.A_CmsLinkValidator#failMessage(org.opencms.file.CmsResource) 113 */ 114 @Override 115 public String failMessage(CmsResource resource) { 116 117 if (brokenResources.size() == 0) { 118 return ""; 119 } 120 return brokenResources.get(resource).iterator().next().getRootPath(); 121 } 122 123 /** 124 * @see org.opencms.ui.apps.linkvalidation.A_CmsLinkValidator#getClickListener() 125 */ 126 @Override 127 public ItemClickListener getClickListener() { 128 129 return new ItemClickListener() { 130 131 private static final long serialVersionUID = -7729459896374968941L; 132 133 public void itemClick(ItemClickEvent event) { 134 135 if (event.getButton().equals(MouseButton.RIGHT)) { 136 return; 137 } 138 if (!property.equals(event.getPropertyId())) { 139 return; 140 } 141 try { 142 CmsObject cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject()); 143 cms.getRequestContext().setSiteRoot(""); 144 CmsResource resource = cms.readResource(new CmsUUID((String)event.getItemId())); 145 Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide); 146 window.setCaption(CmsVaadinUtils.getMessageText(getCaptionKey())); 147 window.setContent( 148 new CmsResourceListDialog(new ArrayList<CmsResource>(brokenResources.get(resource)))); 149 A_CmsUI.get().addWindow(window); 150 } catch (CmsException e) { 151 LOG.error("Unable to show detail resources", e); 152 } 153 } 154 155 }; 156 } 157 158 /** 159 * @see org.opencms.ui.apps.linkvalidation.A_CmsLinkValidator#getPropertyName() 160 */ 161 @Override 162 public String getPropertyName() { 163 164 return "Relations"; 165 } 166 167 /** 168 * @see org.opencms.ui.apps.linkvalidation.A_CmsLinkValidator#getTableProperties() 169 */ 170 @Override 171 public Map<CmsResourceTableProperty, Integer> getTableProperties() { 172 173 property = new CmsResourceTableProperty(getPropertyName(), String.class, "", getCaptionKey(), true, 0, 200); 174 Map<CmsResourceTableProperty, Integer> res = new LinkedHashMap<CmsResourceTableProperty, Integer>( 175 CmsFileTable.DEFAULT_TABLE_PROPERTIES); 176 res.put(property, Integer.valueOf(0)); 177 return res; 178 } 179 180 /** 181 * Returns the caption key.<p> 182 * 183 * @return key for caption 184 */ 185 String getCaptionKey() { 186 187 return org.opencms.ui.apps.Messages.GUI_LINKVALIDATION_CHECK_FOLDER_RELATIONS_COLUMN_HEADER_0; 188 } 189 190 } 191 192 /** 193 * Bean for the state of the app.<p> 194 */ 195 static class CmsStateBean { 196 197 /**State seperator. */ 198 protected static String STATE_SEPERATOR = A_CmsWorkplaceApp.PARAM_SEPARATOR; 199 200 /**Seperator for resources in state. */ 201 private static String RESOURCE_SEPERATOR = ";"; 202 203 /**List of resources. */ 204 private List<String> m_resources; 205 206 /**Reverse the output? */ 207 private boolean m_reverse; 208 209 /**CmsObject */ 210 private CmsObject m_cms = null; 211 212 /** 213 * public constructor.<p> 214 * 215 * @param resources List of resources (Root-paths) 216 * @param reverse boolean 217 * 218 */ 219 public CmsStateBean(List<String> resources, boolean reverse) { 220 221 setCmsObject(); 222 223 m_resources = resources; 224 m_reverse = reverse; 225 } 226 227 /** 228 * public constructor.<p> 229 * 230 * @param resources Resources as state string 231 * @param reverse boolean 232 */ 233 public CmsStateBean(String resources, boolean reverse) { 234 235 setCmsObject(); 236 m_resources = getResourcesFromState(resources); 237 m_reverse = reverse; 238 } 239 240 /** 241 * Parses a given state string to state bean.<p> 242 * 243 * @param state to be read 244 * @return CmsStateBean 245 */ 246 public static CmsStateBean parseState(String state) { 247 248 if (CmsStringUtil.isEmptyOrWhitespaceOnly(state)) { 249 return new CmsStateBean(Collections.emptyList(), false); 250 } 251 String[] parameter = state.split(STATE_SEPERATOR); 252 boolean reverse = false; 253 if (parameter.length > 1) { 254 reverse = Boolean.parseBoolean(parameter[1]); 255 } 256 return new CmsStateBean(parameter[0], reverse); 257 } 258 259 /** 260 * Get the resource list.<p> 261 * 262 * @return List of resource root paths 263 */ 264 public List<String> getResources() { 265 266 return m_resources; 267 } 268 269 /** 270 * Gets the state string of the current bean.<p> 271 * 272 * @return state string 273 */ 274 public String getState() { 275 276 return getResourceString() + STATE_SEPERATOR + Boolean.valueOf(m_reverse).toString(); 277 278 } 279 280 /** 281 * Is reverse mode selected? 282 * 283 * @return boolean 284 */ 285 public boolean isReverse() { 286 287 return m_reverse; 288 } 289 290 /** 291 * Gets resources from state string.<p> 292 * 293 * @param resources state string 294 * @return List of resource paths 295 */ 296 private List<String> getResourcesFromState(String resources) { 297 298 if (CmsStringUtil.isEmptyOrWhitespaceOnly(resources)) { 299 return Collections.EMPTY_LIST; 300 } 301 List<String> res = new ArrayList<String>(); 302 303 for (String uuidString : resources.split(RESOURCE_SEPERATOR)) { 304 try { 305 res.add(m_cms.readResource(new CmsUUID(uuidString)).getRootPath()); 306 } catch (CmsException e) { 307 LOG.error("Can not read resource from state", e); 308 } 309 } 310 return res; 311 } 312 313 /** 314 * Get the state string of the resources.<p> 315 * 316 * @return resources as string to use in state 317 */ 318 private String getResourceString() { 319 320 String res = ""; 321 try { 322 323 for (String resource : m_resources) { 324 res += m_cms.readResource(resource).getStructureId().getStringValue() + RESOURCE_SEPERATOR; 325 } 326 327 } catch (CmsException e) { 328 LOG.error("Can't read resource", e); 329 } 330 return res.length() > 1 ? res.substring(0, res.length() - 1) : res; 331 } 332 333 /** 334 * Prepares the CmsObject.<p> 335 */ 336 private void setCmsObject() { 337 338 if (m_cms == null) { 339 try { 340 m_cms = OpenCms.initCmsObject(A_CmsUI.getCmsObject()); 341 m_cms.getRequestContext().setSiteRoot(""); 342 } catch (CmsException e) { 343 m_cms = A_CmsUI.getCmsObject(); 344 } 345 } 346 } 347 } 348 349 /** The log object for this class. */ 350 static final Log LOG = CmsLog.getLog(CmsLinkInFolderValidationApp.class); 351 352 /**Bean for the state status. */ 353 private CmsStateBean m_stateBean; 354 355 /**Vaadin component. */ 356 Button m_revertButton; 357 358 /**Table */ 359 private CmsLinkValidationInternalTable m_table; 360 361 /**Resource Selector. */ 362 private CmsInternalResources m_resourceSelector; 363 364 /** 365 * @see org.opencms.ui.apps.linkvalidation.I_CmsUpdatableComponent#update(java.util.List) 366 */ 367 public void update(List<String> resources) { 368 369 openSubView(new CmsStateBean(resources, CmsVaadinUtils.isButtonPressed(m_revertButton)).getState(), true); 370 371 } 372 373 /** 374 * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getBreadCrumbForState(java.lang.String) 375 */ 376 @Override 377 protected LinkedHashMap<String, String> getBreadCrumbForState(String state) { 378 379 return null; 380 } 381 382 /** 383 * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getComponentForState(java.lang.String) 384 */ 385 @Override 386 protected Component getComponentForState(String state) { 387 388 m_stateBean = CmsStateBean.parseState(state); 389 if (m_revertButton == null) { 390 addToolbars(); 391 } 392 393 m_rootLayout.setMainHeightFull(true); 394 HorizontalSplitPanel panel = new HorizontalSplitPanel(); 395 VerticalLayout result = new VerticalLayout(); 396 result.setSizeFull(); 397 VerticalLayout intro = CmsVaadinUtils.getInfoLayout(Messages.GUI_LINKVALIDATION_CHECK_FOLDER_RELATIONS_INTRO_0); 398 VerticalLayout nullResult = CmsVaadinUtils.getInfoLayout( 399 Messages.GUI_LINKVALIDATION_CHECK_FOLDER_RELATIONS_NO_RESULT_0); 400 401 nullResult.setVisible(false); 402 m_table = new CmsLinkValidationInternalTable(intro, nullResult, new InFolderValidator()); 403 m_table.setVisible(false); 404 m_table.setSizeFull(); 405 m_table.setWidth("100%"); 406 407 result.addComponent(m_table); 408 result.addComponent(intro); 409 result.addComponent(nullResult); 410 411 m_table.setVisible(false); 412 m_table.setSizeFull(); 413 m_table.setWidth("100%"); 414 m_resourceSelector = new CmsInternalResources(this); 415 panel.setFirstComponent(m_resourceSelector); 416 panel.setSecondComponent(result); 417 418 panel.setSplitPosition(CmsFileExplorer.LAYOUT_SPLIT_POSITION, Unit.PIXELS); 419 420 if (!m_stateBean.getResources().isEmpty()) { 421 m_table.update(m_stateBean.getResources()); 422 m_resourceSelector.clearResources(); 423 for (String resource : m_stateBean.getResources()) { 424 m_resourceSelector.addResource(resource); 425 } 426 } 427 428 return panel; 429 } 430 431 /** 432 * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getSubNavEntries(java.lang.String) 433 */ 434 @Override 435 protected List<NavEntry> getSubNavEntries(String state) { 436 437 return null; 438 } 439 440 /** 441 * Toggle table.<p> 442 */ 443 protected void toggleTable() { 444 445 CmsVaadinUtils.toggleButton(m_revertButton); 446 openSubView( 447 new CmsStateBean(m_stateBean.getResources(), CmsVaadinUtils.isButtonPressed(m_revertButton)).getState(), 448 true); 449 } 450 451 /** 452 * Add toolbar icons.<p> 453 */ 454 private void addToolbars() { 455 456 m_revertButton = CmsToolBar.createButton( 457 FontOpenCms.REDO, 458 CmsVaadinUtils.getMessageText(Messages.GUI_USERMANAGEMENT_GROUPS_TOGGLE_0)); 459 m_revertButton.addClickListener(new ClickListener() { 460 461 private static final long serialVersionUID = 8265075332953321274L; 462 463 public void buttonClick(ClickEvent event) { 464 465 toggleTable(); 466 467 } 468 469 }); 470 if (m_stateBean.isReverse()) { 471 CmsVaadinUtils.toggleButton(m_revertButton); 472 } 473 m_uiContext.addToolbarButton(m_revertButton); 474 } 475}