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.ade.sitemap.client; 029 030import org.opencms.ade.sitemap.client.control.CmsSitemapController; 031import org.opencms.ade.sitemap.client.hoverbar.CmsSitemapHoverbar; 032import org.opencms.ade.sitemap.client.ui.css.I_CmsSitemapItemCss; 033import org.opencms.ade.sitemap.client.ui.css.I_CmsSitemapLayoutBundle; 034import org.opencms.ade.sitemap.shared.CmsClientSitemapEntry; 035import org.opencms.ade.sitemap.shared.CmsClientSitemapEntry.EntryType; 036import org.opencms.ade.sitemap.shared.CmsDetailPageTable; 037import org.opencms.ade.sitemap.shared.CmsSitemapData.EditorMode; 038import org.opencms.file.CmsResource; 039import org.opencms.gwt.client.CmsCoreProvider; 040import org.opencms.gwt.client.dnd.I_CmsDragHandle; 041import org.opencms.gwt.client.dnd.I_CmsDropTarget; 042import org.opencms.gwt.client.property.CmsReloadMode; 043import org.opencms.gwt.client.ui.CmsAlertDialog; 044import org.opencms.gwt.client.ui.CmsListItemWidget; 045import org.opencms.gwt.client.ui.CmsListItemWidget.Background; 046import org.opencms.gwt.client.ui.CmsListItemWidget.I_CmsTitleEditHandler; 047import org.opencms.gwt.client.ui.css.I_CmsInputLayoutBundle; 048import org.opencms.gwt.client.ui.input.CmsLabel; 049import org.opencms.gwt.client.ui.input.CmsLabel.I_TitleGenerator; 050import org.opencms.gwt.client.ui.tree.CmsLazyTreeItem; 051import org.opencms.gwt.client.ui.tree.CmsTreeItem; 052import org.opencms.gwt.client.util.CmsMessages; 053import org.opencms.gwt.client.util.CmsStyleVariable; 054import org.opencms.gwt.client.util.I_CmsSimpleCallback; 055import org.opencms.gwt.shared.CmsAdditionalInfoBean; 056import org.opencms.gwt.shared.CmsListInfoBean; 057import org.opencms.gwt.shared.CmsListInfoBean.LockIcon; 058import org.opencms.gwt.shared.CmsListInfoBean.StateIcon; 059import org.opencms.gwt.shared.property.CmsClientProperty; 060import org.opencms.gwt.shared.property.CmsPropertyModification; 061import org.opencms.util.CmsStringUtil; 062import org.opencms.util.CmsUUID; 063 064import java.util.ArrayList; 065import java.util.HashMap; 066import java.util.List; 067import java.util.Map; 068 069import com.google.gwt.core.client.Scheduler; 070import com.google.gwt.core.client.Scheduler.RepeatingCommand; 071import com.google.gwt.dom.client.Element; 072import com.google.gwt.event.dom.client.ClickEvent; 073import com.google.gwt.event.dom.client.ClickHandler; 074import com.google.gwt.event.logical.shared.OpenEvent; 075import com.google.gwt.event.logical.shared.OpenHandler; 076import com.google.gwt.user.client.ui.Label; 077import com.google.gwt.user.client.ui.TextBox; 078import com.google.gwt.user.client.ui.Widget; 079 080/** 081 * Sitemap entry tree item implementation.<p> 082 * 083 * @since 8.0.0 084 * 085 * @see org.opencms.gwt.client.ui.tree.CmsLazyTreeItem 086 * @see org.opencms.ade.sitemap.shared.CmsClientSitemapEntry 087 */ 088public class CmsSitemapTreeItem extends CmsLazyTreeItem { 089 090 /** 091 * Label generator for the detail page info label.<p> 092 */ 093 protected class DetailPageLabelTitleGenerator implements I_TitleGenerator { 094 095 /** The title to use for the detail page label.*/ 096 private String m_detailPageTitle; 097 098 /** 099 * @see org.opencms.gwt.client.ui.input.CmsLabel.I_TitleGenerator#getTitle(java.lang.String) 100 */ 101 public String getTitle(String originalText) { 102 103 return m_detailPageTitle; 104 } 105 106 /** 107 * Sets the title to use for the detail page label. 108 * 109 * @param detailPageTitle the title to use 110 */ 111 public void setDetailPageTitle(String detailPageTitle) { 112 113 m_detailPageTitle = detailPageTitle; 114 } 115 } 116 117 /** The CSS bundle used by this widget. */ 118 private static final I_CmsSitemapItemCss CSS = I_CmsSitemapLayoutBundle.INSTANCE.sitemapItemCss(); 119 120 /** A map of sitemap tree items by entry id. */ 121 private static Map<CmsUUID, CmsSitemapTreeItem> m_itemsById = new HashMap<CmsUUID, CmsSitemapTreeItem>(); 122 123 /** The current sitemap entry id. */ 124 protected CmsUUID m_entryId; 125 126 /** The detail page label title generator. */ 127 private DetailPageLabelTitleGenerator m_detailPageLabelTitleGenerator; 128 129 /** Style variable for to toggle in navigation style. */ 130 private CmsStyleVariable m_inNavigationStyle; 131 132 /** Style variable for opener. */ 133 private CmsStyleVariable m_openerForNonNavigationStyle; 134 135 /** Style variable for switching between 'children / no children' styles. */ 136 private CmsStyleVariable m_styleHasChildren = new CmsStyleVariable(this); 137 138 /** Style variable for switching between 'navigation children / no navigation children' styles. */ 139 private CmsStyleVariable m_styleHasNavChildren = new CmsStyleVariable(this); 140 141 /** 142 * Default constructor.<p> 143 * 144 * @param entry the sitemap entry 145 */ 146 public CmsSitemapTreeItem(CmsClientSitemapEntry entry) { 147 148 super(generateItemWidget(entry), false); 149 m_opener.addStyleName(CSS.treeItemOpener()); 150 m_styleHasChildren.setValue(CSS.hasChildren()); 151 m_styleHasNavChildren.setValue(CSS.hasNavChildren()); 152 m_entryId = entry.getId(); 153 m_decoratedPanel.addDecorationBoxStyle(CSS.sitemapEntryDecoration()); 154 m_detailPageLabelTitleGenerator = new DetailPageLabelTitleGenerator(); 155 getListItemWidget().setUnselectable(); 156 getListItemWidget().addOpenHandler(new OpenHandler<CmsListItemWidget>() { 157 158 public void onOpen(OpenEvent<CmsListItemWidget> event) { 159 160 CmsSitemapView.getInstance().getController().updateSingleEntry(m_entryId); 161 } 162 }); 163 getListItemWidget().addIconClickHandler(new ClickHandler() { 164 165 public void onClick(ClickEvent event) { 166 167 CmsSitemapController controller = CmsSitemapView.getInstance().getController(); 168 CmsClientSitemapEntry sitemapEntry = controller.getEntryById(m_entryId); 169 if (sitemapEntry != null) { 170 if (sitemapEntry.isSubSitemapType()) { 171 controller.openSiteMap(sitemapEntry.getSitePath()); 172 } else if (sitemapEntry.isNavigationLevelType()) { 173 if (!sitemapEntry.getSubEntries().isEmpty()) { 174 CmsClientSitemapEntry subEntry = sitemapEntry.getSubEntries().get(0); 175 if (!subEntry.isNavigationLevelType()) { 176 controller.leaveEditor(subEntry.getSitePath()); 177 return; 178 } 179 } 180 getListItemWidget().setIconTitle( 181 Messages.get().key(Messages.GUI_NAVIGATION_LEVEL_UNKOWN_TARGET_0)); 182 } else { 183 controller.leaveEditor(sitemapEntry.getSitePath()); 184 } 185 } 186 } 187 }); 188 m_inNavigationStyle = new CmsStyleVariable(this); 189 m_openerForNonNavigationStyle = new CmsStyleVariable(m_opener); 190 getListItemWidget().addTitleStyleName(CSS.itemTitle()); 191 updateInNavigation(entry); 192 m_itemsById.put(m_entryId, this); 193 setId(getName(entry.getSitePath())); 194 updateSitePath(entry.getSitePath()); 195 updateDetailPageStatus(); 196 updateLock(entry); 197 if (!entry.isFolderType()) { 198 hideOpeners(); 199 } 200 setDropEnabled(entry.isFolderType() && !entry.hasForeignFolderLock()); 201 getListItemWidget().setTitleEditHandler(new I_CmsTitleEditHandler() { 202 203 /** 204 * @see org.opencms.gwt.client.ui.CmsListItemWidget.I_CmsTitleEditHandler#handleEdit(org.opencms.gwt.client.ui.input.CmsLabel, com.google.gwt.user.client.ui.TextBox) 205 */ 206 public void handleEdit(CmsLabel titleLabel, TextBox box) { 207 208 final CmsClientSitemapEntry editEntry = getSitemapEntry(); 209 final String newTitle = box.getText(); 210 box.removeFromParent(); 211 if (CmsStringUtil.isEmpty(newTitle)) { 212 titleLabel.setVisible(true); 213 String dialogTitle = Messages.get().key(Messages.GUI_EDIT_TITLE_ERROR_DIALOG_TITLE_0); 214 String dialogText = Messages.get().key(Messages.GUI_TITLE_CANT_BE_EMPTY_0); 215 CmsAlertDialog alert = new CmsAlertDialog(dialogTitle, dialogText); 216 alert.center(); 217 return; 218 } 219 String oldTitle = editEntry.getTitle(); 220 if (!oldTitle.equals(newTitle)) { 221 CmsPropertyModification propMod = new CmsPropertyModification( 222 editEntry.getId(), 223 CmsClientProperty.PROPERTY_NAVTEXT, 224 newTitle, 225 true); 226 final List<CmsPropertyModification> propChanges = new ArrayList<CmsPropertyModification>(); 227 propChanges.add(propMod); 228 final CmsSitemapController controller = CmsSitemapView.getInstance().getController(); 229 if (editEntry.isNew() && !editEntry.isRoot() && !oldTitle.equalsIgnoreCase(newTitle)) { 230 if (oldTitle.equals(editEntry.getPropertyValue(CmsClientProperty.PROPERTY_TITLE))) { 231 CmsPropertyModification titleMod = new CmsPropertyModification( 232 editEntry.getId(), 233 CmsClientProperty.PROPERTY_TITLE, 234 newTitle, 235 true); 236 propChanges.add(titleMod); 237 } 238 controller.ensureUniqueName( 239 CmsResource.getParentFolder(editEntry.getSitePath()), 240 newTitle, 241 new I_CmsSimpleCallback<String>() { 242 243 public void execute(String urlName) { 244 245 controller.editAndChangeName( 246 editEntry, 247 urlName, 248 propChanges, 249 true, 250 CmsReloadMode.reloadEntry); 251 } 252 }); 253 } else { 254 controller.edit(editEntry, propChanges, CmsReloadMode.reloadEntry); 255 } 256 } 257 titleLabel.setVisible(true); 258 } 259 }); 260 } 261 262 /** 263 * Looks up a sitemap tree item by entry id.<p> 264 * 265 * @param id the sitemap entry id 266 * @return the corresponding sitemap tree item, or null if there is none 267 */ 268 public static CmsSitemapTreeItem getItemById(CmsUUID id) { 269 270 return m_itemsById.get(id); 271 } 272 273 /** 274 * Helper method to add an additional info bean to a list.<p> 275 * 276 * @param infos the list of additional info beans 277 * @param label the label for the new bean 278 * @param value the value for the new bean 279 */ 280 protected static void addInfo(List<CmsAdditionalInfoBean> infos, String label, String value) { 281 282 infos.add(new CmsAdditionalInfoBean(label, value, null)); 283 } 284 285 /** 286 * Returns the list info bean for the given entry.<p> 287 * 288 * @param entry the sitemap entry 289 * @param navMode a flag indicating whether we want the info bean for navigation mode or VFS mode 290 * 291 * @return the list info bean 292 */ 293 static CmsListInfoBean getInfoBean(CmsClientSitemapEntry entry, boolean navMode) { 294 295 CmsListInfoBean infoBean = new CmsListInfoBean(); 296 infoBean.setTitle(entry.getTitle()); 297 infoBean.setSubTitle(entry.getSitePath()); 298 // showing the resource type icon of the default file in navigation mode 299 infoBean.setResourceType( 300 CmsStringUtil.isNotEmptyOrWhitespaceOnly(entry.getDefaultFileType()) 301 ? entry.getDefaultFileType() 302 : entry.getResourceTypeName()); 303 infoBean.setResourceState(entry.getResourceState()); 304 CmsMessages msg = Messages.get(); 305 List<CmsAdditionalInfoBean> infos = new ArrayList<CmsAdditionalInfoBean>(); 306 addInfo(infos, msg.key(Messages.GUI_NAME_0), entry.getName()); 307 308 boolean isTitleSet = false; 309 if (navMode) { 310 // in nav mode, display the title of the page rather than that of the folder, if available 311 Map<String, CmsClientProperty> defaultFileProps = entry.getDefaultFileProperties(); 312 CmsClientProperty titleProperty = defaultFileProps == null 313 ? null 314 : defaultFileProps.get(CmsClientProperty.PROPERTY_TITLE); 315 if ((titleProperty != null) && !titleProperty.isEmpty()) { 316 addInfo(infos, msg.key(Messages.GUI_TITLE_PROPERTY_0), titleProperty.getEffectiveValue()); 317 isTitleSet = true; 318 } 319 } 320 if (!isTitleSet) { 321 CmsClientProperty titleProperty = entry.getOwnProperties().get(CmsClientProperty.PROPERTY_TITLE); 322 if ((titleProperty != null) && !titleProperty.isEmpty()) { 323 addInfo(infos, msg.key(Messages.GUI_TITLE_PROPERTY_0), titleProperty.getEffectiveValue()); 324 isTitleSet = true; 325 } 326 } 327 328 String shownPath = entry.getVfsPath(); 329 if (CmsStringUtil.isEmptyOrWhitespaceOnly(shownPath)) { 330 shownPath = "-"; 331 } 332 addInfo(infos, msg.key(Messages.GUI_VFS_PATH_0), shownPath); 333 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(entry.getDateReleased())) { 334 addInfo(infos, msg.key(Messages.GUI_LABEL_DATE_RELEASED_0), entry.getDateReleased()); 335 336 } 337 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(entry.getDateExpired())) { 338 addInfo(infos, msg.key(Messages.GUI_LABEL_DATE_EXPIRED_0), entry.getDateExpired()); 339 340 } 341 if (entry.getEntryType() == EntryType.redirect) { 342 addInfo(infos, msg.key(Messages.GUI_LABEL_TARGET_0), entry.getRedirectTarget()); 343 344 } 345 if (entry.getAliases() != null) { 346 int counter = 1; 347 for (String aliasPath : entry.getAliases()) { 348 addInfo(infos, msg.key(Messages.GUI_LABEL_ALIAS_1, counter + ""), aliasPath); 349 counter += 1; 350 } 351 } 352 infoBean.setAdditionalInfo(infos); 353 return infoBean; 354 } 355 356 /** 357 * Generates the list item widget for the tree item.<p> 358 * 359 * @param entry the sitemap entry 360 * 361 * @return the list item widget 362 */ 363 private static CmsListItemWidget generateItemWidget(final CmsClientSitemapEntry entry) { 364 365 CmsListInfoBean infoBean = getInfoBean(entry, true); 366 final CmsListItemWidget itemWidget = new CmsListItemWidget(infoBean); 367 itemWidget.setUnselectable(); 368 itemWidget.setIcon(CmsSitemapView.getInstance().getIconForEntry(entry)); 369 itemWidget.setTopRightIcon(null, ""); 370 itemWidget.setIconTitle( 371 entry.isSubSitemapType() 372 ? Messages.get().key(Messages.GUI_HOVERBAR_GOTO_SUB_0) 373 : Messages.get().key(Messages.GUI_HOVERBAR_GOTO_0)); 374 setAdditionalStyles(entry, itemWidget); 375 return itemWidget; 376 } 377 378 /** 379 * Sets the additional style to mark expired entries or those that have the hide in navigation property set.<p> 380 * 381 * @param entry the sitemap entry 382 * @param itemWidget the item widget 383 */ 384 private static void setAdditionalStyles(CmsClientSitemapEntry entry, CmsListItemWidget itemWidget) { 385 386 if (!entry.isResleasedAndNotExpired() 387 || ((CmsSitemapView.getInstance().getEditorMode() == EditorMode.navigation) 388 && !entry.isDefaultFileReleased())) { 389 itemWidget.getContentPanel().addStyleName( 390 I_CmsSitemapLayoutBundle.INSTANCE.sitemapItemCss().expiredOrNotReleased()); 391 } else { 392 itemWidget.getContentPanel().removeStyleName( 393 I_CmsSitemapLayoutBundle.INSTANCE.sitemapItemCss().expiredOrNotReleased()); 394 } 395 if (entry.isHiddenNavigationEntry()) { 396 itemWidget.getContentPanel().addStyleName( 397 I_CmsSitemapLayoutBundle.INSTANCE.sitemapItemCss().hiddenNavEntry()); 398 } else { 399 itemWidget.getContentPanel().removeStyleName( 400 I_CmsSitemapLayoutBundle.INSTANCE.sitemapItemCss().hiddenNavEntry()); 401 } 402 } 403 404 /** 405 * Given the path of a sitemap entry, this method returns the URL which should be displayed to the user.<p> 406 * 407 * @param sitePath the site path of a sitemap entry 408 * 409 * @return the URL which should be displayed to the user 410 */ 411 public String getDisplayedUrl(String sitePath) { 412 413 if (getSitemapEntry().isLeafType() && sitePath.endsWith("/")) { 414 sitePath = sitePath.substring(0, sitePath.length() - 1); 415 } 416 CmsSitemapController controller = CmsSitemapView.getInstance().getController(); 417 String exportProp = controller.getEffectiveProperty(getSitemapEntry(), "export"); 418 if ("true".equals(exportProp)) { 419 String exportName = getSitemapEntry().getExportName(); 420 if (exportName == null) { 421 exportName = CmsCoreProvider.get().getSiteRoot(); 422 } 423 String rfsPrefix = CmsSitemapView.getInstance().getController().getData().getExportRfsPrefix(); 424 if (rfsPrefix != null) { 425 return CmsStringUtil.joinPaths(rfsPrefix, exportName, sitePath); 426 } 427 } 428 return CmsCoreProvider.get().link(sitePath); 429 } 430 431 /** 432 * @see org.opencms.gwt.client.dnd.I_CmsDraggable#getDragHelper(I_CmsDropTarget) 433 */ 434 @Override 435 public Element getDragHelper(I_CmsDropTarget target) { 436 437 Element helper = super.getDragHelper(target); 438 // ensure the proper CSS context for the drag helper 439 m_provisionalParent.addClassName(I_CmsSitemapLayoutBundle.INSTANCE.sitemapItemCss().navMode()); 440 return helper; 441 } 442 443 /** 444 * Returns the entry id.<p> 445 * 446 * @return the entry id 447 */ 448 public CmsUUID getEntryId() { 449 450 return m_entryId; 451 } 452 453 /** 454 * @see org.opencms.gwt.client.ui.CmsListItem#getMoveHandle() 455 */ 456 @Override 457 public I_CmsDragHandle getMoveHandle() { 458 459 CmsSitemapHoverbar hoverbar = getHoverbar(); 460 if (hoverbar != null) { 461 int count = hoverbar.getWidgetCount(); 462 if (count > 0) { 463 for (int i = 0; i < count; i++) { 464 Widget w = hoverbar.getWidget(i); 465 if (w instanceof I_CmsDragHandle) { 466 return (I_CmsDragHandle)w; 467 } 468 } 469 } 470 } 471 return null; 472 } 473 474 /** 475 * @see org.opencms.gwt.client.ui.tree.CmsTreeItem#getPath() 476 */ 477 @Override 478 public String getPath() { 479 480 String result = getSitePath(); 481 // ensure that the path of a folder ends with a '/' 482 if (getSitemapEntry().isFolderType() && !result.endsWith("/")) { 483 result += "/"; 484 } 485 return result; 486 } 487 488 /** 489 * Returns the sitemap entry.<p> 490 * 491 * @return the sitemap entry 492 */ 493 public CmsClientSitemapEntry getSitemapEntry() { 494 495 return CmsSitemapView.getInstance().getController().getEntryById(m_entryId); 496 } 497 498 /** 499 * Returns the site path.<p> 500 * 501 * @return the site path 502 */ 503 public String getSitePath() { 504 505 return getSitemapEntry().getSitePath(); 506 } 507 508 /** 509 * Turns the highlighting for this item on or off.<p> 510 * 511 * @param highlightOn if true, the highlighting is turned on, else off 512 */ 513 public void highlight(boolean highlightOn) { 514 515 if (highlightOn) { 516 setBackgroundColor(Background.YELLOW); 517 } else { 518 setBackgroundColor(Background.DEFAULT); 519 } 520 } 521 522 /** 523 * Temporarily highlights an item.<p> 524 * 525 * @param duration the duration for which 526 * @param background the background to color to set when finished 527 */ 528 public void highlightTemporarily(int duration, final Background background) { 529 530 int blinkInterval = 300; 531 final int blinkCount = duration / blinkInterval; 532 533 Scheduler.get().scheduleFixedPeriod(new RepeatingCommand() { 534 535 private int m_counter; 536 537 /** 538 * @see com.google.gwt.core.client.Scheduler.RepeatingCommand#execute() 539 */ 540 public boolean execute() { 541 542 boolean finish = m_counter > blinkCount; 543 highlight(((m_counter % 2) == 0) && !finish); 544 m_counter += 1; 545 if (finish) { 546 setBackgroundColor(background); 547 } 548 return !finish; 549 } 550 }, blinkInterval); 551 } 552 553 /** 554 * @see org.opencms.gwt.client.ui.tree.CmsTreeItem#isDropEnabled() 555 */ 556 @Override 557 public boolean isDropEnabled() { 558 559 CmsClientSitemapEntry entry = getSitemapEntry(); 560 return !entry.hasForeignFolderLock() && entry.isInNavigation() && entry.isFolderType() && super.isDropEnabled(); 561 } 562 563 /** 564 * @see org.opencms.gwt.client.dnd.I_CmsDraggable#onDragCancel() 565 */ 566 @Override 567 public void onDragCancel() { 568 569 removeStyleName(I_CmsSitemapLayoutBundle.INSTANCE.sitemapItemCss().positionIndicator()); 570 super.onDragCancel(); 571 } 572 573 /** 574 * @see org.opencms.gwt.client.dnd.I_CmsDraggable#onDrop(org.opencms.gwt.client.dnd.I_CmsDropTarget) 575 */ 576 @Override 577 public void onDrop(I_CmsDropTarget target) { 578 579 removeStyleName(I_CmsSitemapLayoutBundle.INSTANCE.sitemapItemCss().positionIndicator()); 580 super.onDrop(target); 581 } 582 583 /** 584 * @see org.opencms.gwt.client.ui.CmsListItem#onStartDrag(org.opencms.gwt.client.dnd.I_CmsDropTarget) 585 */ 586 @Override 587 public void onStartDrag(I_CmsDropTarget target) { 588 589 setOpen(false); 590 // transform the widget into a position indicator 591 addStyleName(I_CmsSitemapLayoutBundle.INSTANCE.sitemapItemCss().positionIndicator()); 592 CmsSitemapHoverbar hoverbar = getHoverbar(); 593 if (hoverbar != null) { 594 hoverbar.hide(); 595 } 596 } 597 598 /** 599 * Resets entry appearance.<p> 600 */ 601 public void resetEntry() { 602 603 updateEntry(getSitemapEntry()); 604 } 605 606 /** 607 * Sets the background color of the list item widget.<p> 608 * 609 * If the background is <code>null</code>, the widget will be shown with its default style.<p> 610 * 611 * @param background the background color to set 612 */ 613 public void setBackgroundColor(Background background) { 614 615 getListItemWidget().setBackground(background); 616 } 617 618 /** 619 * Sets the icon.<p> 620 * 621 * @param icon the icon to set 622 */ 623 public void setStateIcon(StateIcon icon) { 624 625 getListItemWidget().setStateIcon(icon); 626 } 627 628 /** 629 * @see com.google.gwt.user.client.ui.UIObject#toString() 630 */ 631 @Override 632 public String toString() { 633 634 StringBuffer sb = new StringBuffer(); 635 sb.append(getSitemapEntry().getSitePath()).append("\n"); 636 for (int i = 0; i < getChildCount(); i++) { 637 CmsTreeItem child = getChild(i); 638 if (child instanceof CmsLazyTreeItem.LoadingItem) { 639 continue; 640 } 641 sb.append(child.toString()); 642 } 643 return sb.toString(); 644 } 645 646 /** 647 * Updates the detail page description.<p> 648 */ 649 public void updateDetailPageStatus() { 650 651 CmsDetailPageTable detailPageTable = CmsSitemapView.getInstance().getController().getDetailPageTable(); 652 String type; 653 String text = null; 654 String suffixTitle = null; 655 switch (detailPageTable.getStatus(m_entryId)) { 656 case firstDetailPage: 657 type = detailPageTable.get(m_entryId).getDisplayType(); 658 suffixTitle = Messages.get().key(Messages.GUI_MAIN_DETAIL_PAGE_TITLE_1, type); 659 text = "(*" + type + ")"; 660 break; 661 case otherDetailPage: 662 type = detailPageTable.get(m_entryId).getDisplayType(); 663 suffixTitle = Messages.get().key(Messages.GUI_DETAIL_PAGE_TITLE_1, type); 664 text = "(" + type + ")"; 665 break; 666 case noDetailPage: 667 default: 668 } 669 m_detailPageLabelTitleGenerator.setDetailPageTitle(suffixTitle); 670 getListItemWidget().updateTruncation(); 671 Widget label = getListItemWidget().getShortExtraInfoLabel(); 672 label.addStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().subtitleSuffix()); 673 getListItemWidget().setExtraInfo(text); 674 } 675 676 /** 677 * Updates the sitemap editor mode.<p> 678 */ 679 public void updateEditorMode() { 680 681 CmsClientSitemapEntry entry = getSitemapEntry(); 682 getListItemWidget().setIcon(CmsSitemapView.getInstance().getIconForEntry(entry)); 683 setAdditionalStyles(entry, getListItemWidget()); 684 for (Widget child : m_children) { 685 if (child instanceof CmsSitemapTreeItem) { 686 ((CmsSitemapTreeItem)child).updateEditorMode(); 687 } 688 } 689 } 690 691 /** 692 * Refreshes the displayed data from the given sitemap entry.<p> 693 * 694 * @param entry the sitemap entry to update 695 */ 696 public void updateEntry(CmsClientSitemapEntry entry) { 697 698 getListItemWidget().setTitleLabel(entry.getTitle()); 699 getListItemWidget().reInitAdditionalInfo(getInfoBean(entry, CmsSitemapView.getInstance().isNavigationMode())); 700 updateSitePath(entry.getSitePath()); 701 updateDetailPageStatus(); 702 updateLock(entry); 703 updateInNavigation(entry); 704 getListItemWidget().setIcon(CmsSitemapView.getInstance().getIconForEntry(entry)); 705 setAdditionalStyles(entry, getListItemWidget()); 706 setDropEnabled(getSitemapEntry().isFolderType() && !getSitemapEntry().hasForeignFolderLock()); 707 if (entry.isSubSitemapType() || entry.isLeafType()) { 708 hideOpeners(); 709 } else { 710 showOpeners(); 711 } 712 getListItemWidget().updateTruncation(); 713 } 714 715 /** 716 * Updates the in navigation properties of the displayed entry.<p> 717 * 718 * @param entry the sitemap entry 719 */ 720 public void updateInNavigation(CmsClientSitemapEntry entry) { 721 722 if (entry.isInNavigation()) { 723 m_inNavigationStyle.setValue(null); 724 getListItemWidget().setTitleEditable(true); 725 } else { 726 m_inNavigationStyle.setValue(CSS.notInNavigationEntry()); 727 getListItemWidget().setTitleEditable(false); 728 } 729 } 730 731 /** 732 * Updates the site path using the current site entry's data.<p> 733 */ 734 public void updateSitePath() { 735 736 updateSitePath(getSitemapEntry().getSitePath()); 737 } 738 739 /** 740 * Updates the recursively the site path.<p> 741 * 742 * @param sitePath the new site path to set 743 */ 744 public void updateSitePath(String sitePath) { 745 746 String newSubTitle = getDisplayedUrl(sitePath); 747 removeInvalidChildren(); 748 getListItemWidget().setSubtitleLabel(newSubTitle); 749 String name = getName(sitePath); 750 setId(name); 751 getListItemWidget().setAdditionalInfoValue(1, name); 752 if (getLoadState() == LoadState.LOADED) { 753 for (int i = 0; i < getChildCount(); i++) { 754 CmsSitemapTreeItem item = (CmsSitemapTreeItem)getChild(i); 755 if ((item != null) 756 && (CmsSitemapView.getInstance().getController().getEntryById(item.getEntryId()) != null)) { 757 String path = CmsStringUtil.joinPaths(sitePath, CmsResource.getName(item.getSitePath())); 758 item.updateSitePath(path); 759 } 760 } 761 } 762 getListItemWidget().updateTruncation(); 763 } 764 765 /** 766 * Helper method for adding the marker widget.<p> 767 * 768 * @param text the text for the marker widget 769 * 770 * @return the new marker widget 771 */ 772 protected Widget addMarker(String text) { 773 774 Label label = new Label(text); 775 label.addStyleName(CSS.marker()); 776 getListItemWidget().addButton(label); 777 return label; 778 } 779 780 /** 781 * Return the name of this item, which can differ from the entry name for root nodes.<p> 782 * 783 * @param sitePath the sitemap entry's site path 784 * 785 * @return the name 786 */ 787 protected String getName(String sitePath) { 788 789 String name = CmsResource.getName(sitePath); 790 if (name.endsWith("/")) { 791 name = name.substring(0, name.length() - 1); 792 } 793 return name; 794 795 } 796 797 /** 798 * @see org.opencms.gwt.client.ui.tree.CmsLazyTreeItem#onChangeChildren() 799 */ 800 @Override 801 protected void onChangeChildren() { 802 803 super.onChangeChildren(); 804 805 if (m_openerForNonNavigationStyle == null) { 806 // happens when initializing 807 return; 808 } 809 removeInvalidChildren(); 810 boolean hasChildren = false; 811 boolean hasNavChildren = false; 812 for (Widget childWidget : m_children) { 813 if (childWidget instanceof CmsSitemapTreeItem) { 814 hasChildren = true; 815 CmsSitemapTreeItem treeItem = (CmsSitemapTreeItem)childWidget; 816 if (treeItem.getSitemapEntry().isInNavigation()) { 817 hasNavChildren = true; 818 break; // both flags set to true, no more iterations needed 819 } 820 } 821 } 822 m_styleHasChildren.setValue(hasChildren ? CSS.hasChildren() : CSS.hasNoChildren()); 823 m_styleHasNavChildren.setValue(hasNavChildren ? CSS.hasNavChildren() : CSS.hasNoNavChildren()); 824 } 825 826 /** 827 * Helper method to remove invalid children that don't have a corresponding CmsSitemapClientEntry. 828 */ 829 protected void removeInvalidChildren() { 830 831 if (getLoadState() == LoadState.LOADED) { 832 List<CmsSitemapTreeItem> toDelete = new ArrayList<CmsSitemapTreeItem>(); 833 for (int i = 0; i < getChildCount(); i++) { 834 CmsSitemapTreeItem item = (CmsSitemapTreeItem)getChild(i); 835 CmsUUID id = item.getEntryId(); 836 if ((id != null) && (CmsSitemapView.getInstance().getController().getEntryById(id) == null)) { 837 toDelete.add(item); 838 } 839 } 840 for (CmsSitemapTreeItem deleteItem : toDelete) { 841 m_children.removeItem(deleteItem); 842 } 843 } 844 } 845 846 /** 847 * Retrieves the hoverbar, can be <code>null</code> if not attached.<p> 848 * 849 * @return the hoverbar, or <code>null</code> if not attached 850 */ 851 private CmsSitemapHoverbar getHoverbar() { 852 853 for (Widget w : getListItemWidget().getContentPanel()) { 854 if (!(w instanceof CmsSitemapHoverbar)) { 855 continue; 856 } 857 return (CmsSitemapHoverbar)w; 858 } 859 return null; 860 } 861 862 /** 863 * Updates the lock icon according to the entry information.<p> 864 * 865 * @param entry the entry 866 */ 867 private void updateLock(CmsClientSitemapEntry entry) { 868 869 LockIcon icon = LockIcon.NONE; 870 String iconTitle = null; 871 if (entry.hasBlockingLockedChildren()) { 872 icon = LockIcon.CLOSED; 873 iconTitle = Messages.get().key(Messages.GUI_BLOCKING_LOCKED_CHILDREN_0); 874 } 875 if (!entry.getLock().isOwnedByUser()) { 876 switch (entry.getLock().getLockType()) { 877 case EXCLUSIVE: 878 case INHERITED: 879 case TEMPORARY: 880 icon = LockIcon.CLOSED; 881 break; 882 case SHARED_EXCLUSIVE: 883 case SHARED_INHERITED: 884 icon = LockIcon.SHARED_CLOSED; 885 break; 886 default: 887 } 888 } else { 889 switch (entry.getLock().getLockType()) { 890 case EXCLUSIVE: 891 case INHERITED: 892 case TEMPORARY: 893 icon = LockIcon.OPEN; 894 break; 895 case SHARED_EXCLUSIVE: 896 case SHARED_INHERITED: 897 icon = LockIcon.SHARED_OPEN; 898 break; 899 default: 900 } 901 } 902 if (entry.getLock().getLockOwner() != null) { 903 iconTitle = org.opencms.gwt.client.Messages.get().key( 904 org.opencms.gwt.client.Messages.GUI_LOCK_OWNED_BY_1, 905 entry.getLock().getLockOwner()); 906 } 907 908 getListItemWidget().setLockIcon(icon, iconTitle); 909 } 910}