View Javadoc

1   /*
2    * Copyright 1999-2006 Faculty of Mathematics, Physics
3    * and Informatics, Comenius University, Bratislava. This file is protected by
4    * the Mozilla Public License version 1.1 (the License); you may not use this
5    * file except in compliance with the License. You may obtain a copy of the
6    * License at http://euromath2.sourceforge.net/license.html Unless required by
7    * applicable law or agreed to in writing, software distributed under the
8    * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
9    * OF ANY KIND, either express or implied. See the License for the specific
10   * language governing permissions and limitations under the License.
11   */
12  package sk.uniba.euromath.foRenderer.figures;
13  
14  import java.util.ArrayList;
15  import java.util.HashMap;
16  import java.util.List;
17  import java.util.Map;
18  
19  import org.apache.fop.area.Area;
20  import org.apache.fop.area.Block;
21  import org.apache.fop.area.BlockViewport;
22  import org.apache.fop.area.Footnote;
23  import org.apache.fop.area.LineArea;
24  import org.apache.fop.area.MainReference;
25  import org.apache.fop.area.NormalFlow;
26  import org.apache.fop.area.RegionViewport;
27  import org.apache.fop.area.Span;
28  import org.apache.fop.area.inline.FilledArea;
29  import org.apache.fop.area.inline.ForeignObject;
30  import org.apache.fop.area.inline.InlineParent;
31  import org.apache.fop.area.inline.Leader;
32  import org.apache.fop.area.inline.Space;
33  import org.apache.fop.area.inline.TextArea;
34  import org.apache.fop.area.inline.UnresolvedPageNumber;
35  import org.eclipse.core.runtime.IStatus;
36  import org.eclipse.draw2d.geometry.Rectangle;
37  
38  import sk.uniba.euromath.EuroMath;
39  import sk.uniba.euromath.foRenderer.Draw2dRenderer;
40  
41  /***
42   * @author TV Created on 14.1.2004
43   * 
44   * Main controller in process of building GEF's figure hierarchy representing
45   * visual page.
46   * 
47   * Sequentially converts Area objects produced by FOP layout mechanisms into
48   * Figure objects. Creation traversal: preorder.
49   * 
50   * Clients communicate with factory through <code>build(Area)</code> method
51   */
52  
53  // One of roles of FigureFactory is to completize the tree being builded.
54  //
55  // Inputs:
56  // 1) RenderingStateProvider - data about renderer's state during
57  public class FOPFigureFactory {
58  
59          private static final Map<Class<Area>, Class<FOPFigureBuilder>> builderClasses = new HashMap<Class<Area>, Class<FOPFigureBuilder>>();
60  
61          static {
62                  registerBuilder(Block.class, BlockFigureBuilder.class);
63                  registerBuilder(BlockViewport.class, BlockFigureBuilder.class); /* Viewport */
64                  registerBuilder(FilledArea.class,
65                                  InlineParentFigureBuilder.class);
66                  registerBuilder(Footnote.class, FootnoteFigureBuilder.class);
67                  registerBuilder(NormalFlow.class, FlowFigureBuilder.class);
68                  registerBuilder(InlineParent.class,
69                                  InlineParentFigureBuilder.class);
70                  registerBuilder(Leader.class, InlineFigureBuilder.class);
71                  registerBuilder(LineArea.class, LineAreaBuilder.class);
72                  registerBuilder(MainReference.class, MainReferenceBuilder.class);
73                  registerBuilder(RegionViewport.class, RegionFigureBuilder.class);
74                  registerBuilder(Space.class, InlineFigureBuilder.class);
75                  registerBuilder(Span.class, SpanFigureBuilder.class);
76                  registerBuilder(TextArea.class, TextAreaBuilder.class);
77                  registerBuilder(UnresolvedPageNumber.class,
78                                  TextAreaBuilder.class);
79                  // registerBuilder(PageViewport.class, PageFigureBuilder.class);
80                  // registerBuilder(Character.class, CharacterAreaBuilder.class);
81                  // registerBuilder(Viewport.class, ViewportFigureBuilder.class);
82                  registerBuilder(ForeignObject.class, ForeignObjectBuilder.class);
83          }
84  
85          private Map builders;
86  
87          private Map orphanRegister;
88  
89          /***
90           * Stores sequence of created Figures. This is used when finding last
91           * created figure of some class.
92           */
93          private List<FOPFigure> figureSequence;
94  
95          private final Draw2dRenderer renderer;
96  
97          private Rectangle locData = null;
98  
99          /***
100          * Constructor Creates and inits internal data members and sets state
101          * provider
102          * 
103          * @param stateProvider
104          *                IRenderingStateProvider
105          */
106         public FOPFigureFactory(Draw2dRenderer renderer) {
107                 this.renderer = renderer;
108                 createInternals();
109                 reset();
110         }
111 
112         /***
113          * Adds figure to sequence of created figures
114          * 
115          * @param f
116          *                FOPFigure to add
117          */
118         private void addFigureToSequence(FOPFigure f) {
119                 this.figureSequence.add(f);
120         }
121 
122         /***
123          * Finds in context of <code>input</code> a <code>builder</code> and
124          * that builds the figure
125          * 
126          * @param input
127          *                Object from that the resulting figure is builed
128          * @return FOPFigure
129          */
130         protected FOPFigure build(Object input) {
131                 if (input == null) {
132                         throw new IllegalArgumentException(
133                                         "FOP Figure Factory: input cannot be null.");
134                 }
135                 FOPFigureBuilder builder = getBuilder(input.getClass());
136                 FOPFigure result = null;
137 
138                 if (builder != null) {
139 
140                         if (locData != null)
141                                 result = builder.build(input, locData.x,
142                                                 locData.y, locData.width,
143                                                 locData.height);
144                         else
145                                 result = builder.build(input);
146 
147                         refreshInternals(result, builder);
148 
149                 } else {
150 
151                         return createUnknown(input);
152                 }
153                 return result;
154         }
155 
156         /***
157          * Builds a FOPFigure to the <code>area</code>. Use it when size and
158          * placement of the figure is left on the builder, that counts it from
159          * <code>renderingStateProvider</code>
160          * 
161          * @param area
162          *                Area from FO area tree
163          * @return FOPFigure
164          */
165         public FOPFigure buildFigure(Area area) {
166                 storeLocationData(0, 0, 0, 0);
167                 return build(area);
168         }
169 
170         /***
171          * Builds a FOPFigure to the <code>area</code>. Use it when size and
172          * placement of the figure is depends on <code>rect</code>
173          * 
174          * @param area
175          *                Area from FO area tree
176          * @param rect
177          *                defines bounds of the Figure
178          * @return FOPFigure
179          */
180         public FOPFigure buildFigure(Area area, Rectangle rect) {
181                 storeLocationData(rect.x, rect.y, rect.width, rect.height);
182                 return build(area);
183         }
184 
185         private void createInternals() {
186                 builders = new HashMap();
187                 figureSequence = new ArrayList<FOPFigure>();
188                 orphanRegister = new HashMap();
189         }
190 
191         protected FOPFigure createUnknown(Object input) {
192                 return new UnsupportedFigure(input);
193         }
194 
195         // ----------------------------------------------------------------------------//
196         // Event sources: //
197         // ----------------------------------------------------------------------------//
198 
199         public FOPFigureBuilder getBuilder(Class areaClass) {
200                 if (!builders.containsKey(areaClass)) {
201                         FOPFigureBuilder newBuilder = initBuilder(areaClass);
202                         if (newBuilder != null) {
203                                 builders.put(areaClass, newBuilder);
204                         } else {
205                                 String msg = "Builder for class "
206                                                 + areaClass.getName()
207                                                 + " is not registered.";
208                                 EuroMath.log(IStatus.WARNING, 0, msg, null);
209                         }
210                 }
211                 return (FOPFigureBuilder) builders.get(areaClass);
212         }
213 
214         public FOPFigure getLastFigure(Class clazz) {
215                 for (int i = figureSequence.size() - 1; i >= 0; i--) {
216                         Object obj = figureSequence.get(i);
217                         if (obj.getClass() == clazz) {
218                                 return (FOPFigure) obj;
219                         }
220                 }
221                 return null;
222         }
223 
224         protected void hookChildrenAreas(FOPFigure figure, List children) {
225                 if (children != null) {
226                         for (int i = 0; i < children.size(); i++) {
227                                 orphanRegister.put(children.get(i), figure);
228                         }
229                 }
230         }
231 
232         protected FOPFigureBuilder initBuilder(Class areaClass) {
233                 FOPFigureBuilder b = null;
234                 try {
235                         final Class<FOPFigureBuilder> bClass = builderClasses
236                                         .get(areaClass);
237                         if (bClass == null)
238                                 throw new IllegalArgumentException(
239                                                 "No figure builder for "
240                                                                 + areaClass
241                                                                                 .getName());
242                         b = bClass.newInstance();
243                         // b.setConverter(this);
244                         b.setFactory(this);
245                         b.setRenderingState(this.renderer);
246                 } catch (Exception e) {
247                         throw new RuntimeException(e);
248                 }
249                 return b;
250         }
251 
252         protected void initialize() {
253                 orphanRegister.clear();
254                 figureSequence.clear();
255         }
256 
257         protected void log(Exception exc) {
258                 EuroMath.log(IStatus.WARNING, 0, "log", exc);
259         }
260 
261         private int convertFontHeight(int millipoints) {
262                 float result = (float) millipoints / 1000.0f;
263                 // result = Math.round((float)result*4.0f/3.0f);
264                 return Math.round(result/*-1*/);
265         }
266 
267         protected void refreshInternals(FOPFigure figure,
268                         FOPFigureBuilder builder) {
269                 addFigureToSequence(figure);
270                 hookChildrenAreas(figure, builder.getChildrenAreas());
271                 sendInfoToParent(figure);
272         }
273 
274         public static void registerBuilder(Class areaClass, Class builderClass) {
275                 builderClasses.put(areaClass, builderClass);
276         }
277 
278         /***
279          * All internal data are destroyed.
280          * 
281          */
282         public void reset() {
283                 initialize();
284         }
285 
286         protected void storeLocationData(int x, int y, int w, int h) {
287                 locData = null;
288                 if ((x != 0) || (y != 0) || (w != 0) || (h != 0)) {
289                         locData = new Rectangle(x, y, w, h);
290                 }
291         }
292 
293         protected void sendInfoToParent(FOPFigure newFigure) {
294                 Object area = newFigure.getArea();
295                 // if (area == null){
296                 // area = ((PageFigure)newFigure).getPageViewport();
297                 // }
298 
299                 if (orphanRegister.containsKey(area)) {
300                         FOPFigure parent = (FOPFigure) orphanRegister.get(area);
301                         parent.add(newFigure);
302                         orphanRegister.remove(area);
303                 }
304         }
305 
306         /*
307          * public FOP2ScreenConverter getConverter() { return this; }
308          */
309         protected int convert(int milipoints) {
310                 return FOFigureUtils.mps2pxs(milipoints);
311         }
312 
313         /*
314          * public Rectangle convert(int x, int y, int w, int h) { return new
315          * Rectangle(convert(x), convert(y), convert(w), convert(h)); } public
316          * Rectangle convert(Rectangle r) { return convert(r.x, r.y, r.width,
317          * r.height); }
318          * 
319          * public Point convert(int x, int y) { return new Point(convert(x),
320          * convert(y)); }
321          */
322 
323         public Draw2dRenderer getRenderer() {
324                 return this.renderer;
325         }
326 }