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.sitemap; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProject; 032import org.opencms.file.CmsProperty; 033import org.opencms.file.CmsPropertyDefinition; 034import org.opencms.file.CmsResource; 035import org.opencms.file.CmsResourceFilter; 036import org.opencms.gwt.CmsCoreService; 037import org.opencms.i18n.CmsLocaleGroupService; 038import org.opencms.i18n.CmsLocaleManager; 039import org.opencms.lock.CmsLockActionRecord; 040import org.opencms.lock.CmsLockActionRecord.LockChange; 041import org.opencms.lock.CmsLockUtil; 042import org.opencms.main.CmsException; 043import org.opencms.main.CmsLog; 044import org.opencms.main.OpenCms; 045import org.opencms.site.CmsSite; 046import org.opencms.ui.A_CmsUI; 047import org.opencms.ui.CmsVaadinUtils; 048import org.opencms.ui.FontOpenCms; 049import org.opencms.ui.I_CmsDialogContext; 050import org.opencms.ui.Messages; 051import org.opencms.ui.actions.CmsResourceInfoAction; 052import org.opencms.ui.apps.CmsSitemapEditorConfiguration; 053import org.opencms.ui.components.CmsBasicDialog; 054import org.opencms.ui.components.CmsBasicDialog.DialogWidth; 055import org.opencms.ui.components.CmsErrorDialog; 056import org.opencms.ui.components.CmsResourceIcon; 057import org.opencms.ui.components.CmsResourceIcon.IconMode; 058import org.opencms.ui.components.CmsResourceInfo; 059import org.opencms.ui.components.OpenCmsTheme; 060import org.opencms.ui.contextmenu.CmsContextMenu; 061import org.opencms.ui.contextmenu.CmsMenuItemVisibilityMode; 062import org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry; 063import org.opencms.util.CmsUUID; 064 065import java.util.Arrays; 066import java.util.Collection; 067import java.util.IdentityHashMap; 068import java.util.List; 069import java.util.Locale; 070 071import org.apache.commons.logging.Log; 072 073import com.google.common.base.Joiner; 074import com.google.common.base.Predicate; 075import com.google.common.collect.Lists; 076import com.vaadin.event.LayoutEvents.LayoutClickEvent; 077import com.vaadin.event.LayoutEvents.LayoutClickListener; 078import com.vaadin.server.FontAwesome; 079import com.vaadin.server.Resource; 080import com.vaadin.ui.AbstractComponent; 081import com.vaadin.ui.Button.ClickEvent; 082import com.vaadin.ui.Button.ClickListener; 083import com.vaadin.ui.Component; 084import com.vaadin.ui.ComponentContainer; 085import com.vaadin.ui.CssLayout; 086import com.vaadin.ui.MenuBar; 087import com.vaadin.ui.MenuBar.Command; 088import com.vaadin.ui.MenuBar.MenuItem; 089import com.vaadin.ui.Notification; 090import com.vaadin.ui.Notification.Type; 091import com.vaadin.ui.UI; 092import com.vaadin.ui.Window; 093 094/** 095 * Manages the sitemap tree in the 'locale comparison' view in the sitemap editor.<p> 096 */ 097public class CmsSitemapTreeController { 098 099 /** 100 * The context used for child dialogs.<p> 101 */ 102 public class DialogContext implements I_CmsDialogContext { 103 104 /** The tree node. */ 105 private CmsSitemapTreeNode m_node; 106 107 /** The resource. */ 108 private CmsResource m_resource; 109 110 /** 111 * Creates a new instance.<p> 112 * 113 * @param resource the resource 114 * @param node the tree node 115 */ 116 public DialogContext(CmsResource resource, CmsSitemapTreeNode node) { 117 m_resource = resource; 118 m_node = node; 119 } 120 121 /** 122 * Closes the dialog window.<p> 123 */ 124 public void closeWindow() { 125 126 if (m_window != null) { 127 m_window.close(); 128 m_window = null; 129 } 130 } 131 132 /** 133 * @see org.opencms.ui.I_CmsDialogContext#error(java.lang.Throwable) 134 */ 135 public void error(Throwable error) { 136 137 getTreeControllerLog().error(error.getLocalizedMessage(), error); 138 CmsErrorDialog.showErrorDialog(error); 139 } 140 141 /** 142 * @see org.opencms.ui.I_CmsDialogContext#finish(org.opencms.file.CmsProject, java.lang.String) 143 */ 144 public void finish(CmsProject project, String siteRoot) { 145 146 closeWindow(); 147 } 148 149 /** 150 * @see org.opencms.ui.I_CmsDialogContext#finish(java.util.Collection) 151 */ 152 @SuppressWarnings("synthetic-access") 153 public void finish(Collection<CmsUUID> result) { 154 155 closeWindow(); 156 if (result.isEmpty()) { 157 return; 158 } 159 if (m_node != null) { 160 if (m_node == m_currentRootNode) { 161 m_localeContext.refreshAll(); 162 } else { 163 updateNode(m_node); 164 } 165 } 166 } 167 168 /** 169 * @see org.opencms.ui.I_CmsDialogContext#focus(org.opencms.util.CmsUUID) 170 */ 171 public void focus(CmsUUID structureId) { 172 // not used 173 } 174 175 /** 176 * @see org.opencms.ui.I_CmsDialogContext#getAllStructureIdsInView() 177 */ 178 public List<CmsUUID> getAllStructureIdsInView() { 179 180 return null; 181 } 182 183 /** 184 * @see org.opencms.ui.I_CmsDialogContext#getAppId() 185 */ 186 public String getAppId() { 187 188 return CmsSitemapEditorConfiguration.APP_ID; 189 } 190 191 /** 192 * @see org.opencms.ui.I_CmsDialogContext#getCms() 193 */ 194 public CmsObject getCms() { 195 196 return A_CmsUI.getCmsObject(); 197 } 198 199 /** 200 * @see org.opencms.ui.I_CmsDialogContext#getContextType() 201 */ 202 public ContextType getContextType() { 203 204 return null; 205 } 206 207 /** 208 * @see org.opencms.ui.I_CmsDialogContext#getResources() 209 */ 210 public List<CmsResource> getResources() { 211 212 return Arrays.asList(m_resource); 213 } 214 215 /** 216 * @see org.opencms.ui.I_CmsDialogContext#navigateTo(java.lang.String) 217 */ 218 public void navigateTo(String appId) { 219 // not used 220 } 221 222 /** 223 * @see org.opencms.ui.I_CmsDialogContext#onViewChange() 224 */ 225 public void onViewChange() { 226 // do nothing 227 } 228 229 /** 230 * @see org.opencms.ui.I_CmsDialogContext#reload() 231 */ 232 public void reload() { 233 234 // do nothing 235 236 } 237 238 /** 239 * @see org.opencms.ui.I_CmsDialogContext#setWindow(com.vaadin.ui.Window) 240 */ 241 public void setWindow(Window window) { 242 243 m_window = window; 244 } 245 246 /** 247 * @see org.opencms.ui.I_CmsDialogContext#start(java.lang.String, com.vaadin.ui.Component) 248 */ 249 public void start(String title, Component dialog) { 250 251 start(title, dialog, DialogWidth.narrow); 252 } 253 254 /** 255 * @see org.opencms.ui.I_CmsDialogContext#start(java.lang.String, com.vaadin.ui.Component, org.opencms.ui.components.CmsBasicDialog.DialogWidth) 256 */ 257 public void start(String title, Component dialog, DialogWidth width) { 258 259 if (dialog != null) { 260 m_window = CmsBasicDialog.prepareWindow(width); 261 m_window.setCaption(title); 262 m_window.setContent(dialog); 263 UI.getCurrent().addWindow(m_window); 264 if (dialog instanceof CmsBasicDialog) { 265 ((CmsBasicDialog)dialog).initActionHandler(m_window); 266 } 267 } 268 } 269 270 /** 271 * @see org.opencms.ui.I_CmsDialogContext#updateUserInfo() 272 */ 273 public void updateUserInfo() { 274 275 // not supported 276 } 277 } 278 279 /** 280 * Copy menu entry. 281 */ 282 class EntryCopy implements I_CmsSimpleContextMenuEntry<MenuContext> { 283 284 /** 285 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object) 286 */ 287 public void executeAction(MenuContext context) { 288 289 openPageCopyDialog(context.getNode(), context.getData()); 290 291 } 292 293 /** 294 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale) 295 */ 296 public String getTitle(Locale locale) { 297 298 return CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_COPY_PAGE_0); 299 } 300 301 /** 302 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object) 303 */ 304 public CmsMenuItemVisibilityMode getVisibility(MenuContext context) { 305 306 return visibleIfTrue(context.getData().isCopyable()); 307 308 } 309 } 310 311 /** 312 * Menu entry for opening the explorer.<p> 313 */ 314 class EntryExplorer implements I_CmsSimpleContextMenuEntry<MenuContext> { 315 316 /** 317 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object) 318 */ 319 public void executeAction(MenuContext context) { 320 321 String link = CmsCoreService.getVaadinWorkplaceLink( 322 A_CmsUI.getCmsObject(), 323 context.getData().getResource().getStructureId()); 324 A_CmsUI.get().getPage().setLocation(link); 325 326 } 327 328 /** 329 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale) 330 */ 331 public String getTitle(Locale locale) { 332 333 return CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_EXPLORER_0); 334 } 335 336 /** 337 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object) 338 */ 339 public CmsMenuItemVisibilityMode getVisibility(MenuContext context) { 340 341 return visibleIfTrue(true); 342 } 343 344 } 345 346 /** 347 * Menu entry for opening the info dialog.<p> 348 */ 349 class EntryInfo implements I_CmsSimpleContextMenuEntry<MenuContext> { 350 351 /** 352 353 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object) 354 */ 355 public void executeAction(MenuContext context) { 356 357 CmsResourceInfoAction infoAction = new CmsResourceInfoAction(); 358 infoAction.executeAction(new DialogContext(context.getData().getResource(), context.getNode())); 359 } 360 361 /** 362 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale) 363 */ 364 public String getTitle(Locale locale) { 365 366 return CmsVaadinUtils.getMessageText(Messages.GUI_RESOURCE_INFO_0); 367 } 368 369 /** 370 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object) 371 */ 372 public CmsMenuItemVisibilityMode getVisibility(MenuContext context) { 373 374 return visibleIfTrue(true); 375 } 376 377 } 378 379 /** 380 * Menu entry for opening the 'LInk locale' dialog.<p> 381 */ 382 class EntryLink implements I_CmsSimpleContextMenuEntry<MenuContext> { 383 384 /** 385 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object) 386 */ 387 @SuppressWarnings("synthetic-access") 388 public void executeAction(MenuContext data) { 389 390 try { 391 DialogContext dialogContext = new DialogContext( 392 A_CmsUI.getCmsObject().readResource( 393 data.getData().getClientEntry().getId(), 394 CmsResourceFilter.IGNORE_EXPIRATION), 395 data.getNode()); 396 CmsLocaleLinkTargetSelectionDialog dialog = new CmsLocaleLinkTargetSelectionDialog( 397 dialogContext, 398 m_localeContext); 399 dialogContext.start( 400 CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_LINK_LOCALE_VARIANT_0), 401 dialog, 402 DialogWidth.narrow); 403 } catch (CmsException e) { 404 LOG.error(e.getLocalizedMessage(), e); 405 CmsErrorDialog.showErrorDialog(e); 406 } 407 } 408 409 /** 410 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale) 411 */ 412 public String getTitle(Locale locale) { 413 414 return CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_LINK_LOCALE_VARIANT_0); 415 } 416 417 /** 418 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object) 419 */ 420 @SuppressWarnings("synthetic-access") 421 public CmsMenuItemVisibilityMode getVisibility(MenuContext context) { 422 423 return activeIfTrue( 424 !context.getData().isLinked() 425 && !context.getData().isMarkedNoTranslation(m_localeContext.getComparisonLocale())); 426 } 427 } 428 429 /** 430 * Context menu entry for the 'Do not translate' mark.<p> 431 */ 432 class EntryMark implements I_CmsSimpleContextMenuEntry<MenuContext> { 433 434 /** 435 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object) 436 */ 437 @SuppressWarnings("synthetic-access") 438 public void executeAction(MenuContext context) { 439 440 CmsSitemapTreeNodeData entry = context.getData(); 441 CmsSitemapTreeNode node = context.getNode(); 442 443 CmsObject cms = A_CmsUI.getCmsObject(); 444 CmsLockActionRecord actionRecord = null; 445 CmsResource fileToModify2 = null; 446 try { 447 448 CmsResource primary = A_CmsUI.getCmsObject().readResource( 449 entry.getClientEntry().getId(), 450 CmsResourceFilter.IGNORE_EXPIRATION); 451 if (primary.isFolder()) { 452 CmsResource defaultFile = A_CmsUI.getCmsObject().readDefaultFile( 453 primary, 454 CmsResourceFilter.IGNORE_EXPIRATION); 455 if (defaultFile != null) { 456 primary = defaultFile; 457 } 458 } 459 final CmsResource primaryFinal = primary; 460 461 fileToModify2 = primaryFinal; 462 if (fileToModify2.isFolder()) { 463 try { 464 fileToModify2 = A_CmsUI.getCmsObject().readDefaultFile( 465 fileToModify2, 466 CmsResourceFilter.IGNORE_EXPIRATION); 467 } catch (CmsException e) { 468 LOG.error(e.getLocalizedMessage(), e); 469 } 470 } 471 472 actionRecord = CmsLockUtil.ensureLock(cms, fileToModify2); 473 m_localeContext.getComparisonLocale().toString(); 474 CmsProperty prop = cms.readPropertyObject( 475 fileToModify2, 476 CmsPropertyDefinition.PROPERTY_LOCALE_NOTRANSLATION, 477 false); 478 String propValue = prop.getValue(); 479 if (propValue == null) { 480 propValue = ""; // make getLocales not return null 481 } 482 List<Locale> currentLocales = CmsLocaleManager.getLocales(propValue); 483 if (!currentLocales.contains(m_localeContext.getComparisonLocale())) { 484 currentLocales.add(m_localeContext.getComparisonLocale()); 485 String newPropValue = Joiner.on(",").join(currentLocales); 486 CmsProperty newProp = new CmsProperty( 487 CmsPropertyDefinition.PROPERTY_LOCALE_NOTRANSLATION, 488 newPropValue, 489 null); 490 cms.writePropertyObjects(fileToModify2, Arrays.asList(newProp)); 491 DialogContext dialogContext = new DialogContext( 492 A_CmsUI.getCmsObject().readResource( 493 entry.getClientEntry().getId(), 494 CmsResourceFilter.IGNORE_EXPIRATION), 495 node); 496 dialogContext.finish(Arrays.asList(fileToModify2.getStructureId())); 497 498 } 499 500 } catch (CmsException e) { 501 LOG.error(e.getLocalizedMessage(), e); 502 CmsErrorDialog.showErrorDialog(e); 503 504 } finally { 505 if ((actionRecord != null) && (actionRecord.getChange() == LockChange.locked)) { 506 try { 507 cms.unlockResource(fileToModify2); 508 } catch (CmsException e) { 509 LOG.error(e.getLocalizedMessage(), e); 510 CmsErrorDialog.showErrorDialog(e); 511 } 512 } 513 } 514 515 } 516 517 /** 518 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale) 519 */ 520 public String getTitle(Locale locale) { 521 522 return CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_ADD_DONT_TRANSLATE_0); 523 } 524 525 /** 526 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object) 527 */ 528 @SuppressWarnings("synthetic-access") 529 public CmsMenuItemVisibilityMode getVisibility(MenuContext context) { 530 531 CmsSitemapTreeNodeData entry = context.getData(); 532 boolean result = context.isMainLocale() 533 && !entry.isMarkedNoTranslation(m_localeContext.getComparisonLocale()) 534 && !entry.isLinked(); 535 return visibleIfTrue(result); 536 537 } 538 539 } 540 541 /** 542 * 'Open page' menu entry.<p> 543 */ 544 class EntryOpen implements I_CmsSimpleContextMenuEntry<MenuContext> { 545 546 /** 547 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object) 548 */ 549 @SuppressWarnings("synthetic-access") 550 public void executeAction(MenuContext context) { 551 552 openTargetPage((CmsSitemapTreeNodeData)(context.getNode().getData()), false); 553 554 } 555 556 /** 557 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale) 558 */ 559 public String getTitle(Locale locale) { 560 561 return CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_OPEN_PAGE_0); 562 563 } 564 565 /** 566 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object) 567 */ 568 public CmsMenuItemVisibilityMode getVisibility(MenuContext data) { 569 570 return visibleIfTrue(true); 571 } 572 573 } 574 575 /** 576 * 'Properties' menu entry.<p> 577 */ 578 class EntryProperties implements I_CmsSimpleContextMenuEntry<MenuContext> { 579 580 /** 581 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object) 582 */ 583 @SuppressWarnings("synthetic-access") 584 public void executeAction(MenuContext context) { 585 586 ((CmsSitemapUI)A_CmsUI.get()).getSitemapExtension().openPropertyDialog( 587 context.getData().getResource().getStructureId(), 588 m_root.getStructureId()); 589 } 590 591 /** 592 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale) 593 */ 594 public String getTitle(Locale locale) { 595 596 return CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_PROPERTIES_0); 597 598 } 599 600 /** 601 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object) 602 */ 603 public CmsMenuItemVisibilityMode getVisibility(MenuContext context) { 604 605 return visibleIfTrue(true); 606 } 607 608 } 609 610 /** 611 * 'Remove mark' menu entry.<p> 612 */ 613 class EntryRemoveMark implements I_CmsSimpleContextMenuEntry<MenuContext> { 614 615 /** 616 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object) 617 */ 618 @SuppressWarnings("synthetic-access") 619 public void executeAction(MenuContext context) { 620 621 CmsSitemapTreeNodeData entry = context.getData(); 622 CmsSitemapTreeNode node = context.getNode(); 623 624 CmsObject cms = A_CmsUI.getCmsObject(); 625 CmsLockActionRecord actionRecord = null; 626 CmsResource fileToModify2 = null; 627 try { 628 CmsResource primary = A_CmsUI.getCmsObject().readResource( 629 entry.getClientEntry().getId(), 630 CmsResourceFilter.IGNORE_EXPIRATION); 631 if (primary.isFolder()) { 632 CmsResource defaultFile = A_CmsUI.getCmsObject().readDefaultFile( 633 primary, 634 CmsResourceFilter.IGNORE_EXPIRATION); 635 if (defaultFile != null) { 636 primary = defaultFile; 637 } 638 } 639 final CmsResource primaryFinal = primary; 640 641 fileToModify2 = primaryFinal; 642 if (fileToModify2.isFolder()) { 643 try { 644 fileToModify2 = A_CmsUI.getCmsObject().readDefaultFile( 645 fileToModify2, 646 CmsResourceFilter.IGNORE_EXPIRATION); 647 } catch (CmsException e) { 648 LOG.error(e.getLocalizedMessage(), e); 649 } 650 } 651 652 actionRecord = CmsLockUtil.ensureLock(cms, fileToModify2); 653 m_localeContext.getComparisonLocale().toString(); 654 CmsProperty prop = cms.readPropertyObject( 655 fileToModify2, 656 CmsPropertyDefinition.PROPERTY_LOCALE_NOTRANSLATION, 657 false); 658 String propValue = prop.getValue(); 659 if (propValue == null) { 660 propValue = ""; // make getLocales not return null 661 } 662 List<Locale> currentLocales = CmsLocaleManager.getLocales(propValue); 663 if (currentLocales.contains(m_localeContext.getComparisonLocale())) { 664 currentLocales.remove(m_localeContext.getComparisonLocale()); 665 String newPropValue = Joiner.on(",").join(currentLocales); 666 CmsProperty newProp = new CmsProperty( 667 CmsPropertyDefinition.PROPERTY_LOCALE_NOTRANSLATION, 668 newPropValue, 669 null); 670 cms.writePropertyObjects(primaryFinal, Arrays.asList(newProp)); 671 DialogContext dialogContext = new DialogContext( 672 A_CmsUI.getCmsObject().readResource( 673 entry.getClientEntry().getId(), 674 CmsResourceFilter.IGNORE_EXPIRATION), 675 node); 676 dialogContext.finish(Arrays.asList(fileToModify2.getStructureId())); 677 } 678 679 } catch (CmsException e) { 680 LOG.error(e.getLocalizedMessage(), e); 681 CmsErrorDialog.showErrorDialog(e); 682 683 } finally { 684 if ((actionRecord != null) && (actionRecord.getChange() == LockChange.locked)) { 685 try { 686 cms.unlockResource(fileToModify2); 687 } catch (CmsException e) { 688 LOG.error(e.getLocalizedMessage(), e); 689 CmsErrorDialog.showErrorDialog(e); 690 } 691 } 692 } 693 694 } 695 696 /** 697 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale) 698 */ 699 public String getTitle(Locale locale) { 700 701 return CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_REMOVE_DONT_TRANSLATE_0); 702 } 703 704 /** 705 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object) 706 */ 707 @SuppressWarnings("synthetic-access") 708 public CmsMenuItemVisibilityMode getVisibility(MenuContext context) { 709 710 boolean result = context.isMainLocale() 711 && context.getData().isMarkedNoTranslation(m_localeContext.getComparisonLocale()); 712 return visibleIfTrue(result); 713 714 } 715 } 716 717 /** 718 * 'Unlink' menu entry.<p> 719 */ 720 class EntryUnlink implements I_CmsSimpleContextMenuEntry<MenuContext> { 721 722 /** 723 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#executeAction(java.lang.Object) 724 */ 725 @SuppressWarnings("synthetic-access") 726 public void executeAction(MenuContext context) { 727 728 try { 729 CmsResource secondary = context.getData().getLinkedResource(); 730 DialogContext dialogContext = new DialogContext( 731 A_CmsUI.getCmsObject().readResource( 732 context.getData().getClientEntry().getId(), 733 CmsResourceFilter.IGNORE_EXPIRATION), 734 context.getNode()); 735 CmsUnlinkDialog dialog = new CmsUnlinkDialog(dialogContext, secondary); 736 dialogContext.start( 737 CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_UNLINK_LOCALE_VARIANT_0), 738 dialog, 739 DialogWidth.wide); 740 } catch (CmsException e) { 741 LOG.error(e.getLocalizedMessage(), e); 742 CmsErrorDialog.showErrorDialog(e); 743 } 744 } 745 746 /** 747 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getTitle(java.util.Locale) 748 */ 749 public String getTitle(Locale locale) { 750 751 return CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_UNLINK_LOCALE_VARIANT_0); 752 } 753 754 /** 755 * @see org.opencms.ui.contextmenu.I_CmsSimpleContextMenuEntry#getVisibility(java.lang.Object) 756 */ 757 @SuppressWarnings("synthetic-access") 758 public CmsMenuItemVisibilityMode getVisibility(final MenuContext context) { 759 760 if (!context.getData().isLinked()) { 761 return visibleIfTrue(false); 762 } 763 try { 764 CmsResource primary = A_CmsUI.getCmsObject().readResource( 765 context.getData().getClientEntry().getId(), 766 CmsResourceFilter.IGNORE_EXPIRATION); 767 if (primary.isFolder()) { 768 CmsResource defaultFile = A_CmsUI.getCmsObject().readDefaultFile( 769 primary, 770 CmsResourceFilter.IGNORE_EXPIRATION); 771 if (defaultFile != null) { 772 primary = defaultFile; 773 } 774 } 775 CmsLocaleGroupService groupService = A_CmsUI.getCmsObject().getLocaleGroupService(); 776 Locale mainLocale = groupService.getMainLocale(m_localeContext.getRoot().getRootPath()); 777 int mainLocaleCount = 0; 778 for (Locale testLocale : Arrays.asList( 779 m_localeContext.getRootLocale(), 780 m_localeContext.getComparisonLocale())) { 781 mainLocaleCount += mainLocale.equals(testLocale) ? 1 : 0; 782 } 783 return visibleIfTrue(mainLocaleCount == 1); 784 } catch (Exception e) { 785 return visibleIfTrue(false); 786 787 } 788 789 } 790 } 791 792 /** 793 * Context object for the context menu.<p> 794 */ 795 class MenuContext { 796 797 /** The tree node data. */ 798 private CmsSitemapTreeNodeData m_data; 799 800 /** The tree node widget. */ 801 private CmsSitemapTreeNode m_node; 802 803 /** 804 * Creates a new instance.<p> 805 * 806 * @param data the sitemap tree data 807 * @param node the tree node widget 808 */ 809 public MenuContext(CmsSitemapTreeNodeData data, CmsSitemapTreeNode node) { 810 m_node = node; 811 m_data = data; 812 } 813 814 /** 815 * Gets the tree node data.<p> 816 * 817 * @return the tree node data 818 */ 819 public CmsSitemapTreeNodeData getData() { 820 821 return m_data; 822 } 823 824 /** 825 * Gets the tree node widget.<p> 826 * 827 * @return the tree node widget 828 */ 829 public CmsSitemapTreeNode getNode() { 830 831 return m_node; 832 } 833 834 /** 835 * Checks if the currently selected locale is the main locale.<p> 836 * 837 * @return true if we are in the main locale 838 */ 839 @SuppressWarnings("synthetic-access") 840 public boolean isMainLocale() { 841 842 return m_localeContext.getRootLocale().equals( 843 A_CmsUI.getCmsObject().getLocaleGroupService().getMainLocale(m_localeContext.getRoot().getRootPath())); 844 } 845 846 } 847 848 /** Default width for linked items displayed on the right side of tree items. */ 849 public static final int RHS_WIDTH = 420; 850 851 /** The log isntance for this class. */ 852 private static final Log LOG = CmsLog.getLog(CmsSitemapTreeController.class); 853 854 /** The context menu. */ 855 CmsContextMenu m_menu = new CmsContextMenu(); 856 857 /** The currently opened window. */ 858 Window m_window; 859 860 /** Map of already loaded nodes. */ 861 private IdentityHashMap<CmsSitemapTreeNode, Void> m_alreadyLoaded = new IdentityHashMap<>(); 862 863 /** Current root node widget. */ 864 private CmsSitemapTreeNode m_currentRootNode; 865 866 /** The locale context. */ 867 private I_CmsLocaleCompareContext m_localeContext; 868 869 /** The resource corresponding to the tree's root. */ 870 private CmsResource m_root; 871 872 /** The tree data provider. */ 873 private CmsSitemapTreeDataProvider m_treeDataProvider; 874 875 /** 876 * Creates a new instance.<p> 877 * 878 * @param cms the CMS context 879 * @param root the tree's root resource 880 * @param context the locale comparison context 881 * @param parent the parent widget in which the tree will be rendered 882 */ 883 public CmsSitemapTreeController( 884 CmsObject cms, 885 CmsResource root, 886 I_CmsLocaleCompareContext context, 887 Component parent) { 888 m_treeDataProvider = new CmsSitemapTreeDataProvider(cms, root, context); 889 m_localeContext = context; 890 m_root = root; 891 m_menu.extend((AbstractComponent)parent); 892 893 } 894 895 /** 896 * Returns VISIBILITY_ACTIVE if the given parameter is true, and VISIBILITY_INACTIVE otherwise.<p> 897 * 898 * @param condition a boolean value 899 * @return the visibility based on the condition value 900 */ 901 public static CmsMenuItemVisibilityMode activeIfTrue(boolean condition) { 902 903 return condition ? CmsMenuItemVisibilityMode.VISIBILITY_ACTIVE : CmsMenuItemVisibilityMode.VISIBILITY_INACTIVE; 904 } 905 906 /** 907 * Returns VISIBILITY_ACTIVE if the given parameter is true, and VISIBILITY_INVISIBLE otherwise.<p> 908 * 909 * @param condition a boolean value 910 * @return the visibility based on the condition value 911 */ 912 public static CmsMenuItemVisibilityMode visibleIfTrue(boolean condition) { 913 914 return condition ? CmsMenuItemVisibilityMode.VISIBILITY_ACTIVE : CmsMenuItemVisibilityMode.VISIBILITY_INVISIBLE; 915 } 916 917 /** 918 * Creates a sitemap tree node widget from a tree node bean.<p> 919 * 920 * @param entry the tree node bean 921 * @return the tree node widget 922 */ 923 public CmsSitemapTreeNode createNode(final CmsSitemapTreeNodeData entry) { 924 925 final CmsSitemapTreeNode node = new CmsSitemapTreeNode(); 926 927 node.addLayoutClickListener(new LayoutClickListener() { 928 929 private static final long serialVersionUID = 1L; 930 931 @SuppressWarnings("synthetic-access") 932 public void layoutClick(LayoutClickEvent event) { 933 934 Component currentComponent = event.getClickedComponent(); 935 if (currentComponent != null) { 936 boolean linked = false; 937 do { 938 currentComponent = currentComponent.getParent(); 939 if ((currentComponent != null) 940 && "linked".equals(((AbstractComponent)currentComponent).getData())) { 941 linked = true; 942 } 943 if (event.getClickedComponent() instanceof CmsResourceIcon) { 944 if (currentComponent == node) { 945 openTargetPage((CmsSitemapTreeNodeData)(node.getData()), linked); 946 } else if (currentComponent instanceof CmsSitemapTreeNode) { 947 break; 948 } 949 } 950 } while (currentComponent != null); 951 } 952 953 } 954 955 }); 956 Resource icon = CmsResourceIcon.getSitemapResourceIcon( 957 A_CmsUI.getCmsObject(), 958 entry.getResource(), 959 IconMode.localeCompare); 960 CmsResourceInfo info = new CmsResourceInfo( 961 entry.getClientEntry().getTitle(), 962 entry.getClientEntry().getSitePath(), 963 icon); 964 info = CmsResourceInfo.createSitemapResourceInfo( 965 entry.getResource(), 966 OpenCms.getSiteManager().getSiteForRootPath(m_localeContext.getRoot().getRootPath())); 967 info.getResourceIcon().addStyleName(OpenCmsTheme.POINTER); 968 info.getResourceIcon().setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_OPEN_PAGE_0)); 969 970 if (entry.getClientEntry().isHiddenNavigationEntry()) { 971 info.addStyleName(OpenCmsTheme.RESOURCE_INFO_WEAK); 972 } 973 final MenuBar menu = new MenuBar(); 974 boolean noTranslation = false; 975 noTranslation = entry.isMarkedNoTranslation(m_localeContext.getComparisonLocale()); 976 977 final MenuItem main = menu.addItem("", null); 978 main.setIcon(FontOpenCms.CONTEXT_MENU); 979 CssLayout rightSide = new CssLayout(); 980 info.setButtonWidget(rightSide); 981 rightSide.addComponent(menu); 982 main.setCommand(new Command() { 983 984 /** Serial version id. */ 985 private static final long serialVersionUID = 1L; 986 987 public void menuSelected(MenuItem selectedItem) { 988 989 List<I_CmsSimpleContextMenuEntry<MenuContext>> entries = Arrays.asList( 990 991 new EntryOpen(), 992 new EntryExplorer(), 993 new EntryProperties(), 994 new EntryLink(), 995 new EntryUnlink(), 996 new EntryMark(), 997 new EntryRemoveMark(), 998 new EntryCopy(), 999 new EntryInfo()); 1000 1001 MenuContext context = new MenuContext(entry, node); 1002 m_menu.setEntries(entries, context); 1003 m_menu.open(menu); 1004 1005 } 1006 1007 }); 1008 1009 menu.addStyleName("borderless o-toolbar-button o-resourceinfo-toolbar"); 1010 if (entry.isLinked()) { 1011 CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(m_localeContext.getRoot().getRootPath()); 1012 CmsResourceInfo linkedInfo = CmsResourceInfo.createSitemapResourceInfo( 1013 readSitemapEntryFolderIfPossible(entry.getLinkedResource()), 1014 site); 1015 linkedInfo.addStyleName(OpenCmsTheme.RESOURCE_INFO_DIRECTLINK); 1016 rightSide.addComponent(linkedInfo, 0); 1017 linkedInfo.setWidth(RHS_WIDTH + "px"); 1018 node.setContent(info); 1019 linkedInfo.setData("linked"); // Data used by click handler to distinguish clicked resource icons 1020 linkedInfo.getResourceIcon().setDescription( 1021 CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_OPEN_PAGE_0)); 1022 linkedInfo.getResourceIcon().addStyleName(OpenCmsTheme.POINTER); 1023 } else { 1024 if (noTranslation) { 1025 CmsResourceInfo noTranslationInfo = new CmsResourceInfo(); 1026 String topMessage = CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_NO_TRANSLATION_TOP_0); 1027 String bottomMessage = CmsVaadinUtils.getMessageText( 1028 Messages.GUI_LOCALECOMPARE_NO_TRANSLATION_BOTTOM_0); 1029 noTranslationInfo.getTopLine().setValue(topMessage); 1030 noTranslationInfo.getBottomLine().setValue(bottomMessage); 1031 noTranslationInfo.getResourceIcon().setValue( 1032 "<span class=\"" 1033 + OpenCmsTheme.RESOURCE_ICON 1034 + " " 1035 + OpenCmsTheme.NO_TRANSLATION_ICON 1036 + "\">" 1037 + FontAwesome.BAN.getHtml() 1038 + "</span>"); 1039 noTranslationInfo.addStyleName(OpenCmsTheme.RESOURCE_INFO_DIRECTLINK); 1040 noTranslationInfo.setWidth(RHS_WIDTH + "px"); 1041 rightSide.addComponent(noTranslationInfo, 0); 1042 } 1043 node.setContent(info); 1044 } 1045 1046 if (entry.hasNoChildren()) { 1047 node.setOpen(true); 1048 node.setOpenerVisible(false); 1049 } 1050 node.setData(entry); 1051 return node; 1052 1053 } 1054 1055 /** 1056 * Creates the root node of the tree.<p> 1057 * 1058 * @return the root node of the tree 1059 */ 1060 public CmsSitemapTreeNode createRootNode() { 1061 1062 m_currentRootNode = createNode(m_treeDataProvider.getRoot()); 1063 return m_currentRootNode; 1064 } 1065 1066 /** 1067 * Gets the resource corresponding to the tree's root.<p> 1068 * 1069 * @return the resource for the root node 1070 */ 1071 public CmsResource getRoot() { 1072 1073 return m_root; 1074 } 1075 1076 /** 1077 * Initializes the event handlers for a tree node widget.<p> 1078 * 1079 * @param node the node for which to initialize the event handlers 1080 */ 1081 public void initEventHandlers(final CmsSitemapTreeNode node) { 1082 1083 node.getOpener().addClickListener(new ClickListener() { 1084 1085 private static final long serialVersionUID = 1L; 1086 1087 public void buttonClick(ClickEvent event) { 1088 1089 CmsSitemapTreeController.this.onClickOpen(node); 1090 } 1091 }); 1092 } 1093 1094 /** 1095 * Called when the user clicks on the 'opener' icon of a sitemap tree entry.<p> 1096 * 1097 * @param node the sitemap node widget 1098 */ 1099 public void onClickOpen(CmsSitemapTreeNode node) { 1100 1101 if (node.isOpen()) { 1102 node.setOpen(false); 1103 } else { 1104 if (!m_alreadyLoaded.containsKey(node)) { 1105 Object nodeData = node.getData(); 1106 List<CmsSitemapTreeNodeData> children = m_treeDataProvider.getChildren( 1107 (CmsSitemapTreeNodeData)nodeData); 1108 m_alreadyLoaded.put(node, null); 1109 if (children.isEmpty()) { 1110 node.setOpenerVisible(false); 1111 } else { 1112 for (CmsSitemapTreeNodeData child : children) { 1113 CmsSitemapTreeNode childNode = createNode(child); 1114 childNode.setData(child); 1115 initEventHandlers(childNode); 1116 node.getChildren().addComponent(childNode); 1117 } 1118 } 1119 } 1120 node.setOpen(true); 1121 } 1122 } 1123 1124 /** 1125 * Opens the page copy dialog for a tree entry.<p> 1126 * 1127 * @param node the tree node widget 1128 * @param entry the tree entry 1129 */ 1130 public void openPageCopyDialog(CmsSitemapTreeNode node, CmsSitemapTreeNodeData entry) { 1131 1132 CmsObject cms = A_CmsUI.getCmsObject(); 1133 try { 1134 CmsResource resource = cms.readResource( 1135 entry.getClientEntry().getId(), 1136 CmsResourceFilter.IGNORE_EXPIRATION); 1137 DialogContext context = new DialogContext(resource, node); 1138 CmsCopyPageDialog dialog = new CmsCopyPageDialog(context); 1139 String title = CmsVaadinUtils.getMessageText(Messages.GUI_COPYPAGE_DIALOG_TITLE_0); 1140 context.start(title, dialog); 1141 } catch (CmsException e) { 1142 LOG.error(e.getLocalizedMessage(), e); 1143 CmsErrorDialog.showErrorDialog(e); 1144 } 1145 } 1146 1147 /** 1148 * Updates a sitemap node widget after the resource it corresponds to has changed.<p> 1149 * 1150 * @param node the sitemap node 1151 */ 1152 public void updateNode(CmsSitemapTreeNode node) { 1153 1154 CmsSitemapTreeNodeData data = (CmsSitemapTreeNodeData)node.getData(); 1155 try { 1156 CmsSitemapTreeNodeData changedData = m_treeDataProvider.getData( 1157 A_CmsUI.getCmsObject().readResource( 1158 data.getClientEntry().getId(), 1159 CmsResourceFilter.IGNORE_EXPIRATION)); 1160 CmsSitemapTreeNode changedNode = createNode(changedData); 1161 initEventHandlers(changedNode); 1162 ComponentContainer parent = (ComponentContainer)(node.getParent()); 1163 parent.replaceComponent(node, changedNode); 1164 } catch (CmsException e) { 1165 LOG.error(e.getLocalizedMessage(), e); 1166 } 1167 } 1168 1169 /** 1170 * Updates the tree node for the resource with the given structure id, if it exists.<p> 1171 * 1172 * @param id the structure id of a resource 1173 */ 1174 public void updateNodeForId(final CmsUUID id) { 1175 1176 final List<CmsSitemapTreeNode> nodes = Lists.newArrayList(); 1177 CmsVaadinUtils.visitDescendants(m_currentRootNode, new Predicate<Component>() { 1178 1179 public boolean apply(Component input) { 1180 1181 if (input instanceof CmsSitemapTreeNode) { 1182 CmsSitemapTreeNode node = (CmsSitemapTreeNode)input; 1183 CmsSitemapTreeNodeData data = (CmsSitemapTreeNodeData)node.getData(); 1184 if (data.getResource().getStructureId().equals(id)) { 1185 nodes.add(node); 1186 return false; 1187 } 1188 } 1189 return true; 1190 } 1191 }); 1192 if (nodes.size() == 1) { 1193 updateNode(nodes.get(0)); 1194 } 1195 1196 } 1197 1198 /** 1199 * If the given resource is the default file of a sitmeap entry folder, then returns that 1200 * folder, else the original file.<p> 1201 * 1202 * @param resource a resource 1203 * @return the resource or its parent folder 1204 */ 1205 protected CmsResource readSitemapEntryFolderIfPossible(CmsResource resource) { 1206 1207 CmsObject cms = A_CmsUI.getCmsObject(); 1208 try { 1209 if (resource.isFolder()) { 1210 return resource; 1211 } 1212 CmsResource parent = cms.readParentFolder(resource.getStructureId()); 1213 CmsResource defaultFile = cms.readDefaultFile(parent, CmsResourceFilter.IGNORE_EXPIRATION); 1214 if ((defaultFile != null) && defaultFile.equals(resource)) { 1215 return parent; 1216 } 1217 return resource; 1218 } catch (CmsException e) { 1219 LOG.error(e.getLocalizedMessage(), e); 1220 return resource; 1221 } 1222 } 1223 1224 /** 1225 * Gets the logger for the tree controller.<p> 1226 * 1227 * @return the logger 1228 */ 1229 Log getTreeControllerLog() { 1230 1231 return LOG; 1232 } 1233 1234 /** 1235 * Opens the page corresponding to a sitemap entry.<p> 1236 * 1237 * @param nodeData the node bean 1238 * @param second true if the user has clicked on the second resource box in a tree node 1239 */ 1240 private void openTargetPage(CmsSitemapTreeNodeData nodeData, boolean second) { 1241 1242 CmsUUID id = nodeData.getClientEntry().getId(); 1243 CmsUUID defaultFileId = nodeData.getClientEntry().getDefaultFileId(); 1244 CmsUUID targetId = defaultFileId; 1245 if (targetId == null) { 1246 targetId = id; 1247 } 1248 try { 1249 CmsResource resource = A_CmsUI.getCmsObject().readResource(targetId, CmsResourceFilter.IGNORE_EXPIRATION); 1250 String link = OpenCms.getLinkManager().substituteLink(A_CmsUI.getCmsObject(), resource); 1251 if (second) { 1252 resource = A_CmsUI.getCmsObject().readResource( 1253 nodeData.getLinkedResource().getStructureId(), 1254 CmsResourceFilter.IGNORE_EXPIRATION); 1255 link = OpenCms.getLinkManager().substituteLink(A_CmsUI.getCmsObject(), resource); 1256 } 1257 1258 String mySiteRoot = A_CmsUI.getCmsObject().getRequestContext().getSiteRoot(); 1259 final boolean sameSite = mySiteRoot.equals(OpenCms.getSiteManager().getSiteRoot(resource.getRootPath())); 1260 1261 if (sameSite) { 1262 A_CmsUI.get().getPage().setLocation(link); 1263 } else { 1264 String message = CmsVaadinUtils.getMessageText( 1265 Messages.GUI_LOCALECOMPARE_SHOW_WRONGSITE_1, 1266 resource.getRootPath()); 1267 1268 Notification.show(message, Type.ERROR_MESSAGE); 1269 } 1270 } catch (CmsException e) { 1271 LOG.error(e.getLocalizedMessage(), e); 1272 } 1273 1274 } 1275 1276}