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