1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package org.xwiki.rendering.internal.renderer.xwiki20

File XWikiSyntaxChainingRenderer.java

 

Coverage histogram

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

Code metrics

84
262
62
1
847
589
124
0.47
4.23
62
2

Classes

Class Line # Actions
XWikiSyntaxChainingRenderer 47 262 0% 124 9
0.9779411697.8%
 

Contributing tests

This file is covered by 295 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.internal.renderer.xwiki20;
21   
22    import java.util.Map;
23   
24    import org.apache.commons.lang3.StringUtils;
25    import org.xwiki.rendering.internal.renderer.xwiki20.reference.XWikiSyntaxResourceRenderer;
26    import org.xwiki.rendering.listener.Format;
27    import org.xwiki.rendering.listener.HeaderLevel;
28    import org.xwiki.rendering.listener.ListType;
29    import org.xwiki.rendering.listener.MetaData;
30    import org.xwiki.rendering.listener.chaining.BlockStateChainingListener;
31    import org.xwiki.rendering.listener.chaining.ListenerChain;
32    import org.xwiki.rendering.listener.chaining.LookaheadChainingListener;
33    import org.xwiki.rendering.listener.chaining.StackableChainingListener;
34    import org.xwiki.rendering.listener.reference.ResourceReference;
35    import org.xwiki.rendering.renderer.AbstractChainingPrintRenderer;
36    import org.xwiki.rendering.renderer.printer.DefaultWikiPrinter;
37    import org.xwiki.rendering.renderer.printer.VoidWikiPrinter;
38    import org.xwiki.rendering.renderer.printer.WikiPrinter;
39    import org.xwiki.rendering.renderer.reference.ResourceReferenceSerializer;
40   
41    /**
42    * Convert listener events to XWiki Syntax 2.0 output.
43    *
44    * @version $Id: dfeb4fbc9c987b3d4dde0ab37253ea67ddc59267 $
45    * @since 1.8RC1
46    */
 
47    public class XWikiSyntaxChainingRenderer extends AbstractChainingPrintRenderer implements StackableChainingListener
48    {
49    private XWikiSyntaxResourceRenderer linkResourceRenderer;
50   
51    private XWikiSyntaxResourceRenderer imageResourceRenderer;
52   
53    private XWikiSyntaxMacroRenderer macroPrinter;
54   
55    protected ResourceReferenceSerializer linkReferenceSerializer;
56   
57    protected ResourceReferenceSerializer imageReferenceSerializer;
58   
59    // Custom States
60   
61    private boolean isFirstElementRendered;
62   
63    private StringBuilder listStyle = new StringBuilder();
64   
65    private Map<String, String> previousFormatParameters;
66   
67    /**
68    * @since 2.5RC1
69    */
 
70  458 toggle public XWikiSyntaxChainingRenderer(ListenerChain listenerChain, ResourceReferenceSerializer linkReferenceSerializer,
71    ResourceReferenceSerializer imageReferenceSerializer)
72    {
73  458 setListenerChain(listenerChain);
74   
75  458 this.linkReferenceSerializer = linkReferenceSerializer;
76  458 this.imageReferenceSerializer = imageReferenceSerializer;
77  458 this.linkResourceRenderer = createXWikiSyntaxLinkRenderer(getListenerChain(), linkReferenceSerializer);
78  458 this.imageResourceRenderer = createXWikiSyntaxImageRenderer(getListenerChain(), imageReferenceSerializer);
79  458 this.macroPrinter = new XWikiSyntaxMacroRenderer();
80    }
81   
82    /**
83    * @since 2.5RC1
84    */
 
85  330 toggle protected XWikiSyntaxResourceRenderer createXWikiSyntaxLinkRenderer(ListenerChain listenerChain,
86    ResourceReferenceSerializer linkReferenceSerializer)
87    {
88  330 return new XWikiSyntaxResourceRenderer((XWikiSyntaxListenerChain) listenerChain, linkReferenceSerializer);
89    }
90   
91    /**
92    * @since 2.5RC1
93    */
 
94  330 toggle protected XWikiSyntaxResourceRenderer createXWikiSyntaxImageRenderer(ListenerChain listenerChain,
95    ResourceReferenceSerializer imageReferenceSerializer)
96    {
97  330 return new XWikiSyntaxResourceRenderer((XWikiSyntaxListenerChain) listenerChain, imageReferenceSerializer);
98    }
99   
100    // State
101   
 
102  726 toggle private BlockStateChainingListener getBlockState()
103    {
104  726 return getXWikiSyntaxListenerChain().getBlockStateChainingListener();
105    }
106   
 
107  44 toggle @Override
108    public StackableChainingListener createChainingListenerInstance()
109    {
110  44 XWikiSyntaxChainingRenderer renderer = new XWikiSyntaxChainingRenderer(getListenerChain(),
111    this.linkReferenceSerializer, this.imageReferenceSerializer);
112  44 renderer.setPrinter(getPrinter());
113  44 return renderer;
114    }
115   
 
116  1425 toggle private XWikiSyntaxListenerChain getXWikiSyntaxListenerChain()
117    {
118  1425 return (XWikiSyntaxListenerChain) getListenerChain();
119    }
120   
 
121  362 toggle private XWikiSyntaxResourceRenderer getLinkRenderer()
122    {
123  362 return this.linkResourceRenderer;
124    }
125   
 
126  74 toggle private XWikiSyntaxResourceRenderer getImageRenderer()
127    {
128  74 return this.imageResourceRenderer;
129    }
130   
 
131  81 toggle private XWikiSyntaxMacroRenderer getMacroPrinter()
132    {
133  81 return this.macroPrinter;
134    }
135   
 
136  45 toggle @Override
137    public void beginGroup(Map<String, String> parameters)
138    {
139  45 if (!getBlockState().isInLine()) {
140  24 printEmptyLine();
141    }
142   
143  45 if (parameters.size() > 0) {
144  15 printParameters(parameters, true);
145    }
146   
147  45 print("(((");
148  45 print("\n");
149   
150    // Create a new listener stack in order to preserve current states, to handle the group.
151  45 getListenerChain().pushAllStackableListeners();
152    }
153   
154    /**
155    * {@inheritDoc}
156    *
157    * @since 3.0M2
158    */
 
159  638 toggle @Override
160    public void endDocument(MetaData metadata)
161    {
162    // Ensure that all data in the escape printer have been flushed
163  638 getXWikiPrinter().flush();
164    }
165   
 
166  45 toggle @Override
167    public void endGroup(Map<String, String> parameters)
168    {
169  45 print("\n");
170  45 print(")))");
171   
172    // Restore previous listeners that were stacked
173  45 getListenerChain().popAllStackableListeners();
174    }
175   
 
176  91 toggle @Override
177    public void beginLink(ResourceReference reference, boolean freestanding, Map<String, String> parameters)
178    {
179    // Flush test content before the link.
180    // TODO: improve the block state renderer to be able to make the difference between what is bufferized
181    // before the link and what in the label link
182  91 getXWikiPrinter().setBeforeLink(true);
183    // escape open link syntax when before a link
184  91 if (getLinkRenderer().forceFullSyntax(getXWikiPrinter(), freestanding, parameters)
185    && getXWikiPrinter().getBuffer().length() > 0
186    && getXWikiPrinter().getBuffer().charAt(getXWikiPrinter().getBuffer().length() - 1) == '[')
187    {
188  1 getXWikiPrinter().setEscapeLastChar(true);
189    }
190  91 getXWikiPrinter().flush();
191  91 getXWikiPrinter().setBeforeLink(false);
192   
193  91 int linkDepth = getBlockState().getLinkDepth();
194   
195    // If we are at a depth of 2 or greater it means we're in a link inside a link and in this case we
196    // shouldn't output the nested link as a link unless it's a free standing link.
197  91 if (linkDepth < 2) {
198  90 getLinkRenderer().beginRenderLink(getXWikiPrinter(), freestanding, parameters);
199   
200  90 XWikiSyntaxEscapeWikiPrinter linkLabelPrinter =
201    new XWikiSyntaxEscapeWikiPrinter(new DefaultWikiPrinter(), getXWikiSyntaxListenerChain());
202   
203    // Make sure the escape handler knows there is already characters before
204  90 linkLabelPrinter.setOnNewLine(getXWikiPrinter().isOnNewLine());
205   
206    // Defer printing the link content since we need to gather all nested elements
207  90 pushPrinter(linkLabelPrinter);
208  1 } else if (freestanding) {
209  1 print(getLinkRenderer().serialize(reference, freestanding));
210    }
211    }
212   
 
213  91 toggle @Override
214    public void endLink(ResourceReference reference, boolean freestanding, Map<String, String> parameters)
215    {
216    // The links in a top level link label are not rendered as link (only the label is printed)
217  91 if (getBlockState().getLinkDepth() == 1) {
218  90 XWikiSyntaxEscapeWikiPrinter linkBlocksPrinter = getXWikiPrinter();
219  90 linkBlocksPrinter.flush();
220  90 String content = linkBlocksPrinter.toString();
221  90 popPrinter();
222   
223  90 getLinkRenderer().renderLinkContent(getXWikiPrinter(), content);
224  90 getLinkRenderer().endRenderLink(getXWikiPrinter(), reference, freestanding, parameters);
225    }
226    }
227   
 
228  119 toggle @Override
229    public void beginFormat(Format format, Map<String, String> parameters)
230    {
231    // If the previous format had parameters and the parameters are different from the current ones then close them
232  119 if (this.previousFormatParameters != null) {
233  31 if (parameters.isEmpty()) {
234    // print("(%%)");
235    // this.previousFormatParameters = null;
236  29 } else if (!this.previousFormatParameters.equals(parameters)) {
237  28 this.previousFormatParameters = null;
238  28 printParameters(parameters, false);
239    } else {
240  1 this.previousFormatParameters = null;
241    }
242  88 } else if (this.previousFormatParameters == null) {
243  88 printParameters(parameters, false);
244    }
245   
246  119 switch (format) {
247  22 case BOLD:
248    // Handle empty formatting parameters.
249  22 handleEmptyParameters();
250   
251  22 getXWikiPrinter().printBeginBold();
252  22 break;
253  17 case ITALIC:
254    // Handle empty formatting parameters.
255  17 handleEmptyParameters();
256   
257  17 getXWikiPrinter().printBeginItalic();
258  17 break;
259  4 case STRIKEDOUT:
260  4 print("--");
261  4 break;
262  2 case UNDERLINED:
263  2 print("__");
264  2 break;
265  3 case SUPERSCRIPT:
266  3 print("^^");
267  3 break;
268  3 case SUBSCRIPT:
269  3 print(",,");
270  3 break;
271  5 case MONOSPACE:
272  5 print("##");
273  5 break;
274  63 case NONE:
275  63 break;
276  0 default:
277  0 break;
278    }
279    }
280   
 
281  119 toggle @Override
282    public void endFormat(Format format, Map<String, String> parameters)
283    {
284  119 switch (format) {
285  22 case BOLD:
286  22 print("**");
287  22 break;
288  17 case ITALIC:
289  17 getXWikiPrinter().printEndItalic();
290  17 break;
291  4 case STRIKEDOUT:
292  4 print("--");
293  4 break;
294  2 case UNDERLINED:
295  2 print("__");
296  2 break;
297  3 case SUPERSCRIPT:
298  3 print("^^");
299  3 break;
300  3 case SUBSCRIPT:
301  3 print(",,");
302  3 break;
303  5 case MONOSPACE:
304  5 print("##");
305  5 break;
306  63 case NONE:
307  63 break;
308  0 default: // Unsupported format
309  0 break;
310    }
311  119 if (!parameters.isEmpty()) {
312  72 this.previousFormatParameters = parameters;
313    }
314    }
315   
 
316  39 toggle private void handleEmptyParameters()
317    {
318  39 if (this.previousFormatParameters != null) {
319  2 getPrinter().print("(%%)");
320  2 this.previousFormatParameters = null;
321    }
322    }
323   
 
324  312 toggle @Override
325    public void beginParagraph(Map<String, String> parameters)
326    {
327  312 printEmptyLine();
328  312 printParameters(parameters);
329    }
330   
 
331  312 toggle @Override
332    public void endParagraph(Map<String, String> parameters)
333    {
334  312 this.previousFormatParameters = null;
335   
336    // Ensure that any not printed characters are flushed.
337    // TODO: Fix this better by introducing a state listener to handle escapes
338  312 getXWikiPrinter().flush();
339    }
340   
 
341  102 toggle @Override
342    public void onNewLine()
343    {
344    // - If we're inside a table cell, a paragraph, a list or a section header then if we have already outputted
345    // a new line before then this new line should be a line break in order not to break the table cell,
346    // paragraph, list or section header.
347   
348    // - If the new line is the last element of the paragraph, list or section header then it should be a line break
349    // as otherwise it'll be considered as an empty line event next time the generated syntax is read by the XWiki
350    // parser.
351   
352  102 if (getBlockState().isInLine()) {
353  100 if (getXWikiSyntaxListenerChain().getConsecutiveNewLineStateChainingListener().getNewLineCount() > 1) {
354  6 print("\\\\");
355  94 } else if (getXWikiSyntaxListenerChain().getLookaheadChainingListener().getNextEvent().eventType
356    .isInlineEnd())
357    {
358  9 print("\\\\");
359    } else {
360  85 print("\n");
361    }
362    } else {
363  2 print("\n");
364    }
365    }
366   
 
367  32 toggle @Override
368    public void onMacro(String id, Map<String, String> parameters, String content, boolean inline)
369    {
370  32 if (!inline) {
371  23 printEmptyLine();
372  23 print(getMacroPrinter().renderMacro(id, parameters, content, inline));
373    } else {
374  9 getXWikiPrinter().printInlineMacro(getMacroPrinter().renderMacro(id, parameters, content, inline));
375    }
376    }
377   
 
378  78 toggle @Override
379    public void beginHeader(HeaderLevel level, String id, Map<String, String> parameters)
380    {
381  78 printEmptyLine();
382  78 printParameters(parameters);
383  78 print(StringUtils.repeat("=", level.getAsInt()) + " ");
384    }
385   
 
386  78 toggle @Override
387    public void endHeader(HeaderLevel level, String id, Map<String, String> parameters)
388    {
389  78 print(" " + StringUtils.repeat("=", level.getAsInt()));
390    }
391   
 
392  1190 toggle @Override
393    public void onWord(String word)
394    {
395  1190 printDelayed(word);
396    }
397   
 
398  622 toggle @Override
399    public void onSpace()
400    {
401  622 printDelayed(" ");
402    }
403   
 
404  284 toggle @Override
405    public void onSpecialSymbol(char symbol)
406    {
407  284 printDelayed("" + symbol);
408    }
409   
 
410  74 toggle @Override
411    public void beginList(ListType type, Map<String, String> parameters)
412    {
413    // This need to be done in case of a subitem before endListItem() is not called
414  74 this.previousFormatParameters = null;
415   
416  74 if (getBlockState().getListDepth() == 1) {
417  38 printEmptyLine();
418    } else {
419  36 getPrinter().print("\n");
420    }
421   
422  74 if (type == ListType.BULLETED) {
423  56 this.listStyle.append("*");
424    } else {
425  18 this.listStyle.append("1");
426    }
427  74 printParameters(parameters);
428    }
429   
 
430  104 toggle @Override
431    public void beginListItem()
432    {
433  104 if (getBlockState().getListItemIndex() > 0) {
434  30 getPrinter().print("\n");
435    }
436   
437  104 print(this.listStyle.toString());
438  104 if (StringUtils.contains(this.listStyle.toString(), '1')) {
439  32 print(".");
440    }
441  104 print(" ");
442   
443    // Stack all events until we either get a standalone one (that will be wrapped in a GroupBlock by the listener)
444    // or until endListItem() is called.
445    // IMPORTANT: We need to put our listener just after the LookaheadChainingListener one since otherwise some of
446    // the already stacked events in LookaheadChainingListener won't reach our new listener!
447  104 getXWikiSyntaxListenerChain().addListener(
448    new ListItemStackingInlineContentChainingListener(getListenerChain()),
449    getListenerChain().indexOf(LookaheadChainingListener.class) + 1);
450    }
451   
 
452  104 toggle @Override
453    public void beginListItem(Map<String, String> parameters)
454    {
455    // TODO: introduce a syntax for list items
456  104 beginListItem();
457    }
458   
 
459  74 toggle @Override
460    public void endList(ListType type, Map<String, String> parameters)
461    {
462  74 this.listStyle.setLength(this.listStyle.length() - 1);
463   
464    // Ensure that any not printed characters are flushed.
465    // TODO: Fix this better by introducing a state listener to handle escapes
466  74 getXWikiPrinter().flush();
467    }
468   
 
469  104 toggle @Override
470    public void endListItem()
471    {
472  104 this.previousFormatParameters = null;
473   
474    // Remove our stacking event listener
475  104 getXWikiSyntaxListenerChain().removeListener(ListItemStackingInlineContentChainingListener.class);
476    }
477   
 
478  0 toggle @Override
479    public void endListItem(Map<String, String> parameters)
480    {
481  0 endListItem();
482    }
483   
 
484  49 toggle @Override
485    public void beginMacroMarker(String name, Map<String, String> parameters, String content, boolean isInline)
486    {
487  49 if (!isInline) {
488  38 printEmptyLine();
489    }
490   
491    // When we encounter a macro marker we ignore all other blocks inside since we're going to use the macro
492    // definition wrapped by the macro marker to construct the xwiki syntax.
493    // However we need to handle the closing of any format block since that's normally handled by any print() calls
494    // but since we use a VoidWikiPrinter this won't have any effect.
495  49 if (this.previousFormatParameters != null) {
496  1 getPrinter().print("(%%)");
497  1 this.previousFormatParameters = null;
498    }
499  49 pushPrinter(new XWikiSyntaxEscapeWikiPrinter(VoidWikiPrinter.VOIDWIKIPRINTER, getXWikiSyntaxListenerChain()));
500    }
501   
 
502  49 toggle @Override
503    public void endMacroMarker(String name, Map<String, String> parameters, String content, boolean isInline)
504    {
505  49 this.previousFormatParameters = null;
506   
507  49 popPrinter();
508   
509  49 print(getMacroPrinter().renderMacro(name, parameters, content, isInline));
510    }
511   
 
512  6 toggle @Override
513    public void onId(String name)
514    {
515  6 print("{{id name=\"" + name + "\"/}}");
516    }
517   
 
518  10 toggle @Override
519    public void onHorizontalLine(Map<String, String> parameters)
520    {
521  10 printEmptyLine();
522  10 printParameters(parameters);
523  10 print("----");
524    }
525   
 
526  22 toggle @Override
527    public void onVerbatim(String content, boolean inline, Map<String, String> parameters)
528    {
529  22 if (!inline) {
530  12 printEmptyLine();
531    }
532  22 printParameters(parameters);
533   
534  22 print("{{{");
535  22 getXWikiPrinter().printVerbatimContent(content);
536  22 print("}}}");
537    }
538   
 
539  10 toggle @Override
540    public void onEmptyLines(int count)
541    {
542  10 print(StringUtils.repeat('\n', count));
543    }
544   
545    /**
546    * {@inheritDoc}
547    *
548    * @since 2.0RC1
549    */
 
550  23 toggle @Override
551    public void beginDefinitionList(Map<String, String> parameters)
552    {
553  23 if (getBlockState().getDefinitionListDepth() == 1 && !getBlockState().isInList()) {
554  14 printEmptyLine();
555    } else {
556  9 print("\n");
557    }
558  23 printParameters(parameters);
559    }
560   
561    /**
562    * {@inheritDoc}
563    *
564    * @since 1.6M2
565    */
 
566  18 toggle @Override
567    public void beginDefinitionTerm()
568    {
569  18 if (getBlockState().getDefinitionListItemIndex() > 0) {
570  2 getPrinter().print("\n");
571    }
572   
573  18 if (this.listStyle.length() > 0) {
574  3 print(this.listStyle.toString());
575  3 if (this.listStyle.charAt(0) == '1') {
576  1 print(".");
577    }
578    }
579  18 print(StringUtils.repeat(':', getBlockState().getDefinitionListDepth() - 1));
580  18 print("; ");
581    }
582   
583    /**
584    * {@inheritDoc}
585    *
586    * @since 1.6M2
587    */
 
588  22 toggle @Override
589    public void beginDefinitionDescription()
590    {
591  22 if (getBlockState().getDefinitionListItemIndex() > 0) {
592  15 getPrinter().print("\n");
593    }
594   
595  22 if (this.listStyle.length() > 0) {
596  3 print(this.listStyle.toString());
597  3 if (this.listStyle.charAt(0) == '1') {
598  1 print(".");
599    }
600    }
601  22 print(StringUtils.repeat(':', getBlockState().getDefinitionListDepth() - 1));
602  22 print(": ");
603    }
604   
 
605  22 toggle @Override
606    public void endDefinitionDescription()
607    {
608  22 this.previousFormatParameters = null;
609   
610  22 getXWikiPrinter().flush();
611    }
612   
 
613  18 toggle @Override
614    public void endDefinitionTerm()
615    {
616  18 this.previousFormatParameters = null;
617   
618  18 getXWikiPrinter().flush();
619    }
620   
621    /**
622    * {@inheritDoc}
623    *
624    * @since 1.6M2
625    */
 
626  13 toggle @Override
627    public void beginQuotation(Map<String, String> parameters)
628    {
629  13 if (!getBlockState().isInQuotationLine()) {
630  9 printEmptyLine();
631    }
632   
633  13 if (!parameters.isEmpty()) {
634  1 printParameters(parameters);
635    }
636    }
637   
638    /**
639    * {@inheritDoc}
640    *
641    * @since 1.6M2
642    */
 
643  21 toggle @Override
644    public void beginQuotationLine()
645    {
646  21 if (getBlockState().getQuotationLineIndex() > 0) {
647  12 getPrinter().print("\n");
648    }
649   
650  21 print(StringUtils.repeat('>', getBlockState().getQuotationDepth()));
651    }
652   
 
653  21 toggle @Override
654    public void endQuotationLine()
655    {
656  21 this.previousFormatParameters = null;
657   
658  21 getXWikiPrinter().flush();
659    }
660   
 
661  29 toggle @Override
662    public void beginTable(Map<String, String> parameters)
663    {
664  29 printEmptyLine();
665  29 if (!parameters.isEmpty()) {
666  2 printParameters(parameters);
667    }
668    }
669   
 
670  49 toggle @Override
671    public void beginTableCell(Map<String, String> parameters)
672    {
673  49 print("|");
674  49 printParameters(parameters, false);
675   
676    // Stack all events until we either get a standalone one (that will be wrapped in a GroupBlock by the listener)
677    // or until endTableCell() is called.
678    // IMPORTANT: We need to put our listener just after the LookaheadChainingListener one since otherwise some of
679    // the already stacked events in LookaheadChainingListener won't reach our new listener!
680  49 getXWikiSyntaxListenerChain().addListener(
681    new TableCellStackingInlineContentChainingListener(getListenerChain()),
682    getListenerChain().indexOf(LookaheadChainingListener.class) + 1);
683    }
684   
 
685  30 toggle @Override
686    public void beginTableHeadCell(Map<String, String> parameters)
687    {
688  30 print("|=");
689  30 printParameters(parameters, false);
690   
691    // Stack all events until we either get a standalone one (that will be wrapped in a GroupBlock by the listener)
692    // or until endTableHeadCell() is called.
693    // IMPORTANT: We need to put our listener just after the LookaheadChainingListener one since otherwise some of
694    // the already stacked events in LookaheadChainingListener won't reach our new listener!
695  30 getXWikiSyntaxListenerChain().addListener(
696    new TableHeadCellStackingInlineContentChainingListener(getListenerChain()),
697    getListenerChain().indexOf(LookaheadChainingListener.class) + 1);
698    }
699   
 
700  44 toggle @Override
701    public void beginTableRow(Map<String, String> parameters)
702    {
703  44 if (getBlockState().getCellRow() > 0) {
704  15 print("\n");
705    }
706   
707  44 printParameters(parameters, false);
708    }
709   
 
710  49 toggle @Override
711    public void endTableCell(Map<String, String> parameters)
712    {
713  49 this.previousFormatParameters = null;
714   
715    // Remove our stacking event listener
716  49 getXWikiSyntaxListenerChain().removeListener(TableCellStackingInlineContentChainingListener.class);
717   
718    // Ensure that any not printed characters are flushed.
719    // TODO: Fix this better by introducing a state listener to handle escapes
720  49 getXWikiPrinter().flush();
721    }
722   
 
723  30 toggle @Override
724    public void endTableHeadCell(Map<String, String> parameters)
725    {
726  30 this.previousFormatParameters = null;
727   
728    // Remove our stacking event listener
729  30 getXWikiSyntaxListenerChain().removeListener(TableHeadCellStackingInlineContentChainingListener.class);
730    }
731   
732    /**
733    * {@inheritDoc}
734    *
735    * @since 2.5RC1
736    */
 
737  37 toggle @Override
738    public void onImage(ResourceReference reference, boolean freestanding, Map<String, String> parameters)
739    {
740  37 getImageRenderer().beginRenderLink(getXWikiPrinter(), freestanding, parameters);
741  37 getImageRenderer().endRenderLink(getXWikiPrinter(), reference, freestanding, parameters);
742    }
743   
 
744  522 toggle protected void printParameters(Map<String, String> parameters)
745    {
746  522 printParameters(parameters, true);
747    }
748   
 
749  776 toggle protected void printParameters(Map<String, String> parameters, boolean newLine)
750    {
751  776 StringBuilder parametersStr = new StringBuilder();
752  776 for (Map.Entry<String, String> entry : parameters.entrySet()) {
753  109 String value = entry.getValue();
754  109 String key = entry.getKey();
755   
756  109 if (key != null && value != null) {
757    // Escape quotes in value to not break parameter value syntax
758  109 value = value.replaceAll("[~\"]", "~$0");
759    // Escape ending custom parameters syntax
760  109 value = value.replace("%)", "~%)");
761  109 parametersStr.append(' ').append(key).append('=').append('\"').append(value).append('\"');
762    }
763    }
764   
765  776 if (parametersStr.length() > 0) {
766  106 StringBuilder buffer = new StringBuilder("(%");
767  106 buffer.append(parametersStr);
768  106 buffer.append(" %)");
769   
770  106 if (newLine) {
771  28 buffer.append('\n');
772    }
773   
774  106 print(buffer.toString());
775    }
776    }
777   
 
778  2096 toggle private void printDelayed(String text)
779    {
780  2096 print(text, true);
781    }
782   
 
783  1428 toggle private void print(String text)
784    {
785  1428 print(text, false);
786    }
787   
 
788  3524 toggle private void print(String text, boolean isDelayed)
789    {
790    // Handle empty formatting parameters.
791  3524 if (this.previousFormatParameters != null) {
792  13 getPrinter().print("(%%)");
793  13 this.previousFormatParameters = null;
794    }
795   
796  3524 if (isDelayed) {
797  2096 getXWikiPrinter().printDelayed(text);
798    } else {
799  1428 getPrinter().print(text);
800    }
801    }
802   
 
803  587 toggle private void printEmptyLine()
804    {
805  587 if (this.isFirstElementRendered) {
806  233 print("\n\n");
807    } else {
808  354 this.isFirstElementRendered = true;
809    }
810    }
811   
812    /**
813    * {@inheritDoc}
814    *
815    * @since 2.0M3
816    */
 
817  458 toggle @Override
818    public void setPrinter(WikiPrinter printer)
819    {
820    // If the printer is already a XWiki Syntax Escape printer don't wrap it again. This case happens when
821    // the createChainingListenerInstance() method is called, ie when this renderer's state is stacked
822    // (for example when a Group event is being handled).
823  458 if (printer instanceof XWikiSyntaxEscapeWikiPrinter) {
824  45 super.setPrinter(printer);
825    } else {
826  413 super.setPrinter(new XWikiSyntaxEscapeWikiPrinter(printer, (XWikiSyntaxListenerChain) getListenerChain()));
827    }
828    }
829   
830    /**
831    * Allows exposing the additional methods of {@link XWikiSyntaxEscapeWikiPrinter}, namely the ability to delay
832    * printing some text and the ability to escape characters that would otherwise have a meaning in XWiki syntax.
833    */
 
834  4434 toggle public XWikiSyntaxEscapeWikiPrinter getXWikiPrinter()
835    {
836  4434 return (XWikiSyntaxEscapeWikiPrinter) super.getPrinter();
837    }
838   
 
839  139 toggle @Override
840    protected void popPrinter()
841    {
842    // Ensure that any not printed characters are flushed
843  139 getXWikiPrinter().flush();
844   
845  139 super.popPrinter();
846    }
847    }