1 /*
2 * $Source$
3 * $Revision$
4 *
5 * Copyright (C) 2006 Tim Pizey
6 *
7 * Part of Melati (http://melati.org), a framework for the rapid
8 * development of clean, maintainable web applications.
9 *
10 * Melati is free software; Permission is granted to copy, distribute
11 * and/or modify this software under the terms either:
12 *
13 * a) the GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at your option)
15 * any later version,
16 *
17 * or
18 *
19 * b) any version of the Melati Software License, as published
20 * at http://melati.org
21 *
22 * You should have received a copy of the GNU General Public License and
23 * the Melati Software License along with this program;
24 * if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26 * GNU General Public License and visit http://melati.org to obtain the
27 * Melati Software License.
28 *
29 * Feel free to contact the Developers of Melati (http://melati.org),
30 * if you would like to work out a different arrangement than the options
31 * outlined here. It is our intention to allow Melati to be used by as
32 * wide an audience as possible.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * Contact details for copyright holder:
40 *
41 * Tim Pizey <timp At paneris.org>
42 * http://paneris.org/~timp
43 */
44
45 package org.melati.template;
46
47 import java.text.DateFormat;
48
49 import org.melati.Melati;
50 import org.melati.poem.Field;
51 import org.melati.poem.PoemLocale;
52 import org.melati.util.MelatiStringWriter;
53 import org.melati.util.MelatiWriter;
54
55 /**
56 * MarkupLanguage provides a variety of methods for rendering objects in a
57 * template.
58 *
59 * Each object to be rendered has 3 methods:
60 * 1 - String rendered(Object o) - this will render the object to a String
61 * 2 - void render(Object o) - renders the object to melati.getWriter()
62 * 3 - void render(Object o, MelatiWriter w) - render the object to w.
63 *
64 * When this class was written it was thought that for maximum
65 * efficiency one should render the object direct to the output stream using
66 * method (2) above.
67 * However now all but (1) is deprecated.
68 */
69
70 public abstract class AbstractMarkupLanguage implements MarkupLanguage {
71
72 protected TempletLoader templetLoader = null;
73 protected Melati melati = null;
74 protected PoemLocale locale = null;
75
76 /** The maximum number of field possibilities to render. */
77 public static final int FIELD_POSSIBILITIES_LIMIT = 10000;
78 /** The maximum number of date field possibilities to render. */
79 public static final int DATE_FIELD_POSSIBILITIES_LIMIT = 50;
80
81 private String name;
82
83 /**
84 * Construct a Markup Language object.
85 *
86 * @param name - the name associated with this markup language.
87 * This is used to determine where to load
88 * templates from ie 'html' templates are
89 * found in the 'html' directory.
90 * @param melati - the melati currently in use
91 * @param templetLoader - the template loader in use
92 * (taken from org.melati.MelatiConfig.properties)
93 * @param locale - the locale in use
94 * (taken from org.melati.MelatiConfig.properties)
95 */
96 public AbstractMarkupLanguage(String name,
97 Melati melati,
98 TempletLoader templetLoader,
99 PoemLocale locale) {
100 this.name = name;
101 this.melati = melati;
102 this.templetLoader = templetLoader;
103 this.locale = locale;
104 }
105
106 /**
107 * Construct a new MarkupLanguage given a new name and an
108 * existing MarkupLanguage.
109 *
110 * @param name - the name of the new MarkupLanguage
111 * @param other - the Markup Language to base this one upon
112 */
113 protected AbstractMarkupLanguage(String name, AbstractMarkupLanguage other) {
114 this(name, other.melati, other.templetLoader, other.locale);
115 }
116
117 /**
118 * {@inheritDoc}
119 * @see org.melati.template.MarkupLanguage#getName()
120 */
121 public String getName() {
122 return name;
123 }
124
125 /**
126 * Name and locale.
127 * {@inheritDoc}
128 * @see java.lang.Object#toString()
129 */
130 public String toString() {
131 return getName() + "/" + locale.toString();
132 }
133
134 private MelatiStringWriter getStringWriter() {
135 return (MelatiStringWriter)melati.getStringWriter();
136 }
137
138 /**
139 * {@inheritDoc}
140 * @see org.melati.template.MarkupLanguage#rendered(java.lang.String, int)
141 */
142 public String rendered(String s, int limit) {
143 MelatiStringWriter sw = getStringWriter();
144 render(s,limit,sw);
145 return sw.toString();
146 }
147
148 /**
149 * {@inheritDoc}
150 * @see org.melati.template.MarkupLanguage#rendered(org.melati.poem.Field, int, int)
151 */
152 public String rendered(Field field, int style, int limit)
153 throws TemplateEngineException {
154 MelatiStringWriter sw = getStringWriter();
155 render(field, style, limit, sw);
156 return sw.toString();
157 }
158
159 /**
160 * {@inheritDoc}
161 * @see org.melati.template.MarkupLanguage#rendered(org.melati.poem.Field, int)
162 */
163 public String rendered(Field field, int style)
164 throws TemplateEngineException {
165 MelatiStringWriter sw = getStringWriter();
166 render(field, style, FIELD_POSSIBILITIES_LIMIT, sw);
167 return sw.toString();
168 }
169
170 /**
171 * {@inheritDoc}
172 * @see org.melati.template.MarkupLanguage#rendered(java.lang.Object)
173 */
174 public String rendered(Object o) {
175 MelatiStringWriter sw = getStringWriter();
176 if (o instanceof String)
177 render((String)o, sw);
178 else if (o instanceof Field)
179 render((Field)o, sw);
180 else
181 render(o, sw);
182 return sw.toString();
183 }
184
185 /**
186 * {@inheritDoc}
187 * @see org.melati.template.MarkupLanguage#renderedMarkup(java.lang.String)
188 */
189 public String renderedMarkup(String s) {
190 MelatiStringWriter sw = getStringWriter();
191 renderMarkup(s, sw);
192 return sw.toString();
193 }
194
195 /**
196 * Render a String in a MarkupLanguage specific way, limiting it's length.
197 * Render to a supplied MelatiWriter.
198 *
199 * @param s - the string to be rendered
200 * @param writer - the MelatiWriter to render this String to
201 * @param limit - the length to trim the string to
202 */
203 protected void render(String s, int limit, MelatiWriter writer) {
204 render(s.length() < limit + 3 ? s : s.substring(0, limit) + "...", writer);
205 }
206
207 /**
208 * Render a String in a MarkupLanguage specific way
209 * to a supplied MelatiWriter.
210 *
211 * @param s - the string to be rendered
212 * @param writer - the MelatiWriter to render this String to
213 */
214 protected abstract void render(String s, MelatiWriter writer);
215
216 /**
217 * Render a markup fragment in a MarkupLanguage specific way
218 * to a supplied MelatiWriter.
219 *
220 * @param s - the fragment to be rendered
221 * @param writer - the MelatiWriter to render this String to
222 */
223 protected abstract void renderMarkup(String s, MelatiWriter writer);
224
225 /**
226 * Render a Field Object in a MarkupLanguage specific way,
227 * rendering to supplied MelatiWriter.
228 *
229 * @param field - the Field to be rendered
230 * @param writer - the MelatiWriter to render this Object to
231 */
232 protected void render(Field field, MelatiWriter writer) {
233 render(field, DateFormat.MEDIUM, FIELD_POSSIBILITIES_LIMIT, writer);
234 }
235
236 /**
237 * Render a Field Object in a MarkupLanguage specific way,
238 * rendering to supplied MelatiWriter.
239 *
240 * @param field - the Field to be rendered
241 * @param style - a style to format this Field.
242 * @see org.melati.poem.DatePoemType#stringOfCooked
243 * (java.lang.Object,org.melati.poem.PoemLocale, int)
244 * @param limit - the length to trim the rendered string to
245 * @param writer - the MelatiWriter to render this Object to
246 */
247 protected void render(Field field, int style, int limit, MelatiWriter writer) {
248 render(field.getCookedString(locale, style), limit, writer);
249 }
250
251
252 /**
253 * {@inheritDoc}
254 * @see org.melati.template.MarkupLanguage#renderedStart(org.melati.poem.Field)
255 */
256 public String renderedStart(Field field) {
257 MelatiStringWriter sw = getStringWriter();
258 renderStart(field, sw);
259 return sw.toString();
260 }
261
262
263 protected void renderStart(Field field, MelatiWriter writer) {
264 render(field, DateFormat.MEDIUM, DATE_FIELD_POSSIBILITIES_LIMIT, writer);
265 }
266
267 /**
268 * Render an Object in a MarkupLanguage specific way, rendering to
269 * the <code>MelatiWriter</code> supplied by <code>melati.getWriter()</code>.
270 *
271 * @param o - the Object to be rendered
272 * @throws TemplateEngineException - if there is a problem with the
273 * ServletTemplateEngine
274 */
275 protected void render(Object o) {
276 MelatiWriter writer = melati.getWriter();
277 render(o, writer);
278 }
279
280 /**
281 * Render an Object in a MarkupLanguage specific way, rendering to
282 * a supplied Writer.
283 *
284 * NOTE The context always contains objects with the names melati, object and ml
285 *
286 * @param o - the Object to be rendered
287 * @param writer - the MelatiWriter to render this Object to
288 */
289 protected void render(Object o, MelatiWriter writer) {
290 if (o == null)
291 throw new NullPointerException();
292 else {
293 TemplateContext vars =
294 melati.getTemplateEngine().getTemplateContext(melati);
295 Template templet =
296 templetLoader.templet(melati.getTemplateEngine(), this, o.getClass());
297 vars.put("object", o);
298 vars.put("melati", melati);
299 vars.put("ml", melati.getMarkupLanguage());
300 expandTemplet(templet, vars, writer);
301 }
302 }
303
304
305 //
306 // =========
307 // Widgets
308 // =========
309 //
310
311 /**
312 * {@inheritDoc}
313 * @see org.melati.template.MarkupLanguage#input(org.melati.poem.Field)
314 */
315 public String input(Field field)
316 throws TemplateEngineException,
317 NotFoundException {
318 return input(field, null, "", false);
319 }
320
321 /**
322 * {@inheritDoc}
323 * @see org.melati.template.MarkupLanguage#inputAs(org.melati.poem.Field, java.lang.String)
324 */
325 public String inputAs(Field field, String templetName)
326 throws TemplateEngineException,
327 NotFoundException {
328 return input(field, templetName, "", false);
329 }
330
331 /**
332 * {@inheritDoc}
333 * @see org.melati.template.MarkupLanguage#searchInput(org.melati.poem.Field, java.lang.String)
334 */
335 public String searchInput(Field field, String nullValue)
336 throws TemplateEngineException,
337 NotFoundException{
338 return input(field, null, nullValue, true);
339 }
340
341 protected String input(Field field,
342 String templetName,
343 String nullValue,
344 boolean overrideNullable)
345 throws NotFoundException {
346
347 Template templet;
348 if (templetName == null)
349 templet = templetLoader.templet(melati.getTemplateEngine(), this, field) ;
350 else
351 templet = templetLoader.templet(melati.getTemplateEngine(), this, templetName);
352
353 TemplateContext vars =
354 melati.getTemplateEngine().getTemplateContext(melati);
355
356 if (overrideNullable) {
357 field = field.withNullable(true);
358 vars.put("nullValue", nullValue);
359 }
360
361 vars.put("melati", melati);
362 vars.put("ml", melati.getMarkupLanguage());
363 vars.put("object", field);
364 vars.put("field", field);
365 MelatiStringWriter sw = getStringWriter();
366 melati.getTemplateEngine().expandTemplate(sw, templet,vars);
367
368 return sw.toString();
369 }
370
371
372 /**
373 * Interpolate a templet and write it out.
374 *
375 * @param templet {@link Template} to interpolate
376 * @param tc {@link TemplateContext} against which to instantiate variables
377 * @param out {@link MelatiWriter} to write results to
378 */
379 protected void expandTemplet(Template templet, TemplateContext tc,
380 MelatiWriter out) {
381 melati.getTemplateEngine().expandTemplate(out, templet, tc);
382 }
383 }
384
385