1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.rendering.block

File AbstractBlock.java

 
testReplaceBlock: Provided Block to replace is not a child
 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

70
158
37
1
570
365
75
0.47
4.27
37
2.03

Classes

Class Line # Actions
AbstractBlock 42 158 0% 75 26
0.901886890.2%
 

Contributing tests

This file is covered by 1287 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.block;
21   
22    import java.security.InvalidParameterException;
23    import java.util.ArrayList;
24    import java.util.Collections;
25    import java.util.LinkedHashMap;
26    import java.util.List;
27    import java.util.Map;
28   
29    import org.apache.commons.lang3.builder.EqualsBuilder;
30    import org.apache.commons.lang3.builder.HashCodeBuilder;
31    import org.xwiki.rendering.block.match.BlockMatcher;
32    import org.xwiki.rendering.block.match.BlockNavigator;
33    import org.xwiki.rendering.listener.Listener;
34   
35    /**
36    * Implementation for Block operations. All blocks should extend this class. Supports the notion of generic parameters
37    * which can be added to a block (see {@link #getParameter(String)} for more details.
38    *
39    * @version $Id: a3ec68c79d4440f6a646b65f3fb5b62565c221ee $
40    * @since 1.5M2
41    */
 
42    public abstract class AbstractBlock implements Block
43    {
44    /**
45    * Store parameters, see {@link #getParameter(String)} for more explanations on what parameters are.
46    */
47    private Map<String, String> parameters;
48   
49    /**
50    * The Blocks this Block contains.
51    */
52    private List<Block> childrenBlocks;
53   
54    /**
55    * The Block containing this Block.
56    */
57    private Block parentBlock;
58   
59    /**
60    * The next Sibling Block or null if no next sibling exists.
61    */
62    private Block nextSiblingBlock;
63   
64    /**
65    * The previous Sibling Block or null if no previous sibling exists.
66    */
67    private Block previousSiblingBlock;
68   
69    /**
70    * Empty constructor to construct an empty block.
71    */
 
72  1637362 toggle public AbstractBlock()
73    {
74    // Nothing to do
75    }
76   
77    /**
78    * Construct a block with parameters.
79    *
80    * @param parameters the parameters to set
81    */
 
82  158933 toggle public AbstractBlock(Map<String, String> parameters)
83    {
84  158931 setParameters(parameters);
85    }
86   
87    /**
88    * Constructs a block with a child block.
89    *
90    * @param childBlock the child block of this block
91    * @since 3.0M1
92    */
 
93  0 toggle public AbstractBlock(Block childBlock)
94    {
95  0 this(childBlock, Collections.<String, String>emptyMap());
96    }
97   
98    /**
99    * Constructs a block with children blocks.
100    *
101    * @param childrenBlocks the list of children blocks of the block to construct
102    * @since 3.0M1
103    */
 
104  73975 toggle public AbstractBlock(List<? extends Block> childrenBlocks)
105    {
106  73975 this(childrenBlocks, Collections.<String, String>emptyMap());
107    }
108   
109    /**
110    * Construct a block with a child block and parameters.
111    *
112    * @param childBlock the child block of this block
113    * @param parameters the parameters to set
114    * @since 3.0M1
115    */
 
116  0 toggle public AbstractBlock(Block childBlock, Map<String, String> parameters)
117    {
118  0 this(parameters);
119   
120  0 addChild(childBlock);
121    }
122   
123    /**
124    * Construct a block with children blocks and parameters.
125    *
126    * @param childrenBlocks the list of children blocks of the block to construct
127    * @param parameters the parameters to set
128    * @since 3.0M1
129    */
 
130  146322 toggle public AbstractBlock(List<? extends Block> childrenBlocks, Map<String, String> parameters)
131    {
132  146322 this(parameters);
133   
134  146320 addChildren(childrenBlocks);
135    }
136   
 
137  3576709 toggle @Override
138    public void addChild(Block blockToAdd)
139    {
140  3576709 insertChildAfter(blockToAdd, null);
141    }
142   
 
143  147062 toggle @Override
144    public void addChildren(List<? extends Block> blocksToAdd)
145    {
146  147071 if (!blocksToAdd.isEmpty()) {
147  132899 if (this.childrenBlocks == null) {
148    // Create the list with just the exact required size
149  132489 this.childrenBlocks = new ArrayList<Block>(blocksToAdd.size());
150    }
151   
152  132897 for (Block blockToAdd : blocksToAdd) {
153  1827673 addChild(blockToAdd);
154    }
155    }
156    }
157   
 
158  149 toggle @Override
159    public void setChildren(List<? extends Block> children)
160    {
161  149 if (children.isEmpty()) {
162  1 if (this.childrenBlocks != null) {
163  1 this.childrenBlocks.clear();
164    }
165    } else {
166  148 if (this.childrenBlocks != null) {
167  147 this.childrenBlocks.clear();
168    }
169   
170  148 addChildren(children);
171    }
172    }
173   
 
174  6980360 toggle @Override
175    public void setNextSiblingBlock(Block nextSiblingBlock)
176    {
177  6980327 this.nextSiblingBlock = nextSiblingBlock;
178    }
179   
 
180  3615848 toggle @Override
181    public void setPreviousSiblingBlock(Block previousSiblingBlock)
182    {
183  3615827 this.previousSiblingBlock = previousSiblingBlock;
184    }
185   
 
186  3576715 toggle @Override
187    public void insertChildBefore(Block blockToInsert, Block nextBlock)
188    {
189  3576714 blockToInsert.setParent(this);
190   
191  3576715 if (nextBlock == null) {
192    // Last block becomes last but one
193  3576719 if (this.childrenBlocks != null && !this.childrenBlocks.isEmpty()) {
194  3364596 Block lastBlock = this.childrenBlocks.get(this.childrenBlocks.size() - 1);
195  3364599 blockToInsert.setPreviousSiblingBlock(lastBlock);
196  3364594 lastBlock.setNextSiblingBlock(blockToInsert);
197    } else {
198  212127 blockToInsert.setPreviousSiblingBlock(null);
199   
200  212131 if (this.childrenBlocks == null) {
201  2277 this.childrenBlocks = new ArrayList<Block>(1);
202    }
203    }
204  3576710 blockToInsert.setNextSiblingBlock(null);
205  3576697 this.childrenBlocks.add(blockToInsert);
206    } else {
207    // If there's a previous block to nextBlock then get it to set its next sibling
208  2 Block previousBlock = nextBlock.getPreviousSibling();
209  2 if (previousBlock != null) {
210  1 previousBlock.setNextSiblingBlock(blockToInsert);
211  1 blockToInsert.setPreviousSiblingBlock(previousBlock);
212    } else {
213  1 blockToInsert.setPreviousSiblingBlock(null);
214    }
215  2 blockToInsert.setNextSiblingBlock(nextBlock);
216  2 nextBlock.setPreviousSiblingBlock(blockToInsert);
217  2 if (this.childrenBlocks == null || this.childrenBlocks.isEmpty()) {
218  0 this.childrenBlocks = new ArrayList<Block>(1);
219  0 this.childrenBlocks.add(blockToInsert);
220    } else {
221  2 this.childrenBlocks.add(indexOfChild(nextBlock), blockToInsert);
222    }
223    }
224    }
225   
 
226  3576723 toggle @Override
227    public void insertChildAfter(Block blockToInsert, Block previousBlock)
228    {
229  3576718 if (previousBlock == null) {
230  3576713 insertChildBefore(blockToInsert, null);
231    } else {
232    // If there's a next block to previousBlock then get it to set its previous sibling
233  2 Block nextBlock = previousBlock.getNextSibling();
234  2 if (nextBlock != null) {
235  1 nextBlock.setPreviousSiblingBlock(blockToInsert);
236  1 blockToInsert.setNextSiblingBlock(nextBlock);
237    } else {
238  1 blockToInsert.setNextSiblingBlock(null);
239    }
240  2 blockToInsert.setPreviousSiblingBlock(previousBlock);
241  2 previousBlock.setNextSiblingBlock(blockToInsert);
242  2 if (this.childrenBlocks == null) {
243  0 this.childrenBlocks = new ArrayList<Block>(1);
244    }
245  2 this.childrenBlocks.add(indexOfChild(previousBlock) + 1, blockToInsert);
246    }
247    }
248   
 
249  18124 toggle @Override
250    public void replaceChild(Block newBlock, Block oldBlock)
251    {
252  18123 Test failure here replaceChild(Collections.singletonList(newBlock), oldBlock);
253    }
254   
 
255  18130 toggle @Override
256    public void replaceChild(List<Block> newBlocks, Block oldBlock)
257    {
258  18130 int position = indexOfChild(oldBlock);
259   
260  18128 if (position == -1) {
261  0 Test failure here throw new InvalidParameterException("Provided Block to replace is not a child");
262    }
263   
264  18129 List<Block> blocks = getChildren();
265   
266    // Remove old child
267  18128 blocks.remove(position);
268  18129 oldBlock.setParent(null);
269   
270    // Insert new children
271  18129 Block previousBlock = oldBlock.getPreviousSibling();
272  18129 if (newBlocks.isEmpty()) {
273  2 previousBlock.setNextSiblingBlock(oldBlock.getNextSibling());
274    }
275  18127 Block lastBlock = null;
276  18127 for (Block block : newBlocks) {
277  18128 block.setParent(this);
278  18127 block.setPreviousSiblingBlock(previousBlock);
279  18128 if (previousBlock != null) {
280  2625 previousBlock.setNextSiblingBlock(block);
281    }
282  18128 previousBlock = block;
283  18128 lastBlock = block;
284    }
285  18129 Block nextBlock = oldBlock.getNextSibling();
286  18128 if (nextBlock != null) {
287  2628 nextBlock.setPreviousSiblingBlock(lastBlock);
288    }
289  18127 if (lastBlock != null) {
290  18127 lastBlock.setNextSiblingBlock(nextBlock);
291    }
292   
293  18129 blocks.addAll(position, newBlocks);
294   
295  18128 oldBlock.setNextSiblingBlock(null);
296  18129 oldBlock.setPreviousSiblingBlock(null);
297    }
298   
299    /**
300    * Get the position of the provided block in the list of children.
301    * <p>
302    * Can't use {@link List#indexOf(Object)} since it's using {@link Object#equals(Object)} internally which is not
303    * what we want since two WordBlock with the same text or two spaces are equals for example but we want to be able
304    * to target one specific Block.
305    *
306    * @param block the block
307    * @return the position of the block, -1 if the block can't be found
308    */
 
309  18132 toggle private int indexOfChild(Block block)
310    {
311  18133 return indexOfBlock(block, getChildren());
312    }
313   
314    /**
315    * Get the position of the provided block in the provided list of blocks.
316    * <p>
317    * Can't use {@link List#indexOf(Object)} since it's using {@link Object#equals(Object)} internally which is not
318    * what we want since two WordBlock with the same text or two spaces are equals for example but we want to be able
319    * to target one specific Block.
320    *
321    * @param block the block for which to find the position
322    * @param blocks the list of blocks in which to look for the passed block
323    * @return the position of the block, -1 if the block can't be found
324    */
 
325  18179 toggle private int indexOfBlock(Block block, List<Block> blocks)
326    {
327  18179 int position = 0;
328   
329  18179 for (Block child : blocks) {
330  55823 if (child == block) {
331  18179 return position;
332    }
333  37644 ++position;
334    }
335   
336  0 return -1;
337    }
338   
 
339  4912030 toggle @Override
340    public List<Block> getChildren()
341    {
342  4912028 return this.childrenBlocks == null ? Collections.<Block>emptyList() : this.childrenBlocks;
343    }
344   
 
345  69646 toggle @Override
346    public Block getParent()
347    {
348  69646 return this.parentBlock;
349    }
350   
 
351  111478 toggle @Override
352    public Map<String, String> getParameters()
353    {
354  111478 return this.parameters == null ? Collections.<String, String>emptyMap() : Collections
355    .unmodifiableMap(this.parameters);
356    }
357   
 
358  1399 toggle @Override
359    public String getParameter(String name)
360    {
361  1399 return this.parameters == null ? null : this.parameters.get(name);
362    }
363   
 
364  511 toggle @Override
365    public void setParameter(String name, String value)
366    {
367  511 if (this.parameters == null) {
368  1 this.parameters = new LinkedHashMap<>(1);
369    }
370   
371  511 this.parameters.put(name, value);
372    }
373   
 
374  158944 toggle @Override
375    public void setParameters(Map<String, String> parameters)
376    {
377  158940 if (this.parameters == null) {
378  158928 this.parameters = new LinkedHashMap<>(parameters);
379    } else {
380  12 this.parameters.clear();
381  12 this.parameters.putAll(parameters);
382    }
383    }
384   
 
385  3740860 toggle @Override
386    public void setParent(Block parentBlock)
387    {
388  3740835 this.parentBlock = parentBlock;
389    }
390   
 
391  30 toggle @Override
392    public Block getRoot()
393    {
394  30 Block block = this;
395   
396  108 while (block.getParent() != null) {
397  78 block = block.getParent();
398    }
399   
400  30 return block;
401    }
402   
 
403  3191370 toggle @Override
404    public Block getNextSibling()
405    {
406  3191370 return this.nextSiblingBlock;
407    }
408   
 
409  18348 toggle @Override
410    public Block getPreviousSibling()
411    {
412  18348 return this.previousSiblingBlock;
413    }
414   
 
415  46 toggle @Override
416    public void removeBlock(Block childBlockToRemove)
417    {
418    // Remove block
419  46 List<Block> children = getChildren();
420  46 int position = indexOfBlock(childBlockToRemove, children);
421  46 if (position == -1) {
422  0 throw new InvalidParameterException("Provided Block to remove is not a child");
423    }
424  46 getChildren().remove(position);
425   
426    // Re-calculate internal links between blocks
427  46 if (childBlockToRemove != null) {
428  46 Block previousBlock = childBlockToRemove.getPreviousSibling();
429  46 if (previousBlock != null) {
430  44 previousBlock.setNextSiblingBlock(childBlockToRemove.getNextSibling());
431    }
432  46 Block nextBlock = childBlockToRemove.getNextSibling();
433  46 if (nextBlock != null) {
434  43 nextBlock.setPreviousSiblingBlock(previousBlock);
435    }
436  46 childBlockToRemove.setNextSiblingBlock(null);
437  46 childBlockToRemove.setPreviousSiblingBlock(null);
438    }
439    }
440   
 
441  48 toggle @Override
442    public boolean equals(Object obj)
443    {
444  48 if (obj == this) {
445  21 return true;
446    }
447   
448  27 if (obj instanceof Block) {
449  27 EqualsBuilder builder = new EqualsBuilder();
450   
451  27 builder.append(getChildren(), ((Block) obj).getChildren());
452  27 builder.append(getParameters(), ((Block) obj).getParameters());
453   
454  27 return builder.isEquals();
455    }
456   
457  0 return false;
458    }
459   
 
460  0 toggle @Override
461    public int hashCode()
462    {
463  0 HashCodeBuilder builder = new HashCodeBuilder();
464   
465  0 builder.append(this.childrenBlocks);
466  0 builder.append(this.parameters);
467   
468  0 return builder.toHashCode();
469    }
470   
 
471  1862599 toggle @Override
472    public Block clone()
473    {
474  1862597 return clone(null);
475    }
476   
477    /**
478    * {@inheritDoc}
479    *
480    * @since 1.8RC2
481    */
 
482  1862912 toggle @Override
483    public Block clone(BlockFilter blockFilter)
484    {
485  1862916 Block block;
486  1862916 try {
487  1862918 block = (AbstractBlock) super.clone();
488    } catch (CloneNotSupportedException e) {
489    // Should never happen
490  0 throw new RuntimeException("Failed to clone object", e);
491    }
492   
493  1862927 if (this.parameters != null) {
494  123984 ((AbstractBlock) block).parameters = new LinkedHashMap<>(this.parameters);
495    }
496   
497  1862923 if (this.childrenBlocks != null) {
498  77217 ((AbstractBlock) block).childrenBlocks = new ArrayList<Block>(this.childrenBlocks.size());
499  77215 for (Block childBlock : this.childrenBlocks) {
500  1746362 if (blockFilter != null) {
501  244 Block clonedChildBlocks = childBlock.clone(blockFilter);
502   
503  244 List<Block> filteredBlocks = blockFilter.filter(clonedChildBlocks);
504   
505  244 if (filteredBlocks.size() == 0) {
506  3 filteredBlocks = clonedChildBlocks.getChildren();
507    }
508   
509  244 block.addChildren(filteredBlocks);
510    } else {
511  1746117 block.addChild(childBlock.clone());
512    }
513    }
514    }
515   
516  1862926 return block;
517    }
518   
 
519  112956 toggle @Override
520    public void traverse(Listener listener)
521    {
522  112954 before(listener);
523   
524  112957 for (Block block : getChildren()) {
525  1285982 block.traverse(listener);
526    }
527   
528  112961 after(listener);
529    }
530   
531    /**
532    * Send {@link org.xwiki.rendering.listener.Listener} events corresponding to the start of the block. For example
533    * for a Bold block, this allows an XHTML Listener (aka a Renderer) to output <code>&lt;b&gt;</code>.
534    *
535    * @param listener the listener that will receive the events sent by this block before its children blocks have
536    * emitted their own events.
537    */
 
538  41494 toggle public void before(Listener listener)
539    {
540    // Do nothing by default, should be overridden by extending Blocks
541    }
542   
543    /**
544    * Send {@link Listener} events corresponding to the end of the block. For example for a Bold block, this allows an
545    * XHTML Listener (aka a Renderer) to output <code>&lt;/b&gt;</code>.
546    *
547    * @param listener the listener that will receive the events sent by this block before its children blocks have
548    * emitted their own events.
549    */
 
550  41495 toggle public void after(Listener listener)
551    {
552    // Do nothing by default, should be overridden by extending Blocks
553    }
554   
 
555  34684 toggle @Override
556    public <T extends Block> List<T> getBlocks(BlockMatcher matcher, Axes axes)
557    {
558  34684 BlockNavigator navigator = new BlockNavigator(matcher);
559   
560  34684 return navigator.getBlocks(this, axes);
561    }
562   
 
563  45981 toggle @Override
564    public <T extends Block> T getFirstBlock(BlockMatcher matcher, Axes axes)
565    {
566  45982 BlockNavigator navigator = new BlockNavigator(matcher);
567   
568  45982 return navigator.getFirstBlock(this, axes);
569    }
570    }