001package com.hfg.xml.msofficexml.xlsx.spreadsheetml.style;
002
003import java.awt.Color;
004import java.awt.Font;
005
006import com.hfg.exception.UnmodifyableObjectException;
007import com.hfg.graphics.ColorUtil;
008import com.hfg.html.attribute.HTMLColor;
009import com.hfg.util.CompareUtil;
010import com.hfg.util.StringBuilderPlus;
011import com.hfg.xml.XMLTag;
012import com.hfg.xml.msofficexml.xlsx.ExcelIndexedColor;
013import com.hfg.xml.msofficexml.xlsx.Xlsx;
014import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXML;
015import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXMLTag;
016
017//------------------------------------------------------------------------------
018/**
019 Represents an Office Open XML spreadsheetml (<ssml:font>) tag.
020 <div>
021 @author J. Alex Taylor, hairyfatguy.com
022 </div>
023 */
024//------------------------------------------------------------------------------
025// com.hfg XML/HTML Coding Library
026//
027// This library is free software; you can redistribute it and/or
028// modify it under the terms of the GNU Lesser General Public
029// License as published by the Free Software Foundation; either
030// version 2.1 of the License, or (at your option) any later version.
031//
032// This library is distributed in the hope that it will be useful,
033// but WITHOUT ANY WARRANTY; without even the implied warranty of
034// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
035// Lesser General Public License for more details.
036//
037// You should have received a copy of the GNU Lesser General Public
038// License along with this library; if not, write to the Free Software
039// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
040//
041// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
042// jataylor@hairyfatguy.com
043//------------------------------------------------------------------------------
044
045public class SsmlFont extends SsmlXMLTag implements Comparable
046{
047   private Integer mIndex;
048   private XMLTag  mSizeTag;
049   private XMLTag  mNameTag;
050   private XMLTag  mColorTag;
051   private XMLTag  mBoldTag;
052   private XMLTag  mItalicTag;
053   private XMLTag  mShadowTag;
054   private XMLTag  mStrikeThroughTag;
055   private XMLTag  mTextVertAlignTag;
056   private XMLTag  mUnderlineTag;
057   // TODO: Family tag
058
059   protected boolean mLocked;
060
061   //##########################################################################
062   // CONSTRUCTORS
063   //##########################################################################
064
065   //---------------------------------------------------------------------------
066   public SsmlFont(SsmlXMLTag inSsmlXMLTag)
067   {
068      this(inSsmlXMLTag.getParentDoc());
069   }
070
071   //---------------------------------------------------------------------------
072   public SsmlFont(Xlsx inXlsx)
073   {
074      this(inXlsx.getStylesPart());
075   }
076
077   //---------------------------------------------------------------------------
078   public SsmlFont(Font inFont, Xlsx inXlsx)
079   {
080      this(inXlsx);
081      setName(inFont.getName());
082      setSize(inFont.getSize());
083      if (inFont.isBold())
084      {
085         setBold(true);
086      }
087
088      if (inFont.isItalic())
089      {
090         setItalic(true);
091      }
092   }
093
094   //---------------------------------------------------------------------------
095   public SsmlFont(StylesPart inStylesPart)
096   {
097      super(SsmlXML.FONT, inStylesPart.getParentDoc());
098      // Register with the styles part
099      mIndex = inStylesPart.defineFont(this);
100   }
101
102   //---------------------------------------------------------------------------
103   public SsmlFont(Xlsx inXlsx, XMLTag inXMLTag)
104   {
105      super(SsmlXML.FONT, inXlsx);
106
107      XMLTag sizeTag = inXMLTag.getOptionalSubtagByName(SsmlXML.SIZE);
108      if (sizeTag != null)
109      {
110         mSizeTag = sizeTag;
111      }
112
113      XMLTag nameTag = inXMLTag.getOptionalSubtagByName(SsmlXML.NAME);
114      if (nameTag != null)
115      {
116         mNameTag = nameTag;
117      }
118
119      XMLTag colorTag = inXMLTag.getOptionalSubtagByName(SsmlXML.COLOR);
120      if (colorTag != null)
121      {
122         mColorTag = colorTag;
123      }
124
125      XMLTag boldTag = inXMLTag.getOptionalSubtagByName(SsmlXML.BOLD);
126      if (boldTag != null)
127      {
128         mBoldTag = boldTag;
129      }
130
131      XMLTag italicTag = inXMLTag.getOptionalSubtagByName(SsmlXML.ITALIC);
132      if (italicTag != null)
133      {
134         mItalicTag = italicTag;
135      }
136
137      XMLTag shadowTag = inXMLTag.getOptionalSubtagByName(SsmlXML.SHADOW);
138      if (shadowTag != null)
139      {
140         mShadowTag = shadowTag;
141      }
142
143      XMLTag strikeTag = inXMLTag.getOptionalSubtagByName(SsmlXML.STRIKE);
144      if (strikeTag != null)
145      {
146         mStrikeThroughTag = strikeTag;
147      }
148
149      XMLTag textVertTag = inXMLTag.getOptionalSubtagByName(SsmlXML.VERTICAL_ALIGN);
150      if (textVertTag != null)
151      {
152         mTextVertAlignTag = textVertTag;
153      }
154
155      XMLTag underlineTag = inXMLTag.getOptionalSubtagByName(SsmlXML.UNDERLINE);
156      if (underlineTag != null)
157      {
158         mUnderlineTag = underlineTag;
159      }
160
161   }
162
163
164   //##########################################################################
165   // PUBLIC METHODS
166   //##########################################################################
167
168   //---------------------------------------------------------------------------
169   public String toString()
170   {
171      StringBuilderPlus buffer = new StringBuilderPlus(getName()).setDelimiter("-");
172      if (isBold())
173      {
174         buffer.delimitedAppend("BOLD");
175         if (isItalic())
176         {
177            buffer.append("ITALIC");
178         }
179      }
180      else if (isItalic())
181      {
182         buffer.delimitedAppend("ITALIC");
183      }
184      else
185      {
186         buffer.delimitedAppend("PLAIN");
187      }
188
189      buffer.delimitedAppend(getSize());
190
191      return buffer.toString();
192   }
193
194   //--------------------------------------------------------------------------
195   @Override
196   public boolean equals(Object inObj2)
197   {
198      return (0 == compareTo(inObj2));
199   }
200
201   //--------------------------------------------------------------------------
202   @Override
203   public int compareTo(Object inObj2)
204   {
205      int result = -1;
206
207      if (inObj2 instanceof SsmlFont)
208      {
209         SsmlFont font2 = (SsmlFont) inObj2;
210
211         result = CompareUtil.compare(getName(), font2.getName());
212
213         if (0 == result)
214         {
215            result = CompareUtil.compare(getSize(), font2.getSize());
216
217            if (0 == result)
218            {
219               result = CompareUtil.compare(getColor(), font2.getColor());
220
221               if (0 == result)
222               {
223                  result = CompareUtil.compare(isBold(), font2.isBold());
224
225                  if (0 == result)
226                  {
227                     result = CompareUtil.compare(isItalic(), font2.isItalic());
228
229                     if (0 == result)
230                     {
231                        result = CompareUtil.compare(hasShadow(), font2.hasShadow());
232
233                        if (0 == result)
234                        {
235                           result = CompareUtil.compare(hasStrikeThrough(), font2.hasStrikeThrough());
236
237                           if (0 == result)
238                           {
239                              result = CompareUtil.compare(getTextVerticalAlignment(), font2.getTextVerticalAlignment());
240
241                              if (0 == result)
242                              {
243                                 result = CompareUtil.compare(getUnderline(), font2.getUnderline());
244                              }
245                           }
246                        }
247                     }
248                  }
249               }
250            }
251         }
252      }
253
254      return result;
255   }
256
257   //--------------------------------------------------------------------------
258   public boolean isLocked()
259   {
260      return mLocked;
261   }
262
263   //--------------------------------------------------------------------------
264   public SsmlFont lock()
265   {
266      mLocked = true;
267      return this;
268   }
269
270   //---------------------------------------------------------------------------
271   @Override
272   public SsmlFont clone()
273   {
274      SsmlFont clone = (SsmlFont) super.clone();
275
276      // The clone should be unlocked (modifiable)
277      clone.mLocked = false;
278      
279      // These cached values will be repopulated if needed
280      clone.clearSubtags();
281      clone.mNameTag = null;
282      clone.mSizeTag = null;
283      clone.mColorTag = null;
284      clone.mBoldTag = null;
285      clone.mItalicTag = null;
286      clone.mShadowTag = null;
287      clone.mUnderlineTag = null;
288      clone.mTextVertAlignTag = null;
289
290      if (getName() != null)
291      {
292         clone.setName(getName());
293      }
294
295      if (mSizeTag != null)
296      {
297         clone.setSize(getSize());
298      }
299
300      if (getColor() != null)
301      {
302         clone.setColor(getColor());
303      }
304
305      if (isBold())
306      {
307         clone.setBold(true);
308      }
309
310      if (isItalic())
311      {
312         clone.setItalic(true);
313      }
314
315      if (hasShadow())
316      {
317         clone.setShadow(true);
318      }
319
320      if (hasStrikeThrough())
321      {
322         clone.setStrikeThrough(true);
323      }
324
325      if (getUnderline() != null)
326      {
327         clone.setUnderline(getUnderline());
328      }
329
330      if (getTextVerticalAlignment() != null)
331      {
332         clone.setTextVerticalAlignment(getTextVerticalAlignment());
333      }
334
335      // Register with the styles part
336      clone.mIndex = getParentDoc().getStylesPart().defineFont(clone);
337
338      return clone;
339   }
340
341   //---------------------------------------------------------------------------
342   public Font toFont()
343   {
344      int style = (mBoldTag != null ? Font.BOLD : 0) + (mItalicTag != null ? Font.ITALIC : 0);
345
346      return new Font(getName(), style, getSize());
347   }
348
349   //---------------------------------------------------------------------------
350   /**
351    Only for use by the StylesPart when setting a new value for the default font.
352    * @param inValue the new index value
353    * @return this object to enable chaining
354    */
355   protected SsmlFont setIndex(Integer inValue)
356   {
357      mIndex = inValue;
358      return this;
359   }
360
361   //---------------------------------------------------------------------------
362   public Integer getIndex()
363   {
364      return mIndex;
365   }
366
367   //---------------------------------------------------------------------------
368   public SsmlFont setSize(int inValue)
369   {
370      checkLock();
371
372      if (null == mSizeTag)
373      {
374         // Check it it has been added via addSubtag()...
375         mSizeTag = getOptionalSubtagByName(SsmlXML.SIZE);
376         if (null == mSizeTag)
377         {
378            mSizeTag = new XMLTag(SsmlXML.SIZE);
379            addSubtag(mSizeTag);
380         }
381      }
382
383      mSizeTag.setAttribute(SsmlXML.VALUE_ATT, inValue);
384
385      return this;
386   }
387
388   //---------------------------------------------------------------------------
389   public int getSize()
390   {
391      return (mSizeTag != null ? Integer.parseInt(mSizeTag.getAttributeValue(SsmlXML.VALUE_ATT)) : 0);
392   }
393
394   //---------------------------------------------------------------------------
395   public boolean isBold()
396   {
397      return mBoldTag != null;
398   }
399
400   //---------------------------------------------------------------------------
401   public SsmlFont setBold(boolean inValue)
402   {
403      checkLock();
404
405      if (null == mBoldTag)
406      {
407         // Check if it has been added via addSubtag()...
408         mBoldTag = getOptionalSubtagByName(SsmlXML.BOLD);
409      }
410
411      if (inValue)
412      {
413         if (null == mBoldTag)
414         {
415            mBoldTag = new XMLTag(SsmlXML.BOLD);
416            addSubtag(mBoldTag);
417         }
418      }
419      else if (mBoldTag != null)
420      {
421         removeSubtag(mBoldTag);
422         mBoldTag = null;
423      }
424
425      return this;
426   }
427
428   //---------------------------------------------------------------------------
429   public boolean isItalic()
430   {
431      return mItalicTag != null;
432   }
433
434   //---------------------------------------------------------------------------
435   public SsmlFont setItalic(boolean inValue)
436   {
437      checkLock();
438
439      if (null == mItalicTag)
440      {
441         // Check it it has been added via addSubtag()...
442         mItalicTag = getOptionalSubtagByName(SsmlXML.ITALIC);
443      }
444
445      if (inValue)
446      {
447         if (null == mItalicTag)
448         {
449            mItalicTag = new XMLTag(SsmlXML.ITALIC);
450            addSubtag(mItalicTag);
451         }
452      }
453      else if (mItalicTag != null)
454      {
455         removeSubtag(mItalicTag);
456         mItalicTag = null;
457      }
458
459      return this;
460   }
461
462
463   //---------------------------------------------------------------------------
464   public boolean hasStrikeThrough()
465   {
466      if (null == mStrikeThroughTag)
467      {
468         // Check if it has been added via addSubtag()...
469         mStrikeThroughTag = getOptionalSubtagByName(SsmlXML.STRIKE);
470      }
471
472      return (mStrikeThroughTag != null);
473   }
474
475   //---------------------------------------------------------------------------
476   public SsmlFont setStrikeThrough(boolean inValue)
477   {
478      checkLock();
479
480      if (null == mStrikeThroughTag)
481      {
482         // Check it it has been added via addSubtag()...
483         mStrikeThroughTag = getOptionalSubtagByName(SsmlXML.STRIKE);
484      }
485
486      if (inValue)
487      {
488         if (null == mStrikeThroughTag)
489         {
490            mStrikeThroughTag = new XMLTag(SsmlXML.STRIKE);
491            addSubtag(mStrikeThroughTag);
492         }
493      }
494      else if (mStrikeThroughTag != null)
495      {
496         removeSubtag(mStrikeThroughTag);
497         mStrikeThroughTag = null;
498      }
499
500      return this;
501   }
502
503
504   //---------------------------------------------------------------------------
505   public boolean hasShadow()
506   {
507      if (null == mShadowTag)
508      {
509         // Check if it has been added via addSubtag()...
510         mShadowTag = getOptionalSubtagByName(SsmlXML.SHADOW);
511      }
512
513      return (mShadowTag != null);
514   }
515
516   //---------------------------------------------------------------------------
517   public SsmlFont setShadow(boolean inValue)
518   {
519      checkLock();
520
521      if (null == mShadowTag)
522      {
523         // Check if it has been added via addSubtag()...
524         mShadowTag = getOptionalSubtagByName(SsmlXML.SHADOW);
525      }
526
527      if (inValue)
528      {
529         if (null == mShadowTag)
530         {
531            mShadowTag = new XMLTag(SsmlXML.SHADOW);
532            addSubtag(mShadowTag);
533         }
534      }
535      else if (mShadowTag != null)
536      {
537         removeSubtag(mShadowTag);
538         mShadowTag = null;
539      }
540
541      return this;
542   }
543
544
545   //---------------------------------------------------------------------------
546   public SsmlUnderlineType getUnderline()
547   {
548      if (null == mUnderlineTag)
549      {
550         // Check if it has been added via addSubtag()...
551         mUnderlineTag = getOptionalSubtagByName(SsmlXML.UNDERLINE);
552      }
553
554      return (mUnderlineTag != null ? SsmlUnderlineType.valueOf(mUnderlineTag.getAttributeValue(SsmlXML.VALUE_ATT)) : null);
555   }
556
557   //---------------------------------------------------------------------------
558   public SsmlFont setUnderline(SsmlUnderlineType inValue)
559   {
560      checkLock();
561
562      if (null == mUnderlineTag)
563      {
564         // Check if it has been added via addSubtag()...
565         mUnderlineTag = getOptionalSubtagByName(SsmlXML.UNDERLINE);
566      }
567
568      if (inValue != null)
569      {
570         if (null == mUnderlineTag)
571         {
572            mUnderlineTag = new XMLTag(SsmlXML.UNDERLINE);
573            addSubtag(mUnderlineTag);
574         }
575
576         mUnderlineTag.setAttribute(SsmlXML.VALUE_ATT, inValue.name());
577      }
578      else if (mUnderlineTag != null)
579      {
580         removeSubtag(mUnderlineTag);
581         mUnderlineTag = null;
582      }
583
584      return this;
585   }
586
587   //---------------------------------------------------------------------------
588   public SsmlFont setTextVerticalAlignment(SsmlTextVerticalAlignRunType inValue)
589   {
590      checkLock();
591
592      if (null == mTextVertAlignTag)
593      {
594         // Check it it has been added via addSubtag()...
595         mTextVertAlignTag = getOptionalSubtagByName(SsmlXML.VERTICAL_ALIGN);
596      }
597
598      if (inValue != null)
599      {
600         if (null == mTextVertAlignTag)
601         {
602            mTextVertAlignTag = new XMLTag(SsmlXML.VERTICAL_ALIGN);
603            addSubtag(mTextVertAlignTag);
604         }
605
606         mTextVertAlignTag.setAttribute(SsmlXML.VALUE_ATT, inValue.name());
607      }
608      else if (mTextVertAlignTag != null)
609      {
610         removeSubtag(mTextVertAlignTag);
611         mTextVertAlignTag = null;
612      }
613
614      return this;
615   }
616
617   //---------------------------------------------------------------------------
618   public SsmlTextVerticalAlignRunType getTextVerticalAlignment()
619   {
620      SsmlTextVerticalAlignRunType value = null;
621
622      if (null == mTextVertAlignTag)
623      {
624         // Check if it has been added via addSubtag()...
625         mTextVertAlignTag = getOptionalSubtagByName(SsmlXML.VERTICAL_ALIGN);
626      }
627
628      if (mTextVertAlignTag != null)
629      {
630         value = SsmlTextVerticalAlignRunType.valueOf(mTextVertAlignTag.getAttributeValue(SsmlXML.VALUE_ATT));
631      }
632
633      return value;
634   }
635
636   //---------------------------------------------------------------------------
637   public SsmlFont setColor(Color inValue)
638   {
639      checkLock();
640
641      if (null == mColorTag)
642      {
643         // Check if it has been added via addSubtag()...
644         mColorTag = getOptionalSubtagByName(SsmlXML.COLOR);
645      }
646
647      if (inValue != null)
648      {
649         if (null == mColorTag)
650         {
651            mColorTag = new XMLTag(SsmlXML.COLOR);
652            addSubtag(mColorTag);
653         }
654
655         if (inValue instanceof ExcelIndexedColor)
656         {
657            mColorTag.setAttribute(SsmlXML.INDEXED_ATT, ((ExcelIndexedColor)inValue).getIndex());
658         }
659         else
660         {
661            mColorTag.setAttribute(SsmlXML.RGB_ATT, ColorUtil.colorToHex(inValue));
662         }
663      }
664      else if (mColorTag != null)
665      {
666         removeSubtag(mColorTag);
667         mColorTag = null;
668      }
669
670      return this;
671   }
672
673   //---------------------------------------------------------------------------
674   public Color getColor()
675   {
676      Color value = null;
677
678      if (null == mColorTag)
679      {
680         // Check if it has been added via addSubtag()...
681         mColorTag = getOptionalSubtagByName(SsmlXML.COLOR);
682      }
683
684      if (mColorTag != null)
685      {
686         if (mColorTag.hasAttribute(SsmlXML.RGB_ATT))
687         {
688            value = HTMLColor.valueOf("#" + mColorTag.getAttributeValue(SsmlXML.RGB_ATT));
689         }
690         else if (mColorTag.hasAttribute(SsmlXML.INDEXED_ATT))
691         {
692            value = ExcelIndexedColor.valueOf(Integer.parseInt(mColorTag.getAttributeValue(SsmlXML.INDEXED_ATT)));
693         }
694      }
695
696      return value;
697   }
698
699
700   //---------------------------------------------------------------------------
701   public SsmlFont setName(String inValue)
702   {
703      checkLock();
704
705      if (null == mNameTag)
706      {
707         // Check if it has been added via addSubtag()...
708         mNameTag = getOptionalSubtagByName(SsmlXML.NAME);
709         if (null == mNameTag)
710         {
711            mNameTag = new XMLTag(SsmlXML.NAME);
712            addSubtag(mNameTag);
713         }
714      }
715
716      mNameTag.setAttribute(SsmlXML.VALUE_ATT, inValue);
717
718      return this;
719   }
720
721   //---------------------------------------------------------------------------
722   public String getName()
723   {
724      return (mNameTag != null ? mNameTag.getAttributeValue(SsmlXML.VALUE_ATT) : null);
725   }
726
727   //##########################################################################
728   // PRIVATE METHODS
729   //##########################################################################
730
731   //---------------------------------------------------------------------------
732   private void checkLock()
733   {
734      if (isLocked())
735      {
736         throw new UnmodifyableObjectException("This " + getClass().getSimpleName() + " object is locked and cannot be modified!");
737      }
738   }
739}