blob: 25b0eb9d197613c8a9eac564d862e4b2d2998a60 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26
27package javax.print.attribute;
28
29import java.io.Serializable;
30
31/**
32 * Class ResolutionSyntax is an abstract base class providing the common
33 * implementation of all attributes denoting a printer resolution.
34 * <P>
35 * A resolution attribute's value consists of two items, the cross feed
36 * direction resolution and the feed direction resolution. A resolution
37 * attribute may be constructed by supplying the two values and indicating the
38 * units in which the values are measured. Methods are provided to return a
39 * resolution attribute's values, indicating the units in which the values are
40 * to be returned. The two most common resolution units are dots per inch (dpi)
41 * and dots per centimeter (dpcm), and exported constants {@link #DPI
42 * <CODE>DPI</CODE>} and {@link #DPCM <CODE>DPCM</CODE>} are provided for
43 * indicating those units.
44 * <P>
45 * Once constructed, a resolution attribute's value is immutable.
46 * <P>
47 * <B>Design</B>
48 * <P>
49 * A resolution attribute's cross feed direction resolution and feed direction
50 * resolution values are stored internally using units of dots per 100 inches
51 * (dphi). Storing the values in dphi rather than, say, metric units allows
52 * precise integer arithmetic conversions between dpi and dphi and between dpcm
53 * and dphi: 1 dpi = 100 dphi, 1 dpcm = 254 dphi. Thus, the values can be stored
54 * into and retrieved back from a resolution attribute in either units with no
55 * loss of precision. This would not be guaranteed if a floating point
56 * representation were used. However, roundoff error will in general occur if a
57 * resolution attribute's values are created in one units and retrieved in
58 * different units; for example, 600 dpi will be rounded to 236 dpcm, whereas
59 * the true value (to five figures) is 236.22 dpcm.
60 * <P>
61 * Storing the values internally in common units of dphi lets two resolution
62 * attributes be compared without regard to the units in which they were
63 * created; for example, 300 dpcm will compare equal to 762 dpi, as they both
64 * are stored as 76200 dphi. In particular, a lookup service can
65 * match resolution attributes based on equality of their serialized
66 * representations regardless of the units in which they were created. Again,
67 * using integers for internal storage allows precise equality comparisons to be
68 * done, which would not be guaranteed if a floating point representation were
69 * used.
70 * <P>
71 * The exported constant {@link #DPI <CODE>DPI</CODE>} is actually the
72 * conversion factor by which to multiply a value in dpi to get the value in
73 * dphi. Likewise, the exported constant {@link #DPCM <CODE>DPCM</CODE>} is the
74 * conversion factor by which to multiply a value in dpcm to get the value in
75 * dphi. A client can specify a resolution value in units other than dpi or dpcm
76 * by supplying its own conversion factor. However, since the internal units of
77 * dphi was chosen with supporting only the external units of dpi and dpcm in
78 * mind, there is no guarantee that the conversion factor for the client's units
79 * will be an exact integer. If the conversion factor isn't an exact integer,
80 * resolution values in the client's units won't be stored precisely.
81 * <P>
82 *
83 * @author David Mendenhall
84 * @author Alan Kaminsky
85 */
86public abstract class ResolutionSyntax implements Serializable, Cloneable {
87
88 private static final long serialVersionUID = 2706743076526672017L;
89
90 /**
91 * Cross feed direction resolution in units of dots per 100 inches (dphi).
92 * @serial
93 */
94 private int crossFeedResolution;
95
96 /**
97 * Feed direction resolution in units of dots per 100 inches (dphi).
98 * @serial
99 */
100 private int feedResolution;
101
102 /**
103 * Value to indicate units of dots per inch (dpi). It is actually the
104 * conversion factor by which to multiply dpi to yield dphi (100).
105 */
106 public static final int DPI = 100;
107
108 /**
109 * Value to indicate units of dots per centimeter (dpcm). It is actually
110 * the conversion factor by which to multiply dpcm to yield dphi (254).
111 */
112 public static final int DPCM = 254;
113
114
115 /**
116 * Construct a new resolution attribute from the given items.
117 *
118 * @param crossFeedResolution
119 * Cross feed direction resolution.
120 * @param feedResolution
121 * Feed direction resolution.
122 * @param units
123 * Unit conversion factor, e.g. {@link #DPI <CODE>DPI</CODE>} or
124 * {@link #DPCM <CODE>DPCM</CODE>}.
125 *
126 * @exception IllegalArgumentException
127 * (unchecked exception) Thrown if <CODE>crossFeedResolution</CODE> <
128 * 1 or <CODE>feedResolution</CODE> < 1 or <CODE>units</CODE> < 1.
129 */
130 public ResolutionSyntax(int crossFeedResolution, int feedResolution,
131 int units) {
132
133 if (crossFeedResolution < 1) {
134 throw new IllegalArgumentException("crossFeedResolution is < 1");
135 }
136 if (feedResolution < 1) {
137 throw new IllegalArgumentException("feedResolution is < 1");
138 }
139 if (units < 1) {
140 throw new IllegalArgumentException("units is < 1");
141 }
142
143 this.crossFeedResolution = crossFeedResolution * units;
144 this.feedResolution = feedResolution * units;
145 }
146
147 /**
148 * Convert a value from dphi to some other units. The result is rounded to
149 * the nearest integer.
150 *
151 * @param dphi
152 * Value (dphi) to convert.
153 * @param units
154 * Unit conversion factor, e.g. {@link #DPI <CODE>DPI</CODE>} or
155 * {@link #DPCM <CODE>DPCM</CODE>}.
156 *
157 * @return The value of <CODE>dphi</CODE> converted to the desired units.
158 *
159 * @exception IllegalArgumentException
160 * (unchecked exception) Thrown if <CODE>units</CODE> < 1.
161 */
162 private static int convertFromDphi(int dphi, int units) {
163 if (units < 1) {
164 throw new IllegalArgumentException(": units is < 1");
165 }
166 int round = units / 2;
167 return (dphi + round) / units;
168 }
169
170 /**
171 * Get this resolution attribute's resolution values in the given units.
172 * The values are rounded to the nearest integer.
173 *
174 * @param units
175 * Unit conversion factor, e.g. {@link #DPI <CODE>DPI</CODE>} or
176 * {@link #DPCM <CODE>DPCM</CODE>}.
177 *
178 * @return A two-element array with the cross feed direction resolution
179 * at index 0 and the feed direction resolution at index 1.
180 *
181 * @exception IllegalArgumentException
182 * (unchecked exception) Thrown if <CODE>units</CODE> < 1.
183 */
184 public int[] getResolution(int units) {
185 return new int[] { getCrossFeedResolution(units),
186 getFeedResolution(units)
187 };
188 }
189
190 /**
191 * Returns this resolution attribute's cross feed direction resolution in
192 * the given units. The value is rounded to the nearest integer.
193 *
194 * @param units
195 * Unit conversion factor, e.g. {@link #DPI <CODE>DPI</CODE>} or
196 * {@link #DPCM <CODE>DPCM</CODE>}.
197 *
198 * @return Cross feed direction resolution.
199 *
200 * @exception IllegalArgumentException
201 * (unchecked exception) Thrown if <CODE>units</CODE> < 1.
202 */
203 public int getCrossFeedResolution(int units) {
204 return convertFromDphi (crossFeedResolution, units);
205 }
206
207 /**
208 * Returns this resolution attribute's feed direction resolution in the
209 * given units. The value is rounded to the nearest integer.
210 *
211 * @param units
212 * Unit conversion factor, e.g. {@link #DPI <CODE>DPI</CODE>} or {@link
213 * #DPCM <CODE>DPCM</CODE>}.
214 *
215 * @return Feed direction resolution.
216 *
217 * @exception IllegalArgumentException
218 * (unchecked exception) Thrown if <CODE>units</CODE> < 1.
219 */
220 public int getFeedResolution(int units) {
221 return convertFromDphi (feedResolution, units);
222 }
223
224 /**
225 * Returns a string version of this resolution attribute in the given units.
226 * The string takes the form <CODE>"<I>C</I>x<I>F</I> <I>U</I>"</CODE>,
227 * where <I>C</I> is the cross feed direction resolution, <I>F</I> is the
228 * feed direction resolution, and <I>U</I> is the units name. The values are
229 * rounded to the nearest integer.
230 *
231 * @param units
232 * Unit conversion factor, e.g. {@link #DPI <CODE>DPI</CODE>} or {@link
233 * #DPCM <CODE>DPCM</CODE>}.
234 * @param unitsName
235 * Units name string, e.g. <CODE>"dpi"</CODE> or <CODE>"dpcm"</CODE>. If
236 * null, no units name is appended to the result.
237 *
238 * @return String version of this resolution attribute.
239 *
240 * @exception IllegalArgumentException
241 * (unchecked exception) Thrown if <CODE>units</CODE> < 1.
242 */
243 public String toString(int units, String unitsName) {
244 StringBuffer result = new StringBuffer();
245 result.append(getCrossFeedResolution (units));
246 result.append('x');
247 result.append(getFeedResolution (units));
248 if (unitsName != null) {
249 result.append (' ');
250 result.append (unitsName);
251 }
252 return result.toString();
253 }
254
255
256 /**
257 * Determine whether this resolution attribute's value is less than or
258 * equal to the given resolution attribute's value. This is true if all
259 * of the following conditions are true:
260 * <UL>
261 * <LI>
262 * This attribute's cross feed direction resolution is less than or equal to
263 * the <CODE>other</CODE> attribute's cross feed direction resolution.
264 * <LI>
265 * This attribute's feed direction resolution is less than or equal to the
266 * <CODE>other</CODE> attribute's feed direction resolution.
267 * </UL>
268 *
269 * @param other Resolution attribute to compare with.
270 *
271 * @return True if this resolution attribute is less than or equal to the
272 * <CODE>other</CODE> resolution attribute, false otherwise.
273 *
274 * @exception NullPointerException
275 * (unchecked exception) Thrown if <CODE>other</CODE> is null.
276 */
277 public boolean lessThanOrEquals(ResolutionSyntax other) {
278 return (this.crossFeedResolution <= other.crossFeedResolution &&
279 this.feedResolution <= other.feedResolution);
280 }
281
282
283 /**
284 * Returns whether this resolution attribute is equivalent to the passed in
285 * object. To be equivalent, all of the following conditions must be true:
286 * <OL TYPE=1>
287 * <LI>
288 * <CODE>object</CODE> is not null.
289 * <LI>
290 * <CODE>object</CODE> is an instance of class ResolutionSyntax.
291 * <LI>
292 * This attribute's cross feed direction resolution is equal to
293 * <CODE>object</CODE>'s cross feed direction resolution.
294 * <LI>
295 * This attribute's feed direction resolution is equal to
296 * <CODE>object</CODE>'s feed direction resolution.
297 * </OL>
298 *
299 * @param object Object to compare to.
300 *
301 * @return True if <CODE>object</CODE> is equivalent to this resolution
302 * attribute, false otherwise.
303 */
304 public boolean equals(Object object) {
305
306 return(object != null &&
307 object instanceof ResolutionSyntax &&
308 this.crossFeedResolution ==
309 ((ResolutionSyntax) object).crossFeedResolution &&
310 this.feedResolution ==
311 ((ResolutionSyntax) object).feedResolution);
312 }
313
314 /**
315 * Returns a hash code value for this resolution attribute.
316 */
317 public int hashCode() {
318 return(((crossFeedResolution & 0x0000FFFF)) |
319 ((feedResolution & 0x0000FFFF) << 16));
320 }
321
322 /**
323 * Returns a string version of this resolution attribute. The string takes
324 * the form <CODE>"<I>C</I>x<I>F</I> dphi"</CODE>, where <I>C</I> is the
325 * cross feed direction resolution and <I>F</I> is the feed direction
326 * resolution. The values are reported in the internal units of dphi.
327 */
328 public String toString() {
329 StringBuffer result = new StringBuffer();
330 result.append(crossFeedResolution);
331 result.append('x');
332 result.append(feedResolution);
333 result.append(" dphi");
334 return result.toString();
335 }
336
337
338 /**
339 * Returns this resolution attribute's cross feed direction resolution in
340 * units of dphi. (For use in a subclass.)
341 *
342 * @return Cross feed direction resolution.
343 */
344 protected int getCrossFeedResolutionDphi() {
345 return crossFeedResolution;
346 }
347
348 /**
349 * Returns this resolution attribute's feed direction resolution in units
350 * of dphi. (For use in a subclass.)
351 *
352 * @return Feed direction resolution.
353 */
354 protected int getFeedResolutionDphi() {
355 return feedResolution;
356 }
357
358}