1 /* 2 * Copyright (c) 1997, 2008, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing.text.rtf; 26 27 import javax.swing.text.StyleConstants; 28 import javax.swing.text.AttributeSet; 29 import javax.swing.text.MutableAttributeSet; 30 import javax.swing.text.TabStop; 31 import java.util.*; 32 import java.io.IOException; 33 34 class RTFAttributes 35 { 36 static RTFAttribute attributes[]; 37 38 static { 39 Vector<RTFAttribute> a = new Vector<RTFAttribute>(); 40 int CHR = RTFAttribute.D_CHARACTER; 41 int PGF = RTFAttribute.D_PARAGRAPH; 42 int SEC = RTFAttribute.D_SECTION; 43 int DOC = RTFAttribute.D_DOCUMENT; 44 int PST = RTFAttribute.D_META; 45 Boolean True = Boolean.valueOf(true); 46 Boolean False = Boolean.valueOf(false); 47 48 a.addElement(new BooleanAttribute(CHR, StyleConstants.Italic, "i")); 49 a.addElement(new BooleanAttribute(CHR, StyleConstants.Bold, "b")); 50 a.addElement(new BooleanAttribute(CHR, StyleConstants.Underline, "ul")); 51 a.addElement(NumericAttribute.NewTwips(PGF, StyleConstants.LeftIndent, "li", 52 0f, 0)); 53 a.addElement(NumericAttribute.NewTwips(PGF, StyleConstants.RightIndent, "ri", 54 0f, 0)); 55 a.addElement(NumericAttribute.NewTwips(PGF, StyleConstants.FirstLineIndent, "fi", 56 0f, 0)); 57 58 a.addElement(new AssertiveAttribute(PGF, StyleConstants.Alignment, 59 "ql", StyleConstants.ALIGN_LEFT)); 60 a.addElement(new AssertiveAttribute(PGF, StyleConstants.Alignment, 61 "qr", StyleConstants.ALIGN_RIGHT)); 62 a.addElement(new AssertiveAttribute(PGF, StyleConstants.Alignment, 63 "qc", StyleConstants.ALIGN_CENTER)); 64 a.addElement(new AssertiveAttribute(PGF, StyleConstants.Alignment, 65 "qj", StyleConstants.ALIGN_JUSTIFIED)); 66 a.addElement(NumericAttribute.NewTwips(PGF, StyleConstants.SpaceAbove, 67 "sa", 0)); 68 a.addElement(NumericAttribute.NewTwips(PGF, StyleConstants.SpaceBelow, 69 "sb", 0)); 70 71 a.addElement(new AssertiveAttribute(PST, RTFReader.TabAlignmentKey, 72 "tqr", TabStop.ALIGN_RIGHT)); 73 a.addElement(new AssertiveAttribute(PST, RTFReader.TabAlignmentKey, 74 "tqc", TabStop.ALIGN_CENTER)); 75 a.addElement(new AssertiveAttribute(PST, RTFReader.TabAlignmentKey, 76 "tqdec", TabStop.ALIGN_DECIMAL)); 77 78 79 a.addElement(new AssertiveAttribute(PST, RTFReader.TabLeaderKey, 80 "tldot", TabStop.LEAD_DOTS)); 81 a.addElement(new AssertiveAttribute(PST, RTFReader.TabLeaderKey, 82 "tlhyph", TabStop.LEAD_HYPHENS)); 83 a.addElement(new AssertiveAttribute(PST, RTFReader.TabLeaderKey, 84 "tlul", TabStop.LEAD_UNDERLINE)); 85 a.addElement(new AssertiveAttribute(PST, RTFReader.TabLeaderKey, 86 "tlth", TabStop.LEAD_THICKLINE)); 87 a.addElement(new AssertiveAttribute(PST, RTFReader.TabLeaderKey, 88 "tleq", TabStop.LEAD_EQUALS)); 89 90 /* The following aren't actually recognized by Swing */ 91 a.addElement(new BooleanAttribute(CHR, Constants.Caps, "caps")); 92 a.addElement(new BooleanAttribute(CHR, Constants.Outline, "outl")); 93 a.addElement(new BooleanAttribute(CHR, Constants.SmallCaps, "scaps")); 94 a.addElement(new BooleanAttribute(CHR, Constants.Shadow, "shad")); 95 a.addElement(new BooleanAttribute(CHR, Constants.Hidden, "v")); 96 a.addElement(new BooleanAttribute(CHR, Constants.Strikethrough, 97 "strike")); 98 a.addElement(new BooleanAttribute(CHR, Constants.Deleted, 99 "deleted")); 100 101 102 103 a.addElement(new AssertiveAttribute(DOC, "saveformat", "defformat", "RTF")); 104 a.addElement(new AssertiveAttribute(DOC, "landscape", "landscape")); 105 106 a.addElement(NumericAttribute.NewTwips(DOC, Constants.PaperWidth, 107 "paperw", 12240)); 108 a.addElement(NumericAttribute.NewTwips(DOC, Constants.PaperHeight, 109 "paperh", 15840)); 110 a.addElement(NumericAttribute.NewTwips(DOC, Constants.MarginLeft, 111 "margl", 1800)); 112 a.addElement(NumericAttribute.NewTwips(DOC, Constants.MarginRight, 113 "margr", 1800)); 114 a.addElement(NumericAttribute.NewTwips(DOC, Constants.MarginTop, 115 "margt", 1440)); 116 a.addElement(NumericAttribute.NewTwips(DOC, Constants.MarginBottom, 117 "margb", 1440)); 118 a.addElement(NumericAttribute.NewTwips(DOC, Constants.GutterWidth, 119 "gutter", 0)); 120 121 a.addElement(new AssertiveAttribute(PGF, Constants.WidowControl, 122 "nowidctlpar", False)); 123 a.addElement(new AssertiveAttribute(PGF, Constants.WidowControl, 124 "widctlpar", True)); 125 a.addElement(new AssertiveAttribute(DOC, Constants.WidowControl, 126 "widowctrl", True)); 127 128 129 RTFAttribute[] attrs = new RTFAttribute[a.size()]; 130 a.copyInto(attrs); 131 attributes = attrs; 132 } 133 134 static Dictionary<String, RTFAttribute> attributesByKeyword() 135 { 136 Dictionary<String, RTFAttribute> d = new Hashtable<String, RTFAttribute>(attributes.length); 137 138 for (RTFAttribute attribute : attributes) { 139 d.put(attribute.rtfName(), attribute); 140 } 141 142 return d; 143 } 144 145 /************************************************************************/ 146 /************************************************************************/ 147 148 abstract static class GenericAttribute 149 { 150 int domain; 151 Object swingName; 152 String rtfName; 153 154 protected GenericAttribute(int d,Object s, String r) 155 { 156 domain = d; 157 swingName = s; 158 rtfName = r; 159 } 160 161 public int domain() { return domain; } 162 public Object swingName() { return swingName; } 163 public String rtfName() { return rtfName; } 164 165 abstract boolean set(MutableAttributeSet target); 166 abstract boolean set(MutableAttributeSet target, int parameter); 167 abstract boolean setDefault(MutableAttributeSet target); 168 169 public boolean write(AttributeSet source, 170 RTFGenerator target, 171 boolean force) 172 throws IOException 173 { 174 return writeValue(source.getAttribute(swingName), target, force); 175 } 176 177 public boolean writeValue(Object value, RTFGenerator target, 178 boolean force) 179 throws IOException 180 { 181 return false; 182 } 183 } 184 185 static class BooleanAttribute 186 extends GenericAttribute 187 implements RTFAttribute 188 { 189 boolean rtfDefault; 190 boolean swingDefault; 191 192 protected static final Boolean True = Boolean.valueOf(true); 193 protected static final Boolean False = Boolean.valueOf(false); 194 195 public BooleanAttribute(int d, Object s, 196 String r, boolean ds, boolean dr) 197 { 198 super(d, s, r); 199 swingDefault = ds; 200 rtfDefault = dr; 201 } 202 203 public BooleanAttribute(int d, Object s, String r) 204 { 205 super(d, s, r); 206 207 swingDefault = false; 208 rtfDefault = false; 209 } 210 211 public boolean set(MutableAttributeSet target) 212 { 213 /* TODO: There's some ambiguity about whether this should 214 *set* or *toggle* the attribute. */ 215 target.addAttribute(swingName, True); 216 217 return true; /* true indicates we were successful */ 218 } 219 220 public boolean set(MutableAttributeSet target, int parameter) 221 { 222 /* See above note in the case that parameter==1 */ 223 Boolean value = ( parameter != 0 ? True : False ); 224 225 target.addAttribute(swingName, value); 226 227 return true; /* true indicates we were successful */ 228 } 229 230 public boolean setDefault(MutableAttributeSet target) 231 { 232 if (swingDefault != rtfDefault || 233 ( target.getAttribute(swingName) != null ) ) 234 target.addAttribute(swingName, Boolean.valueOf(rtfDefault)); 235 return true; 236 } 237 238 public boolean writeValue(Object o_value, 239 RTFGenerator target, 240 boolean force) 241 throws IOException 242 { 243 Boolean val; 244 245 if (o_value == null) 246 val = Boolean.valueOf(swingDefault); 247 else 248 val = (Boolean)o_value; 249 250 if (force || (val.booleanValue() != rtfDefault)) { 251 if (val.booleanValue()) { 252 target.writeControlWord(rtfName); 253 } else { 254 target.writeControlWord(rtfName, 0); 255 } 256 } 257 return true; 258 } 259 } 260 261 262 static class AssertiveAttribute 263 extends GenericAttribute 264 implements RTFAttribute 265 { 266 Object swingValue; 267 268 public AssertiveAttribute(int d, Object s, String r) 269 { 270 super(d, s, r); 271 swingValue = Boolean.valueOf(true); 272 } 273 274 public AssertiveAttribute(int d, Object s, String r, Object v) 275 { 276 super(d, s, r); 277 swingValue = v; 278 } 279 280 public AssertiveAttribute(int d, Object s, String r, int v) 281 { 282 super(d, s, r); 283 swingValue = Integer.valueOf(v); 284 } 285 286 public boolean set(MutableAttributeSet target) 287 { 288 if (swingValue == null) 289 target.removeAttribute(swingName); 290 else 291 target.addAttribute(swingName, swingValue); 292 293 return true; 294 } 295 296 public boolean set(MutableAttributeSet target, int parameter) 297 { 298 return false; 299 } 300 301 public boolean setDefault(MutableAttributeSet target) 302 { 303 target.removeAttribute(swingName); 304 return true; 305 } 306 307 public boolean writeValue(Object value, 308 RTFGenerator target, 309 boolean force) 310 throws IOException 311 { 312 if (value == null) { 313 return ! force; 314 } 315 316 if (value.equals(swingValue)) { 317 target.writeControlWord(rtfName); 318 return true; 319 } 320 321 return ! force; 322 } 323 } 324 325 326 static class NumericAttribute 327 extends GenericAttribute 328 implements RTFAttribute 329 { 330 int rtfDefault; 331 Number swingDefault; 332 float scale; 333 334 protected NumericAttribute(int d, Object s, String r) 335 { 336 super(d, s, r); 337 rtfDefault = 0; 338 swingDefault = null; 339 scale = 1f; 340 } 341 342 public NumericAttribute(int d, Object s, 343 String r, int ds, int dr) 344 { 345 this(d, s, r, Integer.valueOf(ds), dr, 1f); 346 } 347 348 public NumericAttribute(int d, Object s, 349 String r, Number ds, int dr, float sc) 350 { 351 super(d, s, r); 352 swingDefault = ds; 353 rtfDefault = dr; 354 scale = sc; 355 } 356 357 public static NumericAttribute NewTwips(int d, Object s, String r, 358 float ds, int dr) 359 { 360 return new NumericAttribute(d, s, r, Float.valueOf(ds), dr, 20f); 361 } 362 363 public static NumericAttribute NewTwips(int d, Object s, String r, 364 int dr) 365 { 366 return new NumericAttribute(d, s, r, null, dr, 20f); 367 } 368 369 public boolean set(MutableAttributeSet target) 370 { 371 return false; 372 } 373 374 public boolean set(MutableAttributeSet target, int parameter) 375 { 376 Number swingValue; 377 378 if (scale == 1f) 379 swingValue = Integer.valueOf(parameter); 380 else 381 swingValue = Float.valueOf(parameter / scale); 382 target.addAttribute(swingName, swingValue); 383 return true; 384 } 385 386 public boolean setDefault(MutableAttributeSet target) 387 { 388 Number old = (Number)target.getAttribute(swingName); 389 if (old == null) 390 old = swingDefault; 391 if (old != null && ( 392 (scale == 1f && old.intValue() == rtfDefault) || 393 (Math.round(old.floatValue() * scale) == rtfDefault) 394 )) 395 return true; 396 set(target, rtfDefault); 397 return true; 398 } 399 400 public boolean writeValue(Object o_value, 401 RTFGenerator target, 402 boolean force) 403 throws IOException 404 { 405 Number value = (Number)o_value; 406 if (value == null) 407 value = swingDefault; 408 if (value == null) { 409 /* TODO: What is the proper behavior if the Swing object does 410 not specify a value, and we don't know its default value? 411 Currently we pretend that the RTF default value is 412 equivalent (probably a workable assumption) */ 413 return true; 414 } 415 int int_value = Math.round(value.floatValue() * scale); 416 if (force || (int_value != rtfDefault)) 417 target.writeControlWord(rtfName, int_value); 418 return true; 419 } 420 } 421 }