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 }