-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathFontModel.java
More file actions
502 lines (465 loc) · 15.2 KB
/
FontModel.java
File metadata and controls
502 lines (465 loc) · 15.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
package darrylbu.model;
import darrylbu.component.VisualFontDesigner;
import darrylbu.util.TextAttributeConstants;
import java.awt.Color;
import java.awt.Font;
import java.awt.Paint;
import java.awt.font.TextAttribute;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import static java.awt.font.TextAttribute.*;
import java.util.HashMap;
import java.util.Map;
import javax.swing.event.SwingPropertyChangeSupport;
/**
* A class that encapsulates a Font and provides convenient methods to query or change
* various attributes.
* <P>
* The default model for {@link VisualFontDesigner}.
*
* @author Darryl
*/
public class FontModel {
public static final String FONT_PROPERTY = "font";
private Font font;
private Map<TextAttribute, Object> attributes = new HashMap<TextAttribute, Object>();
private SwingPropertyChangeSupport propertyChangeSupport = new SwingPropertyChangeSupport(this);
/**
* Constructs a new <code>FontModel</code> with the specified font.
*
* @param font the font
*/
public FontModel(Font font) {
setFont(font);
}
/**
* Constructs a new <code>FontModel</code> with a font derived from the specified attriburte map.
* This is equivalent to
* <PRE>
Font font = Font.getFont(attributes).deriveFont(attributes);
new FontModel(font);
* </PRE>
*
* @param attributes a Map of <code>TextAttribute</code> keys and their values.
*
* @see Font#getFont(java.util.Map)
* @see Font#deriveFont(java.util.Map)
*/
public FontModel(Map<TextAttribute, Object> attributes) {
setAttributes(attributes);
}
/**
* Returns the font currently held by this model.
*
* @return the font
*/
public Font getFont() {
return font;
}
/**
* Sets the font of this model to the specified font.
*
* @param newFont the new font to be set
*/
@SuppressWarnings(value = "unchecked")
public void setFont(Font newFont) {
if (!newFont.equals(font)) {
Font oldFont = font;
font = newFont;
attributes = (Map<TextAttribute, Object>) font.getAttributes();
firePropertyChange(FONT_PROPERTY, oldFont, newFont);
}
}
/**
* Sets the font held by this model to a font derived from the specified map. This is
* equivalent to
* <PRE>
Font font = Font.getFont(attributes).deriveFont(attributes);
setFont(font);
* </PRE>
*
* @param attributes a Map of <code>TextAttribute</code> keys and their values.
* @see Font#getFont(java.util.Map)
* @see Font#deriveFont(java.util.Map)
*/
@SuppressWarnings(value = "unchecked")
protected void setAttributes(Map<TextAttribute, Object> attributes) {
Font newFont = Font.getFont(attributes).deriveFont(attributes);
setFont(newFont);
}
/**
* Generates and returns code that will programatically recreate this model's Font. Meant for
* use by code generrators.
*
* @return the code needed to programatically recreate the designed Font.
*/
public String getCode() {
final StringBuilder sb = new StringBuilder("Map<TextAttribute, Object>"
+ " attributes\n = new HashMap<TextAttribute, Object>();\n\n");
for (TextAttribute key : TextAttributeConstants.keys()) {
Object value = attributes.get(key);
if (value != null) {
String keyName = String.valueOf(key);
keyName = keyName.replaceAll("^[^(]*\\(([^)]*)\\).*$", "$1").
toUpperCase();
sb.append("attributes.put(TextAttribute." + keyName + ", ");
if (value instanceof String) {
sb.append("\"");
}
String valueName = TextAttributeConstants.lookup(key, value);
if (valueName == null) {
if (value instanceof Color) {
Color color = (Color) value;
sb.append("new Color(" + color.getRed() + ", "
+ color.getGreen() + ", "
+ color.getBlue() + ")");
} else {
sb.append(String.valueOf(value));
}
} else {
sb.append("TextAttribute." + valueName);
}
if (value instanceof String) {
sb.append("\"");
}
sb.append(");\n");
}
}
sb.append("\nFont font = Font.getFont(attributes);\n");
sb.append("font = font.deriveFont(attributes);\n");
return sb.toString();
}
/**
* Returns the value associated with a <code>TextAttribute</code> key for this model's font.
* Returns null if the attribute is not supported by this class, or if no value is presently
* associated with the attribute.
*
* @param attribute the attribute
* @return the value
*/
public Object getAttributeValue(TextAttribute attribute) {
return attributes.get(attribute);
}
/**
* Sets the value to be associated with a <code>TextAttribute</code> key and updates the font.
* The effect of setting a value that is not legal for the attribute is undefined.
*
* @param attribute the attribute
* @param value the value
*/
@SuppressWarnings(value = "unchecked")
public void setAttributeValue(TextAttribute attribute, Object value) {
Font oldFont = font;
attributes.put(attribute, value);
font = font.deriveFont(attributes);
// remove default values form mapping
attributes = (Map<TextAttribute, Object>) font.getAttributes();
firePropertyChange(FONT_PROPERTY, oldFont, font);
}
/**
* Returns the family name of this model's font.
*
* @return the familt name
* @see #setFamily(java.lang.String)
* @see Font#getFamily()
*/
public String getFamily() {
return (String) attributes.get(FAMILY);
}
/**
* Sets the family of this model's font.
*
* @param family the family name
* @see #getFamily()
*/
public void setFamily(String family) {
setAttributeValue(FAMILY, family);
}
/**
* Returns the size of this model's font in float precision
*
* @return the size
* @see #setSize(float)
* @see Font#getSize()
*/
public float getSize() {
Float size = (Float) attributes.get(SIZE);
return size != null ? size : font.getSize();
}
/**
* Sets the size of this model's font
*
* @param size the size
* @see #getSize()
* @see Font#deriveFont(float)
*/
public void setSize(float size) {
setAttributeValue(SIZE, size);
}
/**
* Returns true if this model's font is bold, false otherwise
*
* @return true if the font is bold, false otherwise
* @see #setBold(boolean)
* @see Font#isBold()
*/
public boolean isBold() {
return getAttributeValue(WEIGHT) == WEIGHT_BOLD || font.isBold();
}
/**
* Sets this model's font bold if the parameter is <code>true</code> or not bold otherwise.
*
* @param bold true to set a bold font, false otherwise.
* @see #isBold()
* @see Font#deriveFont(int)
*/
public void setBold(boolean bold) {
setAttributeValue(WEIGHT, bold ? WEIGHT_BOLD : WEIGHT_REGULAR);
}
/**
* Returns true if this model's font is italic, false otherwise
*
* @return true if the font is italic, false otherwise
* @see #setItalic(boolean)
* @see Font#isItalic()
*/
public boolean isItalic() {
return getAttributeValue(POSTURE) == POSTURE_OBLIQUE || font.isItalic();
}
/**
* Sets this model's font italic if the parameter is <code>true</code> or not italic otherwise.
*
* @param italic true to set an italic font, false otherwise.
* @see #isItalic()
* @see Font#deriveFont(int)
*/
public void setItalic(boolean italic) {
setAttributeValue(POSTURE, italic ? POSTURE_OBLIQUE : POSTURE_REGULAR);
}
/**
* Returns true if this model's font is underlined, false otherwise
* <P>
* Note that this method returns true if any kind of underline is applied.
*
* @return true if the font is underlined, false otherwise
* @see #setUnderline(boolean)
* @see #getUnderline()
* @see #setUnderline(int)
*/
public boolean isUnderline() {
Integer underline = (Integer) getAttributeValue(UNDERLINE);
return underline != null && underline != -1;
}
/**
* Sets this model's font to a single underline if the parameter is <code>true</code> or
* not underlined otherwise.
*
* @param underline true to set a single underline, false otherwise.
* @see #isUnderline()
* @see #getUnderline()
* @see #setUnderline(int)
*/
public void setUnderline(boolean underline) {
setAttributeValue(UNDERLINE, underline ? UNDERLINE_ON : -1);
}
/**
* Returns an int corresponding to the type of underline of this model's font. The value will
* be one of those listed as valid values for {@link #setUnderline(int)}, or -1 for no underline.
* <P>
* The descriptuve name for the value can be obtained from
* TextAttributeConstants#getFriendlyName(TextAttribute.UNDERLINE, value) where value is the
* int value returned by this method.
*
* @return the value of the underline attribute.
* @see #isUnderline()
* @see #setUnderline(boolean)
* @see #setUnderline(int)
*/
public int getUnderline() {
Integer underline = (Integer) getAttributeValue(UNDERLINE);
if (underline == null) {
return -1;
} else {
return underline;
}
}
/**
* Sets the type of underline for this model's font. Must be one of
* <ul>
* <li>TextAttribute.UNDERLINE_ON</li>
* <li>TextAttribute.UNDERLINE_LOW_DASHED</li>
* <li>TextAttribute.UNDERLINE_LOW_DOTTED</li>
* <li>TextAttribute.UNDERLINE_LOW_GRAY</li>
* <li>TextAttribute.UNDERLINE_LOW_ONE_PIXEL</li>
* <li>TextAttribute.UNDERLINE_LOW_TWO_PIXEL</li>
* <li>-1 (no underline)</li>
* </ul>
*
* @param underline a legal value for <code>TextAttribure.UNDERLINE</code>.
* @see #isUnderline()
* @see #setUnderline(boolean)
* @see #getUnderline()
*/
public void setUnderline(int underline) {
setAttributeValue(UNDERLINE, underline);
}
/**
* Returns true if this model's font is strikethrough, false otherwise
*
* @return true if the font is strikethrough, false otherwise
* @see #setStrikethrough(boolean)
*/
public boolean isStrikethrough() {
return getAttributeValue(STRIKETHROUGH) == STRIKETHROUGH_ON;
}
/**
* Sets this model's font strikethrough if the parameter is <code>true</code> or
* not strikethrough otherwise.
*
* @param strikethrough true to set the font as strikethrough, false otherwise.
* @see #isStrikethrough()
*/
public void setStrikethrough(boolean strikethrough) {
setAttributeValue(STRIKETHROUGH, strikethrough);
}
/**
* Returns true if this model's font attempts kerning, false otherwise
* <P>
* Note that not all fonts support kerning.
*
* @return true if the font attempts kerning, false otherwise
* @see #setKerning(boolean)
*/
public boolean isKerning() {
return getAttributeValue(KERNING) == KERNING_ON;
}
/**
* Sets this model's font to attempt kerning if the parameter is <code>true</code> or not
* attempt kerning otherwise.
* <P>
* Note that not all fonts support kerning.
*
* @param kerning true to set the font to attempt kerning, false otherwise.
* @see #isKerning()
*/
public void setKerning(boolean kerning) {
setAttributeValue(KERNING, kerning ? KERNING_ON : 0);
}
/**
* Returns the foreground of this model's font.
*
* @return the foreground value
* @see #setForeground(java.awt.Paint)
*/
public Paint getForeground() {
return (Paint) getAttributeValue(FOREGROUND);
}
/**
* Sets the foreground of this model's font. This will most commonly be an instance of Color,
* but some interesting effects can be obtained by setting a gradient or texture paint.
*
* @param paint the foreground to set
* @see #getForeground()
*/
public void setForeground(Paint paint) {
setAttributeValue(FOREGROUND, paint);
}
/**
* Returns the background of this model's font.
*
* @return the background value
* @see #setBackground(java.awt.Paint)
*/
public Paint getBackground() {
return (Paint) getAttributeValue(BACKGROUND);
}
/**
* Sets the background of this model's font. This will most commonly be an instance of Color,
* but some interesting effects can be obtained by setting a gradient or texture paint.
*
* @param paint the background to set
* @see #getBackground()
*/
public void setBackground(Paint paint) {
setAttributeValue(BACKGROUND, paint);
}
/**
* Returns true if this model's font swaps the foreground and background, false otherwise.
*
* @return true if the foreground and background are swapped, false otherwise
* @see #setSwapColors(boolean)
*/
public boolean isSwapColors() {
return getAttributeValue(SWAP_COLORS) == SWAP_COLORS_ON;
}
/**
* Sets whether this model's font's foreground and background should be swapped.
*
* @param swapColors true to swap the foreground and background, false otherwise.
* @see #isSwapColors()
*/
public void setSwapColors(boolean swapColors) {
setAttributeValue(SWAP_COLORS, swapColors);
}
/**
* Adds a PropertyChangeListener to the listener list. The listener
* is registered for all bound properties of this class, including
* the following:
* <ul>
* <li>this FontModel's font ("font")</li>
* </ul>
* <p>
* If <code>listener</code> is <code>null</code>,
* no exception is thrown and no action is performed.
*
* @param listener the property change listener to be added
*
* @see #removePropertyChangeListener
* @see #getPropertyChangeListeners
*/
public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
/**
* Removes a PropertyChangeListener from the listener list. This method
* should be used to remove PropertyChangeListeners that were registered for
* all bound properties of this class.
* <P>
* If listener is null, no exception is thrown and no action is performed.
*
* @param listener the PropertyChangeListener to be removed
*
* @see #addPropertyChangeListener
* @see #getPropertyChangeListeners
*/
public synchronized void removePropertyChangeListener(
PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
/**
* Returns an array of all the property change listeners registered on this model.
*
* @return all of this model's <code>PropertyChangeListener</code>s or an empty array if
* no property change listeners are currently registered
*
* @see #addPropertyChangeListener
* @see #removePropertyChangeListener
*/
public PropertyChangeListener[] getPropertyChangeListeners() {
return propertyChangeSupport.getPropertyChangeListeners();
}
/**
* Support for reporting bound property changes for Object properties. This
* method can be called when a bound property has changed and it will send
* the appropriate <code>PropertyChangeEvent</code> to any registered
* PropertyChangeListeners.
*
* @param propertyName the property whose value has changed
* @param oldValue the property's previous value
* @param newValue the property's new value
*/
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
propertyChangeSupport.firePropertyChange(new PropertyChangeEvent(this, propertyName,
oldValue, newValue));
}
}