All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hfg.xml.msofficexml.docx.drawingml.line.DmlLine Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.xml.msofficexml.docx.drawingml.line;


import java.awt.*;
import java.io.Writer;
import java.util.*;
import java.util.List;

import com.hfg.graphics.units.GfxSize;
import com.hfg.graphics.units.GfxUnits;
import com.hfg.util.CompareUtil;
import com.hfg.xml.XMLNamespace;
import com.hfg.xml.XMLNamespaceSet;
import com.hfg.xml.XMLNode;
import com.hfg.xml.XMLTag;
import com.hfg.xml.msofficexml.OfficeOpenXMLTag;
import com.hfg.xml.msofficexml.OfficeOpenXmlDocument;
import com.hfg.xml.msofficexml.docx.drawingml.DmlXML;
import com.hfg.xml.msofficexml.docx.drawingml.fill.DmlFill;
import com.hfg.xml.msofficexml.docx.drawingml.fill.DmlSolidFill;
import com.hfg.xml.msofficexml.docx.drawingml.line.dash.DmlLineDash;
import com.hfg.xml.msofficexml.docx.drawingml.line.dash.DmlPresetLineDash;
import com.hfg.xml.msofficexml.docx.drawingml.line.dash.DmlPresetLineDashType;
import com.hfg.xml.msofficexml.docx.drawingml.line.join.DmlLineJoin;

//------------------------------------------------------------------------------
/**
 Represents a line (<a:ln>) tag in drawing markup language (DML) from Office Open XML.

 @author J. Alex Taylor, hairyfatguy.com
 */
//------------------------------------------------------------------------------
// com.hfg XML/HTML Coding Library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
// [email protected]
//------------------------------------------------------------------------------
/*
Sequence [1..1]

    1. Choice [0..1]
        a:noFill    No Fill
        a:solidFill    Solid Fill
        a:gradFill    Gradient Fill
        a:pattFill
    2. Choice [0..1]
        a:prstDash    Preset Dash
        a:custDash    Custom Dash
    3. Choice [0..1]
        a:round    Round Line Join
        a:bevel    Line Join Bevel
        a:miter    Miter Line Join
    4. a:headEnd [0..1]    Line Head/End Style
    5. a:tailEnd [0..1]    Tail line end style
    6. a:extLst [0..1]
 */

public class DmlLine extends OfficeOpenXMLTag
{
   private XMLTag         mFillTag;
   private XMLTag         mLineJoinTag;
   private DmlLineHeadEnd mLineHeadEnd;
   private DmlLineTailEnd mLineTailEnd;
   private DmlLineDash    mLineDash;

   private static final SubtagComparator SUBTAG_SEQUENCE_COMPARATOR = new DmlLine(null).new SubtagComparator();

   // TODO: Is subtag sequencing still necessary now that we use the xsd?
   private static List> sSubtagSequence = new ArrayList<>(6);

   static
   {
      Set hashSet = new HashSet<>(4);
      hashSet.add(DmlXML.NO_FILL.getLocalName());
      hashSet.add(DmlXML.SOLID_FILL.getLocalName());
      hashSet.add(DmlXML.GRADIENT_FILL.getLocalName());
      hashSet.add(DmlXML.PATTERN_FILL.getLocalName());
      sSubtagSequence.add(hashSet);

      hashSet = new HashSet<>(2);
      hashSet.add(DmlXML.PRESET_DASH.getLocalName());
      hashSet.add(DmlXML.CUSTOM_DASH.getLocalName());
      sSubtagSequence.add(hashSet);

      hashSet = new HashSet<>(3);
      hashSet.add(DmlXML.ROUND.getLocalName());
      hashSet.add(DmlXML.BEVEL.getLocalName());
      hashSet.add(DmlXML.MITER.getLocalName());
      sSubtagSequence.add(hashSet);

      hashSet = new HashSet<>(1);
      hashSet.add(DmlXML.HEAD_END.getLocalName());
      sSubtagSequence.add(hashSet);

      hashSet = new HashSet<>(1);
      hashSet.add(DmlXML.TAIL_END.getLocalName());
      sSubtagSequence.add(hashSet);

      hashSet = new HashSet<>(1);
      hashSet.add(DmlXML.EXT_LIST.getLocalName());
      sSubtagSequence.add(hashSet);
   }

   //###########################################################################
   // CONSTRUCTORS
   //###########################################################################

   //---------------------------------------------------------------------------
   public DmlLine(OfficeOpenXmlDocument inParentDoc)
   {
      super(DmlXML.LINE, inParentDoc);
      init();
   }

   //---------------------------------------------------------------------------
   private void init()
   {
      getHeadEnd();
      getTailEnd();
   }

   //###########################################################################
   // PUBLIC METHODS
   //###########################################################################

   //---------------------------------------------------------------------------
   /**
    * Specifies the fill type that should be used for the shape.
    */
   public DmlLine setWidth(GfxSize inValue)
   {
      setAttribute(DmlXML.WIDTH_ATT, inValue.toInt(GfxUnits.emus));
      return this;
   }

   //---------------------------------------------------------------------------
   /**
    * Specifies the fill type that should be used for the shape.
    */
   public DmlLine setFill(DmlFill inValue)
   {
      if (mFillTag != null)
      {
         removeSubtag(mFillTag);
      }

      mFillTag = inValue;

      addSubtag(mFillTag);

      return this;
   }

   //---------------------------------------------------------------------------
   /**
    * Specifies the color for a solid fill to be used for the shape.
    */
   public DmlLine setFill(Color inColor)
   {
      if (mFillTag != null)
      {
         removeSubtag(mFillTag);
      }

      mFillTag = new DmlSolidFill(inColor);

      addSubtag(mFillTag);

      return this;
   }

   //---------------------------------------------------------------------------
   /**
    * Specifies the line end cap type.
    */
   public DmlLine setCapType(DmlLineEndCapType inValue)
   {
      setAttribute(DmlXML.CAP_ATT, inValue);

      return this;
   }

   //---------------------------------------------------------------------------
   /**
    * Specifies the compound line type.
    */
   public DmlLine setCompoundLineType(DmlCompoundLineType inValue)
   {
      setAttribute(DmlXML.COMPOUND_ATT, inValue);

      return this;
   }

   //---------------------------------------------------------------------------
   /**
    * Specifies the pen alignment type.
    */
   public DmlLine setPenAlignmentType(DmlPenAlignmentType inValue)
   {
      setAttribute(DmlXML.ALIGN_ATT, inValue);

      return this;
   }

   //---------------------------------------------------------------------------
   /**
    * Specifies the dash type.
    */
   public DmlLine setDash(DmlLineDash inValue)
   {
      if (mLineDash != null)
      {
         removeSubtag(mLineDash);
      }

      addSubtag(inValue);

      return this;
   }

   //---------------------------------------------------------------------------
   /**
    * Specifies the dash type.
    */
   public DmlLine setDash(DmlPresetLineDashType inValue)
   {
      return setDash(new DmlPresetLineDash(getParentDoc(), inValue));
   }

   //---------------------------------------------------------------------------
   /**
    * Specifies the line join that should be used for the shape.
    */
   public DmlLine setLineJoin(DmlLineJoin inValue)
   {
      if (mLineJoinTag != null)
      {
         removeSubtag(mLineJoinTag);
      }

      mLineJoinTag = inValue;

      addSubtag(mLineJoinTag);

      return this;
   }

   //---------------------------------------------------------------------------
   /**
    * Returns the headEnd tag if one exists or else instantiates a new one.
    * @return the headEnd tag for this line
    */
   public DmlLineHeadEnd getHeadEnd()
   {
      if (null == mLineHeadEnd)
      {
         // Check if it has been added via addSubtag()...
         mLineHeadEnd = getOptionalSubtagByName(DmlXML.LINE_HEAD_END);
         if (null == mLineHeadEnd)
         {
            mLineHeadEnd = new DmlLineHeadEnd();
            addSubtag(mLineHeadEnd);
         }
      }

      return mLineHeadEnd;
   }

   //---------------------------------------------------------------------------
   /**
    * Returns the tailEnd tag if one exists or else instantiates a new one.
    * @return the tailEnd tag for this line
    */
   public DmlLineTailEnd getTailEnd()
   {
      if (null == mLineTailEnd)
      {
         // Check if it has been added via addSubtag()...
         mLineTailEnd = getOptionalSubtagByName(DmlXML.LINE_TAIL_END);
         if (null == mLineTailEnd)
         {
            mLineTailEnd = new DmlLineTailEnd();
            addSubtag(mLineTailEnd);
         }
      }

      return mLineTailEnd;
   }

   //---------------------------------------------------------------------------
   @Override
   protected void toXML(Writer inWriter, XMLNamespaceSet inDeclaredNamespaces)
   {
      // Before writing to XML, be sure the subtags are in the proper sequence.
      Collections.sort(mContentAndSubtagList, SUBTAG_SEQUENCE_COMPARATOR);


      super.toXML(inWriter, inDeclaredNamespaces);
   }

   private class SubtagComparator implements Comparator
   {
      //------------------------------------------------------------------------
      public int compare(Object inObj1, Object inObj2)
      {
         int result = 0;

         if (inObj1 instanceof XMLNode
             && inObj1 instanceof XMLNode)
         {
            XMLNode node1 = (XMLNode) inObj1;
            XMLNode node2 = (XMLNode) inObj2;

            result = CompareUtil.compare(getSequenceIndex(node1.getTagName()), getSequenceIndex(node2.getTagName()));
         }

         return result;
      }

      //------------------------------------------------------------------------
      public int getSequenceIndex(String inTagName)
      {
         int index = -1;
         for (int i = 0; i < sSubtagSequence.size(); i++)
         {
            if (sSubtagSequence.get(i).contains(inTagName))
            {
               index = i;
               break;
            }
         }

         return index;
      }
   }
}