001/* 002 * Copyright 2016 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.core.ui.ribbonconfiguration; 017 018import java.util.ArrayList; 019import java.util.List; 020import java.util.UUID; 021 022import org.apache.avalon.framework.configuration.Configuration; 023import org.apache.avalon.framework.configuration.ConfigurationException; 024import org.apache.avalon.framework.configuration.DefaultConfiguration; 025import org.apache.cocoon.xml.AttributesImpl; 026import org.apache.cocoon.xml.XMLUtils; 027import org.slf4j.Logger; 028import org.xml.sax.ContentHandler; 029import org.xml.sax.SAXException; 030 031import org.ametys.core.ui.RibbonManager; 032import org.ametys.core.ui.RibbonTabsManager; 033import org.ametys.runtime.i18n.I18nizableText; 034 035/** 036 * A tab of the ribbon 037 */ 038public class Tab 039{ 040 /** The label of the tab */ 041 protected I18nizableText _label; 042 043 /** The optional id of the contextual client side element determining the state of the ribbon */ 044 protected String _controlId; 045 046 /** The color (between 1 and 6) for a contextual tab */ 047 protected String _contextualColor; 048 049 /** The id of the contextual group (can be null for single contextual tab) */ 050 protected String _contextualGroup; 051 052 /** The label of the contextual group */ 053 protected I18nizableText _contextualLabel; 054 055 /** The tab order */ 056 protected Object _order; 057 058 /** True to order before a tab specified by _order */ 059 protected Boolean _orderBefore; 060 061 /** True to override an existing tab instead of defining a new one */ 062 protected Boolean _override; 063 064 /** The list of groups in the tab */ 065 protected List<Group> _groups = new ArrayList<>(); 066 067 /** helper for group injection */ 068 protected RibbonElementsInjectionHelper<Group> _tabOverrideHelper; 069 070 /** Logger */ 071 protected Logger _log; 072 073 /** 074 * Creates a tab 075 * @param tabConfiguration The configuration of the tab 076 * @param ribbonManager The ribbon manager 077 * @param defaultOrder The default tab order, if not specified. Can be null 078 * @param logger The logger 079 * @throws ConfigurationException if an error occurs in the configuration 080 */ 081 public Tab(Configuration tabConfiguration, RibbonManager ribbonManager, Integer defaultOrder, Logger logger) throws ConfigurationException 082 { 083 _log = logger; 084 085 if (_log.isDebugEnabled()) 086 { 087 _log.debug("Creating tab"); 088 } 089 090 _configureId(tabConfiguration); 091 if (tabConfiguration.getAttribute("ref-id", null) != null || tabConfiguration.getChild("tab-control", false) != null) 092 { 093 _generateTabControl(tabConfiguration, ribbonManager); 094 } 095 096 this._label = new I18nizableText("application", tabConfiguration.getAttribute("label")); 097 if (_log.isDebugEnabled()) 098 { 099 _log.debug("Tab label is " + this._label); 100 } 101 102 this._override = tabConfiguration.getAttributeAsBoolean("override", false); 103 104 _configureGroups(tabConfiguration, ribbonManager); 105 _configureOrder(tabConfiguration, defaultOrder); 106 } 107 108 /** 109 * Get the id of this tab; 110 * @return the id 111 */ 112 public String getId() 113 { 114 return _controlId; 115 } 116 117 /** 118 * Return true if the tab is contextual 119 * @return true if the tab is contextual 120 */ 121 public Boolean isContextual() 122 { 123 return _controlId != null; 124 } 125 126 /** 127 * Configure tab optional id 128 * @param tabConfiguration One tab configuration 129 * @throws ConfigurationException if an error occurred 130 */ 131 protected void _configureId(Configuration tabConfiguration) throws ConfigurationException 132 { 133 this._controlId = tabConfiguration.getAttribute("controlId", null); 134 this._contextualColor = tabConfiguration.getAttribute("contextualColor", null); 135 this._contextualGroup = tabConfiguration.getAttribute("contextualGroup", null); 136 137 String contextualLabelString = tabConfiguration.getAttribute("contextualLabel", null); 138 if (contextualLabelString != null) 139 { 140 this._contextualLabel = new I18nizableText("application", contextualLabelString); 141 } 142 143 if (_log.isDebugEnabled() && this._controlId != null) 144 { 145 _log.debug("Tab control id is " + this._controlId); 146 } 147 } 148 149 /** 150 * Generate a new tab control on the fly 151 * @param tabConfiguration The tab configuration 152 * @param ribbonManager The ribbon manager 153 * @throws ConfigurationException If an error occurs 154 */ 155 protected void _generateTabControl(Configuration tabConfiguration, RibbonManager ribbonManager) throws ConfigurationException 156 { 157 if (this._controlId == null) 158 { 159 this._controlId = UUID.randomUUID().toString(); 160 } 161 162 DefaultConfiguration defaultConfig = new DefaultConfiguration(tabConfiguration.getChild("tab-control")); 163 String refId = defaultConfig.getAttribute("ref-id", null); 164 165 String classname = tabConfiguration.getAttribute("class", null); 166 if (classname == null) 167 { 168 if (refId != null) 169 { 170 defaultConfig.setAttribute("point", tabConfiguration.getAttribute("point", RibbonTabsManager.ROLE)); 171 } 172 else 173 { 174 classname = org.ametys.core.ui.StaticClientSideElement.class.getName(); 175 defaultConfig.setAttribute("class", classname); 176 } 177 } 178 179 ribbonManager.addExtension(this._controlId, "core-ui", null, defaultConfig); 180 181 if (_log.isDebugEnabled()) 182 { 183 _log.debug("Generated Tab control id is " + this._controlId); 184 } 185 } 186 187 /** 188 * Configure tabs groups 189 * @param tabConfiguration One tab configuration 190 * @param ribbonManager The ribbon manager 191 * @throws ConfigurationException if an error occurred 192 */ 193 protected void _configureGroups(Configuration tabConfiguration, RibbonManager ribbonManager) throws ConfigurationException 194 { 195 Configuration[] groupsConfigurations = tabConfiguration.getChild("groups").getChildren("group"); 196 for (Configuration groupConfiguration : groupsConfigurations) 197 { 198 Group group = new Group(groupConfiguration, ribbonManager, _log); 199 _groups.add(group); 200 } 201 } 202 203 private void _configureOrder(Configuration tabConfiguration, Integer defaultOrder) 204 { 205 String order = tabConfiguration.getAttribute("order", null); 206 try 207 { 208 _order = Integer.parseInt(order); 209 } 210 catch (NumberFormatException e) 211 { 212 _order = order != null ? order : defaultOrder; 213 } 214 215 _orderBefore = tabConfiguration.getAttributeAsBoolean("order-before", false); 216 } 217 218 /** 219 * Get the tab label 220 * @return Return the tab label 221 */ 222 public String getLabel() 223 { 224 return _label.toString(); 225 } 226 227 /** 228 * Get the order attribute of the tab 229 * @return Return the order as a String, or null 230 */ 231 public String getOrderAsString() 232 { 233 if (_order instanceof String) 234 { 235 return (String) _order; 236 } 237 return null; 238 } 239 240 /** 241 * Get the order attribute of the tab 242 * @return Return the order as an Integer, or null 243 */ 244 public Integer getOrderAsInteger() 245 { 246 if (_order instanceof Integer) 247 { 248 return (Integer) _order; 249 } 250 return null; 251 } 252 253 /** 254 * Set the order attribute of the tab 255 * @param order The new order value, either a String or an Integer 256 */ 257 public void setOrder(Object order) 258 { 259 _order = order; 260 } 261 262 /** 263 * True if the tab should be ordered before the tab referenced by the attribute order 264 * @return True if the tab should be ordered before the tab referenced by the attribute order 265 */ 266 public boolean orderBefore() 267 { 268 return _orderBefore; 269 } 270 271 /** 272 * Retrieve the list of configured groups 273 * @return The list of groups 274 */ 275 public List<Group> getGroups() 276 { 277 return _groups; 278 } 279 280 /** 281 * Return true if this tab overrides an existing tab 282 * @return True if overrides 283 */ 284 public boolean isOverride() 285 { 286 return _override; 287 } 288 289 /** 290 * Inject a list of groups into this tab 291 * @param groups The list of groups to inject 292 */ 293 public void injectGroups(List<Group> groups) 294 { 295 for (Group group : groups) 296 { 297 if (!group.isOverride()) 298 { 299 if (_tabOverrideHelper == null) 300 { 301 _tabOverrideHelper = new RibbonElementsInjectionHelper<>(_groups, _log); 302 } 303 304 if (_log.isDebugEnabled()) 305 { 306 _log.debug("RibbonConfigurationManager : new group '" + group._label.toString() + "' injected into tab '" + _label.toString() + "'"); 307 } 308 309 _tabOverrideHelper.injectElements(group, group.getOrder()); 310 } 311 } 312 } 313 314 /** 315 * Inject a list of overriding groups into this tab 316 * @param groups The list of groups to inject 317 */ 318 public void injectGroupsOverride(List<Group> groups) 319 { 320 for (Group group : groups) 321 { 322 if (group.isOverride()) 323 { 324 for (Group selfGroup : _groups) 325 { 326 if (selfGroup._label.equals(group._label)) 327 { 328 if (_log.isDebugEnabled()) 329 { 330 _log.debug("RibbonConfigurationManager : overriding group '" + group._label + "' of tab '" + _label + "' to inject new controls"); 331 } 332 333 selfGroup.injectGroup(group); 334 } 335 } 336 } 337 } 338 } 339 340 /** 341 * Sax the configuration of the tab. 342 * @param handler The content handler where to sax 343 * @param groups The list of groups to sax 344 * @throws SAXException if an error occurs 345 */ 346 public void saxGroups(ContentHandler handler, List<Group> groups) throws SAXException 347 { 348 AttributesImpl attrs = new AttributesImpl(); 349 attrs.addCDATAAttribute("label", _label.getCatalogue() + ":" + _label.getKey()); 350 StringBuilder i18nAttr = new StringBuilder("label"); 351 352 if (_controlId != null) 353 { 354 attrs.addCDATAAttribute("controlId", _controlId); 355 if (_contextualColor != null) 356 { 357 attrs.addCDATAAttribute("contextualColor", _contextualColor); 358 } 359 if (_contextualGroup != null) 360 { 361 attrs.addCDATAAttribute("contextualGroup", _contextualGroup); 362 } 363 if (_contextualLabel != null) 364 { 365 attrs.addCDATAAttribute("contextualLabel", _contextualLabel.getCatalogue() + ":" + _contextualLabel.getKey()); 366 i18nAttr.append(" contextualLabel"); 367 } 368 } 369 370 attrs.addCDATAAttribute("http://apache.org/cocoon/i18n/2.1", "attr", "i18n:attr", i18nAttr.toString()); 371 372 XMLUtils.startElement(handler, "tab", attrs); 373 374 XMLUtils.startElement(handler, "groups"); 375 for (Group group : groups) 376 { 377 group.toSAX(handler); 378 } 379 XMLUtils.endElement(handler, "groups"); 380 381 XMLUtils.endElement(handler, "tab"); 382 } 383 384 @Override 385 public String toString() 386 { 387 return super.toString() + "[" + _label + "]"; 388 } 389}