JAL-2388 Unit tests for columns, take 1
[jalview.git] / src / org / jibble / epsgraphics / EpsDocument.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package org.jibble.epsgraphics;
22
23 import jalview.util.MessageManager;
24
25 import java.io.BufferedWriter;
26 import java.io.IOException;
27 import java.io.OutputStream;
28 import java.io.OutputStreamWriter;
29 import java.io.StringWriter;
30 import java.io.Writer;
31 import java.util.Date;
32
33 /**
34  * This represents an EPS document. Several EpsGraphics2D objects may point to
35  * the same EpsDocument.
36  * <p>
37  * Copyright Paul Mutton, <a
38  * href="http://www.jibble.org/">http://www.jibble.org/</a>
39  * 
40  */
41 public class EpsDocument
42 {
43
44   /**
45    * Constructs an empty EpsDevice.
46    */
47   public EpsDocument(String title)
48   {
49     _title = title;
50     minX = Float.POSITIVE_INFINITY;
51     minY = Float.POSITIVE_INFINITY;
52     maxX = Float.NEGATIVE_INFINITY;
53     maxY = Float.NEGATIVE_INFINITY;
54     _stringWriter = new StringWriter();
55     _bufferedWriter = new BufferedWriter(_stringWriter);
56   }
57
58   /**
59    * Constructs an empty EpsDevice that writes directly to a file. Bounds must
60    * be set before use.
61    */
62   public EpsDocument(String title, OutputStream outputStream, int minX,
63           int minY, int maxX, int maxY) throws IOException
64   {
65     _title = title;
66     this.minX = minX;
67     this.minY = minY;
68     this.maxX = maxX;
69     this.maxY = maxY;
70     _bufferedWriter = new BufferedWriter(new OutputStreamWriter(
71             outputStream));
72     write(_bufferedWriter);
73   }
74
75   /**
76    * Returns the title of the EPS document.
77    */
78   public synchronized String getTitle()
79   {
80     return _title;
81   }
82
83   /**
84    * Updates the bounds of the current EPS document.
85    */
86   public synchronized void updateBounds(double x, double y)
87   {
88     if (x > maxX)
89     {
90       maxX = (float) x;
91     }
92     if (x < minX)
93     {
94       minX = (float) x;
95     }
96     if (y > maxY)
97     {
98       maxY = (float) y;
99     }
100     if (y < minY)
101     {
102       minY = (float) y;
103     }
104   }
105
106   /**
107    * Appends a line to the EpsDocument. A new line character is added to the end
108    * of the line when it is added.
109    */
110   public synchronized void append(EpsGraphics2D g, String line)
111   {
112     if (_lastG == null)
113     {
114       _lastG = g;
115     }
116     else if (g != _lastG)
117     {
118       EpsGraphics2D lastG = _lastG;
119       _lastG = g;
120       // We are being drawn on with a different EpsGraphics2D context.
121       // We may need to update the clip, etc from this new context.
122       if (g.getClip() != lastG.getClip())
123       {
124         g.setClip(g.getClip());
125       }
126       if (!g.getColor().equals(lastG.getColor()))
127       {
128         g.setColor(g.getColor());
129       }
130       if (!g.getBackground().equals(lastG.getBackground()))
131       {
132         g.setBackground(g.getBackground());
133       }
134       // We don't need this, as this only affects the stroke and font,
135       // which are dealt with separately later on.
136       // if (!g.getTransform().equals(lastG.getTransform())) {
137       // g.setTransform(g.getTransform());
138       // }
139       if (!g.getPaint().equals(lastG.getPaint()))
140       {
141         g.setPaint(g.getPaint());
142       }
143       if (!g.getComposite().equals(lastG.getComposite()))
144       {
145         g.setComposite(g.getComposite());
146       }
147       if (!g.getComposite().equals(lastG.getComposite()))
148       {
149         g.setComposite(g.getComposite());
150       }
151       if (!g.getFont().equals(lastG.getFont()))
152       {
153         g.setFont(g.getFont());
154       }
155       if (!g.getStroke().equals(lastG.getStroke()))
156       {
157         g.setStroke(g.getStroke());
158       }
159     }
160     _lastG = g;
161
162     try
163     {
164       _bufferedWriter.write(line + "\n");
165     } catch (IOException e)
166     {
167       throw new EpsException(MessageManager.formatMessage(
168               "exception.eps_coudnt_write_output_file",
169               new String[] { e.getMessage() }));
170     }
171   }
172
173   /**
174    * Outputs the contents of the EPS document to the specified Writer, complete
175    * with headers and bounding box.
176    */
177   public synchronized void write(Writer writer) throws IOException
178   {
179     float offsetX = -minX;
180     float offsetY = -minY;
181
182     writer.write("%!PS-Adobe-3.0 EPSF-3.0\n");
183     writer.write("%%Creator: Jalview "
184             + jalview.bin.Cache.getProperty("VERSION") + " \n");
185     writer.write("%%Title: " + _title + "\n");
186     writer.write("%%CreationDate: " + new Date() + "\n");
187     writer.write("%%BoundingBox: 0 0 " + ((int) Math.ceil(maxX + offsetX))
188             + " " + ((int) Math.ceil(maxY + offsetY)) + "\n");
189     writer.write("%%DocumentData: Clean7Bit\n");
190     writer.write("%%DocumentProcessColors: Black\n");
191     writer.write("%%ColorUsage: Color\n");
192     writer.write("%%Origin: 0 0\n");
193     writer.write("%%Pages: 1\n");
194     writer.write("%%Page: 1 1\n");
195     writer.write("%%EndComments\n\n");
196
197     writer.write("gsave\n");
198
199     if (_stringWriter != null)
200     {
201       writer.write(offsetX + " " + (offsetY) + " translate\n");
202
203       _bufferedWriter.flush();
204       StringBuffer buffer = _stringWriter.getBuffer();
205       for (int i = 0; i < buffer.length(); i++)
206       {
207         writer.write(buffer.charAt(i));
208       }
209
210       writeFooter(writer);
211     }
212     else
213     {
214       writer.write(offsetX + " " + ((maxY - minY) - offsetY)
215               + " translate\n");
216     }
217
218     writer.flush();
219   }
220
221   private void writeFooter(Writer writer) throws IOException
222   {
223     writer.write("grestore\n");
224     if (isClipSet())
225     {
226       writer.write("grestore\n");
227     }
228     writer.write("showpage\n");
229     writer.write("\n");
230     writer.write("%%EOF");
231     writer.flush();
232   }
233
234   public synchronized void flush() throws IOException
235   {
236     _bufferedWriter.flush();
237   }
238
239   public synchronized void close() throws IOException
240   {
241     if (_stringWriter == null)
242     {
243       writeFooter(_bufferedWriter);
244       _bufferedWriter.flush();
245       _bufferedWriter.close();
246     }
247   }
248
249   public boolean isClipSet()
250   {
251     return _isClipSet;
252   }
253
254   public void setClipSet(boolean isClipSet)
255   {
256     _isClipSet = isClipSet;
257   }
258
259   private float minX;
260
261   private float minY;
262
263   private float maxX;
264
265   private float maxY;
266
267   private boolean _isClipSet = false;
268
269   private String _title;
270
271   private StringWriter _stringWriter;
272
273   private BufferedWriter _bufferedWriter = null;
274
275   // We need to remember which was the last EpsGraphics2D object to use
276   // us, as we need to replace the clipping region if another EpsGraphics2D
277   // object tries to use us.
278   private EpsGraphics2D _lastG = null;
279
280 }