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