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.widgets; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.configuration.CmsConfigurationReader; 032import org.opencms.ade.configuration.formatters.CmsFormatterChangeSet; 033import org.opencms.ade.configuration.formatters.CmsFormatterConfigurationCacheState; 034import org.opencms.file.CmsFile; 035import org.opencms.file.CmsObject; 036import org.opencms.file.CmsResource; 037import org.opencms.file.CmsResourceFilter; 038import org.opencms.i18n.CmsMessages; 039import org.opencms.main.CmsException; 040import org.opencms.main.CmsLog; 041import org.opencms.main.OpenCms; 042import org.opencms.util.CmsUUID; 043import org.opencms.workplace.CmsWorkplaceMessages; 044import org.opencms.xml.containerpage.I_CmsFormatterBean; 045import org.opencms.xml.content.CmsXmlContent; 046import org.opencms.xml.content.CmsXmlContentFactory; 047import org.opencms.xml.types.A_CmsXmlContentValue; 048 049import java.util.Comparator; 050import java.util.HashSet; 051import java.util.List; 052import java.util.Locale; 053import java.util.Set; 054import java.util.SortedSet; 055import java.util.TreeSet; 056 057import org.apache.commons.logging.Log; 058 059import com.google.common.collect.ComparisonChain; 060import com.google.common.collect.Lists; 061 062/** 063 * Abstract superclass for widgets used to enable or disable formatters.<p> 064 */ 065public abstract class A_CmsFormatterWidget extends CmsSelectWidget { 066 067 /** 068 * Comparator used to sort formatter beans in the order in which they should be displayed in the selection.<p> 069 */ 070 public static class FormatterSelectComparator implements Comparator<I_CmsFormatterBean> { 071 072 /** 073 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) 074 */ 075 public int compare(I_CmsFormatterBean first, I_CmsFormatterBean second) { 076 077 SortedSet<String> firstSet = new TreeSet<String>(first.getResourceTypeNames()); 078 SortedSet<String> secondSet = new TreeSet<String>(second.getResourceTypeNames()); 079 return ComparisonChain.start().compare(firstSet.toString(), secondSet.toString()).compare( 080 first.getRank(), 081 second.getRank()).result(); 082 } 083 } 084 085 /** The logger instance for this class. */ 086 protected static final Log LOG = CmsLog.getLog(A_CmsFormatterWidget.class); 087 088 /** 089 * Creates a widget option corresponding to a formatter bean for an external formatter.<p> 090 * 091 * @param cms the current CMS context 092 * @param formatter the formatter bean 093 * 094 * @return the select option which was created 095 * 096 * @throws Exception in case reading the formatter configuration file fails 097 */ 098 public static CmsSelectWidgetOption getWidgetOptionForFormatter(CmsObject cms, I_CmsFormatterBean formatter) 099 throws Exception { 100 101 String name = formatter.getNiceName(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)) 102 + " " 103 + formatter.getResourceTypeNames().toString() 104 + " " 105 + " (" 106 + formatter.getJspRootPath() 107 + ")"; 108 String path = cms.readResource( 109 new CmsUUID(formatter.getId()), 110 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED).getRootPath(); 111 CmsSelectWidgetOption option = new CmsSelectWidgetOption(path, false, name); 112 return option; 113 } 114 115 /** 116 * Creates a widget option for a resource type.<p> 117 * 118 * @param cms the current CMS context 119 * @param typeName the type for which we want a widget option 120 * 121 * @return the created widget option 122 */ 123 public static CmsSelectWidgetOption getWidgetOptionForType(CmsObject cms, String typeName) { 124 125 String niceTypeName = typeName; 126 try { 127 Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms); 128 niceTypeName = CmsWorkplaceMessages.getResourceTypeName(locale, typeName); 129 } catch (@SuppressWarnings("unused") Exception e) { 130 // resource type name will be used as a fallback 131 } 132 CmsSelectWidgetOption option = new CmsSelectWidgetOption( 133 CmsFormatterChangeSet.keyForType(typeName), 134 false, 135 getMessage(cms, Messages.GUI_SCHEMA_FORMATTER_OPTION_1, niceTypeName)); 136 return option; 137 } 138 139 /** 140 * Gets a message string.<p> 141 * 142 * @param cms the CMS context 143 * @param message the message key 144 * @param args the message arguments 145 * 146 * @return the message string 147 */ 148 static String getMessage(CmsObject cms, String message, Object... args) { 149 150 Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms); 151 return Messages.get().getBundle(locale).key(message, args); 152 } 153 154 /** 155 * @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) 156 */ 157 @Override 158 public String getConfiguration( 159 CmsObject cms, 160 A_CmsXmlContentValue schemaType, 161 CmsMessages messages, 162 CmsResource resource, 163 Locale contentLocale) { 164 165 CmsDummyWidgetDialog widgetDialog = new CmsDummyWidgetDialog(messages.getLocale(), messages); 166 widgetDialog.setResource(resource); 167 String result = getConfiguration(); 168 result += "||"; 169 result += CmsSelectWidgetOption.createConfigurationString( 170 parseSelectOptions(cms, widgetDialog, schemaType, false)); 171 result += "||"; 172 result += CmsSelectWidgetOption.createConfigurationString( 173 parseSelectOptions(cms, widgetDialog, schemaType, true)); 174 return result; 175 } 176 177 /** 178 * @see org.opencms.widgets.I_CmsADEWidget#getWidgetName() 179 */ 180 @Override 181 public String getWidgetName() { 182 183 return A_CmsFormatterWidget.class.getName(); 184 } 185 186 /** 187 * Gets the options corresponding to external (non-schema) formatters.<p> 188 * 189 * @param cms the CMS context 190 * @param config the ADE configuration 191 * @param rootPath the root path of the edited file 192 * @param allRemoved flag, indicating if all inheritedly available formatters should be disabled 193 * 194 * @return the select widget options for the external formatters 195 */ 196 protected abstract List<CmsSelectWidgetOption> getFormatterOptions( 197 CmsObject cms, 198 CmsADEConfigData config, 199 String rootPath, 200 boolean allRemoved); 201 202 /** 203 * Gets the values which have already been selected in the edited resource on the VFS.<p> 204 * 205 * @param reader a sitemap configuration reader 206 * @param content the unmarshalled content 207 * 208 * @return the set of values which have already been selected 209 */ 210 protected abstract Set<String> getSelectedInFile(CmsConfigurationReader reader, CmsXmlContent content); 211 212 /** 213 * Gets the options corresponding to the schemas which define formatters.<p> 214 * 215 * @param cms the current CMS context 216 * @param config the ADE configuration 217 * @param allRemoved flag, indicating if all inheritedly available formatters should be disabled 218 * 219 * @return the select widget options for the content types with formatters in the schema 220 */ 221 protected abstract List<CmsSelectWidgetOption> getTypeOptions( 222 CmsObject cms, 223 CmsADEConfigData config, 224 boolean allRemoved); 225 226 /** 227 * @see org.opencms.widgets.A_CmsSelectWidget#parseSelectOptions(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 228 */ 229 @Override 230 protected List<CmsSelectWidgetOption> parseSelectOptions( 231 CmsObject cms, 232 I_CmsWidgetDialog widgetDialog, 233 I_CmsWidgetParameter param) { 234 235 List<CmsSelectWidgetOption> options = Lists.newArrayList(); 236 options.add(new CmsSelectWidgetOption("", true, getMessage(cms, Messages.GUI_FORMATTER_EMPTY_SELECTION_0))); 237 return options; 238 } 239 240 /** 241 * Returns the list of configured select options, parsing the configuration String if required.<p> 242 * 243 * The list elements are of type <code>{@link CmsSelectWidgetOption}</code>. 244 * The configuration String is parsed only once and then stored internally.<p> 245 * 246 * @param cms the current users OpenCms context 247 * @param widgetDialog the dialog of this widget 248 * @param param the widget parameter of this dialog 249 * @param allRemoved flag, indicating if all inheritedly available formatters should be disabled 250 * 251 * @return the list of select options 252 * 253 * @see CmsSelectWidgetOption 254 */ 255 protected List<CmsSelectWidgetOption> parseSelectOptions( 256 CmsObject cms, 257 I_CmsWidgetDialog widgetDialog, 258 I_CmsWidgetParameter param, 259 boolean allRemoved) { 260 261 String path = getResourcePath(cms, widgetDialog); 262 try { 263 cms = OpenCms.initCmsObject(cms); 264 cms.getRequestContext().setSiteRoot(""); 265 CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfiguration(cms, path); 266 if (adeConfig.parent() != null) { 267 adeConfig = adeConfig.parent(); 268 } 269 Set<String> added = new HashSet<String>(); 270 List<CmsSelectWidgetOption> options = Lists.newArrayList(); 271 options.add(new CmsSelectWidgetOption("", true, getMessage(cms, Messages.GUI_FORMATTER_EMPTY_SELECTION_0))); 272 List<CmsSelectWidgetOption> formatterOptions = getFormatterOptions(cms, adeConfig, path, allRemoved); 273 options.addAll(formatterOptions); 274 List<CmsSelectWidgetOption> typeOptions = getTypeOptions(cms, adeConfig, allRemoved); 275 options.addAll(typeOptions); 276 for (CmsSelectWidgetOption option : options) { 277 added.add(option.getValue()); 278 } 279 try { 280 CmsResource content = cms.readResource(path); 281 CmsFile contentFile = cms.readFile(content); 282 CmsXmlContent xmlContent = CmsXmlContentFactory.unmarshal(cms, contentFile); 283 CmsConfigurationReader reader = new CmsConfigurationReader(cms); 284 Set<String> selected = getSelectedInFile(reader, xmlContent); 285 for (String formatterKey : selected) { 286 if (CmsUUID.isValidUUID(formatterKey)) { 287 CmsFormatterConfigurationCacheState cacheState = OpenCms.getADEManager().getCachedFormatters( 288 cms.getRequestContext().getCurrentProject().isOnlineProject()); 289 CmsUUID mapKey = new CmsUUID(formatterKey); 290 I_CmsFormatterBean formatter = cacheState.getFormatters().get(mapKey); 291 if (formatter != null) { 292 try { 293 CmsSelectWidgetOption option = A_CmsFormatterWidget.getWidgetOptionForFormatter( 294 cms, 295 formatter); 296 297 if (!added.contains(option.getValue())) { 298 options.add(option); 299 } 300 } catch (Exception e) { 301 LOG.error(e.getLocalizedMessage(), e); 302 } 303 } 304 } 305 306 } 307 308 } catch (CmsException e) { 309 LOG.error(e.getLocalizedMessage(), e); 310 } 311 return options; 312 } catch (CmsException e) { 313 // should never happen 314 LOG.error(e.getLocalizedMessage(), e); 315 return null; 316 } 317 } 318 319}