001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH (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 GmbH, 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.widgets; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.configuration.CmsResourceTypeConfig; 032import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants; 033import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants.GalleryMode; 034import org.opencms.file.CmsObject; 035import org.opencms.file.CmsResource; 036import org.opencms.file.types.CmsResourceTypeBinary; 037import org.opencms.file.types.CmsResourceTypeImage; 038import org.opencms.file.types.CmsResourceTypePlain; 039import org.opencms.i18n.CmsMessages; 040import org.opencms.json.JSONException; 041import org.opencms.json.JSONObject; 042import org.opencms.main.CmsLog; 043import org.opencms.main.OpenCms; 044import org.opencms.util.CmsMacroResolver; 045import org.opencms.util.CmsStringUtil; 046import org.opencms.workplace.CmsWorkplace; 047import org.opencms.xml.content.I_CmsXmlContentHandler.DisplayType; 048import org.opencms.xml.types.A_CmsXmlContentValue; 049 050import java.util.List; 051import java.util.Locale; 052import java.util.Set; 053 054import org.apache.commons.collections.Factory; 055import org.apache.commons.logging.Log; 056 057import com.google.common.base.Objects; 058 059/** 060 * Provides a OpenCms VFS file selection widget, for use on a widget dialog.<p> 061 * 062 * @since 6.0.0 063 */ 064public class CmsVfsFileWidget extends A_CmsWidget implements I_CmsADEWidget { 065 066 /** Macro resolver factory to get the default searchable types. */ 067 protected class SearchTypesFactory implements Factory { 068 069 /** The CMS context. */ 070 private CmsObject m_cms; 071 072 /** The resource. */ 073 private CmsResource m_resource; 074 075 /** 076 * Constructor.<p> 077 * 078 * @param cms the CMS context 079 * @param resource the resource 080 */ 081 public SearchTypesFactory(CmsObject cms, CmsResource resource) { 082 083 m_cms = cms; 084 m_resource = resource; 085 } 086 087 /** 088 * @see org.apache.commons.collections.Factory#create() 089 */ 090 public Object create() { 091 092 return getDefaultSearchTypes(m_cms, m_resource); 093 } 094 } 095 096 /** Configuration parameter to set the flag to include files in popup resource tree. */ 097 public static final String CONFIGURATION_EXCLUDEFILES = "excludefiles"; 098 099 /** Configuration parameter to set the flag to show the site selector in popup resource tree. */ 100 public static final String CONFIGURATION_HIDESITESELECTOR = "hidesiteselector"; 101 102 /** Configuration parameter to set the flag to include files in popup resource tree. */ 103 public static final String CONFIGURATION_INCLUDEFILES = "includefiles"; 104 105 /** Configuration parameter to prevent the project awareness flag in the popup resource tree. */ 106 public static final String CONFIGURATION_NOTPROJECTAWARE = "notprojectaware"; 107 108 /** Configuration parameter to set the project awareness flag in the popup resource tree. */ 109 public static final String CONFIGURATION_PROJECTAWARE = "projectaware"; 110 111 /** Configuration parameter to set search types of the gallery widget. */ 112 public static final String CONFIGURATION_SEARCHTYPES = "searchtypes"; 113 114 /** Configuration parameter to set the selectable types of the gallery widget. */ 115 public static final String CONFIGURATION_SELECTABLETYPES = "selectabletypes"; 116 117 /** Configuration parameter to set the flag to show the site selector in popup resource tree. */ 118 public static final String CONFIGURATION_SHOWSITESELECTOR = "showsiteselector"; 119 120 /** Configuration parameter to set start folder. */ 121 public static final String CONFIGURATION_STARTFOLDER = "startfolder"; 122 123 /** Configuration parameter to set start site of the popup resource tree. */ 124 public static final String CONFIGURATION_STARTSITE = "startsite"; 125 126 /** The default search types macro name. */ 127 public static final String DEFAULT_SEARCH_TYPES_MACRO = "defaultSearchTypes"; 128 129 /** The logger instance for this class. */ 130 private static final Log LOG = CmsLog.getLog(CmsVfsFileWidget.class); 131 132 /** Flag to determine if files should be shown in popup window. */ 133 private boolean m_includeFiles; 134 135 /** Flag to determine project awareness, ie. if resources outside of the current project should be displayed as normal. */ 136 private boolean m_projectAware; 137 138 /** The type shown in the gallery types tab. */ 139 private String m_searchTypes; 140 141 /** The types that may be selected through the gallery widget. */ 142 private String m_selectableTypes; 143 144 /** Flag to determine if the site selector should be shown in popup window. */ 145 private boolean m_showSiteSelector; 146 147 /** The start folder. */ 148 private String m_startFolder; 149 150 /** The start site used in the popup window. */ 151 private String m_startSite; 152 153 /** 154 * Creates a new vfs file widget.<p> 155 */ 156 public CmsVfsFileWidget() { 157 158 // empty constructor is required for class registration 159 this(""); 160 } 161 162 /** 163 * Creates a new vfs file widget with the parameters to configure the popup tree window behavior.<p> 164 * 165 * @param showSiteSelector true if the site selector should be shown in the popup window 166 * @param startSite the start site root for the popup window 167 */ 168 public CmsVfsFileWidget(boolean showSiteSelector, String startSite) { 169 170 this(showSiteSelector, startSite, true); 171 } 172 173 /** 174 * Creates a new vfs file widget with the parameters to configure the popup tree window behavior.<p> 175 * 176 * @param showSiteSelector true if the site selector should be shown in the popup window 177 * @param startSite the start site root for the popup window 178 * @param includeFiles true if files should be shown in the popup window 179 */ 180 public CmsVfsFileWidget(boolean showSiteSelector, String startSite, boolean includeFiles) { 181 182 this(showSiteSelector, startSite, includeFiles, true); 183 } 184 185 /** 186 * Creates a new vfs file widget with the parameters to configure the popup tree window behavior.<p> 187 * 188 * @param showSiteSelector true if the site selector should be shown in the popup window 189 * @param startSite the start site root for the popup window 190 * @param includeFiles <code>true</code> if files should be shown in the popup window 191 * @param projectAware <code>true</code> if resources outside of the current project should be displayed as normal 192 */ 193 public CmsVfsFileWidget(boolean showSiteSelector, String startSite, boolean includeFiles, boolean projectAware) { 194 195 m_showSiteSelector = showSiteSelector; 196 m_startSite = startSite; 197 m_includeFiles = includeFiles; 198 m_projectAware = projectAware; 199 } 200 201 /** 202 * Creates a new vfs file widget with the given configuration.<p> 203 * 204 * @param configuration the configuration to use 205 */ 206 public CmsVfsFileWidget(String configuration) { 207 208 super(configuration); 209 } 210 211 /** 212 * Returns a comma separated list of the default search type names.<p> 213 * 214 * @param cms the CMS context 215 * @param resource the edited resource 216 * 217 * @return a comma separated list of the default search type names 218 */ 219 protected static String getDefaultSearchTypes(CmsObject cms, CmsResource resource) { 220 221 StringBuffer result = new StringBuffer(); 222 String referenceSitePath = cms.getSitePath(resource); 223 CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration( 224 cms, 225 cms.getRequestContext().addSiteRoot(cms.getRequestContext().getUri())); 226 Set<String> detailPageTypes = OpenCms.getADEManager().getDetailPageTypes(cms); 227 for (CmsResourceTypeConfig typeConfig : config.getResourceTypes()) { 228 String typeName = typeConfig.getTypeName(); 229 if (!detailPageTypes.contains(typeName)) { 230 continue; 231 } 232 if (typeConfig.checkViewable(cms, referenceSitePath)) { 233 result.append(typeName).append(","); 234 } 235 } 236 result.append(CmsResourceTypeBinary.getStaticTypeName()).append(","); 237 result.append(CmsResourceTypeImage.getStaticTypeName()).append(","); 238 result.append(CmsResourceTypePlain.getStaticTypeName()); 239 return result.toString(); 240 } 241 242 /** 243 * @see org.opencms.widgets.A_CmsWidget#getConfiguration() 244 */ 245 @Override 246 public String getConfiguration() { 247 248 StringBuffer result = new StringBuffer(8); 249 250 // append site selector flag to configuration 251 if (m_showSiteSelector) { 252 result.append(CONFIGURATION_SHOWSITESELECTOR); 253 } else { 254 result.append(CONFIGURATION_HIDESITESELECTOR); 255 } 256 257 // append start site to configuration 258 if (m_startSite != null) { 259 result.append("|"); 260 result.append(CONFIGURATION_STARTSITE); 261 result.append("="); 262 result.append(m_startSite); 263 } 264 265 // append flag for including files 266 result.append("|"); 267 if (m_includeFiles) { 268 result.append(CONFIGURATION_INCLUDEFILES); 269 } else { 270 result.append(CONFIGURATION_EXCLUDEFILES); 271 } 272 273 // append flag for project awareness 274 result.append("|"); 275 if (m_projectAware) { 276 result.append(CONFIGURATION_PROJECTAWARE); 277 } else { 278 result.append(CONFIGURATION_NOTPROJECTAWARE); 279 } 280 if (m_searchTypes != null) { 281 result.append("|"); 282 result.append(CONFIGURATION_SEARCHTYPES); 283 result.append("="); 284 result.append(m_searchTypes); 285 } 286 if (m_selectableTypes != null) { 287 result.append("|"); 288 result.append(CONFIGURATION_SELECTABLETYPES); 289 result.append("="); 290 result.append(m_selectableTypes); 291 } 292 return result.toString(); 293 } 294 295 /** 296 * @see org.opencms.widgets.I_CmsADEWidget#getConfiguration(org.opencms.file.CmsObject, org.opencms.xml.types.A_CmsXmlContentValue, org.opencms.i18n.CmsMessages, org.opencms.file.CmsResource, java.util.Locale) 297 */ 298 public String getConfiguration( 299 CmsObject cms, 300 A_CmsXmlContentValue schemaType, 301 CmsMessages messages, 302 CmsResource resource, 303 Locale contentLocale) { 304 305 JSONObject config = getJsonConfig(cms, schemaType, messages, resource, contentLocale); 306 return config.toString(); 307 } 308 309 /** 310 * @see org.opencms.widgets.I_CmsADEWidget#getCssResourceLinks(org.opencms.file.CmsObject) 311 */ 312 public List<String> getCssResourceLinks(CmsObject cms) { 313 314 return null; 315 } 316 317 /** 318 * @see org.opencms.widgets.I_CmsADEWidget#getDefaultDisplayType() 319 */ 320 public DisplayType getDefaultDisplayType() { 321 322 return DisplayType.wide; 323 } 324 325 /** 326 * @see org.opencms.widgets.I_CmsWidget#getDialogIncludes(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog) 327 */ 328 @Override 329 public String getDialogIncludes(CmsObject cms, I_CmsWidgetDialog widgetDialog) { 330 331 StringBuffer result = new StringBuffer(16); 332 result.append(getJSIncludeFile(CmsWorkplace.getSkinUri() + "commons/tree.js")); 333 result.append("\n"); 334 result.append(getJSIncludeFile(CmsWorkplace.getSkinUri() + "components/widgets/fileselector.js")); 335 return result.toString(); 336 } 337 338 /** 339 * @see org.opencms.widgets.I_CmsWidget#getDialogInitCall(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog) 340 */ 341 @Override 342 public String getDialogInitCall(CmsObject cms, I_CmsWidgetDialog widgetDialog) { 343 344 return "\tinitVfsFileSelector();\n"; 345 } 346 347 /** 348 * @see org.opencms.widgets.I_CmsWidget#getDialogInitMethod(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog) 349 */ 350 @Override 351 public String getDialogInitMethod(CmsObject cms, I_CmsWidgetDialog widgetDialog) { 352 353 StringBuffer result = new StringBuffer(16); 354 result.append("function initVfsFileSelector() {\n"); 355 //initialize tree javascript, does parts of <code>CmsTree.initTree(CmsObject, encoding, skinuri);</code> 356 result.append("\tinitResources(\""); 357 result.append(OpenCms.getWorkplaceManager().getEncoding()); 358 result.append("\", \""); 359 result.append(CmsWorkplace.VFS_PATH_WORKPLACE); 360 result.append("\", \""); 361 result.append(CmsWorkplace.getSkinUri()); 362 result.append("\", \""); 363 result.append(OpenCms.getSystemInfo().getOpenCmsContext()); 364 result.append("\");\n"); 365 result.append("}\n"); 366 return result.toString(); 367 } 368 369 /** 370 * @see org.opencms.widgets.I_CmsWidget#getDialogWidget(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 371 */ 372 public String getDialogWidget(CmsObject cms, I_CmsWidgetDialog widgetDialog, I_CmsWidgetParameter param) { 373 374 String id = param.getId(); 375 StringBuffer result = new StringBuffer(128); 376 377 result.append("<td class=\"xmlTd\">"); 378 result.append("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"maxwidth\"><tr><td style=\"width: 100%;\">"); 379 result.append("<input style=\"width: 99%;\" class=\"xmlInput"); 380 if (param.hasError()) { 381 result.append(" xmlInputError"); 382 } 383 result.append("\" value=\""); 384 result.append(param.getStringValue(cms)); 385 result.append("\" name=\""); 386 result.append(id); 387 result.append("\" id=\""); 388 result.append(id); 389 result.append("\"></td>"); 390 result.append(widgetDialog.dialogHorizontalSpacer(10)); 391 result.append("<td><table class=\"editorbuttonbackground\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>"); 392 393 StringBuffer buttonJs = new StringBuffer(8); 394 buttonJs.append("javascript:openTreeWin('EDITOR', '"); 395 buttonJs.append(id); 396 buttonJs.append("', document, "); 397 buttonJs.append(m_showSiteSelector); 398 buttonJs.append(", '"); 399 if (m_startSite != null) { 400 buttonJs.append(m_startSite); 401 } else { 402 buttonJs.append(cms.getRequestContext().getSiteRoot()); 403 } 404 buttonJs.append("', "); 405 // include files 406 buttonJs.append(m_includeFiles); 407 // project awareness 408 buttonJs.append(", "); 409 buttonJs.append(m_projectAware); 410 buttonJs.append(");return false;"); 411 412 result.append(widgetDialog.button( 413 buttonJs.toString(), 414 null, 415 "folder", 416 org.opencms.workplace.Messages.GUI_DIALOG_BUTTON_SEARCH_0, 417 widgetDialog.getButtonStyle())); 418 result.append("</tr></table>"); 419 result.append("</td></tr></table>"); 420 421 result.append("</td>"); 422 423 return result.toString(); 424 } 425 426 /** 427 * @see org.opencms.widgets.I_CmsADEWidget#getInitCall() 428 */ 429 public String getInitCall() { 430 431 return null; 432 } 433 434 /** 435 * @see org.opencms.widgets.I_CmsADEWidget#getJavaScriptResourceLinks(org.opencms.file.CmsObject) 436 */ 437 public List<String> getJavaScriptResourceLinks(CmsObject cms) { 438 439 return null; 440 } 441 442 /** 443 * Returns the start site root shown by the widget when first displayed.<p> 444 * 445 * If <code>null</code> is returned, the dialog will display the current site of 446 * the current user.<p> 447 * 448 * @return the start site root shown by the widget when first displayed 449 */ 450 public String getStartSite() { 451 452 return m_startSite; 453 } 454 455 /** 456 * @see org.opencms.widgets.I_CmsADEWidget#getWidgetName() 457 */ 458 public String getWidgetName() { 459 460 return CmsVfsFileWidget.class.getName(); 461 } 462 463 /** 464 * @see org.opencms.widgets.I_CmsADEWidget#isInternal() 465 */ 466 public boolean isInternal() { 467 468 return true; 469 } 470 471 /** 472 * Returns <code>true</code> if the site selector is shown.<p> 473 * 474 * The default is <code>true</code>.<p> 475 * 476 * @return <code>true</code> if the site selector is shown 477 */ 478 public boolean isShowingSiteSelector() { 479 480 return m_showSiteSelector; 481 } 482 483 /** 484 * @see org.opencms.widgets.I_CmsWidget#newInstance() 485 */ 486 public I_CmsWidget newInstance() { 487 488 return new CmsVfsFileWidget(getConfiguration()); 489 } 490 491 /** 492 * @see org.opencms.widgets.A_CmsWidget#setConfiguration(java.lang.String) 493 */ 494 @Override 495 public void setConfiguration(String configuration) { 496 497 m_showSiteSelector = true; 498 m_includeFiles = true; 499 m_projectAware = true; 500 501 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(configuration)) { 502 if (configuration.contains(CONFIGURATION_HIDESITESELECTOR)) { 503 // site selector should be hidden 504 m_showSiteSelector = false; 505 } 506 int siteIndex = configuration.indexOf(CONFIGURATION_STARTSITE); 507 if (siteIndex != -1) { 508 // start site is given 509 String site = configuration.substring(siteIndex + CONFIGURATION_STARTSITE.length() + 1); 510 if (site.indexOf('|') != -1) { 511 // cut eventual following configuration values 512 site = site.substring(0, site.indexOf('|')); 513 } 514 m_startSite = site; 515 } 516 if (configuration.contains(CONFIGURATION_EXCLUDEFILES)) { 517 // files should not be included 518 m_includeFiles = false; 519 } 520 if (configuration.contains(CONFIGURATION_NOTPROJECTAWARE)) { 521 // resources outside of the current project should not be disabled 522 m_projectAware = false; 523 } 524 int searchTypesIndex = configuration.indexOf(CONFIGURATION_SEARCHTYPES); 525 if (searchTypesIndex != -1) { 526 String searchTypes = configuration.substring(searchTypesIndex + CONFIGURATION_SEARCHTYPES.length() + 1); 527 if (searchTypes.contains("|")) { 528 m_searchTypes = searchTypes.substring(0, searchTypes.indexOf("|")); 529 } else { 530 m_searchTypes = searchTypes; 531 } 532 } 533 int selectableTypesIndex = configuration.indexOf(CONFIGURATION_SELECTABLETYPES); 534 if (selectableTypesIndex != -1) { 535 String selectableTypes = configuration.substring(selectableTypesIndex 536 + CONFIGURATION_SELECTABLETYPES.length() 537 + 1); 538 if (selectableTypes.contains("|")) { 539 m_selectableTypes = selectableTypes.substring(0, selectableTypes.indexOf("|")); 540 } else { 541 m_selectableTypes = selectableTypes; 542 } 543 } 544 int startFolderIndex = configuration.indexOf(CONFIGURATION_STARTFOLDER); 545 if (startFolderIndex != -1) { 546 String startFolder = configuration.substring(startFolderIndex + CONFIGURATION_STARTFOLDER.length() + 1); 547 if (startFolder.contains("|")) { 548 m_startFolder = startFolder.substring(0, startFolder.indexOf("|")); 549 } else { 550 m_startFolder = startFolder; 551 } 552 } 553 } 554 super.setConfiguration(configuration); 555 } 556 557 /** 558 * Gets the JSON configuration.<p> 559 * 560 * @param cms the current CMS context 561 * @param schemaType the schema type 562 * @param messages the messages 563 * @param resource the content resource 564 * @param contentLocale the content locale 565 * 566 * @return the JSON configuration object 567 */ 568 protected JSONObject getJsonConfig( 569 CmsObject cms, 570 A_CmsXmlContentValue schemaType, 571 CmsMessages messages, 572 CmsResource resource, 573 Locale contentLocale) { 574 575 JSONObject config = new JSONObject(); 576 try { 577 config.put(I_CmsGalleryProviderConstants.CONFIG_START_SITE, m_startSite); 578 String tabConfig = null; 579 if (m_includeFiles) { 580 tabConfig = "selectAll"; 581 } else { 582 tabConfig = "folders"; 583 } 584 config.put(I_CmsGalleryProviderConstants.CONFIG_TAB_CONFIG, tabConfig); 585 config.put(I_CmsGalleryProviderConstants.CONFIG_SHOW_SITE_SELECTOR, m_showSiteSelector); 586 config.put(I_CmsGalleryProviderConstants.CONFIG_REFERENCE_PATH, cms.getSitePath(resource)); 587 config.put(I_CmsGalleryProviderConstants.CONFIG_LOCALE, contentLocale.toString()); 588 config.put(I_CmsGalleryProviderConstants.CONFIG_GALLERY_MODE, GalleryMode.widget.name()); 589 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_selectableTypes)) { 590 config.put(I_CmsGalleryProviderConstants.CONFIG_RESOURCE_TYPES, m_selectableTypes.trim()); 591 } 592 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_searchTypes)) { 593 CmsMacroResolver resolver = CmsMacroResolver.newInstance(); 594 resolver.addDynamicMacro(DEFAULT_SEARCH_TYPES_MACRO, new SearchTypesFactory(cms, resource)); 595 String searchTypes = resolver.resolveMacros(m_searchTypes.trim()); 596 config.put(I_CmsGalleryProviderConstants.CONFIG_SEARCH_TYPES, searchTypes); 597 } else if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_selectableTypes)) { 598 config.put(I_CmsGalleryProviderConstants.CONFIG_SEARCH_TYPES, getDefaultSearchTypes(cms, resource)); 599 } 600 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_startFolder)) { 601 config.put(I_CmsGalleryProviderConstants.CONFIG_START_FOLDER, m_startFolder); 602 } 603 String treeToken = "" 604 + Objects.hashCode(m_startSite, cms.getRequestContext().getSiteRoot(), "" + m_selectableTypes); 605 config.put(I_CmsGalleryProviderConstants.CONFIG_TREE_TOKEN, treeToken); 606 } catch (JSONException e) { 607 LOG.error(e.getLocalizedMessage(), e); 608 } 609 return config; 610 } 611 612 /** 613 * Computes the tree token, which is used to decide which preloaded tree, if any, to load for the VFS/sitemap tabs.<p> 614 * 615 * @param cms the current CMS context 616 * @param value the content value 617 * @param resource the content resource 618 * @param contentLocale the content locale 619 * 620 * @return the tree token 621 */ 622 protected String getTreeToken(CmsObject cms, A_CmsXmlContentValue value, CmsResource resource, Locale contentLocale) { 623 624 return cms.getRequestContext().getSiteRoot(); 625 } 626}