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; 029 030import org.opencms.db.CmsUserSettings; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsProject; 033import org.opencms.file.CmsResource; 034import org.opencms.file.CmsResourceFilter; 035import org.opencms.file.CmsVfsResourceNotFoundException; 036import org.opencms.main.CmsException; 037import org.opencms.main.CmsLog; 038import org.opencms.main.OpenCms; 039import org.opencms.security.CmsPermissionSet; 040import org.opencms.site.CmsSiteManagerImpl; 041import org.opencms.ui.A_CmsUI; 042import org.opencms.ui.CmsVaadinUtils; 043import org.opencms.ui.FontOpenCms; 044import org.opencms.ui.I_CmsDialogContext; 045import org.opencms.ui.I_CmsDialogContext.ContextType; 046import org.opencms.ui.I_CmsUpdateListener; 047import org.opencms.ui.actions.CmsCopyDialogAction; 048import org.opencms.ui.actions.CmsPropertiesDialogAction; 049import org.opencms.ui.actions.I_CmsWorkplaceAction; 050import org.opencms.ui.components.A_CmsFocusShortcutListener; 051import org.opencms.ui.components.CmsErrorDialog; 052import org.opencms.ui.components.CmsExtendedSiteSelector; 053import org.opencms.ui.components.CmsFileTable; 054import org.opencms.ui.components.CmsResourceIcon; 055import org.opencms.ui.components.CmsResourceTableProperty; 056import org.opencms.ui.components.CmsToolBar; 057import org.opencms.ui.components.CmsUploadButton; 058import org.opencms.ui.components.CmsUploadButton.I_UploadListener; 059import org.opencms.ui.components.I_CmsWindowCloseListener; 060import org.opencms.ui.components.OpenCmsTheme; 061import org.opencms.ui.components.extensions.CmsUploadAreaExtension; 062import org.opencms.ui.contextmenu.CmsResourceContextMenuBuilder; 063import org.opencms.ui.dialogs.CmsCopyMoveDialog; 064import org.opencms.ui.dialogs.CmsDeleteDialog; 065import org.opencms.ui.dialogs.CmsNewDialog; 066import org.opencms.util.CmsStringUtil; 067import org.opencms.util.CmsUUID; 068import org.opencms.workplace.CmsWorkplace; 069import org.opencms.workplace.explorer.CmsResourceUtil; 070 071import java.util.ArrayList; 072import java.util.Arrays; 073import java.util.Collection; 074import java.util.Collections; 075import java.util.HashMap; 076import java.util.HashSet; 077import java.util.List; 078import java.util.Map; 079import java.util.Set; 080 081import org.apache.commons.lang.RandomStringUtils; 082import org.apache.commons.logging.Log; 083 084import com.google.common.collect.Lists; 085import com.google.common.collect.Sets; 086import com.vaadin.event.Action; 087import com.vaadin.event.FieldEvents.BlurEvent; 088import com.vaadin.event.FieldEvents.FocusEvent; 089import com.vaadin.event.ShortcutAction; 090import com.vaadin.event.ShortcutAction.KeyCode; 091import com.vaadin.event.dd.DragAndDropEvent; 092import com.vaadin.event.dd.DropHandler; 093import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; 094import com.vaadin.event.dd.acceptcriteria.ServerSideCriterion; 095import com.vaadin.navigator.ViewChangeListener; 096import com.vaadin.server.Page; 097import com.vaadin.server.Sizeable.Unit; 098import com.vaadin.ui.Button; 099import com.vaadin.ui.Button.ClickEvent; 100import com.vaadin.ui.Button.ClickListener; 101import com.vaadin.ui.CssLayout; 102import com.vaadin.ui.HorizontalSplitPanel; 103import com.vaadin.ui.Notification; 104import com.vaadin.ui.UI; 105import com.vaadin.ui.themes.ValoTheme; 106import com.vaadin.v7.data.Container; 107import com.vaadin.v7.data.Item; 108import com.vaadin.v7.data.Property.ValueChangeEvent; 109import com.vaadin.v7.data.Property.ValueChangeListener; 110import com.vaadin.v7.data.util.BeanItemContainer; 111import com.vaadin.v7.data.util.HierarchicalContainer; 112import com.vaadin.v7.event.FieldEvents.TextChangeEvent; 113import com.vaadin.v7.event.FieldEvents.TextChangeListener; 114import com.vaadin.v7.event.ItemClickEvent; 115import com.vaadin.v7.event.ItemClickEvent.ItemClickListener; 116import com.vaadin.v7.shared.ui.combobox.FilteringMode; 117import com.vaadin.v7.ui.AbstractSelect.AbstractSelectTargetDetails; 118import com.vaadin.v7.ui.ComboBox; 119import com.vaadin.v7.ui.HorizontalLayout; 120import com.vaadin.v7.ui.Table; 121import com.vaadin.v7.ui.Table.TableDragMode; 122import com.vaadin.v7.ui.TextField; 123import com.vaadin.v7.ui.Tree; 124import com.vaadin.v7.ui.Tree.CollapseEvent; 125import com.vaadin.v7.ui.Tree.CollapseListener; 126import com.vaadin.v7.ui.Tree.ExpandEvent; 127import com.vaadin.v7.ui.Tree.ExpandListener; 128import com.vaadin.v7.ui.Tree.ItemStyleGenerator; 129import com.vaadin.v7.ui.Tree.TreeDragMode; 130 131/** 132 * The file explorer app.<p> 133 */ 134@SuppressWarnings("deprecation") 135public class CmsFileExplorer 136implements I_CmsWorkplaceApp, I_CmsCachableApp, ViewChangeListener, I_CmsWindowCloseListener, I_CmsHasShortcutActions, 137I_CmsContextProvider, CmsFileTable.I_FolderSelectHandler { 138 139 /** The drop handler for copy/move operations. */ 140 public class ExplorerDropHandler implements DropHandler { 141 142 /** The serial version id. */ 143 private static final long serialVersionUID = 5392136127699472654L; 144 145 /** The copy move action. */ 146 transient final I_CmsWorkplaceAction m_copyMoveAction = new CmsCopyDialogAction(); 147 148 /** 149 * @see com.vaadin.event.dd.DropHandler#drop(com.vaadin.event.dd.DragAndDropEvent) 150 */ 151 public void drop(DragAndDropEvent dragEvent) { 152 153 try { 154 CmsExplorerDialogContext context = getContext(dragEvent); 155 if (m_copyMoveAction.isActive(context)) { 156 CmsCopyMoveDialog dialog = new CmsCopyMoveDialog( 157 context, 158 CmsCopyMoveDialog.DialogMode.copy_and_move); 159 dialog.setTargetFolder(getTargetId(dragEvent)); 160 context.start( 161 CmsVaadinUtils.getMessageText(org.opencms.ui.Messages.GUI_DIALOGTITLE_COPYMOVE_0), 162 dialog); 163 } 164 } catch (Exception e) { 165 LOG.error("Moving resource failed", e); 166 } 167 168 } 169 170 /** 171 * @see com.vaadin.event.dd.DropHandler#getAcceptCriterion() 172 */ 173 public AcceptCriterion getAcceptCriterion() { 174 175 return new ServerSideCriterion() { 176 177 private static final long serialVersionUID = 1L; 178 179 public boolean accept(DragAndDropEvent dragEvent) { 180 181 try { 182 if (!m_copyMoveAction.isActive(getContext(dragEvent))) { 183 return false; 184 } 185 } catch (CmsException e) { 186 LOG.error("Drag an drop evaluation failed", e); 187 return false; 188 } 189 CmsUUID targetId = getTargetId(dragEvent); 190 return mayDrop(targetId); 191 } 192 }; 193 } 194 195 /** 196 * Returns the drag target id.<p> 197 * 198 * @param dragEvent the drag event 199 * 200 * @return the drag target id 201 */ 202 protected CmsUUID getTargetId(DragAndDropEvent dragEvent) { 203 204 CmsUUID targetId = null; 205 if (dragEvent.getTargetDetails() instanceof AbstractSelectTargetDetails) { 206 AbstractSelectTargetDetails target = (AbstractSelectTargetDetails)dragEvent.getTargetDetails(); 207 Object itemOverId = target.getItemIdOver(); 208 if (itemOverId instanceof CmsUUID) { 209 targetId = (CmsUUID)itemOverId; 210 } else if (itemOverId instanceof String) { 211 targetId = m_fileTable.getUUIDFromItemID((String)itemOverId); 212 } 213 } 214 try { 215 CmsObject cms = A_CmsUI.getCmsObject(); 216 CmsResource target = cms.readResource(targetId); 217 if (target.isFile()) { 218 targetId = null; 219 } 220 } catch (CmsException e) { 221 targetId = null; 222 LOG.debug("Checking drop target failed, use current folder.", e); 223 } 224 225 if (targetId == null) { 226 targetId = getCurrentFolder(); 227 } 228 return targetId; 229 } 230 231 /** 232 * Evaluates if a drop on the given target is allowed.<p> 233 * 234 * @param targetId the target id 235 * 236 * @return <code>true</code> if the resources may be dropped to the given target 237 */ 238 protected boolean mayDrop(CmsUUID targetId) { 239 240 boolean result = false; 241 try { 242 CmsObject cms = A_CmsUI.getCmsObject(); 243 CmsResource target = cms.readResource(targetId); 244 result = cms.hasPermissions( 245 target, 246 CmsPermissionSet.ACCESS_WRITE, 247 false, 248 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 249 } catch (Exception e) { 250 LOG.debug("Checking folder write permissions failed", e); 251 } 252 return result; 253 } 254 255 /** 256 * Returns the dialog context to use.<p> 257 * 258 * @param dragEvent the drag event 259 * 260 * @return the dialog context 261 * 262 * @throws CmsException if reading the drag resource fails 263 */ 264 CmsExplorerDialogContext getContext(DragAndDropEvent dragEvent) throws CmsException { 265 266 List<CmsResource> resources; 267 if ((dragEvent.getTransferable().getSourceComponent() instanceof Table) 268 && !m_fileTable.getSelectedResources().isEmpty()) { 269 resources = m_fileTable.getSelectedResources(); 270 } else { 271 CmsObject cms = A_CmsUI.getCmsObject(); 272 CmsUUID sourceId = m_fileTable.getUUIDFromItemID((String)dragEvent.getTransferable().getData("itemId")); 273 CmsResource source = cms.readResource(sourceId, CmsResourceFilter.IGNORE_EXPIRATION); 274 resources = Collections.singletonList(source); 275 } 276 CmsExplorerDialogContext context = new CmsExplorerDialogContext( 277 ContextType.fileTable, 278 m_fileTable, 279 CmsFileExplorer.this, 280 resources); 281 return context; 282 } 283 } 284 285 /** 286 * File tree expand listener.<p> 287 */ 288 public class TreeExpandListener implements ExpandListener { 289 290 /** The serial version id. */ 291 private static final long serialVersionUID = 1L; 292 /** 293 * The path fragment being opened. 294 * Will override folder visibility in case the the target path is visible to the user. 295 **/ 296 private String m_openPathFragment; 297 298 /** 299 * @see com.vaadin.ui.Tree.ExpandListener#nodeExpand(com.vaadin.ui.Tree.ExpandEvent) 300 */ 301 public void nodeExpand(ExpandEvent event) { 302 303 selectTreeItem((CmsUUID)event.getItemId()); 304 readTreeLevel((CmsUUID)event.getItemId(), m_openPathFragment); 305 } 306 307 /** 308 * Sets the open path fragment.<p> 309 * 310 * @param openPathFragment the open path fragment 311 */ 312 public void setOpenPathFragment(String openPathFragment) { 313 314 m_openPathFragment = openPathFragment; 315 } 316 } 317 318 /** Bean representing the file explorer navigation substate. */ 319 static class StateBean { 320 321 /** Current folder. */ 322 private String m_folder; 323 324 /** Project id. */ 325 private String m_projectId; 326 327 /**selected resource.*/ 328 private String m_selectedResource; 329 330 /** The site root. */ 331 private String m_siteRoot; 332 333 /** 334 * Creates a new state bean.<p> 335 * 336 * @param siteRoot the site root 337 * @param folder the folder 338 * @param projectId the project id 339 */ 340 public StateBean(String siteRoot, String folder, String projectId) { 341 342 m_siteRoot = siteRoot; 343 m_folder = folder; 344 m_projectId = projectId; 345 if ("".equals(m_siteRoot)) { 346 m_siteRoot = "/"; 347 } 348 } 349 350 /** 351 * Parses the state bean from a string.<p> 352 * 353 * @param state the state string 354 * @return the state bean 355 */ 356 public static StateBean parse(String state) { 357 358 List<String> fields = CmsStringUtil.splitAsList(state, A_CmsWorkplaceApp.PARAM_SEPARATOR); 359 if (fields.size() >= 3) { 360 String projectId = fields.get(0); 361 String siteRoot = fields.get(1); 362 String folder = fields.get(2); 363 StateBean ret = new StateBean(siteRoot, folder, projectId); 364 if (fields.size() == 4) { 365 ret.setSelectedResource(fields.get(3)); 366 } 367 return ret; 368 } else { 369 return new StateBean(null, null, null); 370 } 371 } 372 373 /** 374 * Converts state bean to a string.<p> 375 * 376 * @return the string format of the state 377 */ 378 public String asString() { 379 380 String result = m_projectId 381 + A_CmsWorkplaceApp.PARAM_SEPARATOR 382 + m_siteRoot 383 + A_CmsWorkplaceApp.PARAM_SEPARATOR 384 + m_folder 385 + A_CmsWorkplaceApp.PARAM_SEPARATOR; 386 return result; 387 } 388 389 /** 390 * Returns the folderId.<p> 391 * 392 * @return the folderId 393 */ 394 public String getFolder() { 395 396 return m_folder; 397 } 398 399 /** 400 * Returns the projectId.<p> 401 * 402 * @return the projectId 403 */ 404 public String getProjectId() { 405 406 return m_projectId; 407 } 408 409 /** 410 * Returns the resource to select, empty if no one was set.<p> 411 * 412 * @return UUID as string 413 */ 414 public String getSelectedResource() { 415 416 return m_selectedResource == null ? "" : m_selectedResource; 417 } 418 419 /** 420 * Returns the siteRoot.<p> 421 * 422 * @return the siteRoot 423 */ 424 public String getSiteRoot() { 425 426 return m_siteRoot; 427 } 428 429 /** 430 * Sets a resource to be selected.<p> 431 * 432 * @param resource to get selected 433 */ 434 public void setSelectedResource(String resource) { 435 436 m_selectedResource = resource; 437 } 438 } 439 440 /** The file explorer attribute key. */ 441 public static final String ATTR_KEY = "CmsFileExplorer"; 442 443 /** The in line editable resource properties. */ 444 public static final Collection<CmsResourceTableProperty> INLINE_EDIT_PROPERTIES = Arrays.asList( 445 CmsResourceTableProperty.PROPERTY_RESOURCE_NAME, 446 CmsResourceTableProperty.PROPERTY_TITLE, 447 CmsResourceTableProperty.PROPERTY_NAVIGATION_TEXT, 448 CmsResourceTableProperty.PROPERTY_COPYRIGHT, 449 CmsResourceTableProperty.PROPERTY_CACHE); 450 451 /** The initial split position between folder tree and file table. */ 452 public static final int LAYOUT_SPLIT_POSITION = 399; 453 454 /** The opened paths session attribute name. */ 455 public static final String OPENED_PATHS = "explorer-opened-paths"; 456 457 /** Site selector caption property. */ 458 public static final String SITE_CAPTION = "site_caption"; 459 460 /** Site selector site root property. */ 461 public static final String SITE_ROOT = "site_root"; 462 463 /** Threshold for updating the complete folder after file changes. */ 464 public static final int UPDATE_FOLDER_THRESHOLD = 200; 465 466 /** Logger instance for this class. */ 467 static final Log LOG = CmsLog.getLog(CmsFileExplorer.class); 468 469 /** The delete shortcut. */ 470 private static final Action ACTION_DELETE = new ShortcutAction("Del", ShortcutAction.KeyCode.DELETE, null); 471 472 /** The open parent folder shortcut. */ 473 private static final Action ACTION_FOLDER_UP = new ShortcutAction( 474 "Alt+ArrowUp", 475 ShortcutAction.KeyCode.ARROW_UP, 476 new int[] {ShortcutAction.ModifierKey.ALT}); 477 478 /** The edit properties shortcut. */ 479 private static final Action ACTION_PROPERTIES = new ShortcutAction( 480 "Alt+Enter", 481 ShortcutAction.KeyCode.ENTER, 482 new int[] {ShortcutAction.ModifierKey.ALT}); 483 484 /** The rename shortcut. */ 485 private static final Action ACTION_RENAME = new ShortcutAction("F2", ShortcutAction.KeyCode.F2, null); 486 487 /** The select all shortcut. */ 488 private static final Action ACTION_SELECT_ALL = new ShortcutAction( 489 "Ctrl+A", 490 ShortcutAction.KeyCode.A, 491 new int[] {ShortcutAction.ModifierKey.CTRL}); 492 493 /** The select all shortcut, (using Apple CMD as modifier). */ 494 private static final Action ACTION_SELECT_ALL_CMD = new ShortcutAction( 495 "CMD+A", 496 ShortcutAction.KeyCode.A, 497 new int[] {ShortcutAction.ModifierKey.META}); 498 499 /** The switch online shortcut. */ 500 private static final Action ACTION_SWITCH_ONLINE = new ShortcutAction( 501 "Ctrl+O", 502 ShortcutAction.KeyCode.O, 503 new int[] {ShortcutAction.ModifierKey.CTRL}); 504 505 /** The switch online shortcut, (using Apple CMD as modifier). */ 506 private static final Action ACTION_SWITCH_ONLINE_CMD = new ShortcutAction( 507 "CMD+O", 508 ShortcutAction.KeyCode.O, 509 new int[] {ShortcutAction.ModifierKey.META}); 510 511 /** The files and folder resource filter. */ 512 private static final CmsResourceFilter FILES_N_FOLDERS = CmsResourceFilter.ONLY_VISIBLE; 513 514 /** The folders resource filter. */ 515 private static final CmsResourceFilter FOLDERS = CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireFolder(); 516 517 /** The serial version id. */ 518 private static final long serialVersionUID = 1L; 519 520 /** The UI context. */ 521 protected I_CmsAppUIContext m_appContext; 522 523 /** Saved explorer state used by dialogs after they have finished. */ 524 protected String m_savedExplorerState = ""; 525 526 /** The table containing the contents of the current folder. */ 527 CmsFileTable m_fileTable; 528 529 /** The info path. */ 530 com.vaadin.ui.TextField m_infoPath; 531 532 /** The explorer shortcuts. */ 533 Map<Action, Runnable> m_shortcutActions; 534 535 /** The bread crumb click listener. */ 536 private ClickListener m_crumbListener; 537 538 /** The path bread crumb container. */ 539 private CssLayout m_crumbs; 540 541 /** The currently viewed folder. */ 542 private CmsUUID m_currentFolder; 543 544 /** The current app state. */ 545 private String m_currentState; 546 547 /** The tree expand listener. */ 548 private TreeExpandListener m_expandListener; 549 550 /** The folder tree. */ 551 private Tree m_fileTree; 552 553 /** The first visible file table item index. */ 554 private int m_firstVisibleTableItemIndex; 555 556 /** The last context menu resources. */ 557 private List<CmsResource> m_lastDialogContextResources; 558 559 /** The quick launch location cache. */ 560 private CmsQuickLaunchLocationCache m_locationCache; 561 562 /** The new button. */ 563 private Button m_newButton; 564 565 /** The publish button. */ 566 private Button m_publishButton; 567 568 /** The search field. */ 569 private TextField m_searchField; 570 571 /** the currently selected file tree folder, may be null. */ 572 private CmsUUID m_selectTreeFolder; 573 574 /** The site selector. */ 575 private ComboBox m_siteSelector; 576 577 /** Button for uploading to folders with special upload actions. */ 578 private Button m_specialUploadButton; 579 580 /** The folder tree data container. */ 581 private HierarchicalContainer m_treeContainer; 582 583 /** Upload action for the current folder. */ 584 private String m_uploadAction; 585 586 /** The upload drop area extension. */ 587 private CmsUploadAreaExtension m_uploadArea; 588 589 /** The upload button. */ 590 private CmsUploadButton m_uploadButton; 591 592 /** The current upload folder. */ 593 private CmsResource m_uploadFolder; 594 595 /** 596 * Constructor.<p> 597 */ 598 public CmsFileExplorer() { 599 600 m_shortcutActions = new HashMap<Action, Runnable>(); 601 m_shortcutActions.put(ACTION_DELETE, new Runnable() { 602 603 public void run() { 604 605 if (!m_fileTable.getSelectedIds().isEmpty()) { 606 I_CmsDialogContext context1 = getDialogContext(); 607 context1.start("Delete", new CmsDeleteDialog(context1)); 608 } 609 } 610 }); 611 612 m_shortcutActions.put(ACTION_FOLDER_UP, new Runnable() { 613 614 public void run() { 615 616 showParentFolder(); 617 } 618 }); 619 620 m_shortcutActions.put(ACTION_PROPERTIES, new Runnable() { 621 622 public void run() { 623 624 I_CmsWorkplaceAction propAction = new CmsPropertiesDialogAction(); 625 I_CmsDialogContext context = getDialogContext(); 626 if (propAction.getVisibility(context).isActive()) { 627 propAction.executeAction(context); 628 } 629 } 630 }); 631 632 m_shortcutActions.put(ACTION_RENAME, new Runnable() { 633 634 public void run() { 635 636 CmsExplorerDialogContext context = getDialogContext(); 637 if (context.isPropertyEditable(CmsResourceTableProperty.PROPERTY_RESOURCE_NAME)) { 638 context.editProperty(CmsResourceTableProperty.PROPERTY_RESOURCE_NAME); 639 } 640 } 641 }); 642 Runnable selectAll = new Runnable() { 643 644 public void run() { 645 646 m_fileTable.selectAll(); 647 } 648 }; 649 m_shortcutActions.put(ACTION_SELECT_ALL, selectAll); 650 m_shortcutActions.put(ACTION_SELECT_ALL_CMD, selectAll); 651 652 Runnable switchOnline = new Runnable() { 653 654 public void run() { 655 656 toggleOnlineOffline(); 657 } 658 }; 659 m_shortcutActions.put(ACTION_SWITCH_ONLINE, switchOnline); 660 m_shortcutActions.put(ACTION_SWITCH_ONLINE_CMD, switchOnline); 661 662 m_fileTable = new CmsFileTable(this); 663 m_fileTable.setSizeFull(); 664 m_fileTable.setMenuBuilder(new CmsResourceContextMenuBuilder()); 665 m_fileTable.setFolderSelectHandler(this); 666 m_uploadArea = new CmsUploadAreaExtension(m_fileTable); 667 m_uploadArea.addUploadListener(new I_UploadListener() { 668 669 public void onUploadFinished(List<String> uploadedFiles) { 670 671 updateAll(true); 672 } 673 }); 674 m_treeContainer = new HierarchicalContainer(); 675 addTreeContainerProperties( 676 CmsResourceTableProperty.PROPERTY_RESOURCE_NAME, 677 CmsResourceTableProperty.PROPERTY_STATE, 678 CmsResourceTableProperty.PROPERTY_TREE_CAPTION, 679 CmsResourceTableProperty.PROPERTY_INSIDE_PROJECT, 680 CmsResourceTableProperty.PROPERTY_RELEASED_NOT_EXPIRED, 681 CmsResourceTableProperty.PROPERTY_DISABLED); 682 m_fileTree = new Tree(); 683 m_fileTree.addStyleName(OpenCmsTheme.SIMPLE_DRAG); 684 m_fileTree.addStyleName(OpenCmsTheme.FULL_WIDTH_PADDING); 685 m_fileTree.setWidth("100%"); 686 m_fileTree.setContainerDataSource(m_treeContainer); 687 // m_fileTree.setItemIconPropertyId(CmsResourceTableProperty.PROPERTY_TYPE_ICON_RESOURCE); 688 m_fileTree.setItemCaptionPropertyId(CmsResourceTableProperty.PROPERTY_TREE_CAPTION); 689 // m_fileTree.setCaptionAsHtml(true); 690 m_fileTree.setHtmlContentAllowed(true); 691 m_expandListener = new TreeExpandListener(); 692 m_fileTree.addExpandListener(m_expandListener); 693 m_fileTree.addCollapseListener(new CollapseListener() { 694 695 private static final long serialVersionUID = 1L; 696 697 public void nodeCollapse(CollapseEvent event) { 698 699 selectTreeItem((CmsUUID)event.getItemId()); 700 clearTreeLevel((CmsUUID)event.getItemId()); 701 } 702 }); 703 704 m_fileTree.addItemClickListener(new ItemClickListener() { 705 706 private static final long serialVersionUID = 1L; 707 708 public void itemClick(ItemClickEvent event) { 709 710 handleFileTreeClick(event); 711 } 712 }); 713 714 m_fileTree.setItemStyleGenerator(new ItemStyleGenerator() { 715 716 private static final long serialVersionUID = 1L; 717 718 public String getStyle(Tree source, Object itemId) { 719 720 return CmsFileTable.getStateStyle(source.getContainerDataSource().getItem(itemId)); 721 } 722 }); 723 m_fileTree.addValueChangeListener(new ValueChangeListener() { 724 725 private static final long serialVersionUID = 1L; 726 727 public void valueChange(ValueChangeEvent event) { 728 729 handleFileTreeValueChange(); 730 } 731 732 }); 733 734 m_fileTree.setNullSelectionAllowed(false); 735 736 // init drag and drop 737 ExplorerDropHandler handler = new ExplorerDropHandler(); 738 m_fileTable.setDropHandler(handler); 739 m_fileTable.setDragMode(TableDragMode.MULTIROW); 740 m_fileTree.setDropHandler(handler); 741 m_fileTree.setDragMode(TreeDragMode.NONE); 742 743 m_siteSelector = createSiteSelect(A_CmsUI.getCmsObject()); 744 m_infoPath = new com.vaadin.ui.TextField(); 745 A_CmsFocusShortcutListener shortcutListener = new A_CmsFocusShortcutListener("Open path", KeyCode.ENTER, null) { 746 747 private static final long serialVersionUID = 1L; 748 749 @Override 750 public void blur(BlurEvent event) { 751 752 super.blur(event); 753 showCrumbs(true); 754 } 755 756 @Override 757 public void focus(FocusEvent event) { 758 759 super.focus(event); 760 showCrumbs(false); 761 } 762 763 @Override 764 public void handleAction(Object sender, Object target) { 765 766 openPath(m_infoPath.getValue()); 767 } 768 }; 769 shortcutListener.installOn(m_infoPath); 770 771 m_crumbs = new CssLayout(); 772 m_crumbs.setPrimaryStyleName(OpenCmsTheme.CRUMBS); 773 m_crumbListener = new ClickListener() { 774 775 private static final long serialVersionUID = 1L; 776 777 public void buttonClick(ClickEvent event) { 778 779 openPath((String)event.getButton().getData()); 780 } 781 }; 782 783 m_searchField = new TextField(); 784 m_searchField.setIcon(FontOpenCms.FILTER); 785 m_searchField.setInputPrompt( 786 Messages.get().getBundle(UI.getCurrent().getLocale()).key(Messages.GUI_EXPLORER_FILTER_0)); 787 m_searchField.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); 788 m_searchField.addTextChangeListener(new TextChangeListener() { 789 790 private static final long serialVersionUID = 1L; 791 792 public void textChange(TextChangeEvent event) { 793 794 filterTable(event.getText()); 795 796 } 797 }); 798 799 m_locationCache = CmsQuickLaunchLocationCache.getLocationCache(CmsAppWorkplaceUi.get().getHttpSession()); 800 String startSite = CmsWorkplace.getStartSiteRoot( 801 A_CmsUI.getCmsObject(), 802 CmsAppWorkplaceUi.get().getWorkplaceSettings()); 803 // remove trailing slashes 804 while (startSite.endsWith("/")) { 805 startSite = startSite.substring(0, startSite.length() - 1); 806 } 807 if (m_locationCache.getFileExplorerLocation(startSite) == null) { 808 // add the configured start folder for the start site 809 String startFolder = CmsAppWorkplaceUi.get().getWorkplaceSettings().getUserSettings().getStartFolder(); 810 m_locationCache.setFileExplorerLocation(startSite, startFolder); 811 } 812 } 813 814 /** 815 * @see com.vaadin.navigator.ViewChangeListener#afterViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent) 816 */ 817 public void afterViewChange(ViewChangeEvent event) { 818 819 m_fileTable.setFirstVisibleItemIndex(m_firstVisibleTableItemIndex); 820 } 821 822 /** 823 * @see com.vaadin.navigator.ViewChangeListener#beforeViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent) 824 */ 825 public boolean beforeViewChange(ViewChangeEvent event) { 826 827 m_firstVisibleTableItemIndex = m_fileTable.getFirstVisibleItemIndex(); 828 829 OpenCms.getWorkplaceAppManager().storeAppSettings( 830 A_CmsUI.getCmsObject(), 831 CmsFileExplorerSettings.class, 832 m_fileTable.getTableSettings()); 833 return true; 834 } 835 836 /** 837 * Changes to the given site and path.<p> 838 * 839 * @param siteRoot the site root 840 * @param path the path inside the site 841 */ 842 public void changeSite(String siteRoot, String path) { 843 844 changeSite(siteRoot, path, false); 845 846 } 847 848 /** 849 * Switches to the requested site.<p> 850 * 851 * @param siteRoot the site root 852 * @param path the folder path to open 853 * @param force force the path change, even if we are currently in the same site 854 */ 855 public void changeSite(String siteRoot, String path, boolean force) { 856 857 CmsObject cms = A_CmsUI.getCmsObject(); 858 String currentSiteRoot = cms.getRequestContext().getSiteRoot(); 859 if (force || !currentSiteRoot.equals(siteRoot) || (path != null)) { 860 CmsAppWorkplaceUi.get().changeSite(siteRoot); 861 if (path == null) { 862 path = m_locationCache.getFileExplorerLocation(siteRoot); 863 if (CmsStringUtil.isEmptyOrWhitespaceOnly(siteRoot) 864 && ((path == null) || !path.startsWith("/system"))) { 865 // switching to the root site and previous root site folder is not below /system 866 // -> stay in the current folder 867 path = m_locationCache.getFileExplorerLocation(currentSiteRoot); 868 if (path != null) { 869 path = CmsStringUtil.joinPaths(currentSiteRoot, path); 870 } 871 } 872 } 873 openPath(path, true); 874 Container container = m_siteSelector.getContainerDataSource(); 875 CmsExtendedSiteSelector.SiteSelectorOption optionToSelect = null; 876 for (Object id : container.getItemIds()) { 877 CmsExtendedSiteSelector.SiteSelectorOption option = (CmsExtendedSiteSelector.SiteSelectorOption)id; 878 if ((option != null) && CmsStringUtil.comparePaths(option.getSite(), siteRoot)) { 879 optionToSelect = option; 880 break; 881 } 882 } 883 m_siteSelector.select(optionToSelect); 884 } 885 } 886 887 /** 888 * Clears the file table selection. 889 */ 890 public void clearSelection() { 891 892 m_fileTable.clearSelection(); 893 } 894 895 /** 896 * Gets all ids of resources in current folder.<p> 897 * 898 * @return the 899 */ 900 public List<CmsUUID> getAllIds() { 901 902 return m_fileTable.getAllIds(); 903 } 904 905 /** 906 * Returns the current folder id.<p> 907 * 908 * @return the current folder structure id 909 */ 910 public CmsUUID getCurrentFolder() { 911 912 return m_currentFolder; 913 } 914 915 /** 916 * @see org.opencms.ui.apps.I_CmsContextProvider#getDialogContext() 917 */ 918 public CmsExplorerDialogContext getDialogContext() { 919 920 List<CmsResource> resources = m_fileTable.getSelectedResources(); 921 m_lastDialogContextResources = resources; 922 CmsExplorerDialogContext context = new CmsExplorerDialogContext( 923 ContextType.fileTable, 924 m_fileTable, 925 this, 926 resources); 927 context.setEditableProperties(INLINE_EDIT_PROPERTIES); 928 return context; 929 } 930 931 /** 932 * @see org.opencms.ui.apps.I_CmsHasShortcutActions#getShortcutActions() 933 */ 934 public Map<Action, Runnable> getShortcutActions() { 935 936 return m_shortcutActions; 937 } 938 939 /** 940 * @see org.opencms.ui.apps.I_CmsWorkplaceApp#initUI(org.opencms.ui.apps.I_CmsAppUIContext) 941 */ 942 public void initUI(I_CmsAppUIContext context) { 943 944 m_appContext = context; 945 m_appContext.setAttribute(ATTR_KEY, this); 946 m_appContext.setMenuDialogContext( 947 new CmsExplorerDialogContext(ContextType.appToolbar, m_fileTable, this, null)); 948 HorizontalSplitPanel sp = new HorizontalSplitPanel(); 949 sp.setSizeFull(); 950 sp.setFirstComponent(m_fileTree); 951 CmsFileExplorerSettings settings; 952 try { 953 settings = OpenCms.getWorkplaceAppManager().getAppSettings( 954 A_CmsUI.getCmsObject(), 955 CmsFileExplorerSettings.class); 956 957 m_fileTable.setTableState(settings); 958 } catch (Exception e) { 959 LOG.error("Error while reading file explorer settings from user.", e); 960 } 961 sp.setSecondComponent(m_fileTable); 962 963 sp.setSplitPosition(LAYOUT_SPLIT_POSITION, Unit.PIXELS); 964 965 context.setAppContent(sp); 966 context.showInfoArea(true); 967 HorizontalLayout inf = new HorizontalLayout(); 968 inf.setSizeFull(); 969 inf.setSpacing(true); 970 inf.setMargin(true); 971 m_siteSelector.setWidth("379px"); 972 inf.addComponent(m_siteSelector); 973 CssLayout crumbWrapper = new CssLayout(); 974 crumbWrapper.setSizeFull(); 975 crumbWrapper.setPrimaryStyleName(OpenCmsTheme.CRUMB_WRAPPER); 976 crumbWrapper.addComponent(m_crumbs); 977 978 m_infoPath.setWidth("100%"); 979 crumbWrapper.addComponent(m_infoPath); 980 inf.addComponent(crumbWrapper); 981 inf.setExpandRatio(crumbWrapper, 1); 982 983 m_searchField.setWidth("200px"); 984 inf.addComponent(m_searchField); 985 context.setAppInfo(inf); 986 987 initToolbarButtons(context); 988 m_fileTable.updateColumnWidths(A_CmsUI.get().getPage().getBrowserWindowWidth() - LAYOUT_SPLIT_POSITION); 989 } 990 991 /** 992 * @see org.opencms.ui.apps.I_CmsCachableApp#isCachable() 993 */ 994 public boolean isCachable() { 995 996 return true; 997 } 998 999 /** 1000 * @see org.opencms.ui.components.CmsFileTable.I_FolderSelectHandler#onFolderSelect(org.opencms.util.CmsUUID) 1001 */ 1002 public void onFolderSelect(CmsUUID itemId) { 1003 1004 expandCurrentFolder(); 1005 if (m_fileTree.getItem(itemId) != null) { 1006 m_fileTree.select(itemId); 1007 } 1008 try { 1009 readFolder(itemId); 1010 } catch (CmsException e) { 1011 CmsErrorDialog.showErrorDialog( 1012 CmsVaadinUtils.getMessageText(Messages.ERR_EXPLORER_CAN_NOT_READ_RESOURCE_1, itemId), 1013 e); 1014 LOG.error(e.getLocalizedMessage(), e); 1015 } 1016 } 1017 1018 /** 1019 * @see org.opencms.ui.apps.I_CmsCachableApp#onRestoreFromCache() 1020 */ 1021 public void onRestoreFromCache() { 1022 1023 if (m_lastDialogContextResources != null) { 1024 List<CmsUUID> updateIds = Lists.newArrayList(); 1025 for (CmsResource resource : m_lastDialogContextResources) { 1026 updateIds.add(resource.getStructureId()); 1027 } 1028 update(updateIds); 1029 } 1030 1031 } 1032 1033 /** 1034 * Call if site and or project have been changed.<p> 1035 * 1036 * @param project the project 1037 * @param siteRoot the site root 1038 */ 1039 public void onSiteOrProjectChange(CmsProject project, String siteRoot) { 1040 1041 if ((siteRoot != null) && !siteRoot.equals(getSiteRootFromState())) { 1042 changeSite(siteRoot, null, true); 1043 } else if ((project != null) && !project.getUuid().equals(getProjectIdFromState())) { 1044 openPath(getPathFromState(), true); 1045 } 1046 m_appContext.updateOnChange(); 1047 setToolbarButtonsEnabled(!CmsAppWorkplaceUi.isOnlineProject()); 1048 } 1049 1050 /** 1051 * @see org.opencms.ui.apps.I_CmsWorkplaceApp#onStateChange(java.lang.String) 1052 */ 1053 public void onStateChange(String state) { 1054 1055 state = normalizeState(state); 1056 if ((m_currentState == null) || !m_currentState.equals(state)) { 1057 m_currentState = state; 1058 CmsObject cms = A_CmsUI.getCmsObject(); 1059 String siteRoot = getSiteRootFromState(); 1060 String path = getPathFromState(); 1061 1062 CmsUUID projectId = getProjectIdFromState(); 1063 if ((projectId != null) && !cms.getRequestContext().getCurrentProject().getUuid().equals(projectId)) { 1064 try { 1065 CmsProject project = cms.readProject(projectId); 1066 cms.getRequestContext().setCurrentProject(project); 1067 CmsAppWorkplaceUi.get().getWorkplaceSettings().setProject(project.getUuid()); 1068 } catch (CmsException e) { 1069 LOG.warn("Error reading project from history state", e); 1070 } 1071 changeSite(siteRoot, path, true); 1072 } else if ((siteRoot != null) 1073 && !CmsStringUtil.comparePaths(siteRoot, cms.getRequestContext().getSiteRoot())) { 1074 String saveState = m_currentState; 1075 changeSite(siteRoot, path); 1076 if (!getSelectionFromState(saveState).isEmpty()) { 1077 m_fileTable.setValue(Collections.singleton(getSelectionFromState(saveState))); 1078 } 1079 } else { 1080 String saveState = m_currentState; 1081 openPath(path, true); 1082 if (!getSelectionFromState(saveState).isEmpty()) { 1083 m_fileTable.setValue(Collections.singleton(getSelectionFromState(saveState))); 1084 } 1085 } 1086 } 1087 } 1088 1089 /** 1090 * @see org.opencms.ui.components.I_CmsWindowCloseListener#onWindowClose() 1091 */ 1092 public void onWindowClose() { 1093 1094 OpenCms.getWorkplaceAppManager().storeAppSettings( 1095 A_CmsUI.getCmsObject(), 1096 CmsFileExplorerSettings.class, 1097 m_fileTable.getTableSettings()); 1098 } 1099 1100 /** 1101 * Fills the file table with the resources from the given path.<p> 1102 * 1103 * @param sitePath a folder site path 1104 */ 1105 public void populateFileTable(String sitePath) { 1106 1107 CmsObject cms = A_CmsUI.getCmsObject(); 1108 m_searchField.clear(); 1109 m_firstVisibleTableItemIndex = 0; 1110 try { 1111 List<CmsResource> folderResources = cms.readResources(sitePath, FILES_N_FOLDERS, false); 1112 m_fileTable.fillTable(cms, folderResources); 1113 } catch (CmsException e) { 1114 CmsErrorDialog.showErrorDialog(e); 1115 LOG.error(e.getLocalizedMessage(), e); 1116 } 1117 } 1118 1119 /** 1120 * Updates the table entries with the given ids.<p> 1121 * 1122 * @param ids the ids of the table entries to update 1123 */ 1124 public void update(Collection<CmsUUID> ids) { 1125 1126 try { 1127 CmsResource currentFolderRes = A_CmsUI.getCmsObject().readResource(m_currentFolder, CmsResourceFilter.ALL); 1128 boolean updateFolder = m_fileTable.getItemCount() < UPDATE_FOLDER_THRESHOLD; 1129 Set<CmsUUID> removeIds = new HashSet<CmsUUID>(); 1130 for (CmsUUID id : ids) { 1131 boolean remove = false; 1132 try { 1133 CmsResource resource = A_CmsUI.getCmsObject().readResource(id, CmsResourceFilter.ALL); 1134 1135 remove = !CmsResource.getParentFolder(resource.getRootPath()).equals( 1136 currentFolderRes.getRootPath()); 1137 1138 } catch (CmsVfsResourceNotFoundException e) { 1139 remove = true; 1140 LOG.debug("Could not read update resource " + id, e); 1141 } 1142 if (remove) { 1143 removeIds.add(id); 1144 } 1145 1146 } 1147 for (CmsUUID id : ids) { 1148 updateTree(id); 1149 } 1150 if (updateFolder) { 1151 updateCurrentFolder(removeIds); 1152 } else { 1153 m_fileTable.update(removeIds, true); 1154 HashSet<CmsUUID> updateIds = new HashSet<CmsUUID>(ids); 1155 ids.removeAll(removeIds); 1156 m_fileTable.update(updateIds, false); 1157 } 1158 m_fileTable.updateSorting(); 1159 m_fileTable.clearSelection(); 1160 } catch (CmsException e) { 1161 CmsErrorDialog.showErrorDialog(e); 1162 } 1163 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_searchField.getValue())) { 1164 filterTable(m_searchField.getValue()); 1165 } 1166 } 1167 1168 /** 1169 * Updates display for all contents of the current folder.<p> 1170 * 1171 * @param clearFilter <code>true</code> to clear the search filter 1172 */ 1173 public void updateAll(boolean clearFilter) { 1174 1175 try { 1176 readFolder(m_currentFolder, clearFilter); 1177 Set<Object> ids = Sets.newHashSet(); 1178 ids.addAll(m_fileTree.getItemIds()); 1179 for (Object id : ids) { 1180 updateTree((CmsUUID)id); 1181 } 1182 } catch (CmsException e) { 1183 CmsErrorDialog.showErrorDialog( 1184 CmsVaadinUtils.getMessageText(Messages.ERR_EXPLORER_CAN_NOT_READ_RESOURCE_1, m_currentFolder), 1185 e); 1186 LOG.error(e.getLocalizedMessage(), e); 1187 } 1188 } 1189 1190 /** 1191 * Updates the give tree item.<p> 1192 * 1193 * @param cms the cms context 1194 * @param id the item id 1195 */ 1196 public void updateResourceInTree(CmsObject cms, CmsUUID id) { 1197 1198 try { 1199 CmsResource resource = cms.readResource(id, CmsResourceFilter.IGNORE_EXPIRATION); 1200 if (resource.isFile()) { 1201 return; 1202 } 1203 // ensuring to only add items belonging to the current site 1204 if (!resource.getRootPath().startsWith(cms.getRequestContext().getSiteRoot())) { 1205 m_treeContainer.removeItemRecursively(id); 1206 return; 1207 } 1208 1209 CmsResource parent = cms.readParentFolder(id); 1210 CmsUUID parentId = null; 1211 if (parent != null) { 1212 parentId = parent.getStructureId(); 1213 } else { 1214 LOG.debug("Parent for resource '" + resource.getRootPath() + "' is null"); 1215 } 1216 Item resourceItem = m_treeContainer.getItem(id); 1217 if (resourceItem != null) { 1218 // use the root path as name in case of the root item 1219 String resName = parentId == null ? resource.getRootPath() : resource.getName(); 1220 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_RESOURCE_NAME).setValue(resName); 1221 CmsResourceUtil resUtil = new CmsResourceUtil(cms, resource); 1222 String iconHTML = CmsResourceIcon.getTreeCaptionHTML(resName, resUtil, null, false); 1223 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_TREE_CAPTION).setValue(iconHTML); 1224 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_STATE).setValue(resource.getState()); 1225 if (parentId != null) { 1226 m_treeContainer.setParent(resource.getStructureId(), parentId); 1227 } 1228 } else { 1229 addTreeItem(cms, resource, parentId, false, m_treeContainer); 1230 } 1231 m_fileTree.markAsDirty(); 1232 } catch (CmsVfsResourceNotFoundException e) { 1233 m_treeContainer.removeItemRecursively(id); 1234 LOG.debug(e.getLocalizedMessage(), e); 1235 } catch (CmsException e) { 1236 CmsErrorDialog.showErrorDialog(e); 1237 LOG.error(e.getLocalizedMessage(), e); 1238 } 1239 } 1240 1241 /** 1242 * Updates the tree items with the given ids.<p> 1243 * 1244 * @param id the 1245 */ 1246 public void updateTree(CmsUUID id) { 1247 1248 CmsObject cms = A_CmsUI.getCmsObject(); 1249 updateResourceInTree(cms, id); 1250 1251 } 1252 1253 /** 1254 * Clears the given tree level.<p> 1255 * 1256 * @param parentId the parent id 1257 */ 1258 protected void clearTreeLevel(CmsUUID parentId) { 1259 1260 // create a new list to avoid concurrent modifications 1261 Collection<?> children = m_treeContainer.getChildren(parentId); 1262 // may be null when monkey clicking 1263 if (children != null) { 1264 List<Object> childIds = new ArrayList<Object>(m_treeContainer.getChildren(parentId)); 1265 for (Object childId : childIds) { 1266 m_treeContainer.removeItemRecursively(childId); 1267 } 1268 } 1269 } 1270 1271 /** 1272 * Reads the given folder.<p> 1273 * 1274 * @param folderId the folder id 1275 * 1276 * @throws CmsException in case reading the folder fails 1277 */ 1278 protected void readFolder(CmsUUID folderId) throws CmsException { 1279 1280 readFolder(folderId, true); 1281 } 1282 1283 /** 1284 * Reads the given folder.<p> 1285 * 1286 * @param folderId the folder id 1287 * @param clearFilter <code>true</code> to clear the search filter 1288 * 1289 * @throws CmsException in case reading the folder fails 1290 */ 1291 protected void readFolder(CmsUUID folderId, boolean clearFilter) throws CmsException { 1292 1293 CmsObject cms = A_CmsUI.getCmsObject(); 1294 if (clearFilter) { 1295 m_searchField.clear(); 1296 } 1297 CmsResource folder = cms.readResource(folderId, FOLDERS); 1298 m_currentFolder = folderId; 1299 String folderPath = cms.getSitePath(folder); 1300 if (OpenCms.getSiteManager().isSharedFolder(cms.getRequestContext().getSiteRoot())) { 1301 folderPath = folderPath.substring(cms.getRequestContext().getSiteRoot().length()); 1302 } 1303 setPathInfo(folderPath); 1304 List<CmsResource> childResources = cms.readResources(folder, FILES_N_FOLDERS, false); 1305 m_fileTable.fillTable(cms, childResources, clearFilter); 1306 boolean hasFolderChild = false; 1307 for (CmsResource child : childResources) { 1308 if (child.isFolder()) { 1309 hasFolderChild = true; 1310 break; 1311 } 1312 } 1313 m_treeContainer.setChildrenAllowed(folderId, hasFolderChild); 1314 String sitePath = folder.getRootPath().equals(cms.getRequestContext().getSiteRoot() + "/") ? "" : folderPath; 1315 String state = new StateBean( 1316 cms.getRequestContext().getSiteRoot(), 1317 sitePath, 1318 cms.getRequestContext().getCurrentProject().getUuid().toString()).asString(); 1319 if (LOG.isDebugEnabled()) { 1320 String p = RandomStringUtils.randomAlphanumeric(5) + " readFolder "; 1321 LOG.debug(p + "siteRoot = " + cms.getRequestContext().getSiteRoot()); 1322 LOG.debug(p + "folder = " + folder.getRootPath()); 1323 LOG.debug(p + "folderPath = " + folderPath); 1324 LOG.debug(p + "sitePath = " + sitePath); 1325 LOG.debug(p + "state = " + state); 1326 LOG.debug(p + "m_currentState = " + m_currentState); 1327 LOG.debug(p + "m_currentState.asString = " + StateBean.parse(m_currentState).asString()); 1328 } 1329 if ((m_currentState == null) || !(state).equals(StateBean.parse(m_currentState).asString())) { 1330 m_currentState = state; 1331 CmsAppWorkplaceUi.get().changeCurrentAppState(m_currentState); 1332 } 1333 m_locationCache.setFileExplorerLocation(cms.getRequestContext().getSiteRoot(), sitePath); 1334 updateUploadButton(folder); 1335 if (!m_fileTree.isExpanded(folderId)) { 1336 expandCurrentFolder(); 1337 } 1338 if (!m_fileTree.isSelected(folderId)) { 1339 m_fileTree.select(folderId); 1340 } 1341 } 1342 1343 /** 1344 * Updates the current folder and removes the given resource items.<p> 1345 * 1346 * @param removeIds the resource item ids to remove 1347 */ 1348 protected void updateCurrentFolder(Collection<CmsUUID> removeIds) { 1349 1350 m_fileTable.update(removeIds, true); 1351 CmsObject cms = A_CmsUI.getCmsObject(); 1352 try { 1353 // current folder may be filtered, so we clear the filters and restore them later 1354 // to make updates work for filtered out resources 1355 m_fileTable.saveFilters(); 1356 m_fileTable.clearFilters(); 1357 CmsResource folder = cms.readResource(m_currentFolder, FOLDERS); 1358 List<CmsResource> childResources = cms.readResources(cms.getSitePath(folder), FILES_N_FOLDERS, false); 1359 Set<CmsUUID> ids = new HashSet<CmsUUID>(); 1360 for (CmsResource child : childResources) { 1361 ids.add(child.getStructureId()); 1362 } 1363 m_fileTable.update(ids, false); 1364 } catch (CmsException e) { 1365 CmsErrorDialog.showErrorDialog(e); 1366 LOG.error(e.getLocalizedMessage(), e); 1367 } finally { 1368 m_fileTable.restoreFilters(); 1369 } 1370 } 1371 1372 /** 1373 * Expands the currently viewed folder in the tree.<p> 1374 */ 1375 void expandCurrentFolder() { 1376 1377 if (m_currentFolder != null) { 1378 m_treeContainer.setChildrenAllowed(m_currentFolder, true); 1379 m_fileTree.expandItem(m_currentFolder); 1380 } 1381 } 1382 1383 /** 1384 * Filters the file table.<p> 1385 * 1386 * @param search the search term 1387 */ 1388 void filterTable(String search) { 1389 1390 m_fileTable.filterTable(search); 1391 } 1392 1393 /** 1394 * Handles the file tree click events.<p> 1395 * 1396 * @param event the event 1397 */ 1398 void handleFileTreeClick(ItemClickEvent event) { 1399 1400 Item resourceItem = m_treeContainer.getItem(event.getItemId()); 1401 if ((resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_DISABLED).getValue() == null) 1402 || !((Boolean)resourceItem.getItemProperty( 1403 CmsResourceTableProperty.PROPERTY_DISABLED).getValue()).booleanValue()) { 1404 // don't handle disabled item clicks 1405 try { 1406 readFolder((CmsUUID)event.getItemId()); 1407 } catch (CmsException e) { 1408 CmsErrorDialog.showErrorDialog( 1409 CmsVaadinUtils.getMessageText(Messages.ERR_EXPLORER_CAN_NOT_READ_RESOURCE_1, event.getItemId()), 1410 e); 1411 LOG.error(e.getLocalizedMessage(), e); 1412 } 1413 } 1414 } 1415 1416 /** 1417 * Handles the file tree value changes.<p> 1418 */ 1419 void handleFileTreeValueChange() { 1420 1421 Item resourceItem = m_treeContainer.getItem(m_fileTree.getValue()); 1422 if (resourceItem != null) { 1423 if ((resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_DISABLED).getValue() != null) 1424 && ((Boolean)resourceItem.getItemProperty( 1425 CmsResourceTableProperty.PROPERTY_DISABLED).getValue()).booleanValue()) { 1426 // in case the folder is disabled due to missing visibility, reset the value to the previous one 1427 m_fileTree.setValue(m_selectTreeFolder); 1428 1429 } else { 1430 m_selectTreeFolder = (CmsUUID)m_fileTree.getValue(); 1431 } 1432 } 1433 } 1434 1435 /** 1436 * Opens the new resource dialog.<p> 1437 */ 1438 void onClickNew() { 1439 1440 try { 1441 CmsObject cms = A_CmsUI.getCmsObject(); 1442 1443 CmsResource folderRes = cms.readResource(m_currentFolder, CmsResourceFilter.IGNORE_EXPIRATION); 1444 I_CmsDialogContext newDialogContext = getDialogContext(); 1445 1446 CmsNewDialog newDialog = new CmsNewDialog(folderRes, newDialogContext); 1447 newDialogContext.start( 1448 CmsVaadinUtils.getMessageText(org.opencms.ui.Messages.GUI_NEWRESOURCEDIALOG_TITLE_0), 1449 newDialog); 1450 1451 } catch (Exception e) { 1452 LOG.error(e.getLocalizedMessage(), e); 1453 } 1454 } 1455 1456 /** 1457 * Opens the given site path.<p> 1458 * 1459 * @param path the path 1460 */ 1461 void openPath(String path) { 1462 1463 openPath(path, false); 1464 } 1465 1466 /** 1467 * Opens the given site path.<p> 1468 * 1469 * @param path the path 1470 * @param initTree <code>true</code> in case the tree needs to be initialized 1471 */ 1472 void openPath(String path, boolean initTree) { 1473 1474 CmsObject cms = A_CmsUI.getCmsObject(); 1475 if (path == null) { 1476 String siteRoot = cms.getRequestContext().getSiteRoot(); 1477 path = m_locationCache.getFileExplorerLocation(siteRoot); 1478 if (path == null) { 1479 path = ""; 1480 } else if (OpenCms.getSiteManager().startsWithShared(path)) { 1481 path = path.substring(siteRoot.length()); 1482 } 1483 } 1484 1485 CmsSiteManagerImpl siteManager = OpenCms.getSiteManager(); 1486 if (siteManager.isSharedFolder(cms.getRequestContext().getSiteRoot()) && siteManager.startsWithShared(path)) { 1487 // siteManager.getSharedFolder() has a trailing slash - we want to cut off the shared folder, but keep a leading slash in path 1488 path = path.substring(siteManager.getSharedFolder().length() - 1); 1489 if ("".equals(path)) { 1490 path = "/"; 1491 } 1492 } 1493 1494 boolean existsPath = CmsStringUtil.isNotEmptyOrWhitespaceOnly(path) 1495 && cms.existsResource(path, FILES_N_FOLDERS); 1496 1497 if (path.startsWith("/")) { 1498 // remove a leading slash to avoid an empty first path fragment 1499 path = path.substring(1); 1500 } 1501 1502 String[] pathItems = path.split("/"); 1503 1504 if (initTree) { 1505 try { 1506 initFolderTree(existsPath); 1507 } catch (CmsException e) { 1508 CmsErrorDialog.showErrorDialog( 1509 CmsVaadinUtils.getMessageText(Messages.ERR_EXPLORER_CAN_NOT_OPEN_PATH_1, path), 1510 e); 1511 LOG.error(e.getLocalizedMessage(), e); 1512 return; 1513 } 1514 } 1515 1516 Collection<?> rootItems = m_treeContainer.rootItemIds(); 1517 if (rootItems.size() != 1) { 1518 throw new RuntimeException("Illeagal state, folder tree has " + rootItems.size() + " children"); 1519 } 1520 1521 CmsUUID folderId = (CmsUUID)rootItems.iterator().next(); 1522 if (initTree) { 1523 if (existsPath) { 1524 m_expandListener.setOpenPathFragment(pathItems[0]); 1525 } 1526 m_fileTree.expandItem(folderId); 1527 m_expandListener.setOpenPathFragment(null); 1528 } 1529 Collection<?> children = m_treeContainer.getChildren(folderId); 1530 for (int i = 0; i < pathItems.length; i++) { 1531 if (CmsStringUtil.isEmptyOrWhitespaceOnly(pathItems[i])) { 1532 continue; 1533 } 1534 CmsUUID level = null; 1535 if (children != null) { 1536 for (Object id : children) { 1537 if (m_treeContainer.getItem(id).getItemProperty( 1538 CmsResourceTableProperty.PROPERTY_RESOURCE_NAME).getValue().equals(pathItems[i])) { 1539 level = (CmsUUID)id; 1540 m_expandListener.setOpenPathFragment( 1541 existsPath && (i < (pathItems.length - 1)) ? pathItems[i + 1] : null); 1542 m_fileTree.expandItem(level); 1543 m_expandListener.setOpenPathFragment(null); 1544 break; 1545 } 1546 } 1547 } 1548 if ((level == null) || level.equals(folderId)) { 1549 break; 1550 } 1551 folderId = level; 1552 children = m_treeContainer.getChildren(folderId); 1553 } 1554 try { 1555 readFolder(folderId); 1556 } catch (CmsException e) { 1557 CmsErrorDialog.showErrorDialog( 1558 CmsVaadinUtils.getMessageText(Messages.ERR_EXPLORER_CAN_NOT_OPEN_PATH_1, path), 1559 e); 1560 LOG.error(e.getLocalizedMessage(), e); 1561 return; 1562 } 1563 } 1564 1565 /** 1566 * Reads the given tree level.<p> 1567 * 1568 * @param parentId the parent id 1569 * @param openPathFragment the open path fragment 1570 */ 1571 void readTreeLevel(CmsUUID parentId, String openPathFragment) { 1572 1573 CmsObject cms = A_CmsUI.getCmsObject(); 1574 boolean openedFragment = false; 1575 try { 1576 CmsResource parent = cms.readResource(parentId, CmsResourceFilter.IGNORE_EXPIRATION); 1577 String folderPath = cms.getSitePath(parent); 1578 List<CmsResource> folderResources = cms.readResources(folderPath, FOLDERS, false); 1579 1580 // sets the parent to leaf mode, in case no child folders are present 1581 m_treeContainer.setChildrenAllowed(parentId, !folderResources.isEmpty()); 1582 1583 for (CmsResource resource : folderResources) { 1584 addTreeItem(cms, resource, parentId, false, m_treeContainer); 1585 openedFragment = openedFragment || resource.getName().equals(openPathFragment); 1586 } 1587 if (!openedFragment && (openPathFragment != null)) { 1588 CmsResource resource = cms.readResource( 1589 CmsStringUtil.joinPaths(folderPath, openPathFragment), 1590 CmsResourceFilter.IGNORE_EXPIRATION); 1591 addTreeItem(cms, resource, parentId, true, m_treeContainer); 1592 } 1593 1594 m_fileTree.markAsDirtyRecursive(); 1595 } catch (CmsException e) { 1596 CmsErrorDialog.showErrorDialog(e); 1597 LOG.error(e.getLocalizedMessage(), e); 1598 } 1599 } 1600 1601 /** 1602 * Selects the item with the given id.<p> 1603 * 1604 * @param itemId the item id 1605 */ 1606 void selectTreeItem(CmsUUID itemId) { 1607 1608 m_fileTree.select(itemId); 1609 } 1610 1611 /** 1612 * Shows and hides the path bread crumb.<p> 1613 * 1614 * @param show <code>true</code> to show the bread crumb 1615 */ 1616 void showCrumbs(boolean show) { 1617 1618 if (show) { 1619 m_crumbs.removeStyleName(OpenCmsTheme.HIDDEN); 1620 CmsAppWorkplaceUi.get().enableGlobalShortcuts(); 1621 } else { 1622 m_crumbs.addStyleName(OpenCmsTheme.HIDDEN); 1623 CmsAppWorkplaceUi.get().disableGlobalShortcuts(); 1624 } 1625 } 1626 1627 /** 1628 * Shows the parent folder, if available.<p> 1629 */ 1630 void showParentFolder() { 1631 1632 CmsUUID parentId = (CmsUUID)m_treeContainer.getParent(m_currentFolder); 1633 if (parentId != null) { 1634 Item resourceItem = m_treeContainer.getItem(parentId); 1635 if ((resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_DISABLED).getValue() == null) 1636 || !((Boolean)resourceItem.getItemProperty( 1637 CmsResourceTableProperty.PROPERTY_DISABLED).getValue()).booleanValue()) { 1638 // don't open disabled parent folders 1639 try { 1640 readFolder(parentId); 1641 m_fileTree.select(parentId); 1642 } catch (CmsException e) { 1643 CmsErrorDialog.showErrorDialog( 1644 CmsVaadinUtils.getMessageText(Messages.ERR_EXPLORER_CAN_NOT_READ_RESOURCE_1, parentId), 1645 e); 1646 LOG.error(e.getLocalizedMessage(), e); 1647 } 1648 } 1649 } 1650 } 1651 1652 /** 1653 * Toggles between the online and the offline project.<p> 1654 */ 1655 void toggleOnlineOffline() { 1656 1657 CmsObject cms = A_CmsUI.getCmsObject(); 1658 CmsProject targetProject = null; 1659 if (cms.getRequestContext().getCurrentProject().isOnlineProject()) { 1660 targetProject = A_CmsUI.get().getLastOfflineProject(); 1661 if (targetProject == null) { 1662 CmsUserSettings userSettings = new CmsUserSettings(cms); 1663 try { 1664 CmsProject project = cms.readProject(userSettings.getStartProject()); 1665 if (!project.isOnlineProject() 1666 && OpenCms.getOrgUnitManager().getAllAccessibleProjects( 1667 cms, 1668 project.getOuFqn(), 1669 false).contains(project)) { 1670 targetProject = project; 1671 } 1672 } catch (CmsException e) { 1673 LOG.debug("Error reading user start project.", e); 1674 } 1675 if (targetProject == null) { 1676 List<CmsProject> availableProjects = CmsVaadinUtils.getAvailableProjects(cms); 1677 for (CmsProject project : availableProjects) { 1678 if (!project.isOnlineProject()) { 1679 targetProject = project; 1680 break; 1681 } 1682 } 1683 } 1684 } 1685 } else { 1686 try { 1687 targetProject = cms.readProject(CmsProject.ONLINE_PROJECT_ID); 1688 } catch (CmsException e) { 1689 LOG.debug("Error reading online project.", e); 1690 } 1691 } 1692 if (targetProject != null) { 1693 A_CmsUI.get().changeProject(targetProject); 1694 onSiteOrProjectChange(targetProject, null); 1695 Notification.show( 1696 CmsVaadinUtils.getMessageText(Messages.GUI_SWITCHED_TO_PROJECT_1, targetProject.getName())); 1697 } 1698 } 1699 1700 /** 1701 * Adds the given properties to the tree container.<p> 1702 * 1703 * @param properties the properties tom add 1704 */ 1705 private void addTreeContainerProperties(CmsResourceTableProperty... properties) { 1706 1707 for (CmsResourceTableProperty property : properties) { 1708 m_treeContainer.addContainerProperty(property, property.getColumnType(), property.getDefaultValue()); 1709 } 1710 } 1711 1712 /** 1713 * Adds an item to the folder tree.<p> 1714 * 1715 * @param cms the cms context 1716 * @param resource the folder resource 1717 * @param parentId the parent folder id 1718 * @param disabled in case the item is disabled, used for non visible parent folders 1719 * @param container the data container 1720 */ 1721 private void addTreeItem( 1722 CmsObject cms, 1723 CmsResource resource, 1724 CmsUUID parentId, 1725 boolean disabled, 1726 HierarchicalContainer container) { 1727 1728 CmsResourceUtil resUtil = new CmsResourceUtil(cms, resource); 1729 Item resourceItem = container.getItem(resource.getStructureId()); 1730 if (resourceItem == null) { 1731 resourceItem = container.addItem(resource.getStructureId()); 1732 } 1733 1734 // use the root path as name in case of the root item 1735 String resName = parentId == null ? resource.getRootPath() : resource.getName(); 1736 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_RESOURCE_NAME).setValue(resName); 1737 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_STATE).setValue(resource.getState()); 1738 1739 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_INSIDE_PROJECT).setValue( 1740 Boolean.valueOf(resUtil.isInsideProject())); 1741 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_RELEASED_NOT_EXPIRED).setValue( 1742 Boolean.valueOf(resUtil.isReleasedAndNotExpired())); 1743 String iconHTML = CmsResourceIcon.getTreeCaptionHTML(resName, resUtil, null, false); 1744 1745 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_TREE_CAPTION).setValue(iconHTML); 1746 if (disabled) { 1747 resourceItem.getItemProperty(CmsResourceTableProperty.PROPERTY_DISABLED).setValue(Boolean.TRUE); 1748 } 1749 if (parentId != null) { 1750 container.setChildrenAllowed(parentId, true); 1751 container.setParent(resource.getStructureId(), parentId); 1752 } 1753 } 1754 1755 /** 1756 * Creates the site selector combo box.<p> 1757 * 1758 * @param cms the current cms context 1759 * 1760 * @return the combo box 1761 */ 1762 private ComboBox createSiteSelect(CmsObject cms) { 1763 1764 final List<CmsExtendedSiteSelector.SiteSelectorOption> sites = CmsExtendedSiteSelector.getExplorerSiteSelectorOptions( 1765 cms, 1766 true); 1767 final BeanItemContainer<CmsExtendedSiteSelector.SiteSelectorOption> container = new BeanItemContainer<>( 1768 CmsExtendedSiteSelector.SiteSelectorOption.class); 1769 for (CmsExtendedSiteSelector.SiteSelectorOption option : sites) { 1770 container.addItem(option); 1771 } 1772 ComboBox combo = new ComboBox(null, container); 1773 combo.setTextInputAllowed(true); 1774 combo.setNullSelectionAllowed(false); 1775 combo.setWidth("200px"); 1776 combo.setInputPrompt( 1777 Messages.get().getBundle(UI.getCurrent().getLocale()).key(Messages.GUI_EXPLORER_CLICK_TO_EDIT_0)); 1778 combo.setItemCaptionPropertyId("label"); 1779 combo.select(new CmsExtendedSiteSelector.SiteSelectorOption(cms.getRequestContext().getSiteRoot(), null, null)); 1780 combo.setFilteringMode(FilteringMode.CONTAINS); 1781 combo.addValueChangeListener(new ValueChangeListener() { 1782 1783 private static final long serialVersionUID = 1L; 1784 1785 /** Flag used to temporarily disable the standard listener behavior, used when we change the combo box's value programatically. */ 1786 private boolean m_disabled; 1787 1788 public void valueChange(ValueChangeEvent event) { 1789 1790 if (m_disabled) { 1791 return; 1792 } 1793 CmsExtendedSiteSelector.SiteSelectorOption option = (CmsExtendedSiteSelector.SiteSelectorOption)(event.getProperty().getValue()); 1794 if (container.containsId(option)) { 1795 changeSite(option.getSite(), option.getPath()); 1796 m_appContext.updateOnChange(); 1797 container.removeAllContainerFilters(); 1798 if (option.getPath() != null) { 1799 try { 1800 m_disabled = true; 1801 combo.select(new CmsExtendedSiteSelector.SiteSelectorOption(option.getSite(), null, null)); 1802 } finally { 1803 m_disabled = false; 1804 } 1805 } 1806 } 1807 } 1808 }); 1809 if (Page.getCurrent().getBrowserWindowHeight() > 650) { 1810 combo.setPageLength(20); 1811 } 1812 return combo; 1813 } 1814 1815 /** 1816 * Returns the site path from the current state.<p> 1817 * 1818 * @return the site path 1819 */ 1820 private String getPathFromState() { 1821 1822 return StateBean.parse(m_currentState).getFolder(); 1823 } 1824 1825 /** 1826 * Returns the project id from the current state.<p> 1827 * 1828 * @return the project id 1829 */ 1830 private CmsUUID getProjectIdFromState() { 1831 1832 String projectIdStr = StateBean.parse(m_currentState).getProjectId(); 1833 if (CmsUUID.isValidUUID(projectIdStr)) { 1834 return new CmsUUID(projectIdStr); 1835 1836 } 1837 return null; 1838 1839 } 1840 1841 /** 1842 * Returns selected resource UUID from state (empty if not set).<p> 1843 * 1844 * @param state current state 1845 * @return uuid as string 1846 */ 1847 private String getSelectionFromState(String state) { 1848 1849 return StateBean.parse(state).getSelectedResource(); 1850 } 1851 1852 /** 1853 * Returns the site root from the current state.<p> 1854 * 1855 * @return the site root 1856 */ 1857 private String getSiteRootFromState() { 1858 1859 String siteRoot = StateBean.parse(m_currentState).getSiteRoot(); 1860 return siteRoot; 1861 } 1862 1863 /** 1864 * Populates the folder tree.<p> 1865 * 1866 * @param showInvisible to show non visible root folder as disabled 1867 * 1868 * @throws CmsException in case reading the root folder fails 1869 */ 1870 private void initFolderTree(boolean showInvisible) throws CmsException { 1871 1872 CmsObject cms = A_CmsUI.getCmsObject(); 1873 m_treeContainer.removeAllItems(); 1874 try { 1875 CmsResource siteRoot = cms.readResource("/", FOLDERS); 1876 addTreeItem(cms, siteRoot, null, false, m_treeContainer); 1877 } catch (CmsException e) { 1878 if (showInvisible) { 1879 CmsResource siteRoot = cms.readResource("/", CmsResourceFilter.IGNORE_EXPIRATION); 1880 addTreeItem(cms, siteRoot, null, true, m_treeContainer); 1881 } else { 1882 throw e; 1883 } 1884 } 1885 1886 } 1887 1888 /** 1889 * Initializes the app specific toolbar buttons.<p> 1890 * 1891 * @param context the UI context 1892 */ 1893 private void initToolbarButtons(I_CmsAppUIContext context) { 1894 1895 m_publishButton = context.addPublishButton(new I_CmsUpdateListener<String>() { 1896 1897 public void onUpdate(List<String> updatedItems) { 1898 1899 updateAll(false); 1900 } 1901 1902 }); 1903 1904 m_newButton = CmsToolBar.createButton( 1905 FontOpenCms.WAND, 1906 CmsVaadinUtils.getMessageText(Messages.GUI_NEW_RESOURCE_TITLE_0)); 1907 if (CmsAppWorkplaceUi.isOnlineProject()) { 1908 m_newButton.setEnabled(false); 1909 m_newButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_TOOLBAR_NOT_AVAILABLE_ONLINE_0)); 1910 } 1911 m_newButton.addClickListener(new ClickListener() { 1912 1913 private static final long serialVersionUID = 1L; 1914 1915 public void buttonClick(ClickEvent event) { 1916 1917 onClickNew(); 1918 } 1919 1920 }); 1921 1922 context.addToolbarButton(m_newButton); 1923 1924 m_uploadButton = new CmsUploadButton(FontOpenCms.UPLOAD, "/"); 1925 m_specialUploadButton = new Button(FontOpenCms.UPLOAD); 1926 m_uploadButton.addStyleName(ValoTheme.BUTTON_BORDERLESS); 1927 m_uploadButton.addStyleName(OpenCmsTheme.TOOLBAR_BUTTON); 1928 if (CmsAppWorkplaceUi.isOnlineProject()) { 1929 m_uploadButton.setEnabled(false); 1930 m_specialUploadButton.setEnabled(false); 1931 m_uploadButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_TOOLBAR_NOT_AVAILABLE_ONLINE_0)); 1932 m_specialUploadButton.setDescription( 1933 CmsVaadinUtils.getMessageText(Messages.GUI_TOOLBAR_NOT_AVAILABLE_ONLINE_0)); 1934 } else { 1935 m_uploadButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_UPLOAD_BUTTON_TITLE_0)); 1936 m_specialUploadButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_UPLOAD_BUTTON_TITLE_0)); 1937 } 1938 m_uploadButton.addUploadListener(new I_UploadListener() { 1939 1940 public void onUploadFinished(List<String> uploadedFiles) { 1941 1942 updateAll(true); 1943 } 1944 }); 1945 m_specialUploadButton.addStyleName(ValoTheme.BUTTON_BORDERLESS); 1946 m_specialUploadButton.addStyleName(OpenCmsTheme.TOOLBAR_BUTTON); 1947 m_specialUploadButton.addClickListener(event -> { 1948 try { 1949 @SuppressWarnings("unchecked") 1950 Class<I_CmsWorkplaceAction> actionClass = (Class<I_CmsWorkplaceAction>)getClass().getClassLoader().loadClass( 1951 m_uploadAction); 1952 I_CmsWorkplaceAction action = actionClass.newInstance(); 1953 List<CmsResource> resources = new ArrayList<>(); 1954 resources.add(m_uploadFolder); 1955 CmsExplorerDialogContext uploadContext = new CmsExplorerDialogContext( 1956 ContextType.fileTable, 1957 m_fileTable, 1958 this, 1959 resources); 1960 action.executeAction(uploadContext); 1961 } catch (Exception e) { 1962 LOG.error(e.getLocalizedMessage(), e); 1963 CmsErrorDialog.showErrorDialog(e); 1964 } 1965 1966 }); 1967 1968 context.addToolbarButton(m_uploadButton); 1969 context.addToolbarButton(m_specialUploadButton); 1970 } 1971 1972 /** 1973 * Normalizes the state string. Ensuring it starts with the right number of slashes resolving an issue with the vaadin state handling.<p> 1974 * 1975 * @param state the state string 1976 * 1977 * @return the normalized state string 1978 */ 1979 private String normalizeState(String state) { 1980 1981 String result = ""; 1982 if (state.contains(A_CmsWorkplaceApp.PARAM_SEPARATOR)) { 1983 result = state; 1984 while (result.startsWith(CmsAppWorkplaceUi.WORKPLACE_STATE_SEPARATOR)) { 1985 result = result.substring(1); 1986 } 1987 } 1988 return result; 1989 } 1990 1991 /** 1992 * Sets the current path info.<p> 1993 * 1994 * @param path the path 1995 */ 1996 private void setPathInfo(String path) { 1997 1998 m_infoPath.setValue(path); 1999 2000 // generate the path bread crumb 2001 m_crumbs.removeAllComponents(); 2002 int i = path.indexOf("/"); 2003 String openPath = ""; 2004 while (i >= 0) { 2005 String fragment = path.substring(0, i + 1); 2006 openPath += fragment; 2007 path = path.substring(i + 1); 2008 i = path.indexOf("/"); 2009 Button crumb = new Button(fragment, m_crumbListener); 2010 crumb.setData(openPath); 2011 crumb.addStyleName(ValoTheme.BUTTON_LINK); 2012 m_crumbs.addComponent(crumb); 2013 } 2014 } 2015 2016 /** 2017 * Sets the toolbar buttons enabled.<p> 2018 * 2019 * @param enabled the enabled flag 2020 */ 2021 private void setToolbarButtonsEnabled(boolean enabled) { 2022 2023 m_publishButton.setEnabled(enabled); 2024 m_newButton.setEnabled(enabled); 2025 m_uploadButton.setEnabled(enabled); 2026 m_specialUploadButton.setEnabled(enabled); 2027 if (enabled) { 2028 m_publishButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_PUBLISH_BUTTON_TITLE_0)); 2029 m_newButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_NEW_RESOURCE_TITLE_0)); 2030 m_uploadButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_UPLOAD_BUTTON_TITLE_0)); 2031 m_specialUploadButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_UPLOAD_BUTTON_TITLE_0)); 2032 } else { 2033 m_publishButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_TOOLBAR_NOT_AVAILABLE_ONLINE_0)); 2034 m_newButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_TOOLBAR_NOT_AVAILABLE_ONLINE_0)); 2035 m_uploadButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_TOOLBAR_NOT_AVAILABLE_ONLINE_0)); 2036 m_specialUploadButton.setDescription( 2037 CmsVaadinUtils.getMessageText(Messages.GUI_TOOLBAR_NOT_AVAILABLE_ONLINE_0)); 2038 } 2039 } 2040 2041 /** 2042 * Updates the upload button state based on the current folder. 2043 * 2044 * @param folder the current folder 2045 */ 2046 private void updateUploadButton(CmsResource folder) { 2047 2048 String uploadAction = null; 2049 m_uploadFolder = folder; 2050 try { 2051 uploadAction = OpenCms.getResourceManager().getResourceType(folder).getConfiguration().get( 2052 "gallery.upload.action"); 2053 } catch (Exception e) { 2054 // Resource type not found? 2055 LOG.error(e.getLocalizedMessage(), e); 2056 } 2057 m_uploadAction = uploadAction; 2058 if (uploadAction != null) { 2059 m_uploadButton.setVisible(false); 2060 m_specialUploadButton.setVisible(true); 2061 m_uploadArea.setTargetFolder(null); 2062 } else { 2063 boolean enabled = OpenCms.getWorkplaceManager().getUploadRestriction().getUploadRestrictionInfo( 2064 A_CmsUI.getCmsObject()).isUploadEnabled(folder.getRootPath()); 2065 m_uploadButton.setVisible(enabled); 2066 m_specialUploadButton.setVisible(false); 2067 m_uploadButton.setTargetFolder(folder.getRootPath()); 2068 m_uploadArea.setTargetFolder(folder.getRootPath()); 2069 } 2070 } 2071}