001package com.hfg.xml.msofficexml; 002 003import java.awt.Color; 004import java.io.Writer; 005import java.util.Comparator; 006import java.util.List; 007import java.util.Map; 008import java.util.Set; 009import java.util.UUID; 010import java.util.logging.Level; 011import java.util.logging.Logger; 012 013import com.hfg.util.collection.CollectionUtil; 014import com.hfg.util.CompareUtil; 015import com.hfg.util.StringUtil; 016import com.hfg.xml.XMLName; 017import com.hfg.xml.XMLNamespaceSet; 018import com.hfg.xml.XMLNode; 019import com.hfg.xml.XMLTag; 020import com.hfg.xml.XMLizable; 021import com.hfg.xml.xsd.XsdElement; 022 023//------------------------------------------------------------------------------ 024/** 025 Base tag class for Office Open XML tags. 026 027 @author J. Alex Taylor, hairyfatguy.com 028 */ 029//------------------------------------------------------------------------------ 030// com.hfg XML/HTML Coding Library 031// 032// This library is free software; you can redistribute it and/or 033// modify it under the terms of the GNU Lesser General Public 034// License as published by the Free Software Foundation; either 035// version 2.1 of the License, or (at your option) any later version. 036// 037// This library is distributed in the hope that it will be useful, 038// but WITHOUT ANY WARRANTY; without even the implied warranty of 039// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 040// Lesser General Public License for more details. 041// 042// You should have received a copy of the GNU Lesser General Public 043// License along with this library; if not, write to the Free Software 044// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 045// 046// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 047// jataylor@hairyfatguy.com 048//------------------------------------------------------------------------------ 049 050public abstract class OfficeOpenXMLTag extends XMLTag implements Cloneable 051{ 052 private OfficeOpenXmlDocument mParentDoc; 053 054 public static Level sSQLLoggingLevel = Level.FINE; 055 056 private final static Logger LOGGER = Logger.getLogger(OfficeXML.class.getPackage().getName()); 057 058 //########################################################################### 059 // CONSTRUCTORS 060 //########################################################################### 061 062 //--------------------------------------------------------------------------- 063 public OfficeOpenXMLTag(XMLName inName, OfficeOpenXmlDocument inParentDoc) 064 { 065 super(inName); 066 mParentDoc = inParentDoc; 067 } 068 069 //########################################################################### 070 // PUBLIC METHODS 071 //########################################################################### 072 073 //--------------------------------------------------------------------------- 074 public static Logger getLogger() 075 { 076 return LOGGER; 077 } 078 079 //-------------------------------------------------------------------------- 080 /** 081 Converts a Color object in to a hex string as Alpha Red Green Blue. 082 */ 083 public static String colorToCT_Color(Color inColor) 084 { 085 String outString = null; 086 087 if (inColor != null) 088 { 089 String alpha = Integer.toHexString(inColor.getAlpha()); 090 String red = Integer.toHexString(inColor.getRed()); 091 String green = Integer.toHexString(inColor.getGreen()); 092 String blue = Integer.toHexString(inColor.getBlue()); 093 094 if (alpha.length() == 1) alpha = "0" + alpha; 095 if (red.length() == 1) red = "0" + red; 096 if (green.length() == 1) green = "0" + green; 097 if (blue.length() == 1) blue = "0" + blue; 098 099 outString = (alpha + red + green + blue).toUpperCase(); 100 } 101 102 return outString; 103 } 104 //--------------------------------------------------------------------------- 105 public OfficeOpenXmlDocument getParentDoc() 106 { 107 return mParentDoc; 108 } 109 110 //--------------------------------------------------------------------------- 111 public void setParentDoc(OfficeOpenXmlDocument inValue) 112 { 113 mParentDoc = inValue; 114 for (XMLizable subtag : getSubtags()) 115 { 116 if (subtag instanceof OfficeOpenXMLTag) 117 { 118 ((OfficeOpenXMLTag) subtag).setParentDoc(inValue); 119 } 120 } 121 } 122 123 124 //--------------------------------------------------------------------------- 125 @Override 126 public void toIndentedXML(Writer inWriter, int inInitialIndentSize, int inIndentSize, 127 XMLNamespaceSet inDeclaredNamespaces) 128 { 129 // Before writing to XML, be sure the subtags are in the proper sequence. 130 orderSubtags(); 131 132 super.toIndentedXML(inWriter, inInitialIndentSize, inIndentSize, inDeclaredNamespaces); 133 } 134 135 //--------------------------------------------------------------------------- 136 @Override 137 protected void toXML(Writer inWriter, XMLNamespaceSet inDeclaredNamespaces) 138 { 139 // Before writing to XML, be sure the subtags are in the proper sequence. 140 orderSubtags(); 141 142 super.toXML(inWriter, inDeclaredNamespaces); 143 } 144 145 //--------------------------------------------------------------------------- 146 // Microsoft is VERY particular about the order of XML tags. We use the DTD to get the ordering correct. 147 protected void orderSubtags() 148 { 149 if (CollectionUtil.hasValues(mContentAndSubtagList) 150 && mContentAndSubtagList.size() > 1) 151 { 152 Set<XsdElement> xsdElements = OfficeOpenXmlXsd.getInstance().getElements(getQualifiedTagName()); 153 if (xsdElements != null) 154 { 155 for (XsdElement xsdElement : xsdElements) 156 { 157 mContentAndSubtagList.sort(new XsdSubtagComparator(xsdElement)); 158 } 159 } 160 else if (getTagName() != null) 161 { 162 System.out.println("No XsdElement for " + StringUtil.singleQuote(getTagName())); 163 } 164 } 165 } 166 167 //--------------------------------------------------------------------------- 168 protected static String generateUID() 169 { 170 return "{" + UUID.randomUUID() + "}"; 171 } 172 173 174 //########################################################################### 175 // INNER CLASS 176 //########################################################################### 177 178 private class XsdSubtagComparator implements Comparator<XMLNode> 179 { 180 private Map<String, List<Integer>> mSubtagIndexMap; 181 182 //------------------------------------------------------------------------ 183 public XsdSubtagComparator(XsdElement inXsdElement) 184 { 185 mSubtagIndexMap = inXsdElement.getSubtagIndexMap(); 186 } 187 188 //------------------------------------------------------------------------ 189 public int compare(XMLNode inNode1, XMLNode inNode2) 190 { 191 int result = 0; 192 193 if (inNode1.getTagName() != null 194 && inNode2.getTagName() != null 195 && ! inNode1.getTagName().equals(inNode2.getTagName())) // No need to compare tags of the same name 196 { 197 List<Integer> index1 = getSubtagIndex(inNode1.getTagName()); 198 List<Integer> index2 = getSubtagIndex(inNode2.getTagName()); 199 200 if (index1 != null) 201 { 202 if (index2 != null) 203 { 204 for (int i = 0; i < index1.size() && i < index2.size() && 0 == result; i++) 205 { 206 result = CompareUtil.compare(index1.get(i), index2.get(i)); 207 } 208 } 209 else 210 { 211 result = -1; 212 } 213 } 214 else if (index2 != null) 215 { 216 result = 1; 217 } 218 219 if (LOGGER.isLoggable(sSQLLoggingLevel)) 220 { 221 LOGGER.log(sSQLLoggingLevel, "Sorting subtag " + inNode1.getTagName() + " vs. " + inNode2.getTagName() + ": " + result); 222 } 223 } 224 225 226 return result; 227 } 228 229 //------------------------------------------------------------------------ 230 private List<Integer> getSubtagIndex(String inSubtagName) 231 { 232 List<Integer> index = null; 233 if (mSubtagIndexMap != null) 234 { 235 index = mSubtagIndexMap.get(inSubtagName); 236 } 237 238 return index != null ? index : null; 239 } 240 241 } 242 243}