View Javadoc

1   /*______________________________________________________________________________
2    * 
3    * Copyright 2006  Arnaud Bailly - 
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    * (1) Redistributions of source code must retain the above copyright
10   *     notice, this list of conditions and the following disclaimer.
11   *
12   * (2) Redistributions in binary form must reproduce the above copyright
13   *     notice, this list of conditions and the following disclaimer in
14   *     the documentation and/or other materials provided with the
15   *     distribution.
16   *
17   * (3) The name of the author may not be used to endorse or promote
18   *     products derived from this software without specific prior
19   *     written permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24   * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27   *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31   * OF THE POSSIBILITY OF SUCH DAMAGE.
32   *
33   * Created on Mon Aug 21 2006
34   *
35   */
36  package oqube.muse;
37  
38  import java.util.regex.Pattern;
39  import java.util.regex.Matcher;
40  import java.util.List;
41  
42  /***
43   * This lexer wraps another sink to format accumulated text lines.
44   * 
45   * A flow lexer wraps the  {@link MuseSink} methods so that the string gets
46   * proper formatting for inline (or *flow*) elements that appear in this block.
47   * The basic idea is then to let block lexers call the wrapped sink methods
48   * instead of the real methods. When {@link MuseSink.text(String)} method is
49   * called, this indicates that parsing is inside a block level element so text
50   * gets accumulated in an internal buffer.
51   * 
52   * When any block level method is called on this sink, the chain of lexer is
53   * asked to format the accumulated text: this text is parsed for appropriate
54   * patterns and each lexer as a chance to do something with matching framgments.
55   * 
56   * Note that the order of lexers in the chain may be important. It is customary
57   * to add the {@see IdentityLexer} at the bottom of the stack to pass final
58   * nested text elements to wrapped sink.
59   * 
60   * 
61   * @author abailly@oqube.muse.com
62   * @version $Id$
63   */
64  public abstract class FlowLexer extends AbstractLexer implements MuseSink {
65  
66    protected StringBuffer text;
67  
68    /* real sink - forwarded events */
69    private MuseSink wrappedSink;
70  
71    /***
72     * Returns the wrapped sink.
73     * 
74     * @return a wrapped MuseSink instance.
75     */
76    public MuseSink getWrappedSink() {
77      return wrappedSink;
78    }
79  
80    /***
81     * Sets the sink to wrap for this lexer.
82     * 
83     * @param wrappedSink
84     *          the Sink to wrap.
85     */
86    public void setWrappedSink(MuseSink wrappedSink) {
87      this.wrappedSink = wrappedSink;
88      if (next != null)
89        ((FlowLexer) next).setWrappedSink(wrappedSink);
90    }
91  
92    /***
93     * Construct a new FlowLexer for given pattern.
94     * 
95     * @param pattern
96     *          the pattern that this lexer matches.
97     * @see java.util.regex.Pattern
98     */
99    public FlowLexer(String pattern) {
100     super(pattern);
101   }
102 
103   public void setLineWidth(int lw) {
104   }
105 
106   public void startPara() {
107     wrappedSink.startPara();
108   }
109 
110   /***
111    * Accumulates text in this lexer. Note that this method is used only in the
112    * first lexer of the chain.
113    */
114   public void text(String txt) {
115     /* initialize buffer */
116     if (text == null)
117       text = new StringBuffer();
118     /* handle eol */
119     Pattern p = Pattern.compile("^(.*)-$");
120     Matcher m = p.matcher(txt);
121     if (m.matches())
122       text.append(m.group(1));
123     else
124       text.append(txt).append(' ');
125   }
126 
127   public void rawText(String text) {
128     wrappedSink.rawText(text);
129   }
130 
131   /*
132    * Main formatting method called at end of blocks. This method is called with
133    * the accumulated block's text as arguemnet.
134    */
135   protected void format(String s) {
136     int i = 0;
137     /* lookup all matches in buffer */
138     matcher.reset(s);
139     while (matcher.find()) {
140       /* extract unmatched part */
141       int st = matcher.start();
142       if (st > i) {
143         String sub = s.substring(i, st);
144         /* pass it over to next lexer */
145         assert next != null;
146         ((FlowLexer) next).format(sub);
147       }
148       handler(); // real work happens here
149       i = matcher.end();
150     }
151     /* format end of string */
152     if (i > 0 && i < s.length() - 2) {// there has been one match and there is a
153                                       // tail
154       assert s.substring(i).length() > 0;
155       ((FlowLexer) next).format(s.substring(i));
156     } else if (i == 0 && s.length() > 0) {// no match
157       assert s.substring(i).length() > 0;
158       ((FlowLexer) next).format(s);
159     }
160   }
161 
162   public void endPara() {
163     if (text != null) {
164       format(text.toString());
165       text = null;
166     }
167     wrappedSink.endPara();
168   }
169 
170   public void startList() {
171     if (text != null) {
172       format(text.toString());
173       text = null;
174     }
175     wrappedSink.startList();
176   }
177 
178   public void endList() {
179     wrappedSink.endList();
180   }
181 
182   public void startItem() {
183     if (text != null) {
184       format(text.toString());
185       text = null;
186     }
187     wrappedSink.startItem();
188   }
189 
190   public void endItem() {
191     if (text != null) {
192       format(text.toString());
193       text = null;
194     }
195     wrappedSink.endItem();
196   }
197 
198   public void startQuote() {
199     if (text != null) {
200       format(text.toString());
201       text = null;
202     }
203     wrappedSink.startQuote();
204   }
205 
206   public void endQuote() {
207     if (text != null) {
208       format(text.toString());
209       text = null;
210     }
211     wrappedSink.endQuote();
212   }
213 
214   public void startCenter() {
215     if (text != null) {
216       format(text.toString());
217       text = null;
218     }
219     wrappedSink.startCenter();
220   }
221 
222   public void endCenter() {
223     if (text != null) {
224       format(text.toString());
225       text = null;
226     }
227     wrappedSink.endCenter();
228   }
229 
230   public void startEnums() {
231     if (text != null) {
232       format(text.toString());
233       text = null;
234     }
235     wrappedSink.startEnums();
236   }
237 
238   public void endEnums() {
239     if (text != null) {
240       format(text.toString());
241       text = null;
242     }
243     wrappedSink.endEnums();
244   }
245 
246   public void startDocument() {
247     wrappedSink.startDocument();
248   }
249 
250   public void endDocument() {
251     if (text != null) {
252       format(text.toString());
253       text = null;
254     }
255     wrappedSink.startDocument();
256   }
257 
258   public void startHeader() {
259     wrappedSink.startHeader();
260   }
261 
262   public void endHeader() {
263     wrappedSink.endHeader();
264   }
265 
266   public void startBody() {
267     wrappedSink.startBody();
268   }
269 
270   public void endBody() {
271     wrappedSink.endBody();
272   }
273 
274   public void startFooter() {
275     wrappedSink.startFooter();
276   }
277 
278   public void endFooter() {
279     wrappedSink.endFooter();
280   }
281 
282   public void startEmph() {
283     wrappedSink.startEmph();
284   }
285 
286   public void endEmph() {
287     wrappedSink.endEmph();
288   }
289 
290   public void startStrong() {
291     wrappedSink.startStrong();
292   }
293 
294   public void endStrong() {
295     wrappedSink.endStrong();
296   }
297 
298   public void startUline() {
299     wrappedSink.startUline();
300   }
301 
302   public void endUline() {
303     wrappedSink.endUline();
304   }
305 
306   public void startVerb() {
307     wrappedSink.startVerb();
308   }
309 
310   public void endVerb() {
311     wrappedSink.endVerb();
312   }
313 
314   public void flow(String s, String content) {
315     wrappedSink.flow(s, content);
316   }
317 
318   public void block(String s, String content) {
319     wrappedSink.block(s, content);
320   }
321 
322   public void startTitle1() {
323     wrappedSink.startTitle1();
324   }
325 
326   public void endTitle1() {
327     if (text != null) {
328       format(text.toString());
329       text = null;
330     }
331     wrappedSink.endTitle1();
332   }
333 
334   public void startTitle2() {
335     wrappedSink.startTitle2();
336   }
337 
338   public void endTitle2() {
339     if (text != null) {
340       format(text.toString());
341       text = null;
342     }
343     wrappedSink.endTitle2();
344   }
345 
346   public void startTitle3() {
347     wrappedSink.startTitle3();
348   }
349 
350   public void endTitle3() {
351     if (text != null) {
352       format(text.toString());
353       text = null;
354     }
355     wrappedSink.endTitle3();
356   }
357 
358   public void startTitle4() {
359     wrappedSink.startTitle4();
360   }
361 
362   public void endTitle4() {
363     if (text != null) {
364       format(text.toString());
365       text = null;
366     }
367     wrappedSink.endTitle4();
368   }
369 
370   public void startTableData() {
371     wrappedSink.startTableData();
372   }
373 
374   public void endTableData() {
375     if (text != null) {
376       format(text.toString());
377       text = null;
378     }
379     wrappedSink.endTableData();
380   }
381 
382   public void startTableHeader() {
383     wrappedSink.startTableHeader();
384   }
385 
386   public void endTableHeader() {
387     if (text != null) {
388       format(text.toString());
389       text = null;
390     }
391     wrappedSink.endTableHeader();
392   }
393 
394   /*
395    * (non-Javadoc)
396    * 
397    * @see oqube.muse.MuseSink#endTable()
398    */
399   public void endTable() {
400     wrappedSink.endTable();
401   }
402 
403   /*
404    * (non-Javadoc)
405    * 
406    * @see oqube.muse.MuseSink#startTable()
407    */
408   public void startTable() {
409     if (text != null) {
410       format(text.toString());
411       text = null;
412     }
413     wrappedSink.startTable();
414   }
415 
416   /* (non-Javadoc)
417    * @see oqube.muse.MuseSink#endTableRow()
418    */
419   public void endTableRow() {
420     wrappedSink.endTableRow();
421   }
422 
423   /* (non-Javadoc)
424    * @see oqube.muse.MuseSink#startTableRow()
425    */
426   public void startTableRow() {
427     wrappedSink.startTableRow();
428   }
429 
430   public void link(String s, String t) {
431     wrappedSink.link(s, t);
432   }
433 
434   public void anchor(String s) {
435     wrappedSink.anchor(s);
436   }
437 
438   public void addMetadata(String s, String t) {
439     wrappedSink.addMetadata(s, t);
440   }
441 
442   public void separator() {
443     wrappedSink.separator();
444   }
445 
446 }