001package com.hfg.xml.msofficexml.xlsx.spreadsheetml.style; 002 003import java.io.BufferedInputStream; 004import java.util.ArrayList; 005import java.util.Collections; 006import java.util.List; 007import java.util.logging.Level; 008import java.util.logging.Logger; 009 010import com.hfg.datetime.DateUtil; 011import com.hfg.util.StringUtil; 012import com.hfg.util.collection.OrderedMap; 013import com.hfg.util.collection.OrderedSet; 014import com.hfg.xml.XMLDoc; 015import com.hfg.util.StackTraceUtil; 016import com.hfg.xml.XMLTag; 017import com.hfg.xml.msofficexml.OfficeOpenXmlException; 018import com.hfg.xml.msofficexml.OfficeXML; 019import com.hfg.xml.msofficexml.xlsx.SsmlRelationshipType; 020import com.hfg.xml.msofficexml.xlsx.Xlsx; 021import com.hfg.xml.msofficexml.xlsx.part.SsmlContentType; 022import com.hfg.xml.msofficexml.xlsx.part.XlsxPart; 023import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlCell; 024import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlRow; 025import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlSheetData; 026import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlWorksheet; 027import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXML; 028import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXMLTag; 029 030//------------------------------------------------------------------------------ 031/** 032 Styles part specific to OfficeOpenXML SpreadsheetML. 033 <div> 034 @author J. Alex Taylor, hairyfatguy.com 035 </div> 036 */ 037//------------------------------------------------------------------------------ 038// com.hfg XML/HTML Coding Library 039// 040// This library is free software; you can redistribute it and/or 041// modify it under the terms of the GNU Lesser General Public 042// License as published by the Free Software Foundation; either 043// version 2.1 of the License, or (at your option) any later version. 044// 045// This library is distributed in the hope that it will be useful, 046// but WITHOUT ANY WARRANTY; without even the implied warranty of 047// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 048// Lesser General Public License for more details. 049// 050// You should have received a copy of the GNU Lesser General Public 051// License along with this library; if not, write to the Free Software 052// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 053// 054// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 055// jataylor@hairyfatguy.com 056//------------------------------------------------------------------------------ 057 058public class StylesPart extends XlsxPart 059{ 060 private XMLTag mStylesheetTag; 061 private XMLTag mNumberFormatsTag; 062 private XMLTag mFontsTag; 063 private XMLTag mFillsTag; 064 private XMLTag mBordersTag; 065 private XMLTag mCellFormatsTag; 066 private XMLTag mStyleFormatsTag; 067 private XMLTag mCellStylesTag; 068 private XMLTag mDifferentialFormatsTag; 069 private SsmlFont mDefaultFont; 070 private SsmlFill mDefaultFill; 071 private SsmlBorder mDefaultBorder; 072 private SsmlStyleFormat mDefaultStyleFormat; 073 private SsmlCellFormat mDefaultCellFormat; 074 private SsmlCellStyle mNormalStyle; 075 private SsmlCellFormat mDefaultDateCellFormat; 076 077 private List<SsmlNumberFormat> mNumberFormats = new ArrayList<>(); 078 private List<SsmlFont> mFonts = new ArrayList<>(); 079 private List<SsmlFill> mFills = new ArrayList<>(); 080 private List<SsmlBorder> mBorders = new ArrayList<>(); 081 private List<SsmlCellFormat> mCellFormats = new ArrayList<>(); 082 private List<SsmlStyleFormat> mCellStyleFormats = new ArrayList<>(); 083 private List<SsmlCellStyle> mCellStyles = new ArrayList<>(); 084 private List<SsmlDifferentialFormat> mDifferentialFormats = new ArrayList<>(); 085 086 private final static Logger LOGGER = OfficeXML.getLogger(); 087 088 //########################################################################## 089 // CONSTRUCTORS 090 //########################################################################## 091 092 //--------------------------------------------------------------------------- 093 /** 094 This constructor should only be used by the Xlsx object. 095 * @param inXlsx the parent Excel document 096 */ 097 public StylesPart(Xlsx inXlsx) 098 { 099 super(inXlsx); 100 setFile(SsmlXML.STYLES_FILE); 101 102 if (! (StackTraceUtil.getCallingClassName().equals(getClass().getName()) 103 || StackTraceUtil.getCallingClassName().equals(Xlsx.class.getName()))) 104 { 105 throw new OfficeOpenXmlException("An Xlsx object can have only one styles part! Use xlsx.getStylesPart() to access it."); 106 } 107 108 // Register the content type 109 inXlsx.getContentTypesPart().addOverride(this, SsmlContentType.SPREADSHEET_STYLES); 110 111 // Register the relationship 112 inXlsx.getWorkbookRelationshipPart().addRelationship(SsmlRelationshipType.STYLES, this); 113 114 mStylesheetTag = new SsmlStylesheet(inXlsx); 115 setRootNode(mStylesheetTag); 116 117// setDefaults(); 118 } 119 120 //--------------------------------------------------------------------------- 121 public StylesPart(Xlsx inXlsx, BufferedInputStream inStream) 122 { 123 this(inXlsx); 124 125 XMLDoc doc = new XMLDoc(inStream); 126 mStylesheetTag = (XMLTag) doc.getRootNode(); 127 128 mNumberFormatsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.NUM_FORMATS); 129 if (mNumberFormatsTag != null) 130 { 131 for (XMLTag subtag : (List<XMLTag>) (Object) mNumberFormatsTag.getSubtagsByName(SsmlXML.NUM_FORMAT)) 132 { 133 mNumberFormats.add(new SsmlNumberFormat(inXlsx, subtag)); 134 } 135 } 136 137 mFontsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.FONTS); 138 if (mFontsTag != null) 139 { 140 for (XMLTag subtag : (List<XMLTag>) (Object) mFontsTag.getSubtagsByName(SsmlXML.FONT)) 141 { 142 mFonts.add(new SsmlFont(inXlsx, subtag)); 143 } 144 } 145 146 // TODO 147 mFillsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.FILLS); 148 // TODO 149 mBordersTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.BORDERS); 150 151 mCellFormatsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.CELL_FORMATS); 152 if (mCellFormatsTag != null) 153 { 154 for (XMLTag subtag : (List<XMLTag>) (Object) mCellFormatsTag.getSubtagsByName(SsmlXML.CELL_FORMAT)) 155 { 156 mCellFormats.add(new SsmlCellFormat(inXlsx, subtag)); 157 } 158 } 159 160 161 mStyleFormatsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.CELL_STYLE_FORMATS); 162 mCellStylesTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.CELL_STYLES); 163 mDifferentialFormatsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.DIFFERENTIAL_FORMATS); 164 } 165 166 //--------------------------------------------------------------------------- 167 public void setDefaults() 168 { 169// mDefaultFont = new SsmlFont(this).setName("Verdana").setSize(10); 170 mDefaultFont = new SsmlFont(this).setName("Calibri").setSize(11).lock(); 171 172 mDefaultFill = new SsmlFill(this).setPatternType(SsmlPatternType.none); 173 // Add a second default fill value that sometimes seems to be required 174 new SsmlFill(this).setPatternType(SsmlPatternType.gray125); 175 176 mDefaultBorder = new SsmlBorder(this); 177 178 179 mDefaultStyleFormat = new SsmlStyleFormat(this) 180 .setFont(mDefaultFont) 181 .setFill(mDefaultFill) 182 .setBorder(mDefaultBorder); 183 184 mDefaultCellFormat = new SsmlCellFormat(this) 185 .setFont(mDefaultFont) 186 .setFill(mDefaultFill) 187 .setBorder(mDefaultBorder) 188 .setStyleFormat(mDefaultStyleFormat); 189 190 mNormalStyle = new SsmlCellStyle(this) 191 .setName("Normal") 192 .setBuiltinId(1) 193 .setStyleFormat(mDefaultStyleFormat); 194 } 195 196 //########################################################################## 197 // PUBLIC METHODS 198 //########################################################################## 199 200 //--------------------------------------------------------------------------- 201 public SsmlFont getDefaultFont() 202 { 203 return mDefaultFont; 204 } 205 206 //--------------------------------------------------------------------------- 207 public StylesPart setDefaultFont(SsmlFont inValue) 208 { 209 mFonts.remove(mDefaultFont); 210 mFontsTag.removeSubtag(mDefaultFont); 211 212 mDefaultFont = inValue.clone(); 213 mFonts.remove(mDefaultFont); 214 mFonts.add(0, mDefaultFont); 215 mFontsTag.removeSubtag(mDefaultFont); 216 mFontsTag.addSubtag(0, mDefaultFont); 217 mDefaultFont.setIndex(0); 218 mDefaultFont.lock(); 219 220 return this; 221 } 222 223 //--------------------------------------------------------------------------- 224 public SsmlFill getDefaultFill() 225 { 226 return mDefaultFill; 227 } 228 229 //--------------------------------------------------------------------------- 230 public SsmlBorder getDefaultBorder() 231 { 232 return mDefaultBorder; 233 } 234 235 //--------------------------------------------------------------------------- 236 public SsmlStyleFormat getDefaultStyleFormat() 237 { 238 return mDefaultStyleFormat; 239 } 240 241 //--------------------------------------------------------------------------- 242 public SsmlCellFormat getDefaultCellFormat() 243 { 244 return mDefaultCellFormat; 245 } 246 247 //--------------------------------------------------------------------------- 248 public SsmlCellFormat getDefaultDateCellFormat() 249 { 250 if (null == mDefaultDateCellFormat) 251 { 252 mDefaultDateCellFormat = new SsmlCellFormat(this) 253 .setNumberFormat(SsmlNumberFormat.DATE_MM_DD_YY) 254 .setFont(mDefaultFont) 255 .setFill(mDefaultFill) 256 .setBorder(mDefaultBorder); 257 } 258 259 return mDefaultDateCellFormat; 260 } 261 262 //--------------------------------------------------------------------------- 263 public List<SsmlNumberFormat> getNumberFormats() 264 { 265 return mNumberFormats; 266 } 267 268 //--------------------------------------------------------------------------- 269 public int defineNumberFormat(SsmlNumberFormat inValue) 270 { 271 int index = mNumberFormats.size(); 272 mNumberFormats.add(inValue); 273 274 if (null == mNumberFormatsTag) 275 { 276 mNumberFormatsTag = new XMLTag(SsmlXML.NUM_FORMATS); 277 mStylesheetTag.addSubtag(mNumberFormatsTag); 278 } 279 280 // Add it to a number formats tag 281 mNumberFormatsTag.addSubtag(inValue); 282 mNumberFormatsTag.setAttribute(SsmlXML.COUNT_ATT, mNumberFormats.size()); 283 284 return index; 285 } 286 287 //--------------------------------------------------------------------------- 288 public int defineFont(SsmlFont inValue) 289 { 290 int index = mFonts.size(); 291 mFonts.add(inValue); 292 293 if (null == mFontsTag) 294 { 295 mFontsTag = new XMLTag(SsmlXML.FONTS); 296 mStylesheetTag.addSubtag(mFontsTag); 297 } 298 299 // Add it to a fonts tag 300 mFontsTag.addSubtag(inValue); 301 mFontsTag.setAttribute(SsmlXML.COUNT_ATT, mFonts.size()); 302 303 return index; 304 } 305 306 //--------------------------------------------------------------------------- 307 public List<SsmlFont> getFonts() 308 { 309 return mFonts; 310 } 311 312 //--------------------------------------------------------------------------- 313 public List<SsmlFill> getFills() 314 { 315 return mFills; 316 } 317 318 //--------------------------------------------------------------------------- 319 public int defineFill(SsmlFill inValue) 320 { 321 int index = mFills.size(); 322 mFills.add(inValue); 323 324 if (null == mFillsTag) 325 { 326 mFillsTag = new XMLTag(SsmlXML.FILLS); 327 mStylesheetTag.addSubtag(mFillsTag); 328 } 329 330 // Add it to a fills tag 331 mFillsTag.addSubtag(inValue); 332 mFillsTag.setAttribute(SsmlXML.COUNT_ATT, mFills.size()); 333 334 return index; 335 } 336 337 //--------------------------------------------------------------------------- 338 public List<SsmlBorder> getBorders() 339 { 340 return mBorders; 341 } 342 343 //--------------------------------------------------------------------------- 344 public int defineBorder(SsmlBorder inValue) 345 { 346 int index = mBorders.size(); 347 mBorders.add(inValue); 348 349 if (null == mBordersTag) 350 { 351 mBordersTag = new XMLTag(SsmlXML.BORDERS); 352 mStylesheetTag.addSubtag(mBordersTag); 353 } 354 355 // Add it to a borders tag 356 mBordersTag.addSubtag(inValue); 357 mBordersTag.setAttribute(SsmlXML.COUNT_ATT, mBorders.size()); 358 359 return index; 360 } 361 362 //--------------------------------------------------------------------------- 363 public int defineCellFormat(SsmlCellFormat inValue) 364 { 365 int index = mCellFormats.size(); 366 mCellFormats.add(inValue); 367 368 if (null == mCellFormatsTag) 369 { 370 mCellFormatsTag = new XMLTag(SsmlXML.CELL_FORMATS); 371 mStylesheetTag.addSubtag(mCellFormatsTag); 372 } 373 374 // Add it to a cell formats (cellXfs) tag 375 mCellFormatsTag.addSubtag(inValue); 376 mCellFormatsTag.setAttribute(SsmlXML.COUNT_ATT, mCellFormats.size()); 377 378 return index; 379 } 380 381 //--------------------------------------------------------------------------- 382 public List<SsmlCellFormat> getCellFormats() 383 { 384 return mCellFormats; 385 } 386 387 //--------------------------------------------------------------------------- 388 public int defineDifferentialFormat(SsmlDifferentialFormat inValue) 389 { 390 int index = mDifferentialFormats.size(); 391 mDifferentialFormats.add(inValue); 392 393 if (null == mDifferentialFormatsTag) 394 { 395 mDifferentialFormatsTag = new XMLTag(SsmlXML.DIFFERENTIAL_FORMATS); 396 mStylesheetTag.addSubtag(mDifferentialFormatsTag); 397 } 398 399 // Add it to a differential formats (dxfs) tag 400 mDifferentialFormatsTag.addSubtag(inValue); 401 mDifferentialFormatsTag.setAttribute(SsmlXML.COUNT_ATT, mDifferentialFormats.size()); 402 403 return index; 404 } 405 406 //--------------------------------------------------------------------------- 407 public List<SsmlDifferentialFormat> getDifferentialFormat() 408 { 409 return mDifferentialFormats; 410 } 411 412 //--------------------------------------------------------------------------- 413 public int defineStyleFormat(SsmlStyleFormat inValue) 414 { 415 int index = mCellStyleFormats.size(); 416 mCellStyleFormats.add(inValue); 417 418 if (null == mCellFormatsTag) 419 { 420 mStyleFormatsTag = new XMLTag(SsmlXML.CELL_STYLE_FORMATS); 421 mStylesheetTag.addSubtag(mStyleFormatsTag); 422 } 423 424 // Add it to a cell style formats (cellStyleXfs) tag 425 mStyleFormatsTag.addSubtag(inValue); 426 mStyleFormatsTag.setAttribute(SsmlXML.COUNT_ATT, mCellStyleFormats.size()); 427 428 return index; 429 } 430 431 //--------------------------------------------------------------------------- 432 public List<SsmlStyleFormat> getCellStyleFormats() 433 { 434 return Collections.unmodifiableList(mCellStyleFormats); 435 } 436 437 //--------------------------------------------------------------------------- 438 public SsmlStyleFormat getStyleFormat(int inIndex) 439 { 440 SsmlStyleFormat requestedStyleFormat = null; 441 if (inIndex >=0 442 && inIndex < mCellStyleFormats.size()) 443 { 444 requestedStyleFormat = mCellStyleFormats.get(inIndex); 445 } 446 447 return requestedStyleFormat; 448 } 449 450 451 //--------------------------------------------------------------------------- 452 public int defineCellStyle(SsmlCellStyle inValue) 453 { 454 int index = mCellStyles.size(); 455 mCellStyles.add(inValue); 456 457 if (null == mCellStylesTag) 458 { 459 mCellStylesTag = new XMLTag(SsmlXML.CELL_STYLES); 460 mStylesheetTag.addSubtag(mCellStylesTag); 461 } 462 463 // Add it to a cell styles (cellStyles) tag 464 mCellStylesTag.addSubtag(inValue); 465 mCellStylesTag.setAttribute(SsmlXML.COUNT_ATT, mCellStyles.size()); 466 467 return index; 468 } 469 470 //--------------------------------------------------------------------------- 471 public List<SsmlCellStyle> getCellStyles() 472 { 473 return Collections.unmodifiableList(mCellStyles); 474 } 475 476 477 //--------------------------------------------------------------------------- 478 public void finalizeStyles() 479 { 480 condenseFonts(); 481 482 // TODO: condenseFills(); 483 484 condenseBorders(); 485 486 // TODO: condenseCellStyleFormats(); 487 488 condenseCellFormats(); 489 } 490 491 //--------------------------------------------------------------------------- 492 private void condenseFonts() 493 { 494 long startTime = System.currentTimeMillis(); 495 496 if (LOGGER.isLoggable(Level.FINE)) 497 { 498 LOGGER.log(Level.FINE, getFonts().size() + " fonts before condensation."); 499 } 500 501 OrderedMap<Integer, SsmlFont> condensedFontMap = new OrderedMap<>(25); 502 for (SsmlFont font : getFonts()) 503 { 504 if (0 == condensedFontMap.size()) 505 { 506 condensedFontMap.put(font.getIndex(), font); 507 } 508 else 509 { 510 boolean isDuplicate = false; 511 for (SsmlFont condensedFont : condensedFontMap.values()) 512 { 513 if (font.equals(condensedFont)) 514 { 515 condensedFontMap.put(font.getIndex(), condensedFont); 516 isDuplicate = true; 517 break; 518 } 519 } 520 521 if (! isDuplicate) 522 { 523 condensedFontMap.put(font.getIndex(), font); 524 } 525 } 526 } 527 528 OrderedSet<SsmlFont> condensedFonts = new OrderedSet<>(condensedFontMap.values()); 529 530 mFontsTag.clearSubtags(); 531 mFontsTag.setAttribute(SsmlXML.COUNT_ATT, condensedFonts.size()); 532 533 int index = 0; 534 for (SsmlFont condensedFont : condensedFonts) 535 { 536 condensedFont.setIndex(index++); 537 mFontsTag.addSubtag(condensedFont); 538 } 539 540 // Now update font ids 541 for (SsmlStyleFormat styleFormat : getCellStyleFormats()) 542 { 543 SsmlFont existingFont = styleFormat.getFont(); 544 if (existingFont != null) 545 { 546 styleFormat.setFont(condensedFontMap.get(existingFont.getIndex())); 547 } 548 } 549 550 for (SsmlCellFormat cellFormat : getCellFormats()) 551 { 552 cellFormat.setFont(condensedFontMap.get(cellFormat.getFontId())); 553 } 554 555 if (LOGGER.isLoggable(Level.INFO)) 556 { 557 if (LOGGER.isLoggable(Level.FINE)) 558 { 559 LOGGER.log(Level.FINE, condensedFonts.size() + " fonts after condensation."); 560 } 561 562 LOGGER.log(Level.INFO, "condenseFonts() timing: " + DateUtil.generateElapsedTimeString(startTime)); 563 } 564 } 565 566 //--------------------------------------------------------------------------- 567 private void condenseBorders() 568 { 569 long startTime = System.currentTimeMillis(); 570 571 if (LOGGER.isLoggable(Level.FINE)) 572 { 573 LOGGER.log(Level.FINE, getBorders().size() + " borders before condensation."); 574 } 575 576 OrderedMap<Integer, SsmlBorder> condensedBorderMap = new OrderedMap<>(25); 577 for (SsmlBorder border : getBorders()) 578 { 579 if (0 == condensedBorderMap.size()) 580 { 581 condensedBorderMap.put(border.getIndex(), border); 582 } 583 else 584 { 585 boolean isDuplicate = false; 586 for (SsmlBorder condensedBorder : condensedBorderMap.values()) 587 { 588 if (border.equals(condensedBorder)) 589 { 590 condensedBorderMap.put(border.getIndex(), condensedBorder); 591 isDuplicate = true; 592 break; 593 } 594 } 595 596 if (! isDuplicate) 597 { 598 condensedBorderMap.put(border.getIndex(), border); 599 } 600 } 601 } 602 603 OrderedSet<SsmlBorder> condensedBorders = new OrderedSet<>(condensedBorderMap.values()); 604 605 mBordersTag.clearSubtags(); 606 mBordersTag.setAttribute(SsmlXML.COUNT_ATT, condensedBorders.size()); 607 608 int index = 0; 609 for (SsmlBorder condensedBorder : condensedBorders) 610 { 611 condensedBorder.setIndex(index++); 612 mBordersTag.addSubtag(condensedBorder); 613 } 614 615 // Now update font ids 616 for (SsmlStyleFormat styleFormat : getCellStyleFormats()) 617 { 618 SsmlBorder existingBorder = styleFormat.getBorder(); 619 if (existingBorder != null) 620 { 621 styleFormat.setBorder(condensedBorderMap.get(existingBorder.getIndex())); 622 } 623 } 624 625 for (SsmlCellFormat cellFormat : getCellFormats()) 626 { 627 cellFormat.setBorder(condensedBorderMap.get(cellFormat.getBorderId())); 628 } 629 630 if (LOGGER.isLoggable(Level.INFO)) 631 { 632 if (LOGGER.isLoggable(Level.FINE)) 633 { 634 LOGGER.log(Level.FINE, condensedBorders.size() + " borders after condensation."); 635 } 636 637 LOGGER.log(Level.INFO, "condenseBorders() timing: " + DateUtil.generateElapsedTimeString(startTime)); 638 } 639 } 640 641 642 //--------------------------------------------------------------------------- 643 private void condenseCellFormats() 644 { 645 long startTime = System.currentTimeMillis(); 646 647 if (LOGGER.isLoggable(Level.FINE)) 648 { 649 LOGGER.log(Level.FINE, getCellFormats().size() + " cell formats before condensation."); 650 } 651 652 // First, build a map of the existing indices to the condensed list of formats 653 OrderedMap<Integer, SsmlCellFormat> condensedCellFormatMap = new OrderedMap<>(25); 654 for (SsmlCellFormat cellFormat : getCellFormats()) 655 { 656 if (0 == condensedCellFormatMap.size()) 657 { 658 condensedCellFormatMap.put(cellFormat.getIndex(), cellFormat); 659 } 660 else 661 { 662 boolean isDuplicate = false; 663 for (SsmlCellFormat condensedCellFormat : condensedCellFormatMap.values()) 664 { 665 if (cellFormat.equals(condensedCellFormat)) 666 { 667 condensedCellFormatMap.put(cellFormat.getIndex(), condensedCellFormat); 668 isDuplicate = true; 669 break; 670 } 671 } 672 673 if (! isDuplicate) 674 { 675 condensedCellFormatMap.put(cellFormat.getIndex(), cellFormat); 676 } 677 } 678 } 679 680 681 // Second, clear the cell format tags from the styles part 682 mCellFormatsTag.clearSubtags(); 683 684 // Third, add back the condensed list of cell formats 685 OrderedSet<SsmlCellFormat> condensedCellFormats = new OrderedSet<>(condensedCellFormatMap.values()); 686 mCellFormatsTag.setAttribute(SsmlXML.COUNT_ATT, condensedCellFormats.size()); 687 688 int index = 0; 689 for (SsmlCellFormat condensedCellFormat : condensedCellFormats) 690 { 691 condensedCellFormat.setIndex(index++); 692 mCellFormatsTag.addSubtag(condensedCellFormat); 693 } 694 695 // Fourth, update references to cell formats 696 for (SsmlWorksheet worksheet : getParentDoc().getWorkbook().getWorksheets()) 697 { 698 SsmlSheetData sheetData = worksheet.getSheetData(); 699 700 for (SsmlRow row : sheetData.getRows()) 701 { 702 for (SsmlCell cell : row.getCells()) 703 { 704 String style = cell.getAttributeValue(SsmlXML.STYLE_IDX_ATT); 705 if (StringUtil.isSet(style)) 706 { 707 SsmlCellFormat newCellFormat = condensedCellFormatMap.get(Integer.parseInt(style)); 708 if (newCellFormat != null) 709 { 710 cell.setAttribute(SsmlXML.STYLE_IDX_ATT, newCellFormat.getIndex()); 711 } 712 else 713 { 714 // This should never be the case. It means that something was referencing a non-existent cell format!? 715 System.err.printf("Dangling cell format reference! Sheet:%s, Cell:%s, StyleIdx:%s%n", worksheet.getName(), cell.getRef(), style); 716 } 717 } 718 } 719 } 720 } 721 722 if (LOGGER.isLoggable(Level.INFO)) 723 { 724 if (LOGGER.isLoggable(Level.FINE)) 725 { 726 LOGGER.log(Level.FINE, condensedCellFormats.size() + " cell formats after condensation."); 727 } 728 729 LOGGER.log(Level.INFO, "condenseCellFormats() timing: " + DateUtil.generateElapsedTimeString(startTime)); 730 } 731 } 732 733 734 private class SsmlStylesheet extends SsmlXMLTag 735 { 736 //--------------------------------------------------------------------------- 737 public SsmlStylesheet(Xlsx inXlsx) 738 { 739 super(SsmlXML.STYLESHEET, inXlsx); 740 } 741 } 742}