View Javadoc

1   /*
2    * Copyright 1999-2006 Faculty of Mathematics, Physics and Informatics, Comenius
3    * University, Bratislava. This file is protected by the Mozilla Public License
4    * version 1.1 (the License); you may not use this file except in compliance
5    * with the License. You may obtain a copy of the License at
6    * http://euromath2.sourceforge.net/license.html Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is
8    * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
9    * KIND, either express or implied. See the License for the specific language
10   * governing permissions and limitations under the License.
11   */
12  package sk.uniba.euromath.foRenderer;
13  
14  import java.io.IOException;
15  import java.util.HashMap;
16  import java.util.LinkedList;
17  import java.util.List;
18  import java.util.Queue;
19  
20  import javax.xml.transform.Source;
21  import javax.xml.transform.TransformerException;
22  import javax.xml.transform.dom.DOMSource;
23  
24  import org.apache.fop.apps.FOPException;
25  import org.eclipse.draw2d.Border;
26  import org.eclipse.draw2d.ColorConstants;
27  import org.eclipse.draw2d.FlowLayout;
28  import org.eclipse.draw2d.IFigure;
29  import org.eclipse.draw2d.geometry.Dimension;
30  import org.eclipse.draw2d.geometry.Point;
31  import org.w3c.dom.Element;
32  import org.w3c.dom.Node;
33  
34  import sk.baka.ikslibs.DOMUtils;
35  import sk.baka.ikslibs.Namespaces;
36  import sk.baka.ikslibs.ids.IDManager;
37  import sk.baka.ikslibs.modify.IChangeCollector;
38  import sk.baka.ikslibs.splitted.SplittedDocHolder;
39  import sk.baka.xml.gene.ExportUtils;
40  import sk.uniba.euromath.document.XMLAccess;
41  import sk.uniba.euromath.editor.EditorException;
42  import sk.uniba.euromath.editor.IInputPreprocessor;
43  import sk.uniba.euromath.editor.IRenderer;
44  import sk.uniba.euromath.editor.RendererInfo;
45  import sk.uniba.euromath.editor.figures.EMFigure;
46  import sk.uniba.euromath.editor.figures.IEMFigure;
47  import sk.uniba.euromath.foRenderer.figures.LineRuleBorder;
48  import sk.uniba.euromath.foRenderer.figures.PageFigure;
49  import sk.uniba.euromath.foRenderer.fop.AbstractFOPLauncher;
50  import sk.uniba.euromath.gene.RendererContext;
51  
52  /***
53   * Renderer for FO XML documents. Rendering is done by processing document by
54   * FOP andrendering FOP areas by {@link Draw2dRenderer} to draw2d figures.
55   */
56  public class FORenderer implements IRenderer {
57  
58          /***
59           * Root node from transformed document(Source).
60           */
61          private Element rootElement;
62  
63          private AbstractFOPLauncher launcher;
64  
65          /***
66           * The renderer info.
67           */
68          private final RendererInfo info;
69  
70          /***
71           * Root figure.
72           */
73          private IEMFigure pageDesktopFigure;
74  
75          /***
76           * Renderer context instance.
77           */
78          private RendererContext rendererContext;
79  
80          /***
81           * Map for holdnig ids of mark elements and for mapping them to parent
82           * figures to position them.
83           */
84          private HashMap<String, IFigure> externalIdFigureMap;
85  
86          /***
87           * Map for mapping ids of mark elements to dimension of contents.
88           */
89          private HashMap<String, Dimension> externalIdDimensionMap;
90  
91          /***
92           * Constructor
93           */
94          public FORenderer(final RendererInfo info) throws FOPException {
95                  super();
96                  rootElement = null;
97                  this.info = info;
98                  launcher = createLauncher();
99          }
100 
101         /***
102          * Creates launcher.
103          * 
104          * @return
105          */
106         protected AbstractFOPLauncher createLauncher() throws FOPException {
107                 AbstractFOPLauncher result = new AbstractFOPLauncher(this);
108                 // result.setController(this);
109                 // result.setStreamProvider(getDomain().getStreamProvider());
110                 return result;
111         }
112 
113         /***
114          * Makes a copy of source, handles mark elements and renders source by
115          * FOP. Accepts only DOMSource.
116          */
117         public void init(Source transformedDoc, RendererContext context)
118                         throws EditorException {
119                 try {
120                         // don't call anything before, these lines
121                         this.rendererContext = context;
122                         
123                         // copy was made by preprocessor
124                         final DOMSource copyOfTransformedDoc = (DOMSource) transformedDoc;
125                         if (copyOfTransformedDoc.getNode() == null)
126                                 throw new NullPointerException("null node");
127 
128                         rootElement = DOMUtils
129                                         .getRootElement(copyOfTransformedDoc);
130 
131                         handleMarkElements();
132 
133                         pageDesktopFigure = createPageDesktopFigure();
134 
135                         Draw2dRenderer bld = (Draw2dRenderer) launcher
136                                         .getRenderer();
137 
138                         launcher.setInput(copyOfTransformedDoc);
139                         launcher.run();
140                         List<PageFigure> pages = bld.getPages();
141                         for (PageFigure figure : pages) {
142                                 pageDesktopFigure.add(figure);
143                         }
144 
145                 } catch (FOPException e) {
146                         throw new EditorException("FO renderer fails to init.",
147                                         e);
148                 } catch (TransformerException e) {
149                         throw new EditorException("FO renderer fails to init.",
150                                         e);
151                 }
152         }
153 
154         /*
155          * (non-Javadoc)
156          * 
157          * @see sk.uniba.euromath.api.editor.IRenderer#reinit(sk.uniba.euromath.api.export.changes.ChangeCollector)
158          */
159         public void reinit(IChangeCollector changes) throws EditorException {
160                 try {                       
161                         // don't call anything before, these lines
162                         launcher.reinit(this);
163                         // copy was made by preprocessor
164                         DOMSource copyOfTransformedDoc = (DOMSource) changes
165                                         .getSource();
166                         rootElement = DOMUtils
167                                         .getRootElement(copyOfTransformedDoc);
168 
169                         handleMarkElements();
170 
171                         pageDesktopFigure = createPageDesktopFigure();
172 
173                         Draw2dRenderer bld = (Draw2dRenderer) launcher
174                                         .getRenderer();
175 
176                         try {
177                                 bld.startRenderer(null);
178                         } catch (IOException e) {
179                                 throw new EditorException(e);
180                         }
181 
182                         launcher.setInput(copyOfTransformedDoc);
183                         launcher.run();
184                         List<PageFigure> pages = bld.getPages();
185                         for (PageFigure figure : pages) {
186                                 pageDesktopFigure.add(figure);
187                         }
188 
189                 } catch (FOPException e) {
190                         throw new EditorException("FO renderer fails to init.",
191                                         e);
192                 } catch (TransformerException e) {
193                         throw new EditorException("FO renderer fails to init.",
194                                         e);
195                 }
196         }
197 
198         /***
199          * Replaces mark elements with <fo:instream-foreign-object>
200          * 
201          * @param transformedDoc
202          * @throws EditorException
203          */
204         private void handleMarkElements() throws EditorException {
205                 externalIdFigureMap = new HashMap<String, IFigure>();
206                 externalIdDimensionMap = new HashMap<String, Dimension>();
207 
208                 Queue<Node> queue = new LinkedList<Node>();
209                 queue.addAll(DOMUtils.nodeListToList(rootElement
210                                 .getChildNodes()));
211                 Node node;
212                 while (!queue.isEmpty()) {
213                         node = queue.poll();
214                         // it is mark element
215                         final String id = FOPreprocessor.getGenerefElementId(node);
216                         if (id != null) {
217                                 // just store ids, figures doesn't exist yet
218                                 Dimension dimension = rendererContext
219                                                 .getCanvasSize(id);
220                                 externalIdDimensionMap.put(id, dimension);
221                                 externalIdFigureMap.put(id, null);
222 
223                                 Node parent = (Element) node.getParentNode();
224                                 // remove mark element
225                                 parent.removeChild(node);
226                                 // if parent is fo-instrem-foreign-object remove
227                                 // it
228                                 if (((Element) parent).getLocalName().contains(
229                                                 "instream-foreign-object")) {
230                                         Node grandParent = parent
231                                                         .getParentNode();
232                                         grandParent.removeChild(parent);
233                                         parent = grandParent;
234                                 }
235                                 // add element for removed mark element
236                                 // add instream-foreign-object
237                                 Element e = parent
238                                                 .getOwnerDocument()
239                                                 .createElementNS(
240                                                                 Namespaces.XSL_FO_NAMESPACE,
241                                                                 "fo:block-container");
242                                 e.setAttributeNS(null, "width", Integer
243                                                 .toString(dimension.width)
244                                                 + "pt");
245                                 e.setAttributeNS(null, "height", Integer
246                                                 .toString(dimension.height)
247                                                 + "pt");
248                                 e.setAttributeNS(null, "id", id);
249                                 parent.appendChild(e);
250                                 parent = e;
251                                 e = parent.getOwnerDocument().createElementNS(
252                                                 Namespaces.XSL_FO_NAMESPACE,
253                                                 "fo:block");
254                                 parent.appendChild(e);
255 
256                                 // it is not mark element
257                         } else {
258                                 queue.addAll(DOMUtils.nodeListToList(node
259                                                 .getChildNodes()));
260                         }
261                 }
262         }
263 
264         /***
265          * Creates root figure - pageDesktopFigure.
266          * 
267          * @return root figure
268          */
269         private IEMFigure createPageDesktopFigure() {
270                 EMFigure result = new EMFigure(IDManager.getIDNull(rootElement,
271                                 ExportUtils.GENE_ID_ATTRIBUTE_QNAME),
272                                 rootElement, true);
273                 // Border border = new LineBorder(ColorConstants.buttonDarker,
274                 // 10);
275                 Border border = new LineRuleBorder();
276                 result.setBorder(border);
277                 result.setBackgroundColor(ColorConstants.buttonDarker);
278 
279                 FlowLayout layout = new FlowLayout(false);
280                 // TODO: GUI thing about why the alignment doesn't work when
281                 // isHorizontal in
282                 // FlowLayout constructor is set
283                 layout.setMajorAlignment(FlowLayout.ALIGN_CENTER);
284                 layout.setMinorAlignment(FlowLayout.ALIGN_CENTER);
285                 layout.setMajorSpacing(10);
286                 layout.setMinorSpacing(10);
287                 result.setLayoutManager(layout);
288 
289                 result.setOpaque(true);
290                 return result;
291 
292         }
293 
294         /***
295          * Returns XMLAccess instance.
296          * 
297          * @return XMLAccess
298          */
299         private XMLAccess getXMLAccess() {
300                 if (rendererContext == null)
301                         throw new IllegalStateException(
302                                         "Cannot getXMLAccess because RendererContext is null, probably renderer is before initialization.");
303                 return rendererContext.xmlAccess;
304         }
305 
306         /*
307          * (non-Javadoc)
308          * 
309          * @see sk.uniba.euromath.api.editor.IRenderer#getPlacement(java.lang.String)
310          */
311 
312         public Point getPlacement(String id) {
313                 IFigure figure = externalIdFigureMap.get(id);
314                 Point result = figure.getClientArea().getTopLeft();
315                 return result;
316         }
317 
318         /*
319          * (non-Javadoc)
320          * 
321          * @see sk.uniba.euromath.api.editor.IRenderer#getCanvasSize()
322          */
323         public Dimension getCanvasSize() throws EditorException {
324                 // TODO GUI maybe problem when is not yet painted
325                 return this.pageDesktopFigure.getBounds().getSize();
326         }
327 
328         /*
329          * (non-Javadoc)
330          * 
331          * @see sk.uniba.euromath.api.editor.IRenderer#getFigure(java.lang.Object)
332          */
333         public IEMFigure getFigure(Object o) {
334                 if (!(o instanceof Node))
335                         throw new IllegalArgumentException(
336                                         "Object must bu instance of node.");
337                 return null;
338         }
339 
340         /*
341          * (non-Javadoc)
342          * 
343          * @see sk.uniba.euromath.api.editor.IRenderer#getRootFigure()
344          */
345         public IEMFigure getRootFigure() {
346                 return pageDesktopFigure;
347         }
348 
349         /*
350          * (non-Javadoc)
351          * 
352          * @see sk.uniba.euromath.api.editor.IRenderer#render(org.eclipse.draw2d.Graphics)
353          */
354         public void render(org.eclipse.draw2d.Graphics g)
355                         throws EditorException {
356                 pageDesktopFigure.paint(g);
357         }
358 
359         /*
360          * (non-Javadoc)
361          * 
362          * @see sk.uniba.euromath.api.editor.IRenderer#offerObject()
363          */
364         public Object offerObject() {
365                 throw new UnsupportedOperationException(
366                                 "FO renderer, offerObject.");
367         }
368 
369         /*
370          * (non-Javadoc)
371          * 
372          * @see sk.uniba.euromath.api.editor.IRenderer#getInfo()
373          */
374         public RendererInfo getInfo() {
375                 return info;
376         }
377 
378         /*
379          * (non-Javadoc)
380          * 
381          * @see sk.uniba.euromath.api.editor.IRenderer#createPreprocessor()
382          */
383         public IInputPreprocessor createPreprocessor() {
384                 return new FOPreprocessor();
385         }
386 
387         /***
388          * Returns map for holdnig ids of mark elements and for mapping them to
389          * parent figures to position them.
390          */
391         public HashMap<String, IFigure> getExternalIdFigureMap() {
392                 return externalIdFigureMap;
393         }
394 
395         /***
396          * Getter for RendererContext.
397          */
398         public RendererContext getRendererContext() {
399                 return rendererContext;
400         }
401 
402         /***
403          * Returns map for mapping ids of mark elements to dimension of
404          * contents.
405          */
406         public HashMap<String, Dimension> getExternalIdDimensionMap() {
407                 return externalIdDimensionMap;
408         }
409 }