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.unusedcontentfinder; 029 030import org.opencms.file.CmsFile; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsProject; 033import org.opencms.file.CmsProperty; 034import org.opencms.file.CmsPropertyDefinition; 035import org.opencms.file.CmsResource; 036import org.opencms.file.CmsResourceFilter; 037import org.opencms.file.types.CmsResourceTypeXmlAdeConfiguration; 038import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 039import org.opencms.file.types.CmsResourceTypeXmlContent; 040import org.opencms.file.types.I_CmsResourceType; 041import org.opencms.main.CmsException; 042import org.opencms.main.CmsLog; 043import org.opencms.main.OpenCms; 044import org.opencms.relations.CmsRelation; 045import org.opencms.relations.CmsRelationFilter; 046import org.opencms.ui.A_CmsUI; 047import org.opencms.ui.CmsVaadinUtils; 048import org.opencms.ui.I_CmsDialogContext; 049import org.opencms.ui.I_CmsDialogContext.ContextType; 050import org.opencms.ui.apps.CmsAppWorkplaceUi; 051import org.opencms.ui.apps.I_CmsContextProvider; 052import org.opencms.ui.apps.Messages; 053import org.opencms.ui.components.CmsComponentState; 054import org.opencms.ui.components.CmsErrorDialog; 055import org.opencms.ui.components.CmsFileTable; 056import org.opencms.ui.components.CmsFileTableDialogContext; 057import org.opencms.ui.components.CmsFolderSelector; 058import org.opencms.ui.components.CmsResourceTableProperty; 059import org.opencms.ui.components.CmsResultFilterComponent; 060import org.opencms.ui.components.CmsSiteSelector; 061import org.opencms.ui.components.CmsTypeSelector; 062import org.opencms.ui.components.OpenCmsTheme; 063import org.opencms.ui.contextmenu.CmsResourceContextMenuBuilder; 064import org.opencms.ui.dialogs.CmsDeleteDialog; 065import org.opencms.util.CmsStringUtil; 066import org.opencms.workplace.explorer.CmsExplorerTypeSettings; 067import org.opencms.xml.CmsXmlContentDefinition; 068import org.opencms.xml.content.I_CmsXmlContentHandler; 069 070import java.util.ArrayList; 071import java.util.List; 072import java.util.Set; 073 074import org.apache.commons.logging.Log; 075 076import com.vaadin.ui.Alignment; 077import com.vaadin.ui.Button; 078import com.vaadin.ui.Button.ClickEvent; 079import com.vaadin.ui.Component; 080import com.vaadin.ui.FormLayout; 081import com.vaadin.v7.data.Property.ValueChangeEvent; 082import com.vaadin.v7.data.Property.ValueChangeListener; 083import com.vaadin.v7.data.util.filter.Or; 084import com.vaadin.v7.data.util.filter.SimpleStringFilter; 085import com.vaadin.v7.event.FieldEvents.TextChangeEvent; 086import com.vaadin.v7.event.FieldEvents.TextChangeListener; 087import com.vaadin.v7.ui.HorizontalLayout; 088import com.vaadin.v7.ui.VerticalLayout; 089 090/** 091 * Component that realizes a unused content finder. 092 */ 093@SuppressWarnings("deprecation") 094public class CmsUnusedContentFinderComposite { 095 096 /** 097 * The delete button of the unused content finder. 098 */ 099 private class DeleteButtonComponent extends Button { 100 101 /** Serial version id. */ 102 private static final long serialVersionUID = 1L; 103 104 /** 105 * Creates a new delete button. 106 */ 107 DeleteButtonComponent() { 108 109 String caption = CmsVaadinUtils.getMessageText(Messages.GUI_UNUSED_CONTENT_FINDER_DELETE_ALL_0); 110 addStyleName(OpenCmsTheme.BUTTON_RED); 111 setCaption(caption); 112 setVisible(false); 113 addClickListener(new ClickListener() { 114 115 private static final long serialVersionUID = 1L; 116 117 public void buttonClick(ClickEvent event) { 118 119 m_resultComponent.getFileTable().selectAll(); 120 I_CmsDialogContext context = m_resultComponent.getFileTable().getContextProvider().getDialogContext(); 121 context.start(caption, new CmsDeleteDialog(context)); 122 } 123 }); 124 } 125 } 126 127 /** 128 * The form component of the unused content finder. 129 */ 130 private class FormComponent extends VerticalLayout { 131 132 /** Serial version id. */ 133 private static final long serialVersionUID = 1L; 134 135 /** The form layout. */ 136 private FormLayout m_formLayout; 137 138 /** The site selector. */ 139 private CmsSiteSelector m_siteSelector; 140 141 /** The folder selector. */ 142 private CmsFolderSelector m_folderSelector; 143 144 /** The type selector. */ 145 private CmsTypeSelector m_typeSelector; 146 147 /** The search button. */ 148 private Button m_searchButton; 149 150 /** 151 * Creates a new form component. 152 */ 153 FormComponent() { 154 155 setMargin(true); 156 setSpacing(true); 157 m_formLayout = new FormLayout(); 158 m_formLayout.setMargin(true); 159 m_formLayout.setSpacing(true); 160 m_formLayout.addStyleName("o-formlayout-narrow"); 161 initSiteSelector(); 162 initFolderSelector(); 163 initTypeSelector(); 164 m_formLayout.addComponent(new VerticalLayout()); // fix layout bug 165 addComponent(m_formLayout); 166 initSearchButton(); 167 initDeleteButton(); 168 } 169 170 /** 171 * Returns the selected folder value. 172 * @return the selected folder value 173 */ 174 String getFolderValue() { 175 176 return m_folderSelector.getValue(); 177 } 178 179 /** 180 * Returns the selected site value. 181 * @return the selected site value 182 */ 183 String getSiteValue() { 184 185 return (String)m_siteSelector.getValue(); 186 } 187 188 /** 189 * Returns the selected type value. 190 * @return the selected type value 191 */ 192 I_CmsResourceType getTypeValue() { 193 194 return (I_CmsResourceType)m_typeSelector.getValue(); 195 } 196 197 /** 198 * Sets the folder selector value. 199 * @param folder the folder to set 200 */ 201 void setFolderValue(String folder) { 202 203 m_folderSelector.setValue(folder); 204 } 205 206 /** 207 * Sets the site selector value. 208 * @param site the site to set 209 */ 210 void setSiteValue(String site) { 211 212 m_siteSelector.setValue(site); 213 } 214 215 /** 216 * Sets the type selector value. 217 * @param type the type to set 218 */ 219 void setTypeValue(I_CmsResourceType type) { 220 221 m_typeSelector.setValue(type); 222 } 223 224 /** 225 * Updates the search root. 226 * @throws CmsException if initializing the CMS object fails 227 */ 228 void updateSearchRoot() throws CmsException { 229 230 CmsObject newCms = OpenCms.initCmsObject(A_CmsUI.getCmsObject()); 231 newCms.getRequestContext().setSiteRoot((String)m_siteSelector.getValue()); 232 m_folderSelector.setCmsObject(newCms); 233 m_folderSelector.setValue("/"); 234 } 235 236 /** 237 * Initializes the delete button. 238 */ 239 private void initDeleteButton() { 240 241 HorizontalLayout layout = new HorizontalLayout(); 242 layout.setMargin(true); 243 layout.setSpacing(true); 244 layout.setWidth("100%"); 245 layout.setStyleName("o-dialog-button-bar"); 246 layout.addComponent(m_deleteButtonComponent); 247 layout.setComponentAlignment(m_deleteButtonComponent, Alignment.TOP_RIGHT); 248 addComponent(layout); 249 } 250 251 /** 252 * Initializes the folder selector. 253 */ 254 private void initFolderSelector() { 255 256 m_folderSelector = new CmsFolderSelector(); 257 m_formLayout.addComponent(m_folderSelector); 258 } 259 260 /** 261 * Initializes the search button. 262 */ 263 private void initSearchButton() { 264 265 HorizontalLayout layout = new HorizontalLayout(); 266 layout.setMargin(true); 267 layout.setSpacing(true); 268 layout.setWidth("100%"); 269 layout.setStyleName("o-dialog-button-bar"); 270 m_searchButton = new Button( 271 CmsVaadinUtils.getMessageText(Messages.GUI_SOURCESEARCH_SEARCH_0), 272 new Button.ClickListener() { 273 274 private static final long serialVersionUID = 1L; 275 276 public void buttonClick(ClickEvent event) { 277 278 search(true); 279 280 } 281 }); 282 m_searchButton.addStyleName(OpenCmsTheme.BUTTON_BLUE); 283 layout.addComponent(m_searchButton); 284 layout.setComponentAlignment(m_searchButton, Alignment.TOP_RIGHT); 285 addComponent(layout); 286 } 287 288 /** 289 * Initializes the site selector. 290 */ 291 @SuppressWarnings("serial") 292 private void initSiteSelector() { 293 294 m_siteSelector = new CmsSiteSelector(); 295 m_siteSelector.setWidthFull(); 296 m_siteSelector.addValueChangeListener(new ValueChangeListener() { 297 298 public void valueChange(ValueChangeEvent event) { 299 300 try { 301 updateSearchRoot(); 302 } catch (CmsException e) { 303 LOG.error("Unable to initialize CmsObject", e); 304 } 305 } 306 307 }); 308 m_formLayout.addComponent(m_siteSelector); 309 } 310 311 /** 312 * Initializes the type selector. 313 */ 314 private void initTypeSelector() { 315 316 m_typeSelector = new CmsTypeSelector(); 317 m_typeSelector.updateTypes(getAvailableTypes()); 318 m_formLayout.addComponent(m_typeSelector); 319 } 320 } 321 322 /** 323 * The result component of the unused content finder. 324 */ 325 private class ResultComponent extends VerticalLayout { 326 327 /** Serial version id. */ 328 private static final long serialVersionUID = 1L; 329 330 /** The file table. */ 331 CmsFileTable m_fileTable; 332 333 /** Layout showing empty result message. */ 334 private VerticalLayout m_infoEmptyResult; 335 336 /** Layout showing introduction message. */ 337 private VerticalLayout m_infoIntroLayout; 338 339 /** Layout showing too many results message. */ 340 private VerticalLayout m_infoTooManyResults; 341 342 /** Layout showing too invalid folder message. */ 343 private VerticalLayout m_infoInvalidFolder; 344 345 /** 346 * Creates a new result component. 347 */ 348 ResultComponent() { 349 350 setSizeFull(); 351 initInfoIntroLayout(); 352 initInfoEmptyResult(); 353 initInfoTooManyResults(); 354 initInfoInvalidFolder(); 355 initFileTable(); 356 } 357 358 /** 359 * Returns the file table. 360 * @return the file table 361 */ 362 CmsFileTable getFileTable() { 363 364 return m_fileTable; 365 } 366 367 /** 368 * Updates the search result. 369 */ 370 void updateResult() { 371 372 if (!isValidFolder()) { 373 showInfoInvalidFolder(); 374 return; 375 } 376 CmsObject cms = getOfflineCms(); 377 I_CmsResourceType type = m_formComponent.getTypeValue(); 378 String folderName = m_formComponent.getFolderValue(); 379 List<CmsResource> resourcesToShow = new ArrayList<CmsResource>(); 380 boolean tooManyResults = false; 381 if (cms.existsResource(folderName)) { 382 try { 383 List<I_CmsResourceType> resourceTypes = new ArrayList<>(); 384 if (type == null) { 385 resourceTypes = getAvailableTypes(); 386 } else { 387 resourceTypes.add(type); 388 } 389 for (I_CmsResourceType resourceType : resourceTypes) { 390 CmsResourceFilter filter = CmsResourceFilter.ONLY_VISIBLE.addRequireType(resourceType); 391 List<CmsResource> resources = cms.readResources(folderName, filter); 392 for (CmsResource resource : resources) { 393 if (isExcludedByProperties(resource, false) 394 || isUsedByOtherContents(resource, false) 395 || isUsedByOtherContents(resource, true)) { 396 // resource is excluded by properties in the offline project 397 // resource is used by other contents in the offline project 398 // resource is used by other contents in the online project 399 } else { 400 resourcesToShow.add(resource); 401 } 402 if (resourcesToShow.size() > MAX_RESULTS) { 403 tooManyResults = true; 404 break; 405 } 406 } 407 } 408 m_fileTable.fillTable(cms, resourcesToShow); 409 } catch (CmsException e) { 410 CmsErrorDialog.showErrorDialog(e); 411 } 412 } 413 m_infoIntroLayout.setVisible(false); 414 if (resourcesToShow.isEmpty()) { 415 showInfoEmptyResult(); 416 m_deleteButtonComponent.setVisible(false); 417 } else if (tooManyResults) { 418 showInfoTooManyResults(); 419 m_deleteButtonComponent.setVisible(false); 420 } else { 421 showFileTable(); 422 m_deleteButtonComponent.setVisible(true); 423 } 424 } 425 426 /** 427 * Initializes the file table. 428 */ 429 private void initFileTable() { 430 431 m_fileTable = new CmsFileTable(null) { 432 433 private static final long serialVersionUID = 1L; 434 435 /** 436 * Path, title, and type columns shall be visible and not collapsed. 437 * @see org.opencms.ui.components.CmsFileTable#applyWorkplaceAppSettings() 438 */ 439 @Override 440 public void applyWorkplaceAppSettings() { 441 442 super.applyWorkplaceAppSettings(); 443 m_fileTable.setColumnCollapsed(CmsResourceTableProperty.PROPERTY_SIZE, true); 444 m_fileTable.setColumnCollapsed(CmsResourceTableProperty.PROPERTY_INTERNAL_RESOURCE_TYPE, false); 445 } 446 447 /** 448 * Filter by path, title, and type names. 449 * @see org.opencms.ui.components.CmsFileTable#filterTable(java.lang.String) 450 */ 451 @Override 452 public void filterTable(String search) { 453 454 m_container.removeAllContainerFilters(); 455 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(search)) { 456 m_container.addContainerFilter( 457 new Or( 458 new SimpleStringFilter( 459 CmsResourceTableProperty.PROPERTY_SITE_PATH, 460 search, 461 true, 462 false), 463 new SimpleStringFilter(CmsResourceTableProperty.PROPERTY_TITLE, search, true, false), 464 new SimpleStringFilter( 465 CmsResourceTableProperty.PROPERTY_RESOURCE_TYPE, 466 search, 467 true, 468 false), 469 new SimpleStringFilter( 470 CmsResourceTableProperty.PROPERTY_INTERNAL_RESOURCE_TYPE, 471 search, 472 true, 473 false))); 474 } 475 if ((m_fileTable.getValue() != null) & !((Set<?>)m_fileTable.getValue()).isEmpty()) { 476 m_fileTable.setCurrentPageFirstItemId(((Set<?>)m_fileTable.getValue()).iterator().next()); 477 } 478 } 479 }; 480 m_fileTable.applyWorkplaceAppSettings(); 481 m_fileTable.setContextProvider(new I_CmsContextProvider() { 482 483 /** 484 * @see org.opencms.ui.apps.I_CmsContextProvider#getDialogContext() 485 */ 486 public I_CmsDialogContext getDialogContext() { 487 488 CmsFileTableDialogContext context = new CmsFileTableDialogContext( 489 CmsUnusedContentFinderConfiguration.APP_ID, 490 ContextType.fileTable, 491 m_fileTable, 492 m_fileTable.getSelectedResources()); 493 return context; 494 } 495 }); 496 m_fileTable.setSizeFull(); 497 m_fileTable.setMenuBuilder(new CmsResourceContextMenuBuilder()); 498 m_fileTable.setVisible(false); 499 addComponent(m_fileTable); 500 setExpandRatio(m_fileTable, 2); 501 } 502 503 /** 504 * Initializes the empty result info box. 505 */ 506 private void initInfoEmptyResult() { 507 508 m_infoEmptyResult = CmsVaadinUtils.getInfoLayout(Messages.GUI_SOURCESEARCH_EMPTY_0); 509 m_infoEmptyResult.setVisible(false); 510 addComponent(m_infoEmptyResult); 511 } 512 513 /** 514 * Initializes the intro info box. 515 */ 516 private void initInfoIntroLayout() { 517 518 m_infoIntroLayout = CmsVaadinUtils.getInfoLayout(Messages.GUI_SOURCESEARCH_INTRO_0); 519 m_infoIntroLayout.setVisible(true); 520 addComponent(m_infoIntroLayout); 521 } 522 523 /** 524 * Initializes the invalid folder info box. 525 */ 526 private void initInfoInvalidFolder() { 527 528 m_infoInvalidFolder = CmsVaadinUtils.getInfoLayout(Messages.GUI_UNUSED_CONTENT_FINDER_INVALID_FOLDER_0); 529 m_infoInvalidFolder.setVisible(false); 530 addComponent(m_infoInvalidFolder); 531 } 532 533 /** 534 * Initializes the too many results info box. 535 */ 536 private void initInfoTooManyResults() { 537 538 m_infoTooManyResults = CmsVaadinUtils.getInfoLayout(Messages.GUI_UNUSED_CONTENT_FINDER_TOO_MANY_RESULTS_0); 539 m_infoTooManyResults.setVisible(false); 540 addComponent(m_infoTooManyResults); 541 } 542 543 /** 544 * Shows the file table. 545 */ 546 private void showFileTable() { 547 548 m_infoIntroLayout.setVisible(false); 549 m_infoTooManyResults.setVisible(false); 550 m_infoInvalidFolder.setVisible(false); 551 m_infoEmptyResult.setVisible(false); 552 m_fileTable.setVisible(true); 553 } 554 555 /** 556 * Shows the empty result info box. 557 */ 558 private void showInfoEmptyResult() { 559 560 m_fileTable.setVisible(false); 561 m_infoIntroLayout.setVisible(false); 562 m_infoTooManyResults.setVisible(false); 563 m_infoInvalidFolder.setVisible(false); 564 m_infoEmptyResult.setVisible(true); 565 } 566 567 /** 568 * Shows the invalid folder info box. 569 */ 570 private void showInfoInvalidFolder() { 571 572 m_fileTable.setVisible(false); 573 m_infoIntroLayout.setVisible(false); 574 m_infoTooManyResults.setVisible(false); 575 m_infoEmptyResult.setVisible(false); 576 m_infoInvalidFolder.setVisible(true); 577 } 578 579 /** 580 * Shows the empty result info box. 581 */ 582 private void showInfoTooManyResults() { 583 584 m_fileTable.setVisible(false); 585 m_infoIntroLayout.setVisible(false); 586 m_infoEmptyResult.setVisible(false); 587 m_infoInvalidFolder.setVisible(false); 588 m_infoTooManyResults.setVisible(true); 589 } 590 } 591 592 /** 593 * Component to filter the result table. 594 */ 595 @SuppressWarnings("serial") 596 private class ResultFilterComponent extends CmsResultFilterComponent { 597 598 /** 599 * Creates a new result filter. 600 */ 601 ResultFilterComponent() { 602 603 super(); 604 addTextChangeListener(new TextChangeListener() { 605 606 public void textChange(TextChangeEvent event) { 607 608 m_resultComponent.getFileTable().filterTable(event.getText()); 609 610 } 611 }); 612 } 613 } 614 615 /** The log object for this class. */ 616 static final Log LOG = CmsLog.getLog(CmsUnusedContentFinderComposite.class); 617 618 /** The maximum number of results. */ 619 static final int MAX_RESULTS = 5000; 620 621 /** Schema parameter name. */ 622 static final String SCHEMA_PARAM_NAME = "unusedcontentfinder"; 623 624 /** Schema parameter value. */ 625 static final String SCHEMA_PARAM_VALUE = "include"; 626 627 /** The delete button of this unused content finder. */ 628 DeleteButtonComponent m_deleteButtonComponent; 629 630 /** The form component of this unused content finder. */ 631 FormComponent m_formComponent; 632 633 /** The result component of this unused content finder. */ 634 ResultComponent m_resultComponent; 635 636 /** The result filter component of this unused content finder. */ 637 ResultFilterComponent m_resultFilterComponent; 638 639 /** 640 * Creates a new component. 641 */ 642 public CmsUnusedContentFinderComposite() { 643 644 m_deleteButtonComponent = new DeleteButtonComponent(); 645 m_formComponent = new FormComponent(); 646 m_resultComponent = new ResultComponent(); 647 m_resultFilterComponent = new ResultFilterComponent(); 648 } 649 650 /** 651 * Returns the delete button component of this unused content finder. 652 * @return the delete button component of this unused content finder 653 */ 654 public Component getDeleteButtonComponent() { 655 656 return m_deleteButtonComponent; 657 } 658 659 /** 660 * Returns the form component of this unused content finder. 661 * @return the form component of this unused content finder 662 */ 663 public Component getFormComponent() { 664 665 return m_formComponent; 666 } 667 668 /** 669 * Returns the result component of this unused content finder. 670 * @return the result component of this unused content finder 671 */ 672 public Component getResultComponent() { 673 674 return m_resultComponent; 675 } 676 677 /** 678 * Returns the result filter component of this unused content finder. 679 * @return the result filter component of this unused content finder 680 */ 681 public Component getResultFilterComponent() { 682 683 return m_resultFilterComponent; 684 } 685 686 /** 687 * Search for unused contents. 688 * @param updateState whether to also update the state when searching 689 */ 690 public void search(boolean updateState) { 691 692 if (updateState) { 693 CmsComponentState componentState = new CmsComponentState(); 694 componentState.setSite(m_formComponent.getSiteValue()); 695 componentState.setFolder(m_formComponent.getFolderValue()); 696 componentState.setResourceType(m_formComponent.getTypeValue()); 697 CmsAppWorkplaceUi.get().changeCurrentAppState(componentState.generateStateString()); 698 } 699 m_resultComponent.updateResult(); 700 } 701 702 /** 703 * Initializes this component with data from a given state bean. 704 * @param componentState the state bean 705 */ 706 public void setState(CmsComponentState componentState) { 707 708 m_formComponent.setSiteValue(componentState.getSite()); 709 m_formComponent.setFolderValue(componentState.getFolder()); 710 m_formComponent.setTypeValue(componentState.getResourceType()); 711 } 712 713 /** 714 * Returns the list of all relevant XML content types. A content type is relevant 715 * if either there is a parameter "unusedcontentfinder" defined in the XML 716 * content schema and the value of this parameter is set to "include"; or, the 717 * "unusedcontentfinder" parameter is not defined at all but the containerPageOnly 718 * attribute of the searchsettings element is set to "true". 719 * @return the list of all relevant XML content types 720 */ 721 List<I_CmsResourceType> getAvailableTypes() { 722 723 List<I_CmsResourceType> result = new ArrayList<>(); 724 CmsObject cms = A_CmsUI.getCmsObject(); 725 List<I_CmsResourceType> types = OpenCms.getResourceManager().getResourceTypes(); 726 for (I_CmsResourceType type : types) { 727 CmsExplorerTypeSettings typeSetting = OpenCms.getWorkplaceManager().getExplorerTypeSetting( 728 type.getTypeName()); 729 if (typeSetting == null) { 730 continue; 731 } 732 if ((type instanceof CmsResourceTypeXmlContent) 733 && !((type instanceof CmsResourceTypeXmlContainerPage) 734 || (type instanceof CmsResourceTypeXmlAdeConfiguration))) { 735 CmsResourceTypeXmlContent xmlType = (CmsResourceTypeXmlContent)type; 736 try { 737 CmsFile schemaFile = cms.readFile(xmlType.getSchema()); 738 CmsXmlContentDefinition definition = CmsXmlContentDefinition.unmarshal( 739 cms, 740 schemaFile.getRootPath()); 741 I_CmsXmlContentHandler contentHandler = definition.getContentHandler(); 742 String parameter = contentHandler.getParameter(SCHEMA_PARAM_NAME); 743 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(parameter)) { 744 if (parameter.equalsIgnoreCase(SCHEMA_PARAM_VALUE)) { 745 result.add(type); 746 } 747 } else if (contentHandler.isContainerPageOnly()) { 748 result.add(type); 749 } 750 } catch (Throwable t) { 751 // may happen for internal types 752 } 753 } 754 } 755 return result; 756 } 757 758 /** 759 * Returns the offline CMS. 760 * @return the offline CMS 761 */ 762 CmsObject getOfflineCms() { 763 764 CmsObject offlineCms = null; 765 try { 766 offlineCms = OpenCms.initCmsObject(A_CmsUI.getCmsObject()); 767 offlineCms.getRequestContext().setSiteRoot(m_formComponent.getSiteValue()); 768 offlineCms.getRequestContext().setCurrentProject(offlineCms.readProject("Offline")); 769 } catch (CmsException e) { 770 LOG.error(e.getLocalizedMessage(), e); 771 } 772 return offlineCms; 773 } 774 775 /** 776 * Return the online CMS. 777 * @return the online CMS 778 */ 779 CmsObject getOnlineCms() { 780 781 CmsObject onlineCms = null; 782 try { 783 onlineCms = OpenCms.initCmsObject(A_CmsUI.getCmsObject()); 784 onlineCms.getRequestContext().setSiteRoot(m_formComponent.getSiteValue()); 785 onlineCms.getRequestContext().setCurrentProject(onlineCms.readProject(CmsProject.ONLINE_PROJECT_ID)); 786 } catch (CmsException e) { 787 LOG.error(e.getLocalizedMessage(), e); 788 } 789 return onlineCms; 790 } 791 792 /** 793 * Returns whether a resource is excluded by a property. This is the case for properties: 794 * <li>element.model=true 795 * <li>NavInfo=keep 796 * @param resource the resource to check 797 * @param online whether to check in the online project 798 * @return whether the resource in not excluded by a property 799 * @throws CmsException if reading the properties fails 800 */ 801 boolean isExcludedByProperties(CmsResource resource, boolean online) throws CmsException { 802 803 CmsObject cms = online ? getOnlineCms() : getOfflineCms(); 804 CmsProperty navInfo = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_NAVINFO, true); 805 if (!navInfo.isNullProperty() && navInfo.getValue().equals("keep")) { 806 return true; 807 } 808 CmsProperty elementModel = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_ELEMENT_MODEL, true); 809 if (!elementModel.isNullProperty() && elementModel.getValue().equals("true")) { 810 return true; 811 } 812 return false; 813 } 814 815 /** 816 * Returns whether a resource is used by other contents. 817 * @param resource the resource to check 818 * @param online whether the check should be performed online 819 * @return whether the resource is used by other contents 820 * @throws CmsException if reading related resources fails 821 */ 822 boolean isUsedByOtherContents(CmsResource resource, boolean online) throws CmsException { 823 824 if (online && resource.getState().isNew()) { 825 return false; 826 } 827 CmsRelationFilter filter = CmsRelationFilter.SOURCES; 828 CmsObject cms = online ? getOnlineCms() : getOfflineCms(); 829 List<CmsRelation> relations = cms.getRelationsForResource(resource, filter); 830 return !relations.isEmpty(); 831 } 832 833 /** 834 * Returns whether the current site and folder selection is valid. 835 * Only path levels greater or equal than 2 are allowed. 836 * @return whether the current site and folder selection is valid 837 */ 838 boolean isValidFolder() { 839 840 String rootPath = CmsStringUtil.joinPaths(m_formComponent.getSiteValue(), m_formComponent.getFolderValue()); 841 if (CmsResource.getPathLevel(rootPath) < 2) { 842 return false; 843 } 844 return true; 845 } 846}