1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package org.xwiki.rendering.macro.box

File AbstractBoxMacro.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

20
57
17
2
323
182
29
0.51
3.35
8.5
1.71

Classes

Class Line # Actions
AbstractBoxMacro 55 21 0% 14 0
1.0100%
AbstractBoxMacro.BoxBlockBuilder 189 36 0% 15 0
1.0100%
 

Contributing tests

This file is covered by 46 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.rendering.macro.box;
21   
22    import java.util.Collections;
23    import java.util.LinkedHashMap;
24    import java.util.List;
25    import java.util.Map;
26   
27    import javax.inject.Inject;
28    import javax.inject.Named;
29   
30    import org.apache.commons.lang3.StringUtils;
31    import org.xwiki.rendering.block.Block;
32    import org.xwiki.rendering.block.FormatBlock;
33    import org.xwiki.rendering.block.GroupBlock;
34    import org.xwiki.rendering.block.ImageBlock;
35    import org.xwiki.rendering.block.NewLineBlock;
36    import org.xwiki.rendering.listener.Format;
37    import org.xwiki.rendering.listener.reference.ResourceReference;
38    import org.xwiki.rendering.listener.reference.ResourceType;
39    import org.xwiki.rendering.macro.AbstractMacro;
40    import org.xwiki.rendering.macro.Macro;
41    import org.xwiki.rendering.macro.MacroContentParser;
42    import org.xwiki.rendering.macro.MacroExecutionException;
43    import org.xwiki.rendering.macro.descriptor.ContentDescriptor;
44    import org.xwiki.rendering.parser.ResourceReferenceParser;
45    import org.xwiki.rendering.transformation.MacroTransformationContext;
46    import org.xwiki.stability.Unstable;
47   
48    /**
49    * Draw a box around provided content.
50    *
51    * @param <P> the type of macro parameters bean.
52    * @version $Id: 3a8d96dc76a1f6c3d9798ae557a6ca4707bb79e1 $
53    * @since 1.7
54    */
 
55    public abstract class AbstractBoxMacro<P extends BoxMacroParameters> extends AbstractMacro<P>
56    {
57    /**
58    * Predefined error message.
59    */
60    public static final String CONTENT_MISSING_ERROR = "The required content is missing.";
61   
62    /**
63    * Parses untyped image references.
64    */
65    @Inject
66    @Named("image/untyped")
67    private ResourceReferenceParser untypedImageReferenceParser;
68   
69    /**
70    * The parser used to parse box content and box title parameter.
71    */
72    @Inject
73    private MacroContentParser contentParser;
74   
75    /**
76    * Creates a new box macro.
77    *
78    * @param name the name of the macro
79    * @param description string describing this macro.
80    * @param contentDescriptor the {@link ContentDescriptor} describing the content of this macro.
81    * @param parametersBeanClass class of the parameters bean.
82    */
 
83  109 toggle protected AbstractBoxMacro(String name, String description, ContentDescriptor contentDescriptor,
84    Class<?> parametersBeanClass)
85    {
86  109 super(name, description, contentDescriptor, parametersBeanClass);
87    }
88   
 
89  1637 toggle @Override
90    public boolean supportsInlineMode()
91    {
92  1637 return true;
93    }
94   
95    /**
96    * @param parameters the macro parameters in the form of a bean defined by the {@link Macro} implementation
97    * @param content the content of the macro
98    * @param context the context of the macros transformation process
99    * @return the title represented as a list of Blocks
100    * @since 10.10
101    */
 
102  7050 toggle @Unstable
103    protected List<? extends Block> getBlockTitle(P parameters, String content, MacroTransformationContext context)
104    {
105  7051 return parameters.getBlockTitle();
106    }
107   
108    /**
109    * @param parameters the macro parameters in the form of a bean defined by the {@link Macro} implementation
110    * @param content the content of the macro
111    * @param context the context of the macros transformation process
112    * @return the image reference to be displayed in the box
113    * @since 10.10
114    */
 
115  7048 toggle @Unstable
116    protected ResourceReference getImageReference(P parameters, String content, MacroTransformationContext context)
117    {
118    // TODO: Refactor this when it'll possible to have a specific converter associated to a macro parameter.
119  7048 ResourceReference imageReference = parameters.getImage();
120    // If the image reference is unknown then resolve it with the untyped resource reference parser
121    // (this happens when the user doesn't specify a type for the image reference).
122  7048 if (imageReference != null && imageReference.getType().equals(ResourceType.UNKNOWN)) {
123  3 imageReference = this.untypedImageReferenceParser.parse(imageReference.getReference());
124    }
125  7048 return imageReference;
126    }
127   
128    /**
129    * @param parameters the macro parameters in the form of a bean defined by the {@link Macro} implementation
130    * @param content the content of the macro
131    * @param context the context of the macros transformation process
132    * @return the title of the box
133    * @since 10.10
134    */
 
135  7051 toggle @Unstable
136    protected String getTitle(P parameters, String content, MacroTransformationContext context)
137    {
138  7051 return parameters.getTitle();
139    }
140   
141    /**
142    * @param parameters the macro parameters in the form of a bean defined by the {@link Macro} implementation
143    * @param content the content of the macro
144    * @param context the context of the macros transformation process
145    * @return the map of parameters to build the box, in the same order as we create them when they are retrieved
146    * by renderers.
147    * @since 10.10
148    */
 
149  7050 toggle @Unstable
150    protected Map<String, String> getBoxParameters(P parameters, String content, MacroTransformationContext context)
151    {
152    // Use a linked hashmap to keep the parameters in the same order as we create them when they are retrieved
153    // by renderers. This is useful for example in the Event renderer to control the order in which the params
154    // are displayed.
155  7050 Map<String, String> boxParameters = new LinkedHashMap<String, String>();
156  7049 String classParameter = parameters.getCssClass();
157  7050 String cssClass =
158  7050 StringUtils.isEmpty(classParameter) ? getClassProperty() : getClassProperty() + " " + classParameter;
159  7051 boxParameters.put("class", cssClass);
160   
161  7050 if (!StringUtils.isEmpty(parameters.getWidth())) {
162  5 boxParameters.put("style", "width:" + parameters.getWidth());
163    }
164   
165  7051 return boxParameters;
166    }
167   
 
168  7050 toggle @Override
169    public List<Block> execute(P parameters, String content, MacroTransformationContext context)
170    throws MacroExecutionException
171    {
172  7051 Block boxBlock = new BoxBlockBuilder()
173    .setParameters(parameters)
174    .setContent(content)
175    .setContext(context)
176    .setBoxParameters(this.getBoxParameters(parameters, content, context))
177    .setImageReference(this.getImageReference(parameters, content, context))
178    .setTitleParameter(this.getTitle(parameters, content, context))
179    .setTitleBlockList(this.getBlockTitle(parameters, content, context))
180    .build();
181   
182  7050 if (boxBlock == null) {
183  3 return Collections.emptyList();
184    }
185   
186  7047 return Collections.singletonList(boxBlock);
187    }
188   
 
189    private final class BoxBlockBuilder
190    {
191    private P parameters;
192   
193    private String content;
194   
195    private MacroTransformationContext context;
196   
197    private Map<String, String> boxParameters;
198   
199    private ResourceReference imageReference;
200   
201    private String titleParameter;
202   
203    private List<? extends Block> titleBlockList;
204   
 
205  7050 toggle public BoxBlockBuilder setParameters(P parameters)
206    {
207  7051 this.parameters = parameters;
208  7051 return this;
209    }
210   
 
211  7051 toggle public BoxBlockBuilder setContent(String content)
212    {
213  7051 this.content = content;
214  7051 return this;
215    }
216   
 
217  7051 toggle public BoxBlockBuilder setContext(MacroTransformationContext context)
218    {
219  7051 this.context = context;
220  7050 return this;
221    }
222   
 
223  7051 toggle public BoxBlockBuilder setBoxParameters(Map<String, String> boxParameters)
224    {
225  7051 this.boxParameters = boxParameters;
226  7051 return this;
227    }
228   
 
229  7051 toggle public BoxBlockBuilder setImageReference(ResourceReference imageReference)
230    {
231  7051 this.imageReference = imageReference;
232  7050 return this;
233    }
234   
 
235  7051 toggle public BoxBlockBuilder setTitleParameter(String titleParameter)
236    {
237  7050 this.titleParameter = titleParameter;
238  7050 return this;
239    }
240   
 
241  7051 toggle public BoxBlockBuilder setTitleBlockList(List<? extends Block> titleBlockList)
242    {
243  7051 this.titleBlockList = titleBlockList;
244  7050 return this;
245    }
246   
 
247  7050 toggle public Block build() throws MacroExecutionException
248    {
249  7050 Block ret = null;
250   
251    // if the content is empty but yet mandatory, we throw an exception
252  7049 if (StringUtils.isEmpty(content)
253    && AbstractBoxMacro.this.getDescriptor().getContentDescriptor().isMandatory()) {
254  1 throw new MacroExecutionException(CONTENT_MISSING_ERROR);
255    }
256   
257    // if it's null but not mandatory we return null
258    // if it's only empty we continue the processing
259  7048 if (content == null) {
260  3 return ret;
261    }
262   
263  7047 if (context.isInline()) {
264  1539 List<Block> contentBlocks = parseContent(parameters, content, context);
265  1539 FormatBlock spanBlock = new FormatBlock(contentBlocks, Format.NONE);
266  1539 spanBlock.setParameters(boxParameters);
267  1539 ret = spanBlock;
268    } else {
269  5507 ret = new GroupBlock(boxParameters);
270   
271    // we add the image, if there is one
272  5507 if (imageReference != null) {
273  6 Block imageBlock = new ImageBlock(imageReference, true);
274  6 ret.addChild(imageBlock);
275  6 ret.addChild(new NewLineBlock());
276    }
277    // we add the title, if there is one
278  5508 if (!StringUtils.isEmpty(titleParameter)) {
279    // Don't execute transformations explicitly. They'll be executed on the generated content later on.
280  24 ret.addChildren(AbstractBoxMacro.this.contentParser.parse(
281    titleParameter, context, false, true).getChildren());
282    }
283  5508 if (titleBlockList != null) {
284  5 ret.addChildren(titleBlockList);
285    }
286  5508 List<Block> contentBlocks = parseContent(parameters, content, context);
287  5508 ret.addChildren(contentBlocks);
288    }
289   
290  7047 return ret;
291    }
292    }
293   
294    /**
295    * Execute macro content and return the result. This methods is separated form
296    * {@link #execute(BoxMacroParameters, String, MacroTransformationContext)} to be able to overwrite it in macro
297    * which need boxes.
298    *
299    * @param parameters the parameters of the macro.
300    * @param content the content of the macro.
301    * @param context the context if the macros transformation.
302    * @return the result of the macro execution.
303    * @throws MacroExecutionException error when executing the macro.
304    */
305    protected abstract List<Block> parseContent(P parameters, String content, MacroTransformationContext context)
306    throws MacroExecutionException;
307   
308    /**
309    * @return the name of the CSS class to use when rendering, in case no cssClass parameter is specified.
310    */
 
311  7051 toggle protected String getClassProperty()
312    {
313  7051 return "box";
314    }
315   
316    /**
317    * @return the macro content parser to use to parse content in wiki syntax
318    */
 
319  6796 toggle protected MacroContentParser getMacroContentParser()
320    {
321  6795 return this.contentParser;
322    }
323    }