001package com.hfg.xml.msofficexml.xlsx.spreadsheetml.style;
002
003import java.awt.Font;
004
005import com.hfg.util.CompareUtil;
006import com.hfg.util.StringUtil;
007import com.hfg.xml.XMLAttribute;
008import com.hfg.xml.XMLTag;
009import com.hfg.xml.msofficexml.xlsx.Xlsx;
010import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXML;
011import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXMLTag;
012
013
014//------------------------------------------------------------------------------
015/**
016 Represents an Office Open XML spreadsheetml (<ssml:xf>) tag.
017 <div>
018 @author J. Alex Taylor, hairyfatguy.com
019 </div>
020 */
021//------------------------------------------------------------------------------
022// com.hfg XML/HTML Coding Library
023//
024// This library is free software; you can redistribute it and/or
025// modify it under the terms of the GNU Lesser General Public
026// License as published by the Free Software Foundation; either
027// version 2.1 of the License, or (at your option) any later version.
028//
029// This library is distributed in the hope that it will be useful,
030// but WITHOUT ANY WARRANTY; without even the implied warranty of
031// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
032// Lesser General Public License for more details.
033//
034// You should have received a copy of the GNU Lesser General Public
035// License along with this library; if not, write to the Free Software
036// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
037//
038// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
039// jataylor@hairyfatguy.com
040//------------------------------------------------------------------------------
041
042public class SsmlCellFormat extends SsmlXMLTag implements Comparable
043{
044   private Integer         mIndex;
045   private SsmlAlignment   mAlignmentTag;
046
047   //##########################################################################
048   // CONSTRUCTORS
049   //##########################################################################
050
051   //---------------------------------------------------------------------------
052   public SsmlCellFormat(Xlsx inXlsx)
053   {
054      this(inXlsx.getStylesPart());
055   }
056
057   //---------------------------------------------------------------------------
058   public SsmlCellFormat(StylesPart inStylesPart)
059   {
060      super(SsmlXML.CELL_FORMAT, inStylesPart.getParentDoc());
061      // Register with the styles part
062      mIndex = inStylesPart.defineCellFormat(this);
063
064      setDefaults(inStylesPart);
065   }
066
067   //---------------------------------------------------------------------------
068   public SsmlCellFormat(Xlsx inXlsx, XMLTag inXMLTag)
069   {
070      super(SsmlXML.CELL_FORMAT, inXlsx);
071
072      for (XMLAttribute attr : inXMLTag.getAttributes())
073      {
074         setAttribute(attr);
075      }
076   }
077
078   //---------------------------------------------------------------------------
079   private void setDefaults(StylesPart inStylesPart)
080   {
081      setStyleFormat(inStylesPart.getStyleFormat(0));
082   }
083
084   //##########################################################################
085   // PUBLIC METHODS
086   //##########################################################################
087
088   //---------------------------------------------------------------------------
089   @Override
090   public SsmlCellFormat clone()
091   {
092      SsmlCellFormat clone = new SsmlCellFormat(getParentDoc());
093
094      if (hasAttribute(SsmlXML.FONT_ID_ATT))
095      {
096         clone.setAttribute(SsmlXML.FONT_ID_ATT, getAttributeValue(SsmlXML.FONT_ID_ATT));
097      }
098
099      if (hasAttribute(SsmlXML.FILL_ID_ATT))
100      {
101         clone.setAttribute(SsmlXML.FONT_ID_ATT, getAttributeValue(SsmlXML.FILL_ID_ATT));
102      }
103
104      if (hasAttribute(SsmlXML.BORDER_ID_ATT))
105      {
106         clone.setAttribute(SsmlXML.BORDER_ID_ATT, getAttributeValue(SsmlXML.BORDER_ID_ATT));
107      }
108
109      if (hasAttribute(SsmlXML.NUM_FORMAT_ID_ATT))
110      {
111         clone.setAttribute(SsmlXML.NUM_FORMAT_ID_ATT, getAttributeValue(SsmlXML.NUM_FORMAT_ID_ATT));
112      }
113
114      if (mAlignmentTag != null)
115      {
116         clone.mAlignmentTag = mAlignmentTag.clone();
117      }
118
119
120      // Register with the styles part
121      clone.mIndex = getParentDoc().getStylesPart().defineCellFormat(clone);
122
123      return clone;
124   }
125
126   //--------------------------------------------------------------------------
127   @Override
128   public boolean equals(Object inObj2)
129   {
130      return (0 == compareTo(inObj2));
131   }
132
133   //--------------------------------------------------------------------------
134   @Override
135   public int compareTo(Object inObj2)
136   {
137      int result = -1;
138
139      if (inObj2 instanceof SsmlCellFormat)
140      {
141         SsmlCellFormat cellFormat2 = (SsmlCellFormat) inObj2;
142
143         result = CompareUtil.compare(getFontId(), cellFormat2.getFontId());
144
145         if (0 == result)
146         {
147            result = CompareUtil.compare(getFillId(), cellFormat2.getFillId());
148
149            if (0 == result)
150            {
151               result = CompareUtil.compare(getBorderId(), cellFormat2.getBorderId());
152
153               if (0 == result)
154               {
155                  result = CompareUtil.compare(getNumberFormatId(), cellFormat2.getNumberFormatId());
156
157                  if (0 == result)
158                  {
159                     if (hasAlignment())
160                     {
161                        if (cellFormat2.hasAlignment())
162                        {
163                           result = CompareUtil.compare(getAlignment(), cellFormat2.getAlignment());
164                        }
165                        else
166                        {
167                           result = 1;
168                        }
169                     }
170                     else if (cellFormat2.hasAlignment())
171                     {
172                        result = -1;
173                     }
174                  }
175               }
176            }
177         }
178      }
179
180      return result;
181   }
182
183   //---------------------------------------------------------------------------
184   public Integer getIndex()
185   {
186      return mIndex;
187   }
188
189   //---------------------------------------------------------------------------
190   public SsmlCellFormat setFont(Font inValue)
191   {
192      return setFont(inValue != null ? new SsmlFont(inValue, getParentDoc()) : null);
193   }
194
195   //---------------------------------------------------------------------------
196   public SsmlCellFormat setFont(SsmlFont inValue)
197   {
198      if (inValue != null)
199      {
200         setAttribute(SsmlXML.FONT_ID_ATT, inValue.getIndex());
201      }
202      else
203      {
204         removeAttribute(SsmlXML.FONT_ID_ATT);
205      }
206
207      return this;
208   }
209
210   //---------------------------------------------------------------------------
211   // TODO: Should we be returning a new SsmlFont when one hasn't been set yet?
212   public SsmlFont getFont()
213   {
214      SsmlFont font;
215
216      if (hasAttribute(SsmlXML.FONT_ID_ATT))
217      {
218         int fontId = Integer.parseInt(getAttributeValue(SsmlXML.FONT_ID_ATT));
219         font = getParentDoc().getStylesPart().getFonts().get(fontId);
220      }
221      else
222      {
223         font = new SsmlFont(getParentDoc());
224         setFont(font);
225      }
226
227      return font;
228   }
229
230   //---------------------------------------------------------------------------
231   public int getFontId()
232   {
233      String value = getAttributeValue(SsmlXML.FONT_ID_ATT);
234      return (StringUtil.isSet(value) ? Integer.parseInt(value) : 0);
235   }
236
237   //---------------------------------------------------------------------------
238   public SsmlCellFormat setFill(SsmlFill inValue)
239   {
240      if (inValue != null)
241      {
242         setAttribute(SsmlXML.FILL_ID_ATT, inValue.getIndex());
243      }
244      else
245      {
246         removeAttribute(SsmlXML.FILL_ID_ATT);
247      }
248
249      return this;
250   }
251
252   //---------------------------------------------------------------------------
253   // TODO: Should we be returning a new SsmlFill when one hasn't been set yet?
254   public SsmlFill getFill()
255   {
256      SsmlFill fill;
257
258      if (hasAttribute(SsmlXML.FILL_ID_ATT))
259      {
260         int fillId = Integer.parseInt(getAttributeValue(SsmlXML.FILL_ID_ATT));
261         fill = getParentDoc().getStylesPart().getFills().get(fillId);
262      }
263      else
264      {
265         fill = new SsmlFill(getParentDoc());
266         setFill(fill);
267      }
268
269      return fill;
270   }
271
272   //---------------------------------------------------------------------------
273   public int getFillId()
274   {
275      String value = getAttributeValue(SsmlXML.FILL_ID_ATT);
276      return (StringUtil.isSet(value) ? Integer.parseInt(value) : 0);
277   }
278
279   //---------------------------------------------------------------------------
280   public SsmlCellFormat setBorder(SsmlBorder inValue)
281   {
282      if (inValue != null)
283      {
284         setAttribute(SsmlXML.BORDER_ID_ATT, inValue.getIndex());
285      }
286      else
287      {
288         removeAttribute(SsmlXML.BORDER_ID_ATT);
289      }
290
291      return this;
292   }
293
294   //---------------------------------------------------------------------------
295   // TODO: Should we be returning a new SsmlBorder when one hasn't been set yet?
296   public SsmlBorder getBorder()
297   {
298      SsmlBorder border;
299
300      if (hasAttribute(SsmlXML.BORDER_ID_ATT))
301      {
302         int borderId = Integer.parseInt(getAttributeValue(SsmlXML.BORDER_ID_ATT));
303         border = getParentDoc().getStylesPart().getBorders().get(borderId);
304      }
305      else
306      {
307         border = new SsmlBorder(getParentDoc());
308         setBorder(border);
309      }
310
311      return border;
312   }
313
314   //---------------------------------------------------------------------------
315   public int getBorderId()
316   {
317      String value = getAttributeValue(SsmlXML.BORDER_ID_ATT);
318      return (StringUtil.isSet(value) ? Integer.parseInt(value) : 0);
319   }
320
321   //---------------------------------------------------------------------------
322   public SsmlCellFormat setNumberFormat(SsmlNumberFormat inValue)
323   {
324      if (inValue != null)
325      {
326         if (null == inValue.getParentDoc())
327         {
328            // This may be true if it was a standard format
329            inValue.setParentDoc(getParentDoc());
330         }
331
332         setAttribute(SsmlXML.NUM_FORMAT_ID_ATT, inValue.getIndex());
333      }
334      else
335      {
336         removeAttribute(SsmlXML.NUM_FORMAT_ID_ATT);
337      }
338
339      return this;
340   }
341
342   //---------------------------------------------------------------------------
343   public SsmlNumberFormat getNumberFormat()
344   {
345      SsmlNumberFormat numberFormat = null;
346
347      if (hasAttribute(SsmlXML.NUM_FORMAT_ID_ATT))
348      {
349         int numFormatId = Integer.parseInt(getAttributeValue(SsmlXML.NUM_FORMAT_ID_ATT));
350         if (numFormatId >= 164) // Custom num format?
351         {
352            for (SsmlNumberFormat customNumFormat : getParentDoc().getStylesPart().getNumberFormats())
353            {
354               if (customNumFormat.getIndex().equals(numFormatId))
355               {
356                  numberFormat = customNumFormat;
357                  break;
358               }
359            }
360         }
361         else
362         {
363            for (SsmlNumberFormat defaultFormat : SsmlNumberFormat.getDefaultValues())
364            {
365               if (defaultFormat.getIndex().equals(numFormatId))
366               {
367                  numberFormat = defaultFormat;
368                  break;
369               }
370            }
371         }
372      }
373
374      return numberFormat;
375   }
376
377   //---------------------------------------------------------------------------
378   public int getNumberFormatId()
379   {
380      String value = getAttributeValue(SsmlXML.NUM_FORMAT_ID_ATT);
381      return (StringUtil.isSet(value) ? Integer.parseInt(value) : 0);
382   }
383
384   //---------------------------------------------------------------------------
385   public boolean hasAlignment()
386   {
387      return (mAlignmentTag != null
388              || getOptionalSubtagByName(SsmlXML.ALIGNMENT) != null);
389   }
390
391   //---------------------------------------------------------------------------
392   public SsmlAlignment getAlignment()
393   {
394      if (null == mAlignmentTag)
395      {
396         // Check if it has been added via addSubtag()...
397         mAlignmentTag = getOptionalSubtagByName(SsmlXML.ALIGNMENT);
398
399         if (null == mAlignmentTag)
400         {
401            setAlignment(new SsmlAlignment(getParentDoc()));
402         }
403      }
404
405      return mAlignmentTag;
406   }
407
408   //---------------------------------------------------------------------------
409   public SsmlCellFormat setAlignment(SsmlAlignment inValue)
410   {
411      removeSubtagsByName(SsmlXML.ALIGNMENT);
412
413      mAlignmentTag = inValue;
414      if (mAlignmentTag != null)
415      {
416         addSubtag(mAlignmentTag);
417      }
418
419      return this;
420   }
421
422   //---------------------------------------------------------------------------
423   public SsmlCellFormat setStyle(SsmlCellStyle inValue)
424   {
425      return setStyleFormat(inValue != null ? inValue.getStyleFormat() : null);
426   }
427
428   //---------------------------------------------------------------------------
429   public SsmlCellFormat setStyleFormat(SsmlStyleFormat inValue)
430   {
431      if (inValue != null)
432      {
433         setAttribute(SsmlXML.STYLE_FORMAT_ID_ATT, inValue.getIndex());
434
435         // TODO: The ECMA-376 documentation indicates that the cell style format should
436         //       be inherited but that does not appear to be true. For now it seems that
437         //       we have to copy format properties from the style.
438         // See old post about cellStyleXfs being ignored:  http://openxmldeveloper.org/discussions/formats/f/14/p/717/1755.aspx#1755
439         if (inValue.getAlignment() != null)
440         {
441            setAlignment(inValue.getAlignment());
442         }
443
444         if (inValue.getBorder() != null)
445         {
446            setBorder(inValue.getBorder());
447         }
448
449         if (inValue.getFill() != null)
450         {
451            setFill(inValue.getFill());
452         }
453
454         if (inValue.getFont() != null)
455         {
456            setFont(inValue.getFont());
457         }
458
459         if (inValue.getNumberFormat() != null)
460         {
461            setNumberFormat(inValue.getNumberFormat());
462         }
463
464      }
465      else
466      {
467         removeAttribute(SsmlXML.STYLE_FORMAT_ID_ATT);
468      }
469
470      return this;
471   }
472
473   //---------------------------------------------------------------------------
474   /**
475    Only for use by the StylesPart when setting a new value for the default font.
476    * @param inValue the new index value
477    * @return this object to enable chaining
478    */
479   protected SsmlCellFormat setIndex(Integer inValue)
480   {
481      mIndex = inValue;
482      return this;
483   }
484
485}