summaryrefslogtreecommitdiff
path: root/sc/source/filter/excel
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/excel')
-rw-r--r--sc/source/filter/excel/colrowst.cxx364
-rw-r--r--sc/source/filter/excel/excdoc.cxx827
-rw-r--r--sc/source/filter/excel/excel.cxx298
-rw-r--r--sc/source/filter/excel/excform.cxx1944
-rw-r--r--sc/source/filter/excel/excform8.cxx1681
-rw-r--r--sc/source/filter/excel/excimp8.cxx859
-rw-r--r--sc/source/filter/excel/excrecds.cxx1060
-rw-r--r--sc/source/filter/excel/exctools.cxx296
-rw-r--r--sc/source/filter/excel/expop2.cxx151
-rw-r--r--sc/source/filter/excel/fontbuff.cxx165
-rw-r--r--sc/source/filter/excel/frmbase.cxx248
-rw-r--r--sc/source/filter/excel/impop.cxx1336
-rw-r--r--sc/source/filter/excel/namebuff.cxx346
-rw-r--r--sc/source/filter/excel/ooxml-export-TODO.txt148
-rw-r--r--sc/source/filter/excel/read.cxx1307
-rw-r--r--sc/source/filter/excel/tokstack.cxx881
-rw-r--r--sc/source/filter/excel/xechart.cxx3525
-rw-r--r--sc/source/filter/excel/xecontent.cxx1496
-rw-r--r--sc/source/filter/excel/xeescher.cxx1641
-rw-r--r--sc/source/filter/excel/xeformula.cxx2629
-rw-r--r--sc/source/filter/excel/xehelper.cxx1127
-rw-r--r--sc/source/filter/excel/xelink.cxx2367
-rw-r--r--sc/source/filter/excel/xename.cxx767
-rw-r--r--sc/source/filter/excel/xepage.cxx436
-rw-r--r--sc/source/filter/excel/xepivot.cxx1971
-rw-r--r--sc/source/filter/excel/xerecord.cxx304
-rw-r--r--sc/source/filter/excel/xeroot.cxx319
-rw-r--r--sc/source/filter/excel/xestream.cxx1221
-rw-r--r--sc/source/filter/excel/xestring.cxx606
-rw-r--r--sc/source/filter/excel/xestyle.cxx2860
-rw-r--r--sc/source/filter/excel/xetable.cxx2443
-rw-r--r--sc/source/filter/excel/xeview.cxx540
-rw-r--r--sc/source/filter/excel/xichart.cxx4332
-rw-r--r--sc/source/filter/excel/xicontent.cxx1329
-rw-r--r--sc/source/filter/excel/xiescher.cxx4206
-rw-r--r--sc/source/filter/excel/xiformula.cxx129
-rw-r--r--sc/source/filter/excel/xihelper.cxx893
-rw-r--r--sc/source/filter/excel/xilink.cxx952
-rw-r--r--sc/source/filter/excel/xiname.cxx279
-rw-r--r--sc/source/filter/excel/xipage.cxx392
-rw-r--r--sc/source/filter/excel/xipivot.cxx1678
-rw-r--r--sc/source/filter/excel/xiroot.cxx311
-rw-r--r--sc/source/filter/excel/xistream.cxx1142
-rw-r--r--sc/source/filter/excel/xistring.cxx215
-rw-r--r--sc/source/filter/excel/xistyle.cxx2000
-rw-r--r--sc/source/filter/excel/xiview.cxx309
-rw-r--r--sc/source/filter/excel/xladdress.cxx165
-rw-r--r--sc/source/filter/excel/xlchart.cxx1351
-rw-r--r--sc/source/filter/excel/xlescher.cxx382
-rw-r--r--sc/source/filter/excel/xlformula.cxx788
-rw-r--r--sc/source/filter/excel/xlpage.cxx277
-rw-r--r--sc/source/filter/excel/xlpivot.cxx1028
-rw-r--r--sc/source/filter/excel/xlroot.cxx440
-rw-r--r--sc/source/filter/excel/xlstyle.cxx1772
-rw-r--r--sc/source/filter/excel/xltoolbar.cxx447
-rw-r--r--sc/source/filter/excel/xltoolbar.hxx127
-rw-r--r--sc/source/filter/excel/xltools.cxx750
-rw-r--r--sc/source/filter/excel/xltracer.cxx266
-rw-r--r--sc/source/filter/excel/xlview.cxx117
59 files changed, 62240 insertions, 0 deletions
diff --git a/sc/source/filter/excel/colrowst.cxx b/sc/source/filter/excel/colrowst.cxx
new file mode 100644
index 000000000000..17270c14fc00
--- /dev/null
+++ b/sc/source/filter/excel/colrowst.cxx
@@ -0,0 +1,364 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include "colrowst.hxx"
+
+#include <string.h>
+
+#include "document.hxx"
+#include "root.hxx"
+#include "ftools.hxx"
+#include "xltable.hxx"
+#include "xistream.hxx"
+#include "xistyle.hxx"
+#include "queryparam.hxx"
+
+// for filter manager
+#include "excimp8.hxx"
+
+// ============================================================================
+
+const sal_uInt8 EXC_COLROW_USED = 0x01;
+const sal_uInt8 EXC_COLROW_DEFAULT = 0x02;
+const sal_uInt8 EXC_COLROW_HIDDEN = 0x04;
+const sal_uInt8 EXC_COLROW_MAN = 0x08;
+
+// ============================================================================
+
+XclImpColRowSettings::XclImpColRowSettings( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ maWidths( MAXCOLCOUNT, 0 ),
+ maColFlags( MAXCOLCOUNT, 0 ),
+ maRowHeights(0, MAXROWCOUNT, 0),
+ maRowFlags(0, MAXROWCOUNT, 0),
+ maHiddenRows(0, MAXROWCOUNT, false),
+ mnLastScRow( -1 ),
+ mnDefWidth( STD_COL_WIDTH ),
+ mnDefHeight( static_cast< sal_uInt16 >( STD_ROW_HEIGHT ) ),
+ mnDefRowFlags( EXC_DEFROW_DEFAULTFLAGS ),
+ mbHasStdWidthRec( false ),
+ mbHasDefHeight( false ),
+ mbDirty( true )
+{
+}
+
+XclImpColRowSettings::~XclImpColRowSettings()
+{
+}
+
+void XclImpColRowSettings::SetDefWidth( sal_uInt16 nDefWidth, bool bStdWidthRec )
+{
+ if( bStdWidthRec )
+ {
+ // STANDARDWIDTH record overrides DEFCOLWIDTH record
+ mnDefWidth = nDefWidth;
+ mbHasStdWidthRec = true;
+ }
+ else if( !mbHasStdWidthRec )
+ {
+ // use DEFCOLWIDTH record only, if no STANDARDWIDTH record exists
+ mnDefWidth = nDefWidth;
+ }
+}
+
+void XclImpColRowSettings::SetWidthRange( SCCOL nScCol1, SCCOL nScCol2, sal_uInt16 nWidth )
+{
+ DBG_ASSERT( (nScCol1 <= nScCol2) && ValidCol( nScCol2 ), "XclImpColRowSettings::SetColWidthRange - invalid column range" );
+ nScCol2 = ::std::min( nScCol2, MAXCOL );
+ if (nScCol2 == 256)
+ // In BIFF8, the column range is 0-255, and the use of 256 probably
+ // means the range should extend to the max column if the loading app
+ // support columns beyond 255.
+ nScCol2 = MAXCOL;
+
+ nScCol1 = ::std::min( nScCol1, nScCol2 );
+ ::std::fill( maWidths.begin() + nScCol1, maWidths.begin() + nScCol2 + 1, nWidth );
+ for( ScfUInt8Vec::iterator aIt = maColFlags.begin() + nScCol1, aEnd = maColFlags.begin() + nScCol2 + 1; aIt != aEnd; ++aIt )
+ ::set_flag( *aIt, EXC_COLROW_USED );
+}
+
+void XclImpColRowSettings::HideCol( SCCOL nScCol )
+{
+ if( ValidCol( nScCol ) )
+ ::set_flag( maColFlags[ nScCol ], EXC_COLROW_HIDDEN );
+}
+
+void XclImpColRowSettings::HideColRange( SCCOL nScCol1, SCCOL nScCol2 )
+{
+ DBG_ASSERT( (nScCol1 <= nScCol2) && ValidCol( nScCol2 ), "XclImpColRowSettings::HideColRange - invalid column range" );
+ nScCol2 = ::std::min( nScCol2, MAXCOL );
+ nScCol1 = ::std::min( nScCol1, nScCol2 );
+ for( ScfUInt8Vec::iterator aIt = maColFlags.begin() + nScCol1, aEnd = maColFlags.begin() + nScCol2 + 1; aIt != aEnd; ++aIt )
+ ::set_flag( *aIt, EXC_COLROW_HIDDEN );
+}
+
+void XclImpColRowSettings::SetDefHeight( sal_uInt16 nDefHeight, sal_uInt16 nFlags )
+{
+ mnDefHeight = nDefHeight;
+ mnDefRowFlags = nFlags;
+ if( mnDefHeight == 0 )
+ {
+ mnDefHeight = static_cast< sal_uInt16 >( STD_ROW_HEIGHT );
+ ::set_flag( mnDefRowFlags, EXC_DEFROW_HIDDEN );
+ }
+ mbHasDefHeight = true;
+}
+
+void XclImpColRowSettings::SetHeight( SCROW nScRow, sal_uInt16 nHeight )
+{
+ if (!ValidRow(nScRow))
+ return;
+
+ sal_uInt16 nRawHeight = nHeight & EXC_ROW_HEIGHTMASK;
+ bool bDefHeight = ::get_flag( nHeight, EXC_ROW_FLAGDEFHEIGHT ) || (nRawHeight == 0);
+ maRowHeights.insert_back(nScRow, nScRow+1, nRawHeight);
+ sal_uInt8 nFlagVal = 0;
+ if (!maRowFlags.search(nScRow, nFlagVal).second)
+ return;
+
+ ::set_flag(nFlagVal, EXC_COLROW_USED);
+ ::set_flag(nFlagVal, EXC_COLROW_DEFAULT, bDefHeight);
+
+ if (!bDefHeight && nRawHeight == 0)
+ maHiddenRows.insert_back(nScRow, nScRow+1, true);
+
+ maRowFlags.insert_back(nScRow, nScRow+1, nFlagVal);
+
+ if (nScRow > mnLastScRow)
+ mnLastScRow = nScRow;
+}
+
+void XclImpColRowSettings::SetRowSettings( SCROW nScRow, sal_uInt16 nHeight, sal_uInt16 nFlags )
+{
+ if (!ValidRow(nScRow))
+ return;
+
+ SetHeight(nScRow, nHeight);
+
+ sal_uInt8 nFlagVal = 0;
+ if (!maRowFlags.search(nScRow, nFlagVal).second)
+ return;
+
+ if (::get_flag(nFlags, EXC_ROW_UNSYNCED))
+ ::set_flag(nFlagVal, EXC_COLROW_MAN);
+
+ maRowFlags.insert_back(nScRow, nScRow+1, nFlagVal);
+
+ if (::get_flag(nFlags, EXC_ROW_HIDDEN))
+ maHiddenRows.insert_back(nScRow, nScRow+1, true);
+}
+
+void XclImpColRowSettings::SetManualRowHeight( SCROW nScRow )
+{
+ if (!ValidRow(nScRow))
+ return;
+
+ sal_uInt8 nFlagVal = 0;
+ if (!maRowFlags.search(nScRow, nFlagVal).second)
+ return;
+
+ ::set_flag(nFlagVal, EXC_COLROW_MAN);
+ maRowFlags.insert_back(nScRow, nScRow+1, nFlagVal);
+}
+
+void XclImpColRowSettings::SetDefaultXF( SCCOL nScCol1, SCCOL nScCol2, sal_uInt16 nXFIndex )
+{
+ /* assign the default column formatting here to ensure that
+ explicit cell formatting is not overwritten. */
+ DBG_ASSERT( (nScCol1 <= nScCol2) && ValidCol( nScCol2 ), "XclImpColRowSettings::SetDefaultXF - invalid column index" );
+ nScCol2 = ::std::min( nScCol2, MAXCOL );
+ nScCol1 = ::std::min( nScCol1, nScCol2 );
+ XclImpXFRangeBuffer& rXFRangeBuffer = GetXFRangeBuffer();
+ for( SCCOL nScCol = nScCol1; nScCol <= nScCol2; ++nScCol )
+ rXFRangeBuffer.SetColumnDefXF( nScCol, nXFIndex );
+}
+
+void XclImpColRowSettings::Convert( SCTAB nScTab )
+{
+ if( !mbDirty )
+ return;
+
+ ScDocument& rDoc = GetDoc();
+ rDoc.IncSizeRecalcLevel( nScTab );
+
+ // column widths ----------------------------------------------------------
+
+ for( SCCOL nScCol = 0; nScCol <= MAXCOL; ++nScCol )
+ {
+ sal_uInt16 nWidth = ::get_flag( maColFlags[ nScCol ], EXC_COLROW_USED ) ? maWidths[ nScCol ] : mnDefWidth;
+ /* Hidden columns: remember hidden state, but do not set hidden state
+ in document here. Needed for #i11776#, no HIDDEN flags in the
+ document, until filters and outlines are inserted. */
+ if( nWidth == 0 )
+ {
+ ::set_flag( maColFlags[ nScCol ], EXC_COLROW_HIDDEN );
+ nWidth = mnDefWidth;
+ }
+ rDoc.SetColWidthOnly( nScCol, nScTab, nWidth );
+ }
+
+ // row heights ------------------------------------------------------------
+
+ // #i54252# set default row height
+ rDoc.SetRowHeightOnly( 0, MAXROW, nScTab, mnDefHeight );
+ if( ::get_flag( mnDefRowFlags, EXC_DEFROW_UNSYNCED ) )
+ // first access to row flags, do not ask for old flags
+ rDoc.SetRowFlags( 0, MAXROW, nScTab, CR_MANUALSIZE );
+
+ maRowHeights.build_tree();
+ if (!maRowHeights.is_tree_valid())
+ return;
+
+ RowFlagsType::const_iterator itrFlags = maRowFlags.begin(), itrFlagsEnd = maRowFlags.end();
+ SCROW nPrevRow = -1;
+ sal_uInt8 nPrevFlags = 0;
+ for (; itrFlags != itrFlagsEnd; ++itrFlags)
+ {
+ SCROW nRow = itrFlags->first;
+ sal_uInt8 nFlags = itrFlags->second;
+ if (nPrevRow >= 0)
+ {
+ sal_uInt16 nHeight = 0;
+
+ if (::get_flag(nPrevFlags, EXC_COLROW_USED))
+ {
+ if (::get_flag(nPrevFlags, EXC_COLROW_DEFAULT))
+ {
+ nHeight = mnDefHeight;
+ rDoc.SetRowHeightOnly(nPrevRow, nRow-1, nScTab, nHeight);
+ }
+ else
+ {
+ for (SCROW i = nPrevRow; i <= nRow - 1; ++i)
+ {
+ SCROW nLast;
+ if (!maRowHeights.search_tree(i, nHeight, NULL, &nLast))
+ {
+ // search failed for some reason
+ return;
+ }
+
+ if (nLast > nRow)
+ nLast = nRow;
+
+ rDoc.SetRowHeightOnly(i, nLast-1, nScTab, nHeight);
+ i = nLast-1;
+ }
+ }
+
+ if (::get_flag(nPrevFlags, EXC_COLROW_MAN))
+ rDoc.SetManualHeight(nPrevRow, nRow-1, nScTab, true);
+ }
+ else
+ {
+ nHeight = mnDefHeight;
+ rDoc.SetRowHeightOnly(nPrevRow, nRow-1, nScTab, nHeight);
+ }
+ }
+
+ nPrevRow = nRow;
+ nPrevFlags = nFlags;
+ }
+
+ // ------------------------------------------------------------------------
+
+ mbDirty = false;
+ rDoc.DecSizeRecalcLevel( nScTab );
+}
+
+void XclImpColRowSettings::ConvertHiddenFlags( SCTAB nScTab )
+{
+ ScDocument& rDoc = GetDoc();
+
+ // hide the columns
+ for( SCCOL nScCol = 0; nScCol <= MAXCOL; ++nScCol )
+ if( ::get_flag( maColFlags[ nScCol ], EXC_COLROW_HIDDEN ) )
+ rDoc.ShowCol( nScCol, nScTab, false );
+
+ // #i38093# rows hidden by filter need extra flag
+ SCROW nFirstFilterScRow = SCROW_MAX;
+ SCROW nLastFilterScRow = SCROW_MAX;
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ const XclImpAutoFilterData* pFilter = GetFilterManager().GetByTab( nScTab );
+ // #i70026# use IsFiltered() to set the CR_FILTERED flag for active filters only
+ if( pFilter && pFilter->IsActive() && pFilter->IsFiltered() )
+ {
+ nFirstFilterScRow = pFilter->StartRow();
+ nLastFilterScRow = pFilter->EndRow();
+ }
+ }
+
+ // In case the excel row limit is lower than calc's, use the visibility of
+ // the last row and extend it to calc's last row.
+ SCROW nLastXLRow = GetRoot().GetXclMaxPos().Row();
+ if (nLastXLRow < MAXROW)
+ {
+ bool bHidden = false;
+ if (!maHiddenRows.search(nLastXLRow, bHidden).second)
+ return;
+
+ maHiddenRows.insert_back(nLastXLRow, MAXROWCOUNT, bHidden);
+ }
+
+ SCROW nPrevRow = -1;
+ bool bPrevHidden = false;
+ RowHiddenType::const_iterator itr = maHiddenRows.begin(), itrEnd = maHiddenRows.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ SCROW nRow = itr->first;
+ bool bHidden = itr->second;
+ if (nPrevRow >= 0)
+ {
+ if (bPrevHidden)
+ {
+ rDoc.ShowRows(nPrevRow, nRow-1, nScTab, false);
+ // #i38093# rows hidden by filter need extra flag
+ if (nFirstFilterScRow <= nPrevRow && nPrevRow <= nLastFilterScRow)
+ {
+ SCROW nLast = ::std::min(nRow-1, nLastFilterScRow);
+ rDoc.SetRowFiltered(nPrevRow, nLast, nScTab, true);
+ }
+ }
+ }
+
+ nPrevRow = nRow;
+ bPrevHidden = bHidden;
+ }
+
+ // #i47438# if default row format is hidden, hide remaining rows
+ if( ::get_flag( mnDefRowFlags, EXC_DEFROW_HIDDEN ) && (mnLastScRow < MAXROW) )
+ rDoc.ShowRows( mnLastScRow + 1, MAXROW, nScTab, false );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/excdoc.cxx b/sc/source/filter/excel/excdoc.cxx
new file mode 100644
index 000000000000..dad9397d488f
--- /dev/null
+++ b/sc/source/filter/excel/excdoc.cxx
@@ -0,0 +1,827 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+//------------------------------------------------------------------------
+
+#include "scitems.hxx"
+
+#include <comphelper/processfactory.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdpage.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/zformat.hxx>
+#include <sot/storage.hxx>
+#include <sfx2/objsh.hxx>
+#include <tools/urlobj.hxx>
+#include <rtl/ustring.hxx>
+
+#include "cell.hxx"
+#include "dociter.hxx"
+#include "document.hxx"
+#include "rangenam.hxx"
+#include "dbcolect.hxx"
+#include "global.hxx"
+#include "globstr.hrc"
+#include "progress.hxx"
+#include "conditio.hxx"
+#include "dpobject.hxx"
+#include "attrib.hxx"
+#include "scextopt.hxx"
+#include "stlsheet.hxx"
+#include "stlpool.hxx"
+#include "olinetab.hxx"
+#include "unonames.hxx"
+#include "convuno.hxx"
+#include "patattr.hxx"
+#include "docoptio.hxx"
+#include "tabprotection.hxx"
+
+#include "excdoc.hxx"
+#include "namebuff.hxx"
+
+#include "xcl97rec.hxx"
+#include "xcl97esc.hxx"
+#include "xetable.hxx"
+#include "xelink.hxx"
+#include "xename.hxx"
+#include "xepage.hxx"
+#include "xeview.hxx"
+#include "xecontent.hxx"
+#include "xeescher.hxx"
+#include "xepivot.hxx"
+#include "XclExpChangeTrack.hxx"
+
+#include <math.h>
+
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <oox/token/tokens.hxx>
+#include <boost/shared_ptr.hpp>
+
+using ::rtl::OString;
+using namespace oox;
+
+static String lcl_GetVbaTabName( SCTAB n )
+{
+ String aRet( RTL_CONSTASCII_USTRINGPARAM( "__VBA__" ) );
+ aRet += String::CreateFromInt32( static_cast<sal_uInt16>(n) );
+ return aRet;
+}
+
+
+static void lcl_AddBookviews( XclExpRecordList<>& aRecList, ExcTable& self )
+{
+ aRecList.AppendNewRecord( new XclExpXmlStartElementRecord( XML_bookViews ) );
+ aRecList.AppendNewRecord( new XclExpWindow1( self.GetRoot() ) );
+ aRecList.AppendNewRecord( new XclExpXmlEndElementRecord( XML_bookViews ) );
+}
+
+static void lcl_AddCalcPr( XclExpRecordList<>& aRecList, ExcTable& self )
+{
+ ScDocument& rDoc = self.GetDoc();
+
+ aRecList.AppendNewRecord( new XclExpXmlStartSingleElementRecord( XML_calcPr ) );
+ // OOXTODO: calcCompleted, calcId, calcMode, calcOnSave,
+ // concurrentCalc, concurrentManualCount,
+ // forceFullCalc, fullCalcOnLoad, fullPrecision
+ aRecList.AppendNewRecord( new XclCalccount( rDoc ) );
+ aRecList.AppendNewRecord( new XclRefmode( rDoc ) );
+ aRecList.AppendNewRecord( new XclIteration( rDoc ) );
+ aRecList.AppendNewRecord( new XclDelta( rDoc ) );
+ aRecList.AppendNewRecord( new XclExpBoolRecord(0x005F, true) ); // SAVERECALC
+ aRecList.AppendNewRecord( new XclExpXmlEndSingleElementRecord() ); // XML_calcPr
+}
+
+static void lcl_AddWorkbookProtection( XclExpRecordList<>& aRecList, ExcTable& self )
+{
+ aRecList.AppendNewRecord( new XclExpXmlStartSingleElementRecord( XML_workbookProtection ) );
+
+ const ScDocProtection* pProtect = self.GetDoc().GetDocProtection();
+ if (pProtect && pProtect->isProtected())
+ {
+ aRecList.AppendNewRecord( new XclExpWindowProtection(pProtect->isOptionEnabled(ScDocProtection::WINDOWS)) );
+ aRecList.AppendNewRecord( new XclExpProtection(pProtect->isOptionEnabled(ScDocProtection::STRUCTURE)) );
+ aRecList.AppendNewRecord( new XclExpPassHash(pProtect->getPasswordHash(PASSHASH_XL)) );
+ }
+
+ aRecList.AppendNewRecord( new XclExpXmlEndSingleElementRecord() ); // XML_workbookProtection
+}
+
+static void lcl_AddScenariosAndFilters( XclExpRecordList<>& aRecList, const XclExpRoot& rRoot, SCTAB nScTab )
+{
+ // Scenarios
+ aRecList.AppendNewRecord( new ExcEScenarioManager( rRoot, nScTab ) );
+ // filter
+ aRecList.AppendRecord( rRoot.GetFilterManager().CreateRecord( nScTab ) );
+}
+
+
+ExcTable::ExcTable( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mnScTab( SCTAB_GLOBAL ),
+ nExcTab( EXC_NOTAB ),
+ pTabNames( new NameBuffer( 0, 16 ) )
+{
+}
+
+
+ExcTable::ExcTable( const XclExpRoot& rRoot, SCTAB nScTab ) :
+ XclExpRoot( rRoot ),
+ mnScTab( nScTab ),
+ nExcTab( rRoot.GetTabInfo().GetXclTab( nScTab ) ),
+ pTabNames( new NameBuffer( 0, 16 ) )
+{
+}
+
+
+ExcTable::~ExcTable()
+{
+ delete pTabNames;
+}
+
+
+void ExcTable::Add( XclExpRecordBase* pRec )
+{
+ DBG_ASSERT( pRec, "-ExcTable::Add(): pRec ist NULL!" );
+ aRecList.AppendNewRecord( pRec );
+}
+
+
+void ExcTable::FillAsHeader( ExcBoundsheetList& rBoundsheetList )
+{
+ InitializeGlobals();
+
+ RootData& rR = GetOldRoot();
+ ScDocument& rDoc = GetDoc();
+ XclExpTabInfo& rTabInfo = GetTabInfo();
+
+ if ( GetBiff() <= EXC_BIFF5 )
+ Add( new ExcBofW );
+ else
+ Add( new ExcBofW8 );
+
+ SCTAB nC;
+ String aTmpString;
+ SCTAB nScTabCount = rTabInfo.GetScTabCount();
+ sal_uInt16 nExcTabCount = rTabInfo.GetXclTabCount();
+ sal_uInt16 nCodenames = static_cast< sal_uInt16 >( GetExtDocOptions().GetCodeNameCount() );
+
+ SfxObjectShell* pShell = GetDocShell();
+ sal_uInt16 nWriteProtHash = pShell ? pShell->GetModifyPasswordHash() : 0;
+ bool bRecommendReadOnly = pShell && pShell->IsLoadReadonly();
+
+ if( (nWriteProtHash > 0) || bRecommendReadOnly )
+ Add( new XclExpEmptyRecord( EXC_ID_WRITEPROT ) );
+
+ // TODO: correct codepage for BIFF5?
+ sal_uInt16 nCodePage = XclTools::GetXclCodePage( (GetBiff() <= EXC_BIFF5) ? RTL_TEXTENCODING_MS_1252 : RTL_TEXTENCODING_UNICODE );
+
+ if( GetBiff() <= EXC_BIFF5 )
+ {
+ Add( new XclExpEmptyRecord( EXC_ID_INTERFACEHDR ) );
+ Add( new XclExpUInt16Record( EXC_ID_MMS, 0 ) );
+ Add( new XclExpEmptyRecord( EXC_ID_TOOLBARHDR ) );
+ Add( new XclExpEmptyRecord( EXC_ID_TOOLBAREND ) );
+ Add( new XclExpEmptyRecord( EXC_ID_INTERFACEEND ) );
+ Add( new ExcDummy_00 );
+ }
+ else
+ {
+ if( IsDocumentEncrypted() )
+ Add( new XclExpFileEncryption( GetRoot() ) );
+ Add( new XclExpInterfaceHdr( nCodePage ) );
+ Add( new XclExpUInt16Record( EXC_ID_MMS, 0 ) );
+ Add( new XclExpInterfaceEnd );
+ Add( new XclExpWriteAccess );
+ }
+
+ Add( new XclExpFileSharing( GetRoot(), nWriteProtHash, bRecommendReadOnly ) );
+ Add( new XclExpUInt16Record( EXC_ID_CODEPAGE, nCodePage ) );
+
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ Add( new XclExpBoolRecord( EXC_ID_DSF, false ) );
+ Add( new XclExpEmptyRecord( EXC_ID_XL9FILE ) );
+ rR.pTabId = new XclExpChTrTabId( Max( nExcTabCount, nCodenames ) );
+ Add( rR.pTabId );
+ if( HasVbaStorage() )
+ {
+ Add( new XclObproj );
+ const String& rCodeName = GetExtDocOptions().GetDocSettings().maGlobCodeName;
+ if( rCodeName.Len() )
+ Add( new XclCodename( rCodeName ) );
+ }
+ }
+
+ Add( new XclExpUInt16Record( EXC_ID_FNGROUPCOUNT, 14 ) );
+
+ // erst Namen- und Tabellen-Eintraege aufbauen
+ String aName;
+
+ for( nC = 0 ; nC < nScTabCount ; nC++ )
+ if( rTabInfo.IsExportTab( nC ) )
+ {
+ rDoc.GetName( nC, aTmpString );
+ *pTabNames << aTmpString;
+ }
+
+ if ( GetBiff() <= EXC_BIFF5 )
+ {
+ // global link table: EXTERNCOUNT, EXTERNSHEET, NAME
+ aRecList.AppendRecord( CreateRecord( EXC_ID_EXTERNSHEET ) );
+ aRecList.AppendRecord( CreateRecord( EXC_ID_NAME ) );
+ }
+
+ // document protection options
+ if( GetOutput() == EXC_OUTPUT_BINARY )
+ {
+ lcl_AddWorkbookProtection( aRecList, *this );
+
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ Add( new XclExpProt4Rev );
+ Add( new XclExpProt4RevPass );
+ }
+
+ lcl_AddBookviews( aRecList, *this );
+ }
+
+ Add( new XclExpXmlStartSingleElementRecord( XML_workbookPr ) );
+ if ( GetBiff() == EXC_BIFF8 && GetOutput() != EXC_OUTPUT_BINARY )
+ {
+ Add( new XclExpBoolRecord(0x0040, false, XML_backupFile ) ); // BACKUP
+ Add( new XclExpBoolRecord(0x008D, false, XML_showObjects ) ); // HIDEOBJ
+ }
+
+ if ( GetBiff() == EXC_BIFF8 )
+ {
+ Add( new XclExpBoolRecord(0x0040, false) ); // BACKUP
+ Add( new XclExpBoolRecord(0x008D, false) ); // HIDEOBJ
+ }
+
+ if( GetBiff() <= EXC_BIFF5 )
+ {
+ Add( new ExcDummy_040 );
+ Add( new Exc1904( rDoc ) );
+ Add( new ExcDummy_041 );
+ }
+ else
+ {
+ // BIFF8
+ Add( new Exc1904( rDoc ) );
+ Add( new XclExpBoolRecord( 0x000E, !rDoc.GetDocOptions().IsCalcAsShown() ) );
+ Add( new XclExpBoolRecord(0x01B7, false) ); // REFRESHALL
+ Add( new XclExpBoolRecord(0x00DA, false) ); // BOOKBOOL
+ // OOXTODO: The following /workbook/workbookPr attributes are mapped
+ // to various BIFF records that are not currently supported:
+ //
+ // XML_allowRefreshQuery: QSISTAG 802h: fEnableRefresh
+ // XML_autoCompressPictures: COMPRESSPICTURES 89Bh: fAutoCompressPictures
+ // XML_checkCompatibility: COMPAT12 88Ch: fNoCompatChk
+ // XML_codeName: "Calc"
+ // XML_defaultThemeVersion: ???
+ // XML_filterPrivacy: BOOKEXT 863h: fFilterPrivacy
+ // XML_hidePivotFieldList: BOOKBOOL DAh: fHidePivotTableFList
+ // XML_promptedSolutions: BOOKEXT 863h: fBuggedUserAboutSolution
+ // XML_publishItems: NAMEPUBLISH 893h: fPublished
+ // XML_saveExternalLinkValues: BOOKBOOL DAh: fNoSavSupp
+ // XML_showBorderUnselectedTables: BOOKBOOL DAh: fHideBorderUnsels
+ // XML_showInkAnnotation: BOOKEXT 863h: fShowInkAnnotation
+ // XML_showPivotChart: PIVOTCHARTBITS 859h: fGXHide??
+ // XML_updateLinks: BOOKBOOL DAh: grbitUpdateLinks
+ }
+ Add( new XclExpXmlEndSingleElementRecord() ); // XML_workbookPr
+
+ // Formatting: FONT, FORMAT, XF, STYLE, PALETTE
+ if( GetOutput() != EXC_OUTPUT_BINARY )
+ {
+ aRecList.AppendNewRecord( new XclExpXmlStyleSheet( *this ) );
+ }
+ else
+ {
+ aRecList.AppendRecord( CreateRecord( EXC_ID_FONTLIST ) );
+ aRecList.AppendRecord( CreateRecord( EXC_ID_FORMATLIST ) );
+ aRecList.AppendRecord( CreateRecord( EXC_ID_XFLIST ) );
+ aRecList.AppendRecord( CreateRecord( EXC_ID_PALETTE ) );
+ }
+
+
+ if( GetBiff() <= EXC_BIFF5 )
+ {
+ // Bundlesheet
+ for( nC = 0 ; nC < nScTabCount ; nC++ )
+ if( rTabInfo.IsExportTab( nC ) )
+ {
+ ExcBoundsheetList::RecordRefType xBoundsheet( new ExcBundlesheet( rR, nC ) );
+ aRecList.AppendRecord( xBoundsheet );
+ rBoundsheetList.AppendRecord( xBoundsheet );
+ }
+ }
+ else
+ {
+ // Pivot Cache
+ GetPivotTableManager().CreatePivotTables();
+ aRecList.AppendRecord( GetPivotTableManager().CreatePivotCachesRecord() );
+
+ // Change tracking
+ if( rDoc.GetChangeTrack() )
+ {
+ rR.pUserBViewList = new XclExpUserBViewList( *rDoc.GetChangeTrack() );
+ Add( rR.pUserBViewList );
+ }
+
+ // Natural Language Formulas Flag
+ aRecList.AppendNewRecord( new XclExpBoolRecord( EXC_ID_USESELFS, GetDoc().GetDocOptions().IsLookUpColRowNames() ) );
+
+ if( GetOutput() != EXC_OUTPUT_BINARY )
+ {
+ lcl_AddWorkbookProtection( aRecList, *this );
+ lcl_AddBookviews( aRecList, *this );
+ }
+
+ // Bundlesheet
+ aRecList.AppendNewRecord( new XclExpXmlStartElementRecord( XML_sheets ) );
+ for( nC = 0 ; nC < nScTabCount ; nC++ )
+ if( rTabInfo.IsExportTab( nC ) )
+ {
+ ExcBoundsheetList::RecordRefType xBoundsheet( new ExcBundlesheet8( rR, nC ) );
+ aRecList.AppendRecord( xBoundsheet );
+ rBoundsheetList.AppendRecord( xBoundsheet );
+ }
+ aRecList.AppendNewRecord( new XclExpXmlEndElementRecord( XML_sheets ) );
+
+ for( SCTAB nAdd = 0; nC < static_cast<SCTAB>(nCodenames) ; nC++, nAdd++ )
+ {
+ aTmpString = lcl_GetVbaTabName( nAdd );
+ ExcBoundsheetList::RecordRefType xBoundsheet( new ExcBundlesheet8( aTmpString ) );
+ aRecList.AppendRecord( xBoundsheet );
+ rBoundsheetList.AppendRecord( xBoundsheet );
+ }
+
+ // COUNTRY - in BIFF8 in workbook globals
+ Add( new XclExpCountry( GetRoot() ) );
+ // link table: SUPBOOK, XCT, CRN, EXTERNNAME, EXTERNSHEET, NAME
+ aRecList.AppendRecord( CreateRecord( EXC_ID_EXTERNSHEET ) );
+ aRecList.AppendRecord( CreateRecord( EXC_ID_NAME ) );
+
+ if( GetOutput() != EXC_OUTPUT_BINARY )
+ lcl_AddCalcPr( aRecList, *this );
+
+ Add( new XclExpRecalcId );
+
+ // MSODRAWINGGROUP per-document data
+ aRecList.AppendRecord( GetObjectManager().CreateDrawingGroup() );
+ // Shared string table: SST, EXTSST
+ aRecList.AppendRecord( CreateRecord( EXC_ID_SST ) );
+
+ Add( new XclExpBookExt );
+ }
+
+ Add( new ExcEof );
+}
+
+
+void ExcTable::FillAsTable( SCTAB nCodeNameIdx )
+{
+ InitializeTable( mnScTab );
+
+ RootData& rR = GetOldRoot();
+ XclBiff eBiff = GetBiff();
+ ScDocument& rDoc = GetDoc();
+
+ DBG_ASSERT( (mnScTab >= 0L) && (mnScTab <= MAXTAB), "-ExcTable::Table(): mnScTab - no ordinary table!" );
+ DBG_ASSERT( nExcTab <= static_cast<sal_uInt16>(MAXTAB), "-ExcTable::Table(): nExcTab - no ordinary table!" );
+
+ // create a new OBJ list for this sheet (may be used by notes, autofilter, data validation)
+ if( eBiff == EXC_BIFF8 )
+ GetObjectManager().StartSheet();
+
+ // cell table: DEFROWHEIGHT, DEFCOLWIDTH, COLINFO, DIMENSIONS, ROW, cell records
+ mxCellTable.reset( new XclExpCellTable( GetRoot() ) );
+
+ if( GetOutput() != EXC_OUTPUT_BINARY )
+ {
+ FillAsXmlTable( nCodeNameIdx );
+ return;
+ }
+
+
+ // WSBOOL needs data from page settings, create it here, add it later
+ boost::shared_ptr< XclExpPageSettings > xPageSett( new XclExpPageSettings( GetRoot() ) );
+ bool bFitToPages = xPageSett->GetPageData().mbFitToPages;
+
+ if( eBiff <= EXC_BIFF5 )
+ {
+ Add( new ExcBof );
+ Add( new ExcDummy_02a );
+ }
+ else
+ {
+ Add( new ExcBof8 );
+ lcl_AddCalcPr( aRecList, *this );
+ }
+
+ // GUTS (count & size of outline icons)
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_GUTS ) );
+ // DEFROWHEIGHT, created by the cell table
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID2_DEFROWHEIGHT ) );
+
+ // COUNTRY - in BIFF5/7 in every worksheet
+ if( eBiff <= EXC_BIFF5 )
+ Add( new XclExpCountry( GetRoot() ) );
+
+ Add( new XclExpWsbool( bFitToPages ) );
+
+ // page settings (SETUP and various other records)
+ aRecList.AppendRecord( xPageSett );
+
+ const ScTableProtection* pTabProtect = rDoc.GetTabProtection(mnScTab);
+ if (pTabProtect && pTabProtect->isProtected())
+ {
+ Add( new XclExpProtection(true) );
+ Add( new XclExpBoolRecord(0x00DD, pTabProtect->isOptionEnabled(ScTableProtection::SCENARIOS)) );
+ Add( new XclExpBoolRecord(0x0063, pTabProtect->isOptionEnabled(ScTableProtection::OBJECTS)) );
+ Add( new XclExpPassHash(pTabProtect->getPasswordHash(PASSHASH_XL)) );
+ }
+
+ // local link table: EXTERNCOUNT, EXTERNSHEET
+ if( eBiff <= EXC_BIFF5 )
+ aRecList.AppendRecord( CreateRecord( EXC_ID_EXTERNSHEET ) );
+
+ if ( eBiff == EXC_BIFF8 )
+ lcl_AddScenariosAndFilters( aRecList, GetRoot(), mnScTab );
+
+ // cell table: DEFCOLWIDTH, COLINFO, DIMENSIONS, ROW, cell records
+ aRecList.AppendRecord( mxCellTable );
+
+ // MERGEDCELLS record, generated by the cell table
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_MERGEDCELLS ) );
+ // label ranges
+ if( eBiff == EXC_BIFF8 )
+ Add( new XclExpLabelranges( GetRoot() ) );
+ // data validation (DVAL and list of DV records), generated by the cell table
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_DVAL ) );
+
+ if( eBiff == EXC_BIFF8 )
+ {
+ // all MSODRAWING and OBJ stuff of this sheet goes here
+ aRecList.AppendRecord( GetObjectManager().ProcessDrawing( GetSdrPage( mnScTab ) ) );
+ // pivot tables
+ aRecList.AppendRecord( GetPivotTableManager().CreatePivotTablesRecord( mnScTab ) );
+ }
+
+ // list of NOTE records, generated by the cell table
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_NOTE ) );
+
+ // sheet view settings: WINDOW2, SCL, PANE, SELECTION
+ aRecList.AppendNewRecord( new XclExpTabViewSettings( GetRoot(), mnScTab ) );
+
+ if( eBiff == EXC_BIFF8 )
+ {
+ // sheet protection options
+ Add( new XclExpSheetProtectOptions( GetRoot(), mnScTab ) );
+
+ // web queries
+ Add( new XclExpWebQueryBuffer( GetRoot() ) );
+
+ // conditional formats
+ Add( new XclExpCondFormatBuffer( GetRoot() ) );
+
+ if( HasVbaStorage() )
+ if( nCodeNameIdx < GetExtDocOptions().GetCodeNameCount() )
+ Add( new XclCodename( GetExtDocOptions().GetCodeName( nCodeNameIdx ) ) );
+ }
+
+ // list of HLINK records, generated by the cell table
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_HLINK ) );
+
+ // change tracking
+ if( rR.pUserBViewList )
+ {
+ for( const XclExpUserBView* pBView = rR.pUserBViewList->First(); pBView; pBView = rR.pUserBViewList->Next() )
+ {
+ Add( new XclExpUsersViewBegin( pBView->GetGUID(), nExcTab ) );
+ Add( new XclExpUsersViewEnd );
+ }
+ }
+
+ // EOF
+ Add( new ExcEof );
+}
+
+void ExcTable::FillAsXmlTable( SCTAB nCodeNameIdx )
+{
+ RootData& rR = GetOldRoot();
+
+ // WSBOOL needs data from page settings, create it here, add it later
+ boost::shared_ptr< XclExpPageSettings > xPageSett( new XclExpPageSettings( GetRoot() ) );
+ bool bFitToPages = xPageSett->GetPageData().mbFitToPages;
+
+ Add( new ExcBof8 );
+
+ Add( new XclExpWsbool( bFitToPages, mnScTab, &GetFilterManager() ) );
+
+ // GUTS (count & size of outline icons)
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_GUTS ) );
+ // DEFROWHEIGHT, created by the cell table
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID2_DEFROWHEIGHT ) );
+
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID3_DIMENSIONS ) );
+
+ // sheet view settings: WINDOW2, SCL, PANE, SELECTION
+ aRecList.AppendNewRecord( new XclExpTabViewSettings( GetRoot(), mnScTab ) );
+
+ // cell table: DEFCOLWIDTH, COLINFO, DIMENSIONS, ROW, cell records
+ aRecList.AppendRecord( mxCellTable );
+
+ // label ranges
+ Add( new XclExpLabelranges( GetRoot() ) );
+
+ // DFF not needed in MSOOXML export
+// GetObjectManager().AddSdrPage();
+// //! close Escher group shape and ESCHER_DgContainer
+// //! opened by XclExpObjList ctor MSODRAWING
+// rR.pObjRecs->EndSheet();
+// // all MSODRAWING and OBJ stuff of this sheet goes here
+// Add( rR.pObjRecs );
+
+ // pivot tables
+ aRecList.AppendRecord( GetPivotTableManager().CreatePivotTablesRecord( mnScTab ) );
+
+ // list of NOTE records, generated by the cell table
+ XclExpRecordRef xNotes = mxCellTable->CreateRecord( EXC_ID_NOTE );
+ XclExpRecordList< XclExpNote >* xNoteList = dynamic_cast< XclExpRecordList< XclExpNote >* >( xNotes.get() );
+ if( xNoteList != NULL )
+ aRecList.AppendNewRecord( new XclExpComments( mnScTab, *xNoteList ) );
+
+ // web queries
+ Add( new XclExpWebQueryBuffer( GetRoot() ) );
+
+ lcl_AddScenariosAndFilters( aRecList, GetRoot(), mnScTab );
+
+ // MERGEDCELLS record, generated by the cell table
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_MERGEDCELLS ) );
+
+ // conditional formats
+ Add( new XclExpCondFormatBuffer( GetRoot() ) );
+
+ if( HasVbaStorage() )
+ if( nCodeNameIdx < GetExtDocOptions().GetCodeNameCount() )
+ Add( new XclCodename( GetExtDocOptions().GetCodeName( nCodeNameIdx ) ) );
+
+ // data validation (DVAL and list of DV records), generated by the cell table
+ aRecList.AppendRecord( mxCellTable->CreateRecord( EXC_ID_DVAL ) );
+
+ // list of HLINK records, generated by the cell table
+ XclExpRecordRef xHyperlinks = mxCellTable->CreateRecord( EXC_ID_HLINK );
+ XclExpHyperlinkList* xHyperlinkList = dynamic_cast<XclExpHyperlinkList*>(xHyperlinks.get());
+ if( xHyperlinkList != NULL && !xHyperlinkList->IsEmpty() )
+ {
+ aRecList.AppendNewRecord( new XclExpXmlStartElementRecord( XML_hyperlinks ) );
+ aRecList.AppendRecord( xHyperlinks );
+ aRecList.AppendNewRecord( new XclExpXmlEndElementRecord( XML_hyperlinks ) );
+ }
+
+ aRecList.AppendRecord( xPageSett );
+
+ // change tracking
+ if( rR.pUserBViewList )
+ {
+ for( const XclExpUserBView* pBView = rR.pUserBViewList->First(); pBView; pBView = rR.pUserBViewList->Next() )
+ {
+ Add( new XclExpUsersViewBegin( pBView->GetGUID(), nExcTab ) );
+ Add( new XclExpUsersViewEnd );
+ }
+ }
+
+ // all MSODRAWING and OBJ stuff of this sheet goes here
+ aRecList.AppendRecord( GetObjectManager().ProcessDrawing( GetSdrPage( mnScTab ) ) );
+
+ // EOF
+ Add( new ExcEof );
+}
+
+
+void ExcTable::FillAsEmptyTable( SCTAB nCodeNameIdx )
+{
+ InitializeTable( mnScTab );
+
+ if( HasVbaStorage() && (nCodeNameIdx < GetExtDocOptions().GetCodeNameCount()) )
+ {
+ if( GetBiff() <= EXC_BIFF5 )
+ {
+ Add( new ExcBof );
+ }
+ else
+ {
+ Add( new ExcBof8 );
+ Add( new XclCodename( GetExtDocOptions().GetCodeName( nCodeNameIdx ) ) );
+ }
+ // sheet view settings: WINDOW2, SCL, PANE, SELECTION
+ aRecList.AppendNewRecord( new XclExpTabViewSettings( GetRoot(), mnScTab ) );
+ Add( new ExcEof );
+ }
+}
+
+
+void ExcTable::Write( XclExpStream& rStrm )
+{
+ SetCurrScTab( mnScTab );
+ if( mxCellTable.get() )
+ mxCellTable->Finalize();
+ aRecList.Save( rStrm );
+}
+
+
+void ExcTable::WriteXml( XclExpXmlStream& rStrm )
+{
+ if (GetTabInfo().IsExportTab( mnScTab ) )
+ {
+ // worksheet export
+ String sSheetName = XclXmlUtils::GetStreamName( "xl/", "worksheets/sheet", mnScTab+1 );
+
+ sax_fastparser::FSHelperPtr pWorksheet = rStrm.GetStreamForPath( sSheetName );
+
+ rStrm.PushStream( pWorksheet );
+
+ pWorksheet->startElement( XML_worksheet,
+ XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
+ FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
+ FSEND );
+ }
+
+ SetCurrScTab( mnScTab );
+ if( mxCellTable.get() )
+ mxCellTable->Finalize();
+ aRecList.SaveXml( rStrm );
+
+ if (GetTabInfo().IsExportTab( mnScTab ) )
+ {
+ rStrm.GetCurrentStream()->endElement( XML_worksheet );
+ rStrm.PopStream();
+ }
+}
+
+
+ExcDocument::ExcDocument( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ aHeader( rRoot ),
+ pExpChangeTrack( NULL )
+{
+}
+
+
+ExcDocument::~ExcDocument()
+{
+ maTableList.RemoveAllRecords(); //! for the following assertion
+ delete pExpChangeTrack;
+}
+
+
+void ExcDocument::ReadDoc( void )
+{
+ InitializeConvert();
+
+ aHeader.FillAsHeader( maBoundsheetList );
+
+ SCTAB nScTab = 0, nScTabCount = GetTabInfo().GetScTabCount();
+ SCTAB nCodeNameIdx = 0, nCodeNameCount = GetExtDocOptions().GetCodeNameCount();
+
+ for( ; nScTab < nScTabCount; ++nScTab )
+ {
+ if( GetTabInfo().IsExportTab( nScTab ) )
+ {
+ ExcTableList::RecordRefType xTab( new ExcTable( GetRoot(), nScTab ) );
+ maTableList.AppendRecord( xTab );
+ xTab->FillAsTable( nCodeNameIdx );
+ ++nCodeNameIdx;
+ }
+ }
+ for( ; nCodeNameIdx < nCodeNameCount; ++nScTab, ++nCodeNameIdx )
+ {
+ ExcTableList::RecordRefType xTab( new ExcTable( GetRoot(), nScTab ) );
+ maTableList.AppendRecord( xTab );
+ xTab->FillAsEmptyTable( nCodeNameIdx );
+ }
+
+ if ( GetBiff() == EXC_BIFF8 )
+ {
+ // complete temporary Escher stream
+ GetObjectManager().EndDocument();
+
+ // change tracking
+ if ( GetDoc().GetChangeTrack() )
+ pExpChangeTrack = new XclExpChangeTrack( GetRoot() );
+ }
+}
+
+
+void ExcDocument::Write( SvStream& rSvStrm )
+{
+ if( !maTableList.IsEmpty() )
+ {
+ InitializeSave();
+
+ XclExpStream aXclStrm( rSvStrm, GetRoot() );
+
+ aHeader.Write( aXclStrm );
+
+ OSL_ENSURE( maTableList.GetSize() == maBoundsheetList.GetSize(),
+ "ExcDocument::Write - different number of sheets and BOUNDSHEET records" );
+
+ for( size_t nTab = 0, nTabCount = maTableList.GetSize(); nTab < nTabCount; ++nTab )
+ {
+ // set current stream position in BOUNDSHEET record
+ ExcBoundsheetRef xBoundsheet = maBoundsheetList.GetRecord( nTab );
+ if( xBoundsheet.get() )
+ xBoundsheet->SetStreamPos( aXclStrm.GetSvStreamPos() );
+ // write the table
+ maTableList.GetRecord( nTab )->Write( aXclStrm );
+ }
+
+ // write the table stream positions into the BOUNDSHEET records
+ for( size_t nBSheet = 0, nBSheetCount = maBoundsheetList.GetSize(); nBSheet < nBSheetCount; ++nBSheet )
+ maBoundsheetList.GetRecord( nBSheet )->UpdateStreamPos( aXclStrm );
+ }
+ if( pExpChangeTrack )
+ pExpChangeTrack->Write();
+}
+
+void ExcDocument::WriteXml( XclExpXmlStream& rStrm )
+{
+ SfxObjectShell* pDocShell = GetDocShell();
+
+ using namespace ::com::sun::star;
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
+ uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
+
+ rStrm.exportDocumentProperties( xDocProps );
+
+ sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
+ rWorkbook->startElement( XML_workbook,
+ XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
+ FSNS(XML_xmlns, XML_r), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
+ FSEND );
+ rWorkbook->singleElement( XML_fileVersion,
+ XML_appName, "Calc",
+ // OOXTODO: XML_codeName
+ // OOXTODO: XML_lastEdited
+ // OOXTODO: XML_lowestEdited
+ // OOXTODO: XML_rupBuild
+ FSEND );
+
+ if( !maTableList.IsEmpty() )
+ {
+ InitializeSave();
+
+ aHeader.WriteXml( rStrm );
+
+ for( size_t nTab = 0, nTabCount = maTableList.GetSize(); nTab < nTabCount; ++nTab )
+ {
+ // write the table
+ maTableList.GetRecord( nTab )->WriteXml( rStrm );
+ }
+ }
+
+ if( pExpChangeTrack )
+ pExpChangeTrack->WriteXml( rStrm );
+
+ rWorkbook->endElement( XML_workbook );
+ rWorkbook.reset();
+
+ rStrm.commitStorage();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/excel.cxx b/sc/source/filter/excel/excel.cxx
new file mode 100644
index 000000000000..4bd3654caa64
--- /dev/null
+++ b/sc/source/filter/excel/excel.cxx
@@ -0,0 +1,298 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/request.hxx>
+#include <sot/storage.hxx>
+#include <sot/exchange.hxx>
+#include <tools/globname.hxx>
+#include <comphelper/mediadescriptor.hxx>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include "scitems.hxx"
+#include <svl/stritem.hxx>
+#include "filter.hxx"
+#include "document.hxx"
+#include "xistream.hxx"
+
+#include "scerrors.hxx"
+#include "root.hxx"
+#include "imp_op.hxx"
+#include "excimp8.hxx"
+#include "exp_op.hxx"
+
+
+FltError ScFormatFilterPluginImpl::ScImportExcel( SfxMedium& rMedium, ScDocument* pDocument, const EXCIMPFORMAT eFormat )
+{
+ // check the passed Calc document
+ DBG_ASSERT( pDocument, "::ScImportExcel - no document" );
+ if( !pDocument ) return eERR_INTERN; // should not happen
+
+ /* Import all BIFF versions regardless on eFormat, needed for import of
+ external cells (file type detection returns Excel4.0). */
+ if( (eFormat != EIF_AUTO) && (eFormat != EIF_BIFF_LE4) && (eFormat != EIF_BIFF5) && (eFormat != EIF_BIFF8) )
+ {
+ DBG_ERRORFILE( "::ScImportExcel - wrong file format specification" );
+ return eERR_FORMAT;
+ }
+
+ // check the input stream from medium
+ SvStream* pMedStrm = rMedium.GetInStream();
+ DBG_ASSERT( pMedStrm, "::ScImportExcel - medium without input stream" );
+ if( !pMedStrm ) return eERR_OPEN; // should not happen
+
+#if OSL_DEBUG_LEVEL > 0
+ using namespace ::com::sun::star;
+ using namespace ::comphelper;
+
+ /* Environment variable "OOO_OOXBIFFFILTER":
+ - "1" = use new OOX filter for import;
+ - undef/other = use old sc filter for import (OOX only as file dumper). */
+ const sal_Char* pcFileName = ::getenv( "OOO_OOXBIFFFILTER" );
+ bool bUseOoxFilter = pcFileName && (*pcFileName == '1') && (*(pcFileName + 1) == 0);
+ if( SfxObjectShell* pDocShell = pDocument->GetDocumentShell() ) try
+ {
+ uno::Reference< lang::XComponent > xComponent( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
+
+ uno::Sequence< beans::NamedValue > aArgSeq( 1 );
+ aArgSeq[ 0 ].Name = CREATE_OUSTRING( "UseBiffFilter" );
+ aArgSeq[ 0 ].Value <<= bUseOoxFilter;
+
+ uno::Sequence< uno::Any > aArgs( 2 );
+ aArgs[ 0 ] <<= getProcessServiceFactory();
+ aArgs[ 1 ] <<= aArgSeq;
+ uno::Reference< document::XImporter > xImporter( ScfApiHelper::CreateInstanceWithArgs(
+ CREATE_OUSTRING( "com.sun.star.comp.oox.xls.ExcelBiffFilter" ), aArgs ), uno::UNO_QUERY_THROW );
+ xImporter->setTargetDocument( xComponent );
+
+ MediaDescriptor aMediaDesc;
+ SfxItemSet* pItemSet = rMedium.GetItemSet();
+ if( pItemSet )
+ {
+ SFX_ITEMSET_ARG( pItemSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, false);
+ if( pFileNameItem )
+ aMediaDesc[ MediaDescriptor::PROP_URL() ] <<= ::rtl::OUString( pFileNameItem->GetValue() );
+
+ SFX_ITEMSET_ARG( pItemSet, pPasswordItem, SfxStringItem, SID_PASSWORD, false);
+ if( pPasswordItem )
+ aMediaDesc[ MediaDescriptor::PROP_PASSWORD() ] <<= ::rtl::OUString( pPasswordItem->GetValue() );
+
+ SFX_ITEMSET_ARG( pItemSet, pEncryptionDataItem, SfxUnoAnyItem, SID_ENCRYPTIONDATA, false);
+ if( pEncryptionDataItem )
+ aMediaDesc[ MediaDescriptor::PROP_ENCRYPTIONDATA() ] = pEncryptionDataItem->GetValue();
+ }
+ aMediaDesc[ MediaDescriptor::PROP_INPUTSTREAM() ] <<= rMedium.GetInputStream();
+ aMediaDesc[ MediaDescriptor::PROP_INTERACTIONHANDLER() ] <<= rMedium.GetInteractionHandler();
+
+ // call the filter
+ uno::Reference< document::XFilter > xFilter( xImporter, uno::UNO_QUERY_THROW );
+ bool bResult = xFilter->filter( aMediaDesc.getAsConstPropertyValueList() );
+
+ // if filter returns false, document is invalid, or dumper has disabled import -> exit here
+ if( !bResult )
+ return ERRCODE_ABORT;
+
+ // if OOX filter has been used, exit with OK code
+ if( bUseOoxFilter )
+ return eERR_OK;
+ }
+ catch( uno::Exception& )
+ {
+ if( bUseOoxFilter )
+ return ERRCODE_ABORT;
+ // else ignore exception and import the document with this filter
+ }
+#endif
+
+ SvStream* pBookStrm = 0; // The "Book"/"Workbook" stream containing main data.
+ XclBiff eBiff = EXC_BIFF_UNKNOWN; // The BIFF version of the main stream.
+
+ // try to open an OLE storage
+ SotStorageRef xRootStrg;
+ SotStorageStreamRef xStrgStrm;
+ if( SotStorage::IsStorageFile( pMedStrm ) )
+ {
+ xRootStrg = new SotStorage( pMedStrm, false );
+ if( xRootStrg->GetError() )
+ xRootStrg = 0;
+ }
+
+ // try to open "Book" or "Workbook" stream in OLE storage
+ if( xRootStrg.Is() )
+ {
+ // try to open the "Book" stream
+ SotStorageStreamRef xBookStrm = ScfTools::OpenStorageStreamRead( xRootStrg, EXC_STREAM_BOOK );
+ XclBiff eBookBiff = xBookStrm.Is() ? XclImpStream::DetectBiffVersion( *xBookStrm ) : EXC_BIFF_UNKNOWN;
+
+ // try to open the "Workbook" stream
+ SotStorageStreamRef xWorkbookStrm = ScfTools::OpenStorageStreamRead( xRootStrg, EXC_STREAM_WORKBOOK );
+ XclBiff eWorkbookBiff = xWorkbookStrm.Is() ? XclImpStream::DetectBiffVersion( *xWorkbookStrm ) : EXC_BIFF_UNKNOWN;
+
+ // decide which stream to use
+ if( (eWorkbookBiff != EXC_BIFF_UNKNOWN) && ((eBookBiff == EXC_BIFF_UNKNOWN) || (eWorkbookBiff > eBookBiff)) )
+ {
+ /* Only "Workbook" stream exists; or both streams exist,
+ and "Workbook" has higher BIFF version than "Book" stream. */
+ xStrgStrm = xWorkbookStrm;
+ eBiff = eWorkbookBiff;
+ }
+ else if( eBookBiff != EXC_BIFF_UNKNOWN )
+ {
+ /* Only "Book" stream exists; or both streams exist,
+ and "Book" has higher BIFF version than "Workbook" stream. */
+ xStrgStrm = xBookStrm;
+ eBiff = eBookBiff;
+ }
+
+ pBookStrm = xStrgStrm;
+ }
+
+ // no "Book" or "Workbook" stream found, try plain input stream from medium (even for BIFF5+)
+ if( !pBookStrm )
+ {
+ eBiff = XclImpStream::DetectBiffVersion( *pMedStrm );
+ if( eBiff != EXC_BIFF_UNKNOWN )
+ pBookStrm = pMedStrm;
+ }
+
+ // try to import the file
+ FltError eRet = eERR_UNKN_BIFF;
+ if( pBookStrm )
+ {
+ pBookStrm->SetBufferSize( 0x8000 ); // still needed?
+
+ XclImpRootData aImpData( eBiff, rMedium, xRootStrg, *pDocument, RTL_TEXTENCODING_MS_1252 );
+ ::std::auto_ptr< ImportExcel > xFilter;
+ switch( eBiff )
+ {
+ case EXC_BIFF2:
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ case EXC_BIFF5:
+ xFilter.reset( new ImportExcel( aImpData, *pBookStrm ) );
+ break;
+ case EXC_BIFF8:
+ xFilter.reset( new ImportExcel8( aImpData, *pBookStrm ) );
+ break;
+ default: DBG_ERROR_BIFF();
+ }
+
+ eRet = xFilter.get() ? xFilter->Read() : eERR_INTERN;
+ }
+
+ return eRet;
+}
+
+
+static FltError lcl_ExportExcelBiff( SfxMedium& rMedium, ScDocument *pDocument,
+ SvStream* pMedStrm, sal_Bool bBiff8, CharSet eNach )
+{
+ // try to open an OLE storage
+ SotStorageRef xRootStrg = new SotStorage( pMedStrm, false );
+ if( xRootStrg->GetError() ) return eERR_OPEN;
+
+ // create BIFF dependent strings
+ String aStrmName, aClipName, aClassName;
+ if( bBiff8 )
+ {
+ aStrmName = EXC_STREAM_WORKBOOK;
+ aClipName = CREATE_STRING( "Biff8" );
+ aClassName = CREATE_STRING( "Microsoft Excel 97-Tabelle" );
+ }
+ else
+ {
+ aStrmName = EXC_STREAM_BOOK;
+ aClipName = CREATE_STRING( "Biff5" );
+ aClassName = CREATE_STRING( "Microsoft Excel 5.0-Tabelle" );
+ }
+
+ // open the "Book"/"Workbook" stream
+ SotStorageStreamRef xStrgStrm = ScfTools::OpenStorageStreamWrite( xRootStrg, aStrmName );
+ if( !xStrgStrm.Is() || xStrgStrm->GetError() ) return eERR_OPEN;
+
+ xStrgStrm->SetBufferSize( 0x8000 ); // still needed?
+
+ FltError eRet = eERR_UNKN_BIFF;
+ XclExpRootData aExpData( bBiff8 ? EXC_BIFF8 : EXC_BIFF5, rMedium, xRootStrg, *pDocument, eNach );
+ if ( bBiff8 )
+ {
+ ExportBiff8 aFilter( aExpData, *xStrgStrm );
+ eRet = aFilter.Write();
+ }
+ else
+ {
+ ExportBiff5 aFilter( aExpData, *xStrgStrm );
+ eRet = aFilter.Write();
+ }
+
+ if( eRet == eERR_RNGOVRFLW )
+ eRet = SCWARN_EXPORT_MAXROW;
+
+ SvGlobalName aGlobName( 0x00020810, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 );
+ sal_uInt32 nClip = SotExchange::RegisterFormatName( aClipName );
+ xRootStrg->SetClass( aGlobName, nClip, aClassName );
+
+ xStrgStrm->Commit();
+ xRootStrg->Commit();
+
+ return eRet;
+}
+
+FltError ScFormatFilterPluginImpl::ScExportExcel5( SfxMedium& rMedium, ScDocument *pDocument,
+ ExportFormatExcel eFormat, CharSet eNach )
+{
+ if( eFormat != ExpBiff5 && eFormat != ExpBiff8 )
+ return eERR_NI;
+
+ // check the passed Calc document
+ DBG_ASSERT( pDocument, "::ScImportExcel - no document" );
+ if( !pDocument ) return eERR_INTERN; // should not happen
+
+ // check the output stream from medium
+ SvStream* pMedStrm = rMedium.GetOutStream();
+ DBG_ASSERT( pMedStrm, "::ScExportExcel5 - medium without output stream" );
+ if( !pMedStrm ) return eERR_OPEN; // should not happen
+
+ FltError eRet = eERR_UNKN_BIFF;
+ if( eFormat == ExpBiff5 || eFormat == ExpBiff8 )
+ eRet = lcl_ExportExcelBiff( rMedium, pDocument, pMedStrm, eFormat == ExpBiff8, eNach );
+
+ return eRet;
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/excform.cxx b/sc/source/filter/excel/excform.cxx
new file mode 100644
index 000000000000..949cb0fb0615
--- /dev/null
+++ b/sc/source/filter/excel/excform.cxx
@@ -0,0 +1,1944 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "excform.hxx"
+#include <osl/endian.h>
+
+#include "cell.hxx"
+#include "document.hxx"
+#include "rangenam.hxx"
+#include "global.hxx"
+#include "formula/errorcodes.hxx"
+
+#include "imp_op.hxx"
+#include "root.hxx"
+#include "xltracer.hxx"
+#include "xihelper.hxx"
+#include "xilink.hxx"
+#include "xiname.hxx"
+
+using ::std::vector;
+
+const sal_uInt16 ExcelToSc::nRowMask = 0x3FFF;
+const sal_uInt16 ExcelToSc::nLastInd = 399;
+
+
+
+
+void ImportExcel::Formula25()
+{
+ XclAddress aXclPos;
+ sal_uInt16 nXF = 0, nFormLen;
+ double fCurVal;
+ sal_uInt8 nFlag0;
+ sal_Bool bShrFmla;
+
+ aIn >> aXclPos;
+
+ if( GetBiff() == EXC_BIFF2 )
+ {// BIFF2
+ sal_uInt8 nDummy;
+
+ aIn.Ignore( 3 );
+
+ aIn >> fCurVal;
+ aIn.Ignore( 1 );
+ aIn >> nDummy;
+ nFormLen = nDummy;
+ bShrFmla = false;
+ }
+ else
+ {// BIFF5
+ aIn >> nXF >> fCurVal >> nFlag0;
+ aIn.Ignore( 5 );
+
+ aIn >> nFormLen;
+
+ bShrFmla = nFlag0 & 0x08; // shared or not shared
+ }
+
+ nLastXF = nXF;
+
+ Formula( aXclPos, nXF, nFormLen, fCurVal, bShrFmla );
+}
+
+
+void ImportExcel::Formula3()
+{
+ Formula4();
+}
+
+
+void ImportExcel::Formula4()
+{
+ XclAddress aXclPos;
+ sal_uInt16 nXF, nFormLen;
+ double fCurVal;
+ sal_uInt8 nFlag0;
+
+ aIn >> aXclPos >> nXF >> fCurVal >> nFlag0;
+ aIn.Ignore( 1 );
+ aIn >> nFormLen;
+
+ nLastXF = nXF;
+
+ Formula( aXclPos, nXF, nFormLen, fCurVal, false );
+}
+
+
+void ImportExcel::Formula( const XclAddress& rXclPos,
+ sal_uInt16 nXF, sal_uInt16 nFormLen, double& rCurVal, sal_Bool bShrFmla )
+{
+ ConvErr eErr = ConvOK;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, rXclPos, GetCurrScTab(), true ) )
+ {
+ // jetzt steht Lesemarke auf Formel, Laenge in nFormLen
+ const ScTokenArray* pErgebnis = 0;
+ sal_Bool bConvert;
+
+ pFormConv->Reset( aScPos );
+
+ if( bShrFmla )
+ bConvert = !pFormConv->GetShrFmla( pErgebnis, maStrm, nFormLen );
+ else
+ bConvert = sal_True;
+
+ if( bConvert )
+ eErr = pFormConv->Convert( pErgebnis, maStrm, nFormLen, true, FT_CellFormula);
+
+ ScFormulaCell* pZelle = NULL;
+
+ if( pErgebnis )
+ {
+ pZelle = new ScFormulaCell( pD, aScPos, pErgebnis );
+ pD->PutCell( aScPos.Col(), aScPos.Row(), aScPos.Tab(), pZelle, (sal_Bool)sal_True );
+ }
+ else
+ {
+ CellType eCellType;
+ ScBaseCell* pBaseCell;
+ pD->GetCellType( aScPos.Col(), aScPos.Row(), aScPos.Tab(), eCellType );
+ if( eCellType == CELLTYPE_FORMULA )
+ {
+ pD->GetCell( aScPos.Col(), aScPos.Row(), aScPos.Tab(), pBaseCell );
+ pZelle = ( ScFormulaCell* ) pBaseCell;
+ if( pZelle )
+ pZelle->AddRecalcMode( RECALCMODE_ONLOAD_ONCE );
+ }
+ }
+
+ if( pZelle )
+ {
+ if( eErr != ConvOK )
+ ExcelToSc::SetError( *pZelle, eErr );
+ (void)rCurVal;
+ }
+
+ GetXFRangeBuffer().SetXF( aScPos, nXF );
+ }
+}
+
+
+
+
+ExcelToSc::ExcelToSc( const XclImpRoot& rRoot ) :
+ ExcelConverterBase( 512 ),
+ XclImpRoot( rRoot ),
+ maFuncProv( rRoot ),
+ meBiff( rRoot.GetBiff() )
+{
+}
+
+ExcelToSc::~ExcelToSc()
+{
+}
+
+void ExcelToSc::GetDummy( const ScTokenArray*& pErgebnis )
+{
+ aPool.Store( CREATE_STRING( "Dummy()" ) );
+ aPool >> aStack;
+ pErgebnis = aPool[ aStack.Get() ];
+}
+
+
+// if bAllowArrays is false stream seeks to first byte after <nFormulaLen>
+// otherwise it will seek to the first byte after the additional content (eg
+// inline arrays) following <nFormulaLen>
+ConvErr ExcelToSc::Convert( const ScTokenArray*& pErgebnis, XclImpStream& aIn, sal_Size nFormulaLen, bool bAllowArrays, const FORMULA_TYPE eFT )
+{
+ RootData& rR = GetOldRoot();
+ sal_uInt8 nOp, nLen, nByte;
+ sal_uInt16 nUINT16;
+ sal_Int16 nINT16;
+ double fDouble;
+ String aString;
+ sal_Bool bError = false;
+ sal_Bool bArrayFormula = false;
+ TokenId nMerk0;
+ const sal_Bool bRangeName = eFT == FT_RangeName;
+ const sal_Bool bSharedFormula = eFT == FT_SharedFormula;
+ const sal_Bool bRNorSF = bRangeName || bSharedFormula;
+
+ ScSingleRefData aSRD;
+ ScComplexRefData aCRD;
+ ExtensionTypeVec aExtensions;
+
+ bExternName = false;
+
+ if( eStatus != ConvOK )
+ {
+ aIn.Ignore( nFormulaLen );
+ return eStatus;
+ }
+
+ if( nFormulaLen == 0 )
+ {
+ aPool.Store( CREATE_STRING( "-/-" ) );
+ aPool >> aStack;
+ pErgebnis = aPool[ aStack.Get() ];
+ return ConvOK;
+ }
+
+ sal_Size nEndPos = aIn.GetRecPos() + nFormulaLen;
+
+ while( (aIn.GetRecPos() < nEndPos) && !bError )
+ {
+ aIn >> nOp;
+
+ // always reset flags
+ aSRD.InitFlags();
+ aCRD.InitFlags();
+
+ switch( nOp ) // Buch Seite:
+ { // SDK4 SDK5
+ case 0x01: // Array Formula [325 ]
+ // Array Formula or Shared Formula [ 277]
+ case 0x02: // Data Table [325 277]
+ nUINT16 = 3;
+
+ if( meBiff != EXC_BIFF2 )
+ nUINT16++;
+
+ aIn.Ignore( nUINT16 );
+
+ bArrayFormula = sal_True;
+ break;
+ case 0x03: // Addition [312 264]
+ aStack >> nMerk0;
+ aPool << aStack << ocAdd << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x04: // Subtraction [313 264]
+ // SECOMD-TOP minus TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocSub << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x05: // Multiplication [313 264]
+ aStack >> nMerk0;
+ aPool << aStack << ocMul << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x06: // Division [313 264]
+ // divide TOP by SECOND-TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocDiv << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x07: // Exponetiation [313 265]
+ // raise SECOND-TOP to power of TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocPow << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x08: // Concatenation [313 265]
+ // append TOP to SECOND-TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocAmpersand << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x09: // Less Than [313 265]
+ // SECOND-TOP < TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocLess << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0A: // Less Than or Equal [313 265]
+ // SECOND-TOP <= TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocLessEqual << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0B: // Equal [313 265]
+ // SECOND-TOP == TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocEqual << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0C: // Greater Than or Equal [313 265]
+ // SECOND-TOP == TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocGreaterEqual << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0D: // Greater Than [313 265]
+ // SECOND-TOP == TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocGreater << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0E: // Not Equal [313 265]
+ // SECOND-TOP == TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocNotEqual << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0F: // Intersection [314 265]
+ aStack >> nMerk0;
+ aPool << aStack << ocIntersect << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x10: // Union [314 265]
+ // ocSep behelfsweise statt 'ocUnion'
+ aStack >> nMerk0;
+ aPool << aStack << ocSep << nMerk0;
+ // doesn't fit exactly, but is more Excel-like
+ aPool >> aStack;
+ break;
+ case 0x11: // Range [314 265]
+ aStack >> nMerk0;
+ aPool << aStack << ocRange << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x12: // Unary Plus [312 264]
+ aPool << ocAdd << aStack;
+ aPool >> aStack;
+ break;
+ case 0x13: // Unary Minus [312 264]
+ aPool << ocNegSub << aStack;
+ aPool >> aStack;
+ break;
+ case 0x14: // Percent Sign [312 264]
+ aPool << aStack << ocPercentSign;
+ aPool >> aStack;
+ break;
+ case 0x15: // Parenthesis [326 278]
+ aPool << ocOpen << aStack << ocClose;
+ aPool >> aStack;
+ break;
+ case 0x16: // Missing Argument [314 266]
+ aPool << ocMissing;
+ aPool >> aStack;
+ GetTracer().TraceFormulaMissingArg();
+ break;
+ case 0x17: // String Constant [314 266]
+ aIn >> nLen;
+ aString = aIn.ReadRawByteString( nLen );
+
+ aStack << aPool.Store( aString );
+ break;
+ case 0x19: // Special Attribute [327 279]
+ {
+ sal_uInt16 nData, nFakt;
+ sal_uInt8 nOpt;
+
+ aIn >> nOpt;
+
+ if( meBiff == EXC_BIFF2 )
+ {
+ nData = aIn.ReaduInt8();
+ nFakt = 1;
+ }
+ else
+ {
+ aIn >> nData;
+ nFakt = 2;
+ }
+
+ if( nOpt & 0x04 )
+ {// nFakt -> Bytes oder Words ueberlesen AttrChoose
+ nData++;
+ aIn.Ignore( nData * nFakt );
+ }
+ else if( nOpt & 0x10 ) // AttrSum
+ DoMulArgs( ocSum, 1 );
+ }
+ break;
+ case 0x1A: // External Reference [330 ]
+ switch( meBiff )
+ {
+ case EXC_BIFF2: aIn.Ignore( 7 ); break;
+ case EXC_BIFF3:
+ case EXC_BIFF4: aIn.Ignore( 10 ); break;
+ case EXC_BIFF5:
+ DBG_WARNING( "-ExcelToSc::Convert(): 0x1A gibt's nicht in Biff5!" );
+ default:
+ DBG_WARNING( "-ExcelToSc::Convert(): Ein wenig vergesslich, was?" );
+ }
+ break;
+ case 0x1B: // End External Reference [330 ]
+ switch( meBiff )
+ {
+ case EXC_BIFF2: aIn.Ignore( 3 ); break;
+ case EXC_BIFF3:
+ case EXC_BIFF4: aIn.Ignore( 4 ); break;
+ case EXC_BIFF5:
+ DBG_WARNING( "-ExcelToSc::Convert(): 0x1B gibt's nicht in Biff5!" );
+ default:
+ DBG_WARNING( "-ExcelToSc::Convert(): Ein wenig vergesslich, was?" );
+ }
+ break;
+ case 0x1C: // Error Value [314 266]
+ {
+ aIn >> nByte;
+ DefTokenId eOc;
+ switch( nByte )
+ {
+ case EXC_ERR_NULL:
+ case EXC_ERR_DIV0:
+ case EXC_ERR_VALUE:
+ case EXC_ERR_REF:
+ case EXC_ERR_NAME:
+ case EXC_ERR_NUM: eOc = ocStop; break;
+ case EXC_ERR_NA: eOc = ocNotAvail; break;
+ default: eOc = ocNoName;
+ }
+ aPool << eOc;
+ if( eOc != ocStop )
+ aPool << ocOpen << ocClose;
+ aPool >> aStack;
+ }
+ break;
+ case 0x1D: // Boolean [315 266]
+ aIn >> nByte;
+ if( nByte == 0 )
+ aPool << ocFalse << ocOpen << ocClose;
+ else
+ aPool << ocTrue << ocOpen << ocClose;
+ aPool >> aStack;
+ break;
+ case 0x1E: // Integer [315 266]
+ aIn >> nUINT16;
+ aStack << aPool.Store( ( double ) nUINT16 );
+ break;
+ case 0x1F: // Number [315 266]
+ aIn >> fDouble;
+ aStack << aPool.Store( fDouble );
+ break;
+ case 0x40:
+ case 0x60:
+ case 0x20: // Array Constant [317 268]
+ aIn >> nByte >> nUINT16;
+ aIn.Ignore( (meBiff == EXC_BIFF2) ? 3 : 4 );
+ if( bAllowArrays )
+ {
+ aStack << aPool.StoreMatrix();
+ aExtensions.push_back( EXTENSION_ARRAY );
+ }
+ else
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ }
+ break;
+ case 0x41:
+ case 0x61:
+ case 0x21: // Function, Fixed Number of Arguments [333 282]
+ {
+ sal_uInt16 nXclFunc;
+ if( meBiff <= EXC_BIFF3 )
+ nXclFunc = aIn.ReaduInt8();
+ else
+ aIn >> nXclFunc;
+ if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclFunc( nXclFunc ) )
+ DoMulArgs( pFuncInfo->meOpCode, pFuncInfo->mnMaxParamCount );
+ else
+ DoMulArgs( ocNoName, 0 );
+ }
+ break;
+ case 0x42:
+ case 0x62:
+ case 0x22: // Function, Variable Number of Arg. [333 283]
+ {
+ sal_uInt16 nXclFunc;
+ sal_uInt8 nParamCount;
+ aIn >> nParamCount;
+ nParamCount &= 0x7F;
+ if( meBiff <= EXC_BIFF3 )
+ nXclFunc = aIn.ReaduInt8();
+ else
+ aIn >> nXclFunc;
+ if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclFunc( nXclFunc ) )
+ DoMulArgs( pFuncInfo->meOpCode, nParamCount );
+ else
+ DoMulArgs( ocNoName, 0 );
+ }
+ break;
+ case 0x43:
+ case 0x63:
+ case 0x23: // Name [318 269]
+ {
+ aIn >> nUINT16;
+ switch( meBiff )
+ {
+ case EXC_BIFF2: aIn.Ignore( 5 ); break;
+ case EXC_BIFF3:
+ case EXC_BIFF4: aIn.Ignore( 8 ); break;
+ case EXC_BIFF5: aIn.Ignore( 12 ); break;
+ default:
+ OSL_FAIL(
+ "-ExcelToSc::Convert(): Ein wenig vergesslich, was?" );
+ }
+ const XclImpName* pName = GetNameManager().GetName( nUINT16 );
+ if(pName && !pName->GetScRangeData())
+ aStack << aPool.Store( ocMacro, pName->GetXclName() );
+ else
+ aStack << aPool.StoreName(nUINT16, true);
+ }
+ break;
+ case 0x44:
+ case 0x64:
+ case 0x24: // Cell Reference [319 270]
+ case 0x4A:
+ case 0x6A:
+ case 0x2A: // Deleted Cell Reference [323 273]
+ aIn >> nUINT16 >> nByte;
+ aSRD.nCol = static_cast<SCsCOL>(nByte);
+ aSRD.nRow = nUINT16 & 0x3FFF;
+ aSRD.nRelTab = 0;
+ aSRD.SetTabRel( sal_True );
+ aSRD.SetFlag3D( bRangeName );
+
+ ExcRelToScRel( nUINT16, nByte, aSRD, bRangeName );
+
+ switch ( nOp )
+ {
+ case 0x4A:
+ case 0x6A:
+ case 0x2A: // Deleted Cell Reference [323 273]
+ // no information which part is deleted, set both
+ aSRD.SetColDeleted( sal_True );
+ aSRD.SetRowDeleted( sal_True );
+ }
+
+ aStack << aPool.Store( aSRD );
+ break;
+ case 0x45:
+ case 0x65:
+ case 0x25: // Area Reference [320 270]
+ case 0x4B:
+ case 0x6B:
+ case 0x2B: // Deleted Area Refernce [323 273]
+ {
+ sal_uInt16 nRowFirst, nRowLast;
+ sal_uInt8 nColFirst, nColLast;
+ ScSingleRefData& rSRef1 = aCRD.Ref1;
+ ScSingleRefData& rSRef2 = aCRD.Ref2;
+
+ aIn >> nRowFirst >> nRowLast >> nColFirst >> nColLast;
+
+ rSRef1.nRelTab = rSRef2.nRelTab = 0;
+ rSRef1.SetTabRel( sal_True );
+ rSRef2.SetTabRel( sal_True );
+ rSRef1.SetFlag3D( bRangeName );
+ rSRef2.SetFlag3D( bRangeName );
+
+ ExcRelToScRel( nRowFirst, nColFirst, aCRD.Ref1, bRangeName );
+ ExcRelToScRel( nRowLast, nColLast, aCRD.Ref2, bRangeName );
+
+ if( IsComplColRange( nColFirst, nColLast ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRowFirst, nRowLast ) )
+ SetComplRow( aCRD );
+
+ switch ( nOp )
+ {
+ case 0x4B:
+ case 0x6B:
+ case 0x2B: // Deleted Area Refernce [323 273]
+ // no information which part is deleted, set all
+ rSRef1.SetColDeleted( sal_True );
+ rSRef1.SetRowDeleted( sal_True );
+ rSRef2.SetColDeleted( sal_True );
+ rSRef2.SetRowDeleted( sal_True );
+ }
+
+ aStack << aPool.Store( aCRD );
+ }
+ break;
+ case 0x46:
+ case 0x66:
+ case 0x26: // Constant Reference Subexpression [321 271]
+ aExtensions.push_back( EXTENSION_MEMAREA );
+ // fall through
+
+ case 0x47:
+ case 0x67:
+ case 0x27: // Erroneous Constant Reference Subexpr. [322 272]
+ case 0x48:
+ case 0x68:
+ case 0x28: // Incomplete Constant Reference Subexpr.[331 281]
+ aIn.Ignore( (meBiff == EXC_BIFF2) ? 4 : 6 );
+ break;
+ case 0x4C:
+ case 0x6C:
+ case 0x2C: // Cell Reference Within a Name [323 ]
+ // Cell Reference Within a Shared Formula[ 273]
+ {
+ aIn >> nUINT16 >> nByte; // >> Attribute, Row >> Col
+
+ aSRD.nRelTab = 0;
+ aSRD.SetTabRel( sal_True );
+ aSRD.SetFlag3D( bRangeName );
+
+ ExcRelToScRel( nUINT16, nByte, aSRD, bRNorSF );
+
+ aStack << aPool.Store( aSRD );
+ }
+ break;
+ case 0x4D:
+ case 0x6D:
+ case 0x2D: // Area Reference Within a Name [324 ]
+ { // Area Reference Within a Shared Formula[ 274]
+ sal_uInt16 nRowFirst, nRowLast;
+ sal_uInt8 nColFirst, nColLast;
+
+ aCRD.Ref1.nRelTab = aCRD.Ref2.nRelTab = 0;
+ aCRD.Ref1.SetTabRel( sal_True );
+ aCRD.Ref2.SetTabRel( sal_True );
+ aCRD.Ref1.SetFlag3D( bRangeName );
+ aCRD.Ref2.SetFlag3D( bRangeName );
+
+ aIn >> nRowFirst >> nRowLast >> nColFirst >> nColLast;
+
+ ExcRelToScRel( nRowFirst, nColFirst, aCRD.Ref1, bRNorSF );
+ ExcRelToScRel( nRowLast, nColLast, aCRD.Ref2, bRNorSF );
+
+ if( IsComplColRange( nColFirst, nColLast ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRowFirst, nRowLast ) )
+ SetComplRow( aCRD );
+
+ aStack << aPool.Store( aCRD );
+ }
+ break;
+ case 0x49:
+ case 0x69:
+ case 0x29: // Variable Reference Subexpression [331 281]
+ case 0x4E:
+ case 0x6E:
+ case 0x2E: // Reference Subexpression Within a Name [332 282]
+ case 0x4F:
+ case 0x6F:
+ case 0x2F: // Incomplete Reference Subexpression... [332 282]
+ aIn.Ignore( (meBiff == EXC_BIFF2) ? 1 : 2 );
+ break;
+ case 0x58:
+ case 0x78:
+ case 0x38: // Command-Equivalent Function [333 ]
+ aString.AssignAscii( "COMM_EQU_FUNC" );
+ aIn >> nByte;
+ aString += String::CreateFromInt32( nByte );
+ aIn >> nByte;
+ aStack << aPool.Store( aString );
+ DoMulArgs( ocPush, nByte + 1 );
+ break;
+ case 0x59:
+ case 0x79:
+ case 0x39: // Name or External Name [ 275]
+ aIn >> nINT16;
+ aIn.Ignore( 8 );
+ aIn >> nUINT16;
+ if( nINT16 >= 0 )
+ {
+ const ExtName* pExtName = rR.pExtNameBuff->GetNameByIndex( nINT16, nUINT16 );
+ if( pExtName && pExtName->IsDDE() &&
+ rR.pExtSheetBuff->IsLink( ( sal_uInt16 ) nINT16 ) )
+ {
+ String aAppl, aExtDoc;
+ TokenId nPar1, nPar2;
+
+ rR.pExtSheetBuff->GetLink( ( sal_uInt16 ) nINT16 , aAppl, aExtDoc );
+ nPar1 = aPool.Store( aAppl );
+ nPar2 = aPool.Store( aExtDoc );
+ nMerk0 = aPool.Store( pExtName->aName );
+ aPool << ocDde << ocOpen << nPar1 << ocSep << nPar2 << ocSep
+ << nMerk0 << ocClose;
+
+ GetDoc().CreateDdeLink( aAppl, aExtDoc, pExtName->aName, SC_DDE_DEFAULT, ScMatrixRef() );
+ }
+ else
+ aPool << ocBad;
+
+ aPool >> aStack;
+ }
+ else
+ aStack << aPool.StoreName( nUINT16, true );
+ aIn.Ignore( 12 );
+ break;
+ case 0x5A:
+ case 0x7A:
+ case 0x3A: // 3-D Cell Reference [ 275]
+ case 0x5C:
+ case 0x7C:
+ case 0x3C: // Deleted 3-D Cell Reference [ 277]
+ {
+ sal_uInt16 nTabFirst, nTabLast, nRow;
+ sal_Int16 nExtSheet;
+ sal_uInt8 nCol;
+
+ aIn >> nExtSheet;
+ aIn.Ignore( 8 );
+ aIn >> nTabFirst >> nTabLast >> nRow >> nCol;
+
+ if( nExtSheet >= 0 )
+ { // von extern
+ if( rR.pExtSheetBuff->GetScTabIndex( nExtSheet, nTabLast ) )
+ {
+ nTabFirst = nTabLast;
+ nExtSheet = 0; // gefunden
+ }
+ else
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ nExtSheet = 1; // verhindert Erzeugung einer SingleRef
+ }
+ }
+
+ if( nExtSheet <= 0 )
+ { // in aktuellem Workbook
+ aSRD.nTab = static_cast<SCTAB>(nTabFirst);
+ aSRD.SetFlag3D( sal_True );
+ aSRD.SetTabRel( false );
+
+ ExcRelToScRel( nRow, nCol, aSRD, bRangeName );
+
+ switch ( nOp )
+ {
+ case 0x5C:
+ case 0x7C:
+ case 0x3C: // Deleted 3-D Cell Reference [ 277]
+ // no information which part is deleted, set both
+ aSRD.SetColDeleted( sal_True );
+ aSRD.SetRowDeleted( sal_True );
+ }
+ if ( !ValidTab(static_cast<SCTAB>(nTabFirst)) )
+ aSRD.SetTabDeleted( sal_True );
+
+ if( nTabLast != nTabFirst )
+ {
+ aCRD.Ref1 = aCRD.Ref2 = aSRD;
+ aCRD.Ref2.nTab = static_cast<SCTAB>(nTabLast);
+ aCRD.Ref2.SetTabDeleted( !ValidTab(static_cast<SCTAB>(nTabLast)) );
+ aStack << aPool.Store( aCRD );
+ }
+ else
+ aStack << aPool.Store( aSRD );
+ }
+ }
+
+ break;
+ case 0x5B:
+ case 0x7B:
+ case 0x3B: // 3-D Area Reference [ 276]
+ case 0x5D:
+ case 0x7D:
+ case 0x3D: // Deleted 3-D Area Reference [ 277]
+ {
+ sal_uInt16 nTabFirst, nTabLast, nRowFirst, nRowLast;
+ sal_Int16 nExtSheet;
+ sal_uInt8 nColFirst, nColLast;
+
+ aIn >> nExtSheet;
+ aIn.Ignore( 8 );
+ aIn >> nTabFirst >> nTabLast >> nRowFirst >> nRowLast
+ >> nColFirst >> nColLast;
+
+ if( nExtSheet >= 0 )
+ // von extern
+ {
+ if( rR.pExtSheetBuff->GetScTabIndex( nExtSheet, nTabLast ) )
+ {
+ nTabFirst = nTabLast;
+ nExtSheet = 0; // gefunden
+ }
+ else
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ nExtSheet = 1; // verhindert Erzeugung einer CompleteRef
+ }
+ }
+
+ if( nExtSheet <= 0 )
+ {// in aktuellem Workbook
+ // erster Teil des Bereichs
+ ScSingleRefData& rR1 = aCRD.Ref1;
+ ScSingleRefData& rR2 = aCRD.Ref2;
+
+ rR1.nTab = static_cast<SCTAB>(nTabFirst);
+ rR2.nTab = static_cast<SCTAB>(nTabLast);
+ rR1.SetFlag3D( sal_True );
+ rR1.SetTabRel( false );
+ rR2.SetFlag3D( nTabFirst != nTabLast );
+ rR2.SetTabRel( false );
+
+ ExcRelToScRel( nRowFirst, nColFirst, aCRD.Ref1, bRangeName );
+ ExcRelToScRel( nRowLast, nColLast, aCRD.Ref2, bRangeName );
+
+ if( IsComplColRange( nColFirst, nColLast ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRowFirst, nRowLast ) )
+ SetComplRow( aCRD );
+
+ switch ( nOp )
+ {
+ case 0x5D:
+ case 0x7D:
+ case 0x3D: // Deleted 3-D Area Reference [ 277]
+ // no information which part is deleted, set all
+ rR1.SetColDeleted( sal_True );
+ rR1.SetRowDeleted( sal_True );
+ rR2.SetColDeleted( sal_True );
+ rR2.SetRowDeleted( sal_True );
+ }
+ if ( !ValidTab(static_cast<SCTAB>(nTabFirst)) )
+ rR1.SetTabDeleted( sal_True );
+ if ( !ValidTab(static_cast<SCTAB>(nTabLast)) )
+ rR2.SetTabDeleted( sal_True );
+
+ aStack << aPool.Store( aCRD );
+ }//ENDE in aktuellem Workbook
+ }
+ break;
+ default: bError = sal_True;
+ }
+ bError |= !aIn.IsValid();
+ }
+
+ ConvErr eRet;
+
+ if( bError )
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ pErgebnis = aPool[ aStack.Get() ];
+ eRet = ConvErrNi;
+ }
+ else if( aIn.GetRecPos() != nEndPos )
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ pErgebnis = aPool[ aStack.Get() ];
+ eRet = ConvErrCount;
+ }
+ else if( bExternName )
+ {
+ pErgebnis = aPool[ aStack.Get() ];
+ eRet = ConvErrExternal;
+ }
+ else if( bArrayFormula )
+ {
+ pErgebnis = NULL;
+ eRet = ConvOK;
+ }
+ else
+ {
+ pErgebnis = aPool[ aStack.Get() ];
+ eRet = ConvOK;
+ }
+
+ aIn.Seek( nEndPos );
+
+ if( eRet == ConvOK )
+ ReadExtensions( aExtensions, aIn );
+
+ return eRet;
+}
+
+
+// stream seeks to first byte after <nFormulaLen>
+ConvErr ExcelToSc::Convert( _ScRangeListTabs& rRangeList, XclImpStream& aIn, sal_Size nFormulaLen,
+ SCsTAB nTab, const FORMULA_TYPE eFT )
+{
+ RootData& rR = GetOldRoot();
+ sal_uInt8 nOp, nLen;
+ sal_Size nIgnore;
+ sal_uInt16 nUINT16;
+ sal_uInt8 nByte;
+ sal_Bool bError = false;
+ sal_Bool bArrayFormula = false;
+ const sal_Bool bRangeName = eFT == FT_RangeName;
+ const sal_Bool bSharedFormula = eFT == FT_SharedFormula;
+ const sal_Bool bRNorSF = bRangeName || bSharedFormula;
+
+ ScSingleRefData aSRD;
+ ScComplexRefData aCRD;
+ aCRD.Ref1.nTab = aCRD.Ref2.nTab = aEingPos.Tab();
+
+ bExternName = false;
+
+ if( eStatus != ConvOK )
+ {
+ aIn.Ignore( nFormulaLen );
+ return eStatus;
+ }
+
+ if( nFormulaLen == 0 )
+ return ConvOK;
+
+ sal_Size nEndPos = aIn.GetRecPos() + nFormulaLen;
+
+ while( (aIn.GetRecPos() < nEndPos) && !bError )
+ {
+ aIn >> nOp;
+ nIgnore = 0;
+
+ // always reset flags
+ aSRD.InitFlags();
+ aCRD.InitFlags();
+
+ switch( nOp ) // Buch Seite:
+ { // SDK4 SDK5
+ case 0x01: // Array Formula [325 ]
+ // Array Formula or Shared Formula [ 277]
+ nIgnore = (meBiff == EXC_BIFF2) ? 3 : 4;
+ bArrayFormula = sal_True;
+ break;
+ case 0x02: // Data Table [325 277]
+ nIgnore = (meBiff == EXC_BIFF2) ? 3 : 4;
+ break;
+ case 0x03: // Addition [312 264]
+ case 0x04: // Subtraction [313 264]
+ case 0x05: // Multiplication [313 264]
+ case 0x06: // Division [313 264]
+ case 0x07: // Exponetiation [313 265]
+ case 0x08: // Concatenation [313 265]
+ case 0x09: // Less Than [313 265]
+ case 0x0A: // Less Than or Equal [313 265]
+ case 0x0B: // Equal [313 265]
+ case 0x0C: // Greater Than or Equal [313 265]
+ case 0x0D: // Greater Than [313 265]
+ case 0x0E: // Not Equal [313 265]
+ case 0x0F: // Intersection [314 265]
+ case 0x10: // Union [314 265]
+ case 0x11: // Range [314 265]
+ case 0x12: // Unary Plus [312 264]
+ case 0x13: // Unary Minus [312 264]
+ case 0x14: // Percent Sign [312 264]
+ case 0x15: // Parenthesis [326 278]
+ case 0x16: // Missing Argument [314 266]
+ break;
+ case 0x17: // String Constant [314 266]
+ aIn >> nLen;
+ nIgnore = nLen;
+ break;
+ case 0x19: // Special Attribute [327 279]
+ {
+ sal_uInt16 nData, nFakt;
+ sal_uInt8 nOpt;
+
+ aIn >> nOpt;
+
+ if( meBiff == EXC_BIFF2 )
+ {
+ nData = aIn.ReaduInt8();
+ nFakt = 1;
+ }
+ else
+ {
+ aIn >> nData;
+ nFakt = 2;
+ }
+
+ if( nOpt & 0x04 )
+ {// nFakt -> Bytes oder Words ueberlesen AttrChoose
+ nData++;
+ aIn.Ignore( nData * nFakt );
+ }
+ }
+ break;
+ case 0x1A: // External Reference [330 ]
+ switch( meBiff )
+ {
+ case EXC_BIFF2: nIgnore = 7; break;
+ case EXC_BIFF3:
+ case EXC_BIFF4: nIgnore = 10; break;
+ case EXC_BIFF5: DBG_WARNING( "-ExcelToSc::Convert(): 0x1A gibt's nicht in Biff5!" );
+ default: DBG_WARNING( "-ExcelToSc::Convert(): Ein wenig vergesslich, was?" );
+ }
+ break;
+ case 0x1B: // End External Reference [330 ]
+ switch( meBiff )
+ {
+ case EXC_BIFF2: nIgnore = 3; break;
+ case EXC_BIFF3:
+ case EXC_BIFF4: nIgnore = 4; break;
+ case EXC_BIFF5: DBG_WARNING( "-ExcelToSc::Convert(): 0x1B gibt's nicht in Biff5!" );
+ default: DBG_WARNING( "-ExcelToSc::Convert(): Ein wenig vergesslich, was?" );
+ }
+ break;
+ case 0x1C: // Error Value [314 266]
+ case 0x1D: // Boolean [315 266]
+ nIgnore = 1;
+ break;
+ case 0x1E: // Integer [315 266]
+ nIgnore = 2;
+ break;
+ case 0x1F: // Number [315 266]
+ nIgnore = 8;
+ break;
+ case 0x40:
+ case 0x60:
+ case 0x20: // Array Constant [317 268]
+ nIgnore = (meBiff == EXC_BIFF2) ? 6 : 7;
+ break;
+ case 0x41:
+ case 0x61:
+ case 0x21: // Function, Fixed Number of Arguments [333 282]
+ nIgnore = (meBiff <= EXC_BIFF3) ? 1 : 2;
+ break;
+ case 0x42:
+ case 0x62:
+ case 0x22: // Function, Variable Number of Arg. [333 283]
+ nIgnore = (meBiff <= EXC_BIFF3) ? 2 : 3;
+ break;
+ case 0x43:
+ case 0x63:
+ case 0x23: // Name [318 269]
+ switch( meBiff )
+ {
+ case EXC_BIFF2: nIgnore = 7; break;
+ case EXC_BIFF3:
+ case EXC_BIFF4: nIgnore = 10; break;
+ case EXC_BIFF5: nIgnore = 14; break;
+ default: OSL_FAIL( "-ExcelToSc::Convert(): Ein wenig vergesslich, was?" );
+ }
+ break;
+ case 0x44:
+ case 0x64:
+ case 0x24: // Cell Reference [319 270]
+ aIn >> nUINT16 >> nByte;
+ aSRD.nCol = static_cast<SCsCOL>(nByte);
+ aSRD.nRow = nUINT16 & 0x3FFF;
+ aSRD.nRelTab = 0;
+ aSRD.SetTabRel( sal_True );
+ aSRD.SetFlag3D( bRangeName );
+
+ ExcRelToScRel( nUINT16, nByte, aSRD, bRangeName );
+
+ rRangeList.Append( aSRD, nTab );
+ break;
+ case 0x45:
+ case 0x65:
+ case 0x25: // Area Reference [320 270]
+ {
+ sal_uInt16 nRowFirst, nRowLast;
+ sal_uInt8 nColFirst, nColLast;
+ ScSingleRefData &rSRef1 = aCRD.Ref1;
+ ScSingleRefData &rSRef2 = aCRD.Ref2;
+
+ aIn >> nRowFirst >> nRowLast >> nColFirst >> nColLast;
+
+ rSRef1.nRelTab = rSRef2.nRelTab = 0;
+ rSRef1.SetTabRel( sal_True );
+ rSRef2.SetTabRel( sal_True );
+ rSRef1.SetFlag3D( bRangeName );
+ rSRef2.SetFlag3D( bRangeName );
+
+ ExcRelToScRel( nRowFirst, nColFirst, aCRD.Ref1, bRangeName );
+ ExcRelToScRel( nRowLast, nColLast, aCRD.Ref2, bRangeName );
+
+ if( IsComplColRange( nColFirst, nColLast ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRowFirst, nRowLast ) )
+ SetComplRow( aCRD );
+
+ rRangeList.Append( aCRD, nTab );
+ }
+ break;
+ case 0x46:
+ case 0x66:
+ case 0x26: // Constant Reference Subexpression [321 271]
+ case 0x47:
+ case 0x67:
+ case 0x27: // Erroneous Constant Reference Subexpr. [322 272]
+ case 0x48:
+ case 0x68:
+ case 0x28: // Incomplete Constant Reference Subexpr.[331 281]
+ nIgnore = (meBiff == EXC_BIFF2) ? 4 : 6;
+ break;
+ case 0x4A:
+ case 0x6A:
+ case 0x2A: // Deleted Cell Reference [323 273]
+ nIgnore = 3;
+ break;
+ case 0x4B:
+ case 0x6B:
+ case 0x2B: // Deleted Area Refernce [323 273]
+ nIgnore = 6;
+ break;
+ case 0x4C:
+ case 0x6C:
+ case 0x2C: // Cell Reference Within a Name [323 ]
+ // Cell Reference Within a Shared Formula[ 273]
+ {
+ aIn >> nUINT16 >> nByte; // >> Attribute, Row >> Col
+
+ aSRD.nRelTab = 0;
+ aSRD.SetTabRel( sal_True );
+ aSRD.SetFlag3D( bRangeName );
+
+ ExcRelToScRel( nUINT16, nByte, aSRD, bRNorSF );
+
+ rRangeList.Append( aSRD, nTab );
+ }
+ break;
+ case 0x4D:
+ case 0x6D:
+ case 0x2D: // Area Reference Within a Name [324 ]
+ { // Area Reference Within a Shared Formula[ 274]
+ sal_uInt16 nRowFirst, nRowLast;
+ sal_uInt8 nColFirst, nColLast;
+
+ aCRD.Ref1.nRelTab = aCRD.Ref2.nRelTab = 0;
+ aCRD.Ref1.SetTabRel( sal_True );
+ aCRD.Ref2.SetTabRel( sal_True );
+ aCRD.Ref1.SetFlag3D( bRangeName );
+ aCRD.Ref2.SetFlag3D( bRangeName );
+
+ aIn >> nRowFirst >> nRowLast >> nColFirst >> nColLast;
+
+ ExcRelToScRel( nRowFirst, nColFirst, aCRD.Ref1, bRNorSF );
+ ExcRelToScRel( nRowLast, nColLast, aCRD.Ref2, bRNorSF );
+
+ if( IsComplColRange( nColFirst, nColLast ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRowFirst, nRowLast ) )
+ SetComplRow( aCRD );
+
+ rRangeList.Append( aCRD, nTab );
+ }
+ break;
+ case 0x49:
+ case 0x69:
+ case 0x29: // Variable Reference Subexpression [331 281]
+ case 0x4E:
+ case 0x6E:
+ case 0x2E: // Reference Subexpression Within a Name [332 282]
+ case 0x4F:
+ case 0x6F:
+ case 0x2F: // Incomplete Reference Subexpression... [332 282]
+ nIgnore = (meBiff == EXC_BIFF2) ? 1 : 2;
+ break;
+ case 0x58:
+ case 0x78:
+ case 0x38: // Command-Equivalent Function [333 ]
+ nIgnore = 2;
+ break;
+ case 0x59:
+ case 0x79:
+ case 0x39: // Name or External Name [ 275]
+ nIgnore = 24;
+ break;
+ case 0x5A:
+ case 0x7A:
+ case 0x3A: // 3-D Cell Reference [ 275]
+ {
+ sal_uInt16 nTabFirst, nTabLast, nRow;
+ sal_Int16 nExtSheet;
+ sal_uInt8 nCol;
+
+ aIn >> nExtSheet;
+ aIn.Ignore( 8 );
+ aIn >> nTabFirst >> nTabLast >> nRow >> nCol;
+
+ if( nExtSheet >= 0 )
+ // von extern
+ {
+ if( rR.pExtSheetBuff->GetScTabIndex( nExtSheet, nTabLast ) )
+ {
+ nTabFirst = nTabLast;
+ nExtSheet = 0; // gefunden
+ }
+ else
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ nExtSheet = 1; // verhindert Erzeugung einer SingleRef
+ }
+ }
+
+ if( nExtSheet <= 0 )
+ {// in aktuellem Workbook
+ sal_Bool b3D = ( static_cast<SCTAB>(nTabFirst) != aEingPos.Tab() ) || bRangeName;
+ aSRD.nTab = static_cast<SCTAB>(nTabFirst);
+ aSRD.SetFlag3D( b3D );
+ aSRD.SetTabRel( false );
+
+ ExcRelToScRel( nRow, nCol, aSRD, bRangeName );
+
+ if( nTabLast != nTabFirst )
+ {
+ aCRD.Ref1 = aSRD;
+ aCRD.Ref2.nCol = aSRD.nCol;
+ aCRD.Ref2.nRow = aSRD.nRow;
+ aCRD.Ref2.nTab = static_cast<SCTAB>(nTabLast);
+ b3D = ( static_cast<SCTAB>(nTabLast) != aEingPos.Tab() );
+ aCRD.Ref2.SetFlag3D( b3D );
+ aCRD.Ref2.SetTabRel( false );
+ rRangeList.Append( aCRD, nTab );
+ }
+ else
+ rRangeList.Append( aSRD, nTab );
+ }
+ }
+
+ break;
+ case 0x5B:
+ case 0x7B:
+ case 0x3B: // 3-D Area Reference [ 276]
+ {
+ sal_uInt16 nTabFirst, nTabLast, nRowFirst, nRowLast;
+ sal_Int16 nExtSheet;
+ sal_uInt8 nColFirst, nColLast;
+
+ aIn >> nExtSheet;
+ aIn.Ignore( 8 );
+ aIn >> nTabFirst >> nTabLast >> nRowFirst >> nRowLast
+ >> nColFirst >> nColLast;
+
+ if( nExtSheet >= 0 )
+ // von extern
+ {
+ if( rR.pExtSheetBuff->GetScTabIndex( nExtSheet, nTabLast ) )
+ {
+ nTabFirst = nTabLast;
+ nExtSheet = 0; // gefunden
+ }
+ else
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ nExtSheet = 1; // verhindert Erzeugung einer CompleteRef
+ }
+ }
+
+ if( nExtSheet <= 0 )
+ {// in aktuellem Workbook
+ // erster Teil des Bereichs
+ ScSingleRefData &rR1 = aCRD.Ref1;
+ ScSingleRefData &rR2 = aCRD.Ref2;
+
+ rR1.nTab = static_cast<SCTAB>(nTabFirst);
+ rR2.nTab = static_cast<SCTAB>(nTabLast);
+ rR1.SetFlag3D( ( static_cast<SCTAB>(nTabFirst) != aEingPos.Tab() ) || bRangeName );
+ rR1.SetTabRel( false );
+ rR2.SetFlag3D( ( static_cast<SCTAB>(nTabLast) != aEingPos.Tab() ) || bRangeName );
+ rR2.SetTabRel( false );
+
+ ExcRelToScRel( nRowFirst, nColFirst, aCRD.Ref1, bRangeName );
+ ExcRelToScRel( nRowLast, nColLast, aCRD.Ref2, bRangeName );
+
+ if( IsComplColRange( nColFirst, nColLast ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRowFirst, nRowLast ) )
+ SetComplRow( aCRD );
+
+ rRangeList.Append( aCRD, nTab );
+ }//ENDE in aktuellem Workbook
+ }
+ break;
+ case 0x5C:
+ case 0x7C:
+ case 0x3C: // Deleted 3-D Cell Reference [ 277]
+ nIgnore = 17;
+ break;
+ case 0x5D:
+ case 0x7D:
+ case 0x3D: // Deleted 3-D Area Reference [ 277]
+ nIgnore = 20;
+ break;
+ default: bError = sal_True;
+ }
+ bError |= !aIn.IsValid();
+
+ aIn.Ignore( nIgnore );
+ }
+
+ ConvErr eRet;
+
+ if( bError )
+ eRet = ConvErrNi;
+ else if( aIn.GetRecPos() != nEndPos )
+ eRet = ConvErrCount;
+ else if( bExternName )
+ eRet = ConvErrExternal;
+ else if( bArrayFormula )
+ eRet = ConvOK;
+ else
+ eRet = ConvOK;
+
+ aIn.Seek( nEndPos );
+ return eRet;
+}
+
+ConvErr ExcelToSc::ConvertExternName( const ScTokenArray*& /*rpArray*/, XclImpStream& /*rStrm*/, sal_Size /*nFormulaLen*/,
+ const String& /*rUrl*/, const vector<String>& /*rTabNames*/ )
+{
+ // not implemented ...
+ return ConvErrNi;
+}
+
+sal_Bool ExcelToSc::GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen )
+{
+ DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF5 );
+ if( GetBiff() != EXC_BIFF5 )
+ return false;
+
+ sal_uInt8 nOp;
+ sal_uInt16 nRow1, nRow2;
+ sal_uInt8 nCol1, nCol2;
+ SCTAB nTab1, nTab2;
+ sal_uInt16 nTabFirst, nTabLast;
+ sal_Int16 nRefIdx;
+
+ sal_Size nSeek;
+ sal_Size nEndPos = rStrm.GetRecPos() + nLen;
+
+ while( rStrm.IsValid() && (rStrm.GetRecPos() < nEndPos) )
+ {
+ rStrm >> nOp;
+ nSeek = 0;
+
+ switch( nOp )
+ {
+ case 0x44:
+ case 0x64:
+ case 0x24: // Cell Reference [319 270]
+ case 0x4C:
+ case 0x6C:
+ case 0x2C: // Cell Reference Within a Name [323 ]
+ // Cell Reference Within a Shared Formula[ 273]
+ rStrm >> nRow1 >> nCol1;
+
+ nRow2 = nRow1;
+ nCol2 = nCol1;
+ nTab1 = nTab2 = GetCurrScTab();
+ goto _common;
+ case 0x45:
+ case 0x65:
+ case 0x25: // Area Reference [320 270]
+ case 0x4D:
+ case 0x6D:
+ case 0x2D: // Area Reference Within a Name [324 ]
+ // Area Reference Within a Shared Formula[ 274]
+ rStrm >> nRow1 >> nRow2 >> nCol1 >> nCol2;
+
+ nTab1 = nTab2 = GetCurrScTab();
+ goto _common;
+ case 0x5A:
+ case 0x7A:
+ case 0x3A: // 3-D Cell Reference [ 275]
+ rStrm >> nRefIdx;
+ rStrm.Ignore( 8 );
+ rStrm >> nTabFirst >> nTabLast >> nRow1 >> nCol1;
+
+ nRow2 = nRow1;
+ nCol2 = nCol1;
+
+ goto _3d_common;
+ case 0x5B:
+ case 0x7B:
+ case 0x3B: // 3-D Area Reference [ 276]
+ rStrm >> nRefIdx;
+ rStrm.Ignore( 8 );
+ rStrm >> nTabFirst >> nTabLast >> nRow1 >> nRow2 >> nCol1 >> nCol2;
+
+ _3d_common:
+ nTab1 = static_cast< SCTAB >( nTabFirst );
+ nTab2 = static_cast< SCTAB >( nTabLast );
+
+ // skip references to deleted sheets
+ if( (nRefIdx >= 0) || !ValidTab( nTab1 ) || (nTab1 != nTab2) )
+ break;
+
+ goto _common;
+ _common:
+ // do not check abs/rel flags, linked controls have set them!
+// if( !(( nCol1 & 0xC000 ) || ( nCol2 & 0xC000 )) )
+ {
+ ScRange aScRange;
+ nRow1 &= 0x3FFF;
+ nRow2 &= 0x3FFF;
+ if( GetAddressConverter().ConvertRange( aScRange, XclRange( nCol1, nRow1, nCol2, nRow2 ), nTab1, nTab2, true ) )
+ rRangeList.Append( aScRange );
+ }
+ break;
+
+ case 0x03: // Addition [312 264]
+ case 0x04: // Subtraction [313 264]
+ case 0x05: // Multiplication [313 264]
+ case 0x06: // Division [313 264]
+ case 0x07: // Exponetiation [313 265]
+ case 0x08: // Concatenation [313 265]
+ case 0x09: // Less Than [313 265]
+ case 0x0A: // Less Than or Equal [313 265]
+ case 0x0B: // Equal [313 265]
+ case 0x0C: // Greater Than or Equal [313 265]
+ case 0x0D: // Greater Than [313 265]
+ case 0x0E: // Not Equal [313 265]
+ case 0x0F: // Intersection [314 265]
+ case 0x10: // Union [314 265]
+ case 0x11: // Range [314 265]
+ case 0x12: // Unary Plus [312 264]
+ case 0x13: // Unary Minus [312 264]
+ case 0x14: // Percent Sign [312 264]
+ case 0x15: // Parenthesis [326 278]
+ case 0x16: // Missing Argument [314 266]
+ break;
+ case 0x1C: // Error Value [314 266]
+ case 0x1D: // Boolean [315 266]
+ nSeek = 1;
+ break;
+ case 0x1E: // Integer [315 266]
+ case 0x41:
+ case 0x61:
+ case 0x21: // Function, Fixed Number of Arguments [333 282]
+ case 0x49:
+ case 0x69:
+ case 0x29: // Variable Reference Subexpression [331 281]
+ case 0x4E:
+ case 0x6E:
+ case 0x2E: // Reference Subexpression Within a Name [332 282]
+ case 0x4F:
+ case 0x6F:
+ case 0x2F: // Incomplete Reference Subexpression... [332 282]
+ case 0x58:
+ case 0x78:
+ case 0x38: // Command-Equivalent Function [333 ]
+ nSeek = 2;
+ break;
+ case 0x42:
+ case 0x62:
+ case 0x22: // Function, Variable Number of Arg. [333 283]
+ case 0x4A:
+ case 0x6A:
+ case 0x2A: // Deleted Cell Reference [323 273]
+ nSeek = 3;
+ break;
+ case 0x01: // Array Formula [325 ]
+ // Array Formula or Shared Formula [ 277]
+ case 0x02: // Data Table [325 277]
+ nSeek = 4;
+ break;
+ case 0x46:
+ case 0x66:
+ case 0x26: // Constant Reference Subexpression [321 271]
+ case 0x47:
+ case 0x67:
+ case 0x27: // Erroneous Constant Reference Subexpr. [322 272]
+ case 0x48:
+ case 0x68:
+ case 0x28: // Incomplete Constant Reference Subexpr.[331 281]
+ case 0x4B:
+ case 0x6B:
+ case 0x2B: // Deleted Area Refernce [323 273]
+ nSeek = 6;
+ break;
+ case 0x40:
+ case 0x60:
+ case 0x20: // Array Constant [317 268]
+ nSeek = 7;
+ break;
+ case 0x1F: // Number [315 266]
+ nSeek = 8;
+ break;
+ case 0x43:
+ case 0x63:
+ case 0x23: // Name [318 269]
+ nSeek = 14;
+ break;
+ case 0x5C:
+ case 0x7C:
+ case 0x3C: // Deleted 3-D Cell Reference [ 277]
+ nSeek = 17;
+ break;
+ case 0x5D:
+ case 0x7D:
+ case 0x3D: // Deleted 3-D Area Reference [ 277]
+ nSeek = 20;
+ break;
+ case 0x59:
+ case 0x79:
+ case 0x39: // Name or External Name [ 275]
+ nSeek = 24;
+ break;
+ case 0x17: // String Constant [314 266]
+ nSeek = rStrm.ReaduInt8();
+ break;
+ case 0x19: // Special Attribute [327 279]
+ {
+ sal_uInt8 nOpt;
+ sal_uInt16 nData;
+ rStrm >> nOpt >> nData;
+ if( nOpt & 0x04 )
+ nSeek = nData * 2 + 2;
+ }
+ break;
+ }
+
+ rStrm.Ignore( nSeek );
+ }
+ rStrm.Seek( nEndPos );
+
+ return !rRangeList.empty();
+}
+
+void ExcelToSc::DoMulArgs( DefTokenId eId, sal_uInt8 nAnz )
+{
+ TokenId eParam[ 256 ];
+ sal_Int32 nLauf;
+
+ if( eId == ocCeil || eId == ocFloor )
+ {
+ aStack << aPool.Store( 1.0 ); // default, da in Excel nicht vorhanden
+ nAnz++;
+ }
+
+ for( nLauf = 0; aStack.HasMoreTokens() && (nLauf < nAnz); nLauf++ )
+ aStack >> eParam[ nLauf ];
+ // #i70925# reduce parameter count, if no more tokens available on token stack
+ if( nLauf < nAnz )
+ nAnz = static_cast< sal_uInt8 >( nLauf );
+
+ if( nAnz > 0 && eId == ocExternal )
+ {
+ TokenId n = eParam[ nAnz - 1 ];
+//##### GRUETZE FUER BASIC-FUNCS RICHTEN!
+ if( const String* pExt = aPool.GetExternal( n ) )
+ {
+ if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclMacroName( *pExt ) )
+ aPool << pFuncInfo->meOpCode;
+ else
+ aPool << n;
+ nAnz--;
+ }
+ else
+ aPool << eId;
+ }
+ else
+ aPool << eId;
+
+ aPool << ocOpen;
+
+ if( nAnz > 0 )
+ {
+ // attention: 0 = last parameter, nAnz-1 = first parameter
+ sal_Int16 nNull = -1; // skip this parameter
+ sal_Int16 nSkipEnd = -1; // skip all parameters <= nSkipEnd
+
+ sal_Int16 nLast = nAnz - 1;
+
+ // Funktionen, bei denen Parameter wegfallen muessen
+ if( eId == ocPercentrank && nAnz == 3 )
+ nSkipEnd = 0; // letzten Parameter bei Bedarf weglassen
+
+ // Joost-Spezialfaelle
+ else if( eId == ocIf )
+ {
+ sal_uInt16 nNullParam = 0;
+ for( nLauf = 0 ; nLauf < nAnz ; nLauf++ )
+ {
+ if( aPool.IsSingleOp( eParam[ nLauf ], ocMissing ) )
+ {
+ if( !nNullParam )
+ nNullParam = (sal_uInt16) aPool.Store( ( double ) 0.0 );
+ eParam[ nLauf ] = nNullParam;
+ }
+ }
+ }
+
+ // [Parameter{;Parameter}]
+ if( nLast > nSkipEnd )
+ {
+ aPool << eParam[ nLast ];
+ for( nLauf = nLast - 1 ; nLauf > nSkipEnd ; nLauf-- )
+ {
+ if( nLauf != nNull )
+ aPool << ocSep << eParam[ nLauf ];
+ }
+ }
+ }
+ aPool << ocClose;
+
+ aPool >> aStack;
+}
+
+
+void ExcelToSc::ExcRelToScRel( sal_uInt16 nRow, sal_uInt8 nCol, ScSingleRefData &rSRD, const sal_Bool bName )
+{
+ if( bName )
+ {
+ // C O L
+ if( nRow & 0x4000 )
+ {// rel Col
+ rSRD.SetColRel( sal_True );
+ rSRD.nRelCol = static_cast<SCsCOL>(static_cast<sal_Int8>(nCol));
+ }
+ else
+ {// abs Col
+ rSRD.SetColRel( false );
+ rSRD.nCol = static_cast<SCCOL>(nCol);
+ }
+
+ // R O W
+ if( nRow & 0x8000 )
+ {// rel Row
+ rSRD.SetRowRel( sal_True );
+ if( nRow & 0x2000 ) // Bit 13 gesetzt?
+ // -> Row negativ
+ rSRD.nRelRow = static_cast<SCsROW>(static_cast<sal_Int16>(nRow | 0xC000));
+ else
+ // -> Row positiv
+ rSRD.nRelRow = static_cast<SCsROW>(nRow & nRowMask);
+ }
+ else
+ {// abs Row
+ rSRD.SetRowRel( false );
+ rSRD.nRow = static_cast<SCROW>(nRow & nRowMask);
+ }
+
+ // T A B
+ // abs needed if rel in shared formula for ScCompiler UpdateNameReference
+ if ( rSRD.IsTabRel() && !rSRD.IsFlag3D() )
+ rSRD.nTab = GetCurrScTab();
+ }
+ else
+ {
+ // C O L
+ rSRD.SetColRel( ( nRow & 0x4000 ) > 0 );
+ rSRD.nCol = static_cast<SCsCOL>(nCol);
+
+ // R O W
+ rSRD.SetRowRel( ( nRow & 0x8000 ) > 0 );
+ rSRD.nRow = static_cast<SCsROW>(nRow & nRowMask);
+
+ if ( rSRD.IsColRel() )
+ rSRD.nRelCol = rSRD.nCol - aEingPos.Col();
+ if ( rSRD.IsRowRel() )
+ rSRD.nRelRow = rSRD.nRow - aEingPos.Row();
+
+ // T A B
+ // #i10184# abs needed if rel in shared formula for ScCompiler UpdateNameReference
+ if ( rSRD.IsTabRel() && !rSRD.IsFlag3D() )
+ rSRD.nTab = GetCurrScTab() + rSRD.nRelTab;
+ }
+}
+
+
+const ScTokenArray* ExcelToSc::GetBoolErr( XclBoolError eType )
+{
+ sal_uInt16 nError;
+ aPool.Reset();
+ aStack.Reset();
+
+ DefTokenId eOc;
+
+ switch( eType )
+ {
+ case xlErrNull: eOc = ocStop; nError = errNoCode; break;
+ case xlErrDiv0: eOc = ocStop; nError = errDivisionByZero; break;
+ case xlErrValue: eOc = ocStop; nError = errNoValue; break;
+ case xlErrRef: eOc = ocStop; nError = errNoRef; break;
+ case xlErrName: eOc = ocStop; nError = errNoName; break;
+ case xlErrNum: eOc = ocStop; nError = errIllegalFPOperation; break;
+ case xlErrNA: eOc = ocNotAvail; nError = NOTAVAILABLE; break;
+ case xlErrTrue: eOc = ocTrue; nError = 0; break;
+ case xlErrFalse: eOc = ocFalse; nError = 0; break;
+ case xlErrUnknown: eOc = ocStop; nError = errUnknownState; break;
+ default:
+ OSL_FAIL( "ExcelToSc::GetBoolErr - wrong enum!" );
+ eOc = ocNoName;
+ nError = errUnknownState;
+ }
+
+ aPool << eOc;
+ if( eOc != ocStop )
+ aPool << ocOpen << ocClose;
+
+ aPool >> aStack;
+
+ const ScTokenArray* pErgebnis = aPool[ aStack.Get() ];
+ if( nError )
+ ( ( ScTokenArray* ) pErgebnis )->SetCodeError( nError );
+
+ ( ( ScTokenArray* ) pErgebnis )->SetRecalcModeNormal();
+
+ return pErgebnis;
+}
+
+
+// if a shared formula was found, stream seeks to first byte after <nFormulaLen>,
+// else stream pointer stays unchanged
+sal_Bool ExcelToSc::GetShrFmla( const ScTokenArray*& rpErgebnis, XclImpStream& aIn, sal_Size nFormulaLen )
+{
+ sal_uInt8 nOp;
+ sal_Bool bRet = sal_True;
+
+ if( nFormulaLen == 0 )
+ bRet = false;
+ else
+ {
+ aIn.PushPosition();
+
+ aIn >> nOp;
+
+ if( nOp == 0x01 ) // Shared Formula [ 277]
+ {
+ sal_uInt16 nCol, nRow;
+
+ aIn >> nRow >> nCol;
+
+ aStack << aPool.StoreName( GetOldRoot().pShrfmlaBuff->Find(
+ ScAddress(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), GetCurrScTab())), true);
+
+ bRet = sal_True;
+ }
+ else
+ bRet = false;
+
+ aIn.PopPosition();
+ }
+
+ if( bRet )
+ {
+ aIn.Ignore( nFormulaLen );
+ rpErgebnis = aPool[ aStack.Get() ];
+ }
+ else
+ rpErgebnis = NULL;
+
+ return bRet;
+}
+
+
+void ExcelToSc::SetError( ScFormulaCell &rCell, const ConvErr eErr )
+{
+ sal_uInt16 nInd;
+
+ switch( eErr )
+ {
+ case ConvErrNi: nInd = errUnknownToken; break;
+ case ConvErrNoMem: nInd = errCodeOverflow; break;
+ case ConvErrExternal: nInd = errNoName; break;
+ case ConvErrCount: nInd = errCodeOverflow; break;
+ default: nInd = errNoCode; // hier fiel mir nichts
+ // Besseres ein...
+ }
+
+ rCell.SetErrCode( nInd );
+}
+
+
+void ExcelToSc::SetComplCol( ScComplexRefData &rCRD )
+{
+ ScSingleRefData &rSRD = rCRD.Ref2;
+ if( rSRD.IsColRel() )
+ rSRD.nRelCol = MAXCOL - aEingPos.Col();
+ else
+ rSRD.nCol = MAXCOL;
+}
+
+
+void ExcelToSc::SetComplRow( ScComplexRefData &rCRD )
+{
+ ScSingleRefData &rSRD = rCRD.Ref2;
+ if( rSRD.IsRowRel() )
+ rSRD.nRelRow = MAXROW - aEingPos.Row();
+ else
+ rSRD.nRow = MAXROW;
+}
+
+void ExcelToSc::ReadExtensionArray( unsigned int n, XclImpStream& aIn )
+{
+ // printf( "inline array;\n" );
+
+ sal_uInt8 nByte;
+ sal_uInt16 nUINT16;
+ double fDouble;
+ String aString;
+ ScMatrix* pMatrix;
+
+ aIn >> nByte >> nUINT16;
+
+ SCSIZE nC, nCols;
+ SCSIZE nR, nRows;
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ nCols = nByte + 1;
+ nRows = nUINT16 + 1;
+ }
+ else
+ {
+ nCols = nByte ? nByte : 256;
+ nRows = nUINT16;
+ }
+
+ pMatrix = aPool.GetMatrix( n );
+
+ if( NULL != pMatrix )
+ {
+ pMatrix->Resize(nCols, nRows);
+ pMatrix->GetDimensions( nC, nR);
+ if( nC != nCols || nR != nRows )
+ {
+ DBG_ERRORFILE( "ExcelToSc::ReadExtensionArray - matrix size mismatch" );
+ pMatrix = NULL;
+ }
+ }
+ else
+ {
+ DBG_ERRORFILE( "ExcelToSc::ReadExtensionArray - missing matrix" );
+ }
+
+ for( nR = 0 ; nR < nRows; nR++ )
+ {
+ for( nC = 0 ; nC < nCols; nC++ )
+ {
+ aIn >> nByte;
+ switch( nByte )
+ {
+ case EXC_CACHEDVAL_EMPTY:
+ aIn.Ignore( 8 );
+ if( NULL != pMatrix )
+ {
+ pMatrix->PutEmpty( nC, nR );
+ }
+ break;
+
+ case EXC_CACHEDVAL_DOUBLE:
+ aIn >> fDouble;
+ if( NULL != pMatrix )
+ {
+ pMatrix->PutDouble( fDouble, nC, nR );
+ }
+ break;
+
+ case EXC_CACHEDVAL_STRING:
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ aIn >> nUINT16;
+ aString = aIn.ReadUniString( nUINT16 );
+ }
+ else
+ {
+ aIn >> nByte;
+ aString = aIn.ReadRawByteString( nByte );
+ }
+ if( NULL != pMatrix )
+ {
+ pMatrix->PutString( aString, nC, nR );
+ }
+ break;
+
+ case EXC_CACHEDVAL_BOOL:
+ aIn >> nByte;
+ aIn.Ignore( 7 );
+ if( NULL != pMatrix )
+ {
+ pMatrix->PutBoolean( nByte != 0, nC, nR );
+ }
+ break;
+
+ case EXC_CACHEDVAL_ERROR:
+ aIn >> nByte;
+ aIn.Ignore( 7 );
+ if( NULL != pMatrix )
+ {
+ pMatrix->PutError( XclTools::GetScErrorCode( nByte ), nC, nR );
+ }
+ break;
+ }
+ }
+ }
+}
+
+void ExcelToSc::ReadExtensionNlr( XclImpStream& aIn )
+{
+ // printf( "natural lang fmla;\n" );
+
+ sal_uInt32 nFlags;
+ aIn >> nFlags;
+
+ sal_uInt32 nCount = nFlags & EXC_TOK_NLR_ADDMASK;
+ aIn.Ignore( nCount * 4 ); // Drop the cell positions
+}
+
+void ExcelToSc::ReadExtensionMemArea( XclImpStream& aIn )
+{
+ // printf( "mem area;\n" );
+
+ sal_uInt16 nCount;
+ aIn >> nCount;
+
+ aIn.Ignore( nCount * ((GetBiff() == EXC_BIFF8) ? 8 : 6) ); // drop the ranges
+}
+
+void ExcelToSc::ReadExtensions( const ExtensionTypeVec& rExtensions,
+ XclImpStream& aIn )
+{
+ unsigned int nArray = 0;
+
+ for( unsigned int i = 0 ; i < rExtensions.size() ; i++ )
+ {
+ ExtensionType eType = rExtensions[i];
+
+ switch( eType )
+ {
+ case EXTENSION_ARRAY:
+ ReadExtensionArray( nArray++, aIn );
+ break;
+
+ case EXTENSION_NLR:
+ ReadExtensionNlr( aIn );
+ break;
+
+ case EXTENSION_MEMAREA:
+ ReadExtensionMemArea( aIn );
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/excform8.cxx b/sc/source/filter/excel/excform8.cxx
new file mode 100644
index 000000000000..f989abc3c196
--- /dev/null
+++ b/sc/source/filter/excel/excform8.cxx
@@ -0,0 +1,1681 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "excform.hxx"
+
+#include "cell.hxx"
+#include "document.hxx"
+#include "rangenam.hxx"
+#include "xltracer.hxx"
+#include "xistream.hxx"
+#include "xihelper.hxx"
+#include "xilink.hxx"
+#include "xiname.hxx"
+
+#include "externalrefmgr.hxx"
+
+#include <vector>
+#include <cstring>
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::std::vector;
+
+namespace {
+
+/**
+ * Extract a file path from OLE link path. An OLE link path is expected to
+ * be in the following format:
+ *
+ * Excel.Sheet.8 \3 [file path]
+ */
+bool extractFilePath(const OUString& rUrl, OUString& rPath)
+{
+ const char* prefix = "Excel.Sheet.8\3";
+ size_t nPrefixLen = ::std::strlen(prefix);
+
+ sal_Int32 n = rUrl.getLength();
+ if (n <= static_cast<sal_Int32>(nPrefixLen))
+ // needs to have the specified prefix.
+ return false;
+
+ OUStringBuffer aBuf;
+ const sal_Unicode* p = rUrl.getStr();
+ for (size_t i = 0; i < static_cast<size_t>(n); ++i, ++p)
+ {
+ if (i < nPrefixLen)
+ {
+ sal_Unicode pc = static_cast<sal_Unicode>(*prefix++);
+ if (pc != *p)
+ return false;
+
+ continue;
+ }
+ aBuf.append(*p);
+ }
+
+ rPath = aBuf.makeStringAndClear();
+ return true;
+}
+
+}
+
+ExcelToSc8::ExternalTabInfo::ExternalTabInfo() :
+ mnFileId(0), mbExternal(false)
+{
+}
+
+// ============================================================================
+
+ExcelToSc8::ExcelToSc8( const XclImpRoot& rRoot ) :
+ ExcelToSc( rRoot ),
+ rLinkMan( rRoot.GetLinkManager() )
+{
+}
+
+
+ExcelToSc8::~ExcelToSc8()
+{
+}
+
+bool ExcelToSc8::GetExternalFileIdFromXti( sal_uInt16 nIxti, sal_uInt16& rFileId ) const
+{
+ const String* pFileUrl = rLinkMan.GetSupbookUrl(nIxti);
+ if (!pFileUrl || pFileUrl->Len() == 0 || !GetDocShell())
+ return false;
+
+ String aFileUrl = ScGlobal::GetAbsDocName(*pFileUrl, GetDocShell());
+ ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
+ rFileId = pRefMgr->getExternalFileId(aFileUrl);
+
+ return true;
+}
+
+bool ExcelToSc8::Read3DTabReference( sal_uInt16 nIxti, SCTAB& rFirstTab, SCTAB& rLastTab, ExternalTabInfo& rExtInfo )
+{
+ rFirstTab = rLastTab = 0;
+ rExtInfo.mbExternal = !rLinkMan.IsSelfRef(nIxti);
+ bool bSuccess = rLinkMan.GetScTabRange(rFirstTab, rLastTab, nIxti);
+ if (!bSuccess)
+ return false;
+
+ if (!rExtInfo.mbExternal)
+ // This is internal reference. Stop here.
+ return true;
+
+ rExtInfo.maTabName = rLinkMan.GetSupbookTabName(nIxti, rFirstTab);
+ return GetExternalFileIdFromXti(nIxti, rExtInfo.mnFileId);
+}
+
+bool ExcelToSc8::HandleOleLink(sal_uInt16 nXtiIndex, const XclImpExtName& rExtName, ExternalTabInfo& rExtInfo)
+{
+ const String* pUrl = rLinkMan.GetSupbookUrl(nXtiIndex);
+ if (!pUrl)
+ return false;
+
+ OUString aPath;
+ if (!extractFilePath(*pUrl, aPath))
+ // file path extraction failed.
+ return false;
+
+ OUString aFileUrl = ScGlobal::GetAbsDocName(aPath, GetDocShell());
+ return rExtName.CreateOleData(GetDoc(), aFileUrl, rExtInfo.mnFileId, rExtInfo.maTabName, rExtInfo.maRange);
+}
+
+// if bAllowArrays is false stream seeks to first byte after <nFormulaLen>
+// otherwise it will seek to the first byte past additional content after <nFormulaLen>
+ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, sal_Size nFormulaLen, bool bAllowArrays, const FORMULA_TYPE eFT )
+{
+ sal_uInt8 nOp, nLen, nByte;
+ sal_uInt16 nUINT16;
+ double fDouble;
+ String aString;
+ sal_Bool bError = false;
+ sal_Bool bArrayFormula = false;
+ TokenId nMerk0;
+ const sal_Bool bRangeName = eFT == FT_RangeName;
+ const sal_Bool bSharedFormula = eFT == FT_SharedFormula;
+ const sal_Bool bRNorSF = bRangeName || bSharedFormula;
+
+ ScSingleRefData aSRD;
+ ScComplexRefData aCRD;
+ ExtensionTypeVec aExtensions;
+
+ if( eStatus != ConvOK )
+ {
+ aIn.Ignore( nFormulaLen );
+ return eStatus;
+ }
+
+ if( nFormulaLen == 0 )
+ {
+ aPool.Store( CREATE_STRING( "-/-" ) );
+ aPool >> aStack;
+ rpTokArray = aPool[ aStack.Get() ];
+ return ConvOK;
+ }
+
+ sal_Size nEndPos = aIn.GetRecPos() + nFormulaLen;
+
+ while( (aIn.GetRecPos() < nEndPos) && !bError )
+ {
+ aIn >> nOp;
+
+ // always reset flags
+ aSRD.InitFlags();
+ aCRD.InitFlags();
+
+ switch( nOp ) // Buch Seite:
+ { // SDK4 SDK5
+ case 0x01: // Array Formula [325 ]
+ // Array Formula or Shared Formula [ 277]
+ case 0x02: // Data Table [325 277]
+ aIn.Ignore( 4 );
+
+ bArrayFormula = sal_True;
+ break;
+ case 0x03: // Addition [312 264]
+ aStack >> nMerk0;
+ aPool << aStack << ocAdd << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x04: // Subtraction [313 264]
+ // SECOMD-TOP minus TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocSub << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x05: // Multiplication [313 264]
+ aStack >> nMerk0;
+ aPool << aStack << ocMul << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x06: // Division [313 264]
+ // divide TOP by SECOND-TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocDiv << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x07: // Exponetiation [313 265]
+ // raise SECOND-TOP to power of TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocPow << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x08: // Concatenation [313 265]
+ // append TOP to SECOND-TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocAmpersand << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x09: // Less Than [313 265]
+ // SECOND-TOP < TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocLess << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0A: // Less Than or Equal [313 265]
+ // SECOND-TOP <= TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocLessEqual << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0B: // Equal [313 265]
+ // SECOND-TOP == TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocEqual << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0C: // Greater Than or Equal [313 265]
+ // SECOND-TOP == TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocGreaterEqual << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0D: // Greater Than [313 265]
+ // SECOND-TOP == TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocGreater << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0E: // Not Equal [313 265]
+ // SECOND-TOP == TOP
+ aStack >> nMerk0;
+ aPool << aStack << ocNotEqual << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x0F: // Intersection [314 265]
+ aStack >> nMerk0;
+ aPool << aStack << ocIntersect << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x10: // Union [314 265]
+ // ocSep behelfsweise statt 'ocUnion'
+ aStack >> nMerk0;
+ aPool << aStack << ocSep << nMerk0;
+ // doesn't fit exactly, but is more Excel-like
+ aPool >> aStack;
+ break;
+ case 0x11: // Range [314 265]
+ aStack >> nMerk0;
+ aPool << aStack << ocRange << nMerk0;
+ aPool >> aStack;
+ break;
+ case 0x12: // Unary Plus [312 264]
+ aPool << ocAdd << aStack;
+ aPool >> aStack;
+ break;
+ case 0x13: // Unary Minus [312 264]
+ aPool << ocNegSub << aStack;
+ aPool >> aStack;
+ break;
+ case 0x14: // Percent Sign [312 264]
+ aPool << aStack << ocPercentSign;
+ aPool >> aStack;
+ break;
+ case 0x15: // Parenthesis [326 278]
+ aPool << ocOpen << aStack << ocClose;
+ aPool >> aStack;
+ break;
+ case 0x16: // Missing Argument [314 266]
+ aPool << ocMissing;
+ aPool >> aStack;
+ GetTracer().TraceFormulaMissingArg();
+ break;
+ case 0x17: // String Constant [314 266]
+ aIn >> nLen; // und?
+ aString = aIn.ReadUniString( nLen ); // reads Grbit even if nLen==0
+
+ aStack << aPool.Store( aString );
+ break;
+ case 0x18: // natural language formula
+ {
+ sal_uInt8 nEptg;
+ sal_uInt16 nCol, nRow;
+ aIn >> nEptg;
+ switch( nEptg )
+ { // name size ext type
+ case 0x01: // Lel 4 - err
+ aIn.Ignore( 4 );
+ aPool << ocBad;
+ aPool >> aStack;
+ break;
+ case 0x02: // Rw 4 - ref
+ case 0x03: // Col 4 - ref
+ case 0x06: // RwV 4 - val
+ case 0x07: // ColV 4 - val
+ aIn >> nRow >> nCol;
+
+ aSRD.InitAddress( ScAddress( static_cast<SCCOL>(nCol & 0xFF), static_cast<SCROW>(nRow), aEingPos.Tab() ) );
+
+ if( nEptg == 0x02 || nEptg == 0x06 )
+ aSRD.SetRowRel( sal_True );
+ else
+ aSRD.SetColRel( sal_True );
+
+ aSRD.CalcRelFromAbs( aEingPos );
+
+ aStack << aPool.StoreNlf( aSRD );
+ break;
+ case 0x0A: // Radical 13 - ref
+ aIn >> nRow >> nCol;
+ aIn.Ignore( 9 );
+
+ aSRD.InitAddress( ScAddress( static_cast<SCCOL>(nCol & 0xFF), static_cast<SCROW>(nRow), aEingPos.Tab() ) );
+
+ aSRD.SetColRel( sal_True );
+
+ aSRD.CalcRelFromAbs( aEingPos );
+
+ aStack << aPool.StoreNlf( aSRD );
+ break;
+ case 0x0B: // RadicalS 13 x ref
+ aIn.Ignore( 13 );
+ aExtensions.push_back( EXTENSION_NLR );
+ aPool << ocBad;
+ aPool >> aStack;
+ break;
+ case 0x0C: // RwS 4 x ref
+ case 0x0D: // ColS 4 x ref
+ case 0x0E: // RwSV 4 x val
+ case 0x0F: // ColSV 4 x val
+ aIn.Ignore( 4 );
+ aExtensions.push_back( EXTENSION_NLR );
+ aPool << ocBad;
+ aPool >> aStack;
+ break;
+ case 0x10: // RadicalLel 4 - err
+ case 0x1D: // SxName 4 - val
+ aIn.Ignore( 4 );
+ aPool << ocBad;
+ aPool >> aStack;
+ break;
+ default:
+ aPool << ocBad;
+ aPool >> aStack;
+ }
+ }
+ break;
+ case 0x19: // Special Attribute [327 279]
+ {
+ sal_uInt16 nData, nFakt;
+ sal_uInt8 nOpt;
+
+ aIn >> nOpt >> nData;
+ nFakt = 2;
+
+ if( nOpt & 0x04 )
+ {// nFakt -> Bytes oder Words ueberlesen AttrChoose
+ nData++;
+ aIn.Ignore( nData * nFakt );
+ }
+ else if( nOpt & 0x10 ) // AttrSum
+ DoMulArgs( ocSum, 1 );
+ }
+ break;
+ case 0x1C: // Error Value [314 266]
+ {
+ aIn >> nByte;
+
+ DefTokenId eOc;
+ switch( nByte )
+ {
+ case EXC_ERR_NULL:
+ case EXC_ERR_DIV0:
+ case EXC_ERR_VALUE:
+ case EXC_ERR_REF:
+ case EXC_ERR_NAME:
+ case EXC_ERR_NUM: eOc = ocStop; break;
+ case EXC_ERR_NA: eOc = ocNotAvail; break;
+ default: eOc = ocNoName;
+ }
+ aPool << eOc;
+ if( eOc != ocStop )
+ aPool << ocOpen << ocClose;
+ aPool >> aStack;
+ }
+ break;
+ case 0x1D: // Boolean [315 266]
+ aIn >> nByte;
+ if( nByte == 0 )
+ aPool << ocFalse << ocOpen << ocClose;
+ else
+ aPool << ocTrue << ocOpen << ocClose;
+ aPool >> aStack;
+ break;
+ case 0x1E: // Integer [315 266]
+ aIn >> nUINT16;
+ aStack << aPool.Store( ( double ) nUINT16 );
+ break;
+ case 0x1F: // Number [315 266]
+ aIn >> fDouble;
+ aStack << aPool.Store( fDouble );
+ break;
+ case 0x40:
+ case 0x60:
+ case 0x20: // Array Constant [317 268]
+ aIn >> nByte >> nUINT16;
+ aIn.Ignore( 4 );
+ if( bAllowArrays )
+ {
+ aStack << aPool.StoreMatrix();
+ aExtensions.push_back( EXTENSION_ARRAY );
+ }
+ else
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ }
+ break;
+ case 0x41:
+ case 0x61:
+ case 0x21: // Function, Fixed Number of Arguments [333 282]
+ {
+ sal_uInt16 nXclFunc;
+ aIn >> nXclFunc;
+ if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclFunc( nXclFunc ) )
+ DoMulArgs( pFuncInfo->meOpCode, pFuncInfo->mnMaxParamCount );
+ else
+ DoMulArgs( ocNoName, 0 );
+ }
+ break;
+ case 0x42:
+ case 0x62:
+ case 0x22: // Function, Variable Number of Arg. [333 283]
+ {
+ sal_uInt16 nXclFunc;
+ sal_uInt8 nParamCount;
+ aIn >> nParamCount >> nXclFunc;
+ nParamCount &= 0x7F;
+ if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclFunc( nXclFunc ) )
+ DoMulArgs( pFuncInfo->meOpCode, nParamCount );
+ else
+ DoMulArgs( ocNoName, 0 );
+ }
+ break;
+ case 0x43:
+ case 0x63:
+ case 0x23: // Name [318 269]
+ {
+ aIn >> nUINT16;
+ aIn.Ignore( 2 );
+ const XclImpName* pName = GetNameManager().GetName( nUINT16 );
+ if (pName)
+ {
+ if (pName->GetScRangeData())
+ aStack << aPool.StoreName(nUINT16, pName->IsGlobal());
+ else
+ // used-defined macro name.
+ aStack << aPool.Store(ocMacro, pName->GetXclName());
+ }
+ }
+ break;
+ case 0x44:
+ case 0x64:
+ case 0x24: // Cell Reference [319 270]
+ case 0x4A:
+ case 0x6A:
+ case 0x2A: // Deleted Cell Reference [323 273]
+ {
+ sal_uInt16 nCol, nRow;
+
+ aIn >> nRow >> nCol;
+
+ aSRD.nCol = static_cast<SCCOL>(nCol);
+ aSRD.nRow = nRow & 0x3FFF;
+ aSRD.nRelTab = 0;
+ aSRD.SetTabRel( sal_True );
+ aSRD.SetFlag3D( bRangeName );
+
+ ExcRelToScRel8( nRow, nCol, aSRD, bRangeName );
+
+ switch ( nOp )
+ {
+ case 0x4A:
+ case 0x6A:
+ case 0x2A: // Deleted Cell Reference [323 273]
+ // no information which part is deleted, set both
+ aSRD.SetColDeleted( sal_True );
+ aSRD.SetRowDeleted( sal_True );
+ }
+
+ aStack << aPool.Store( aSRD );
+ }
+ break;
+ case 0x45:
+ case 0x65:
+ case 0x25: // Area Reference [320 270]
+ case 0x4B:
+ case 0x6B:
+ case 0x2B: // Deleted Area Refernce [323 273]
+ {
+ sal_uInt16 nRowFirst, nRowLast;
+ sal_uInt16 nColFirst, nColLast;
+ ScSingleRefData &rSRef1 = aCRD.Ref1;
+ ScSingleRefData &rSRef2 = aCRD.Ref2;
+
+ aIn >> nRowFirst >> nRowLast >> nColFirst >> nColLast;
+
+ rSRef1.nRelTab = rSRef2.nRelTab = 0;
+ rSRef1.SetTabRel( sal_True );
+ rSRef2.SetTabRel( sal_True );
+ rSRef1.SetFlag3D( bRangeName );
+ rSRef2.SetFlag3D( bRangeName );
+
+ ExcRelToScRel8( nRowFirst, nColFirst, aCRD.Ref1, bRangeName );
+ ExcRelToScRel8( nRowLast, nColLast, aCRD.Ref2, bRangeName );
+
+ if( IsComplColRange( nColFirst, nColLast ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRowFirst, nRowLast ) )
+ SetComplRow( aCRD );
+
+ switch ( nOp )
+ {
+ case 0x4B:
+ case 0x6B:
+ case 0x2B: // Deleted Area Refernce [323 273]
+ // no information which part is deleted, set all
+ rSRef1.SetColDeleted( sal_True );
+ rSRef1.SetRowDeleted( sal_True );
+ rSRef2.SetColDeleted( sal_True );
+ rSRef2.SetRowDeleted( sal_True );
+ }
+
+ aStack << aPool.Store( aCRD );
+ }
+ break;
+ case 0x46:
+ case 0x66:
+ case 0x26: // Constant Reference Subexpression [321 271]
+ aExtensions.push_back( EXTENSION_MEMAREA );
+ aIn.Ignore( 6 ); // mehr steht da nicht!
+ break;
+ case 0x47:
+ case 0x67:
+ case 0x27: // Erroneous Constant Reference Subexpr. [322 272]
+ aIn.Ignore( 6 ); // mehr steht da nicht!
+// aPool << ocBad;
+// aPool >> aStack;
+ break;
+ case 0x48:
+ case 0x68:
+ case 0x28: // Incomplete Constant Reference Subexpr.[331 281]
+ aIn.Ignore( 6 ); // mehr steht da nicht!
+// aPool << ocBad;
+// aPool >> aStack;
+ break;
+ case 0x49:
+ case 0x69:
+ case 0x29: // Variable Reference Subexpression [331 281]
+ aIn.Ignore( 2 ); // mehr steht da nicht!
+ break;
+ case 0x4C:
+ case 0x6C:
+ case 0x2C: // Cell Reference Within a Name [323 ]
+ // Cell Reference Within a Shared Formula[ 273]
+ {
+ sal_uInt16 nRow, nCol;
+
+ aIn >> nRow >> nCol;
+
+ aSRD.nRelTab = 0;
+ aSRD.SetTabRel( sal_True );
+ aSRD.SetFlag3D( bRangeName );
+
+ ExcRelToScRel8( nRow, nCol, aSRD, bRNorSF );
+
+ aStack << aPool.Store( aSRD );
+ }
+ break;
+ case 0x4D:
+ case 0x6D:
+ case 0x2D: // Area Reference Within a Name [324 ]
+ { // Area Reference Within a Shared Formula[ 274]
+ sal_uInt16 nRowFirst, nRowLast;
+ sal_uInt16 nColFirst, nColLast;
+
+ aCRD.Ref1.nRelTab = aCRD.Ref2.nRelTab = 0;
+ aCRD.Ref1.SetTabRel( sal_True );
+ aCRD.Ref2.SetTabRel( sal_True );
+ aCRD.Ref1.SetFlag3D( bRangeName );
+ aCRD.Ref2.SetFlag3D( bRangeName );
+
+ aIn >> nRowFirst >> nRowLast >> nColFirst >> nColLast;
+
+ ExcRelToScRel8( nRowFirst, nColFirst, aCRD.Ref1, bRNorSF );
+ ExcRelToScRel8( nRowLast, nColLast, aCRD.Ref2, bRNorSF );
+
+ if( IsComplColRange( nColFirst, nColLast ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRowFirst, nRowLast ) )
+ SetComplRow( aCRD );
+
+ aStack << aPool.Store( aCRD );
+ }
+ break;
+ case 0x4E:
+ case 0x6E:
+ case 0x2E: // Reference Subexpression Within a Name [332 282]
+ aIn.Ignore( 2 ); // mehr steht da nicht!
+// aPool << ocBad;
+// aPool >> aStack;
+ break;
+ case 0x4F:
+ case 0x6F:
+ case 0x2F: // Incomplete Reference Subexpression... [332 282]
+ aIn.Ignore( 2 ); // mehr steht da nicht!
+// aPool << ocBad;
+// aPool >> aStack;
+ break;
+ case 0x58:
+ case 0x78:
+ case 0x38: // Command-Equivalent Function [333 ]
+ aString.AssignAscii( "COMM_EQU_FUNC" );
+ aIn >> nByte;
+ aString += String::CreateFromInt32( nByte );
+ aIn >> nByte;
+ aStack << aPool.Store( aString );
+ DoMulArgs( ocPush, nByte + 1 );
+ break;
+ case 0x59:
+ case 0x79:
+ case 0x39: // Name or External Name [ 275]
+ {
+ sal_uInt16 nXtiIndex, nNameIdx;
+ aIn >> nXtiIndex >> nNameIdx;
+ aIn.Ignore( 2 );
+
+ if( rLinkMan.IsSelfRef( nXtiIndex ) )
+ {
+ // internal defined name with explicit sheet, i.e.: =Sheet1!AnyName
+ const XclImpName* pName = GetNameManager().GetName( nNameIdx );
+ if (pName)
+ {
+ if (pName->GetScRangeData())
+ aStack << aPool.StoreName( nNameIdx, pName->IsGlobal());
+ else
+ aStack << aPool.Store(ocMacro, pName->GetXclName());
+ }
+ }
+ else if( const XclImpExtName* pExtName = rLinkMan.GetExternName( nXtiIndex, nNameIdx ) )
+ {
+ switch( pExtName->GetType() )
+ {
+ case xlExtName:
+ {
+ /* FIXME: enable this code for #i4385# once
+ * external name reference can be stored in ODF,
+ * which remains to be done for #i3740#. Until then
+ * create a #NAME? token. */
+#if 1
+ sal_uInt16 nFileId;
+ if (!GetExternalFileIdFromXti(nXtiIndex, nFileId) || !pExtName->HasFormulaTokens())
+ {
+ aStack << aPool.Store(ocNoName, pExtName->GetName());
+ break;
+ }
+
+ aStack << aPool.StoreExtName(nFileId, pExtName->GetName());
+ pExtName->CreateExtNameData(GetDoc(), nFileId);
+#else
+ aStack << aPool.Store( ocNoName, pExtName->GetName() );
+#endif
+ }
+ break;
+
+ case xlExtAddIn:
+ {
+ aStack << aPool.Store( ocExternal, pExtName->GetName() );
+ }
+ break;
+
+ case xlExtDDE:
+ {
+ String aApplic, aTopic;
+ if( rLinkMan.GetLinkData( aApplic, aTopic, nXtiIndex ) )
+ {
+ TokenId nPar1 = aPool.Store( aApplic );
+ TokenId nPar2 = aPool.Store( aTopic );
+ nMerk0 = aPool.Store( pExtName->GetName() );
+ aPool << ocDde << ocOpen << nPar1 << ocSep << nPar2 << ocSep
+ << nMerk0 << ocClose;
+ aPool >> aStack;
+ pExtName->CreateDdeData( GetDoc(), aApplic, aTopic );
+ }
+ }
+ break;
+
+ case xlExtEuroConvert:
+ {
+ aStack << aPool.Store( ocEuroConvert, String() );
+ }
+ break;
+ case xlExtOLE:
+ {
+ ExternalTabInfo aExtInfo;
+ if (HandleOleLink(nXtiIndex, *pExtName, aExtInfo))
+ {
+ if (aExtInfo.maRange.aStart == aExtInfo.maRange.aEnd)
+ {
+ // single cell
+ aSRD.InitAddress(aExtInfo.maRange.aStart);
+ aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aSRD);
+ }
+ else
+ {
+ // range
+ aCRD.InitRange(aExtInfo.maRange);
+ aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aCRD);
+ }
+ }
+ else
+ aStack << aPool.Store(ocNoName, pExtName->GetName());
+ }
+ break;
+ default:
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ }
+ }
+ }
+ else
+ {
+ //aStack << ocNoName;
+ aPool << ocBad;
+ aPool >> aStack;
+ }
+ }
+ break;
+ case 0x5A:
+ case 0x7A:
+ case 0x3A: // 3-D Cell Reference [ 275]
+ case 0x5C:
+ case 0x7C:
+ case 0x3C: // Deleted 3-D Cell Reference [ 277]
+ {
+ sal_uInt16 nIxti, nRw, nGrbitCol;
+ SCTAB nTabFirst, nTabLast;
+
+ aIn >> nIxti >> nRw >> nGrbitCol;
+
+ ExternalTabInfo aExtInfo;
+ if (!Read3DTabReference(nIxti, nTabFirst, nTabLast, aExtInfo))
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ break;
+ }
+
+ aSRD.nTab = nTabFirst;
+ aSRD.SetFlag3D( sal_True );
+ aSRD.SetTabRel( false );
+
+ ExcRelToScRel8( nRw, nGrbitCol, aSRD, bRangeName );
+
+ switch ( nOp )
+ {
+ case 0x5C:
+ case 0x7C:
+ case 0x3C: // Deleted 3-D Cell Reference [ 277]
+ // no information which part is deleted, set both
+ aSRD.SetColDeleted( sal_True );
+ aSRD.SetRowDeleted( sal_True );
+ }
+
+ if (aExtInfo.mbExternal)
+ {
+ // nTabFirst and nTabLast are the indices of the refernced
+ // sheets in the SUPBOOK record, hence do not represent
+ // the actual indices of the original sheets since the
+ // SUPBOOK record only stores referenced sheets and skips
+ // the ones that are not referenced.
+
+ if (nTabLast != nTabFirst)
+ {
+ aCRD.Ref1 = aCRD.Ref2 = aSRD;
+ aCRD.Ref2.nTab = nTabLast;
+ aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aCRD);
+ }
+ else
+ aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aSRD);
+ }
+ else
+ {
+ if ( !ValidTab(nTabFirst))
+ aSRD.SetTabDeleted( sal_True );
+
+ if( nTabLast != nTabFirst )
+ {
+ aCRD.Ref1 = aCRD.Ref2 = aSRD;
+ aCRD.Ref2.nTab = nTabLast;
+ aCRD.Ref2.SetTabDeleted( !ValidTab(nTabLast) );
+ aStack << aPool.Store( aCRD );
+ }
+ else
+ aStack << aPool.Store( aSRD );
+ }
+ }
+ break;
+ case 0x5B:
+ case 0x7B:
+ case 0x3B: // 3-D Area Reference [ 276]
+ case 0x5D:
+ case 0x7D:
+ case 0x3D: // Deleted 3-D Area Reference [ 277]
+ {
+ sal_uInt16 nIxti, nRw1, nGrbitCol1, nRw2, nGrbitCol2;
+ SCTAB nTabFirst, nTabLast;
+ aIn >> nIxti >> nRw1 >> nRw2 >> nGrbitCol1 >> nGrbitCol2;
+
+ ExternalTabInfo aExtInfo;
+ if (!Read3DTabReference(nIxti, nTabFirst, nTabLast, aExtInfo))
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ break;
+ }
+ ScSingleRefData &rR1 = aCRD.Ref1;
+ ScSingleRefData &rR2 = aCRD.Ref2;
+
+
+ rR1.nTab = nTabFirst;
+ rR2.nTab = nTabLast;
+ rR1.SetFlag3D( sal_True );
+ rR1.SetTabRel( false );
+ rR2.SetFlag3D( nTabFirst != nTabLast );
+ rR2.SetTabRel( false );
+
+ ExcRelToScRel8( nRw1, nGrbitCol1, aCRD.Ref1, bRangeName );
+ ExcRelToScRel8( nRw2, nGrbitCol2, aCRD.Ref2, bRangeName );
+
+ if( IsComplColRange( nGrbitCol1, nGrbitCol2 ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRw1, nRw2 ) )
+ SetComplRow( aCRD );
+
+ switch ( nOp )
+ {
+ case 0x5D:
+ case 0x7D:
+ case 0x3D: // Deleted 3-D Area Reference [ 277]
+ // no information which part is deleted, set all
+ rR1.SetColDeleted( sal_True );
+ rR1.SetRowDeleted( sal_True );
+ rR2.SetColDeleted( sal_True );
+ rR2.SetRowDeleted( sal_True );
+ }
+
+ if (aExtInfo.mbExternal)
+ {
+ aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aCRD);
+ }
+ else
+ {
+ if ( !ValidTab(nTabFirst) )
+ rR1.SetTabDeleted( sal_True );
+ if ( !ValidTab(nTabLast) )
+ rR2.SetTabDeleted( sal_True );
+
+ aStack << aPool.Store( aCRD );
+ }
+ }
+ break;
+ default: bError = sal_True;
+ }
+ bError |= !aIn.IsValid();
+ }
+
+ ConvErr eRet;
+
+ if( bError )
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ rpTokArray = aPool[ aStack.Get() ];
+ eRet = ConvErrNi;
+ }
+ else if( aIn.GetRecPos() != nEndPos )
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ rpTokArray = aPool[ aStack.Get() ];
+ eRet = ConvErrCount;
+ }
+ else if( bArrayFormula )
+ {
+ rpTokArray = NULL;
+ eRet = ConvOK;
+ }
+ else
+ {
+ rpTokArray = aPool[ aStack.Get() ];
+ eRet = ConvOK;
+ }
+
+ aIn.Seek( nEndPos );
+
+ if( eRet == ConvOK)
+ ReadExtensions( aExtensions, aIn );
+
+ return eRet;
+}
+
+
+// stream seeks to first byte after <nFormulaLen>
+ConvErr ExcelToSc8::Convert( _ScRangeListTabs& rRangeList, XclImpStream& aIn, sal_Size nFormulaLen,
+ SCsTAB nTab, const FORMULA_TYPE eFT )
+{
+ sal_uInt8 nOp, nLen;//, nByte;
+ sal_Bool bError = false;
+ const sal_Bool bRangeName = eFT == FT_RangeName;
+ const sal_Bool bSharedFormula = eFT == FT_SharedFormula;
+ const sal_Bool bRNorSF = bRangeName || bSharedFormula;
+
+ ScSingleRefData aSRD;
+ ScComplexRefData aCRD;
+
+ bExternName = false;
+
+ if( eStatus != ConvOK )
+ {
+ aIn.Ignore( nFormulaLen );
+ return eStatus;
+ }
+
+ if( nFormulaLen == 0 )
+ return ConvOK;
+
+ sal_Size nEndPos = aIn.GetRecPos() + nFormulaLen;
+
+ while( (aIn.GetRecPos() < nEndPos) && !bError )
+ {
+ aIn >> nOp;
+
+ // always reset flags
+ aSRD.InitFlags();
+ aCRD.InitFlags();
+
+ switch( nOp ) // Buch Seite:
+ { // SDK4 SDK5
+ case 0x01: // Array Formula [325 ]
+ // Array Formula or Shared Formula [ 277]
+ aIn.Ignore( 4 );
+ break;
+ case 0x02: // Data Table [325 277]
+ aIn.Ignore( 4 );
+ break;
+ case 0x03: // Addition [312 264]
+ case 0x04: // Subtraction [313 264]
+ case 0x05: // Multiplication [313 264]
+ case 0x06: // Division [313 264]
+ case 0x07: // Exponetiation [313 265]
+ case 0x08: // Concatenation [313 265]
+ case 0x09: // Less Than [313 265]
+ case 0x0A: // Less Than or Equal [313 265]
+ case 0x0B: // Equal [313 265]
+ case 0x0C: // Greater Than or Equal [313 265]
+ case 0x0D: // Greater Than [313 265]
+ case 0x0E: // Not Equal [313 265]
+ case 0x0F: // Intersection [314 265]
+ case 0x10: // Union [314 265]
+ case 0x11: // Range [314 265]
+ case 0x12: // Unary Plus [312 264]
+ case 0x13: // Unary Minus [312 264]
+ case 0x14: // Percent Sign [312 264]
+ case 0x15: // Parenthesis [326 278]
+ case 0x16: // Missing Argument [314 266]
+ break;
+ case 0x17: // String Constant [314 266]
+ aIn >> nLen; // und?
+
+ aIn.IgnoreUniString( nLen ); // reads Grbit even if nLen==0
+ break;
+ case 0x19: // Special Attribute [327 279]
+ {
+ sal_uInt16 nData, nFakt;
+ sal_uInt8 nOpt;
+
+ aIn >> nOpt >> nData;
+ nFakt = 2;
+
+ if( nOpt & 0x04 )
+ {// nFakt -> Bytes oder Words ueberlesen AttrChoose
+ nData++;
+ aIn.Ignore( nData * nFakt );
+ }
+ }
+ break;
+ case 0x1C: // Error Value [314 266]
+ case 0x1D: // Boolean [315 266]
+ aIn.Ignore( 1 );
+ break;
+ case 0x1E: // Integer [315 266]
+ aIn.Ignore( 2 );
+ break;
+ case 0x1F: // Number [315 266]
+ aIn.Ignore( 8 );
+ break;
+ case 0x40:
+ case 0x60:
+ case 0x20: // Array Constant [317 268]
+ aIn.Ignore( 7 );
+ break;
+ case 0x41:
+ case 0x61:
+ case 0x21: // Function, Fixed Number of Arguments [333 282]
+ aIn.Ignore( 2 );
+ break;
+ case 0x42:
+ case 0x62:
+ case 0x22: // Function, Variable Number of Arg. [333 283]
+ aIn.Ignore( 3 );
+ break;
+ case 0x43:
+ case 0x63:
+ case 0x23: // Name [318 269]
+ aIn.Ignore( 4 );
+ break;
+ case 0x44:
+ case 0x64:
+ case 0x24: // Cell Reference [319 270]
+ {
+ sal_uInt16 nCol, nRow;
+
+ aIn >> nRow >> nCol;
+
+ aSRD.nCol = static_cast<SCCOL>(nCol);
+ aSRD.nRow = nRow & 0x3FFF;
+ aSRD.nRelTab = 0;
+ aSRD.SetTabRel( sal_True );
+ aSRD.SetFlag3D( bRangeName );
+
+ ExcRelToScRel8( nRow, nCol, aSRD, bRangeName );
+
+ rRangeList.Append( aSRD, nTab );
+ }
+ break;
+ case 0x45:
+ case 0x65:
+ case 0x25: // Area Reference [320 270]
+ {
+ sal_uInt16 nRowFirst, nRowLast;
+ sal_uInt16 nColFirst, nColLast;
+ ScSingleRefData &rSRef1 = aCRD.Ref1;
+ ScSingleRefData &rSRef2 = aCRD.Ref2;
+
+ aIn >> nRowFirst >> nRowLast >> nColFirst >> nColLast;
+
+ rSRef1.nRelTab = rSRef2.nRelTab = 0;
+ rSRef1.SetTabRel( sal_True );
+ rSRef2.SetTabRel( sal_True );
+ rSRef1.SetFlag3D( bRangeName );
+ rSRef2.SetFlag3D( bRangeName );
+
+ ExcRelToScRel8( nRowFirst, nColFirst, aCRD.Ref1, bRangeName );
+ ExcRelToScRel8( nRowLast, nColLast, aCRD.Ref2, bRangeName );
+
+ if( IsComplColRange( nColFirst, nColLast ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRowFirst, nRowLast ) )
+ SetComplRow( aCRD );
+
+ rRangeList.Append( aCRD, nTab );
+ }
+ break;
+ case 0x46:
+ case 0x66:
+ case 0x26: // Constant Reference Subexpression [321 271]
+ case 0x47:
+ case 0x67:
+ case 0x27: // Erroneous Constant Reference Subexpr. [322 272]
+ case 0x48:
+ case 0x68:
+ case 0x28: // Incomplete Constant Reference Subexpr.[331 281]
+ aIn.Ignore( 6 ); // mehr steht da nicht!
+ break;
+ case 0x49:
+ case 0x69:
+ case 0x29: // Variable Reference Subexpression [331 281]
+ aIn.Ignore( 2 ); // mehr steht da nicht!
+ break;
+ case 0x4A:
+ case 0x6A:
+ case 0x2A: // Deleted Cell Reference [323 273]
+ aIn.Ignore( 3 );
+ break;
+ case 0x4B:
+ case 0x6B:
+ case 0x2B: // Deleted Area Refernce [323 273]
+ aIn.Ignore( 6 );
+ break;
+ case 0x4C:
+ case 0x6C:
+ case 0x2C: // Cell Reference Within a Name [323 ]
+ // Cell Reference Within a Shared Formula[ 273]
+ {
+ sal_uInt16 nRow, nCol;
+
+ aIn >> nRow >> nCol;
+
+ aSRD.nRelTab = 0;
+ aSRD.SetTabRel( sal_True );
+ aSRD.SetFlag3D( bRangeName );
+
+ ExcRelToScRel8( nRow, nCol, aSRD, bRNorSF );
+
+ rRangeList.Append( aSRD, nTab );
+ }
+ break;
+ case 0x4D:
+ case 0x6D:
+ case 0x2D: // Area Reference Within a Name [324 ]
+ { // Area Reference Within a Shared Formula[ 274]
+ sal_uInt16 nRowFirst, nRowLast;
+ sal_uInt16 nColFirst, nColLast;
+
+ aCRD.Ref1.nRelTab = aCRD.Ref2.nRelTab = 0;
+ aCRD.Ref1.SetTabRel( sal_True );
+ aCRD.Ref2.SetTabRel( sal_True );
+ aCRD.Ref1.SetFlag3D( bRangeName );
+ aCRD.Ref2.SetFlag3D( bRangeName );
+
+ aIn >> nRowFirst >> nRowLast >> nColFirst >> nColLast;
+
+ ExcRelToScRel8( nRowFirst, nColFirst, aCRD.Ref1, bRNorSF );
+ ExcRelToScRel8( nRowLast, nColLast, aCRD.Ref2, bRNorSF );
+
+ if( IsComplColRange( nColFirst, nColLast ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRowFirst, nRowLast ) )
+ SetComplRow( aCRD );
+
+ rRangeList.Append( aCRD, nTab );
+ }
+ break;
+ case 0x4E:
+ case 0x6E:
+ case 0x2E: // Reference Subexpression Within a Name [332 282]
+ case 0x4F:
+ case 0x6F:
+ case 0x2F: // Incomplete Reference Subexpression... [332 282]
+ case 0x58:
+ case 0x78:
+ case 0x38: // Command-Equivalent Function [333 ]
+ aIn.Ignore( 2 );
+ break;
+ case 0x59:
+ case 0x79:
+ case 0x39: // Name or External Name [ 275]
+ aIn.Ignore( 24 );
+ break;
+ case 0x5A:
+ case 0x7A:
+ case 0x3A: // 3-D Cell Reference [ 275]
+ {
+ sal_uInt16 nIxti, nRw, nGrbitCol;
+
+ aIn >> nIxti >> nRw >> nGrbitCol;
+
+ SCTAB nFirstScTab, nLastScTab;
+ if( rLinkMan.GetScTabRange( nFirstScTab, nLastScTab, nIxti ) )
+ {
+ aSRD.nTab = nFirstScTab;
+ aSRD.SetFlag3D( sal_True );
+ aSRD.SetTabRel( false );
+
+ ExcRelToScRel8( nRw, nGrbitCol, aSRD, bRangeName );
+
+ if( nFirstScTab != nLastScTab )
+ {
+ aCRD.Ref1 = aSRD;
+ aCRD.Ref2.nCol = aSRD.nCol;
+ aCRD.Ref2.nRow = aSRD.nRow;
+ aCRD.Ref2.nTab = nLastScTab;
+ rRangeList.Append( aCRD, nTab );
+ }
+ else
+ rRangeList.Append( aSRD, nTab );
+ }
+ }
+ break;
+ case 0x5B:
+ case 0x7B:
+ case 0x3B: // 3-D Area Reference [ 276]
+ {
+ sal_uInt16 nIxti, nRw1, nGrbitCol1, nRw2, nGrbitCol2;
+
+ aIn >> nIxti >> nRw1 >> nRw2 >> nGrbitCol1 >> nGrbitCol2;
+
+ SCTAB nFirstScTab, nLastScTab;
+ if( rLinkMan.GetScTabRange( nFirstScTab, nLastScTab, nIxti ) )
+ {
+ ScSingleRefData &rR1 = aCRD.Ref1;
+ ScSingleRefData &rR2 = aCRD.Ref2;
+
+ rR1.nTab = nFirstScTab;
+ rR2.nTab = nLastScTab;
+ rR1.SetFlag3D( sal_True );
+ rR1.SetTabRel( false );
+ rR2.SetFlag3D( nFirstScTab != nLastScTab );
+ rR2.SetTabRel( false );
+
+ ExcRelToScRel8( nRw1, nGrbitCol1, aCRD.Ref1, bRangeName );
+ ExcRelToScRel8( nRw2, nGrbitCol2, aCRD.Ref2, bRangeName );
+
+ if( IsComplColRange( nGrbitCol1, nGrbitCol2 ) )
+ SetComplCol( aCRD );
+ else if( IsComplRowRange( nRw1, nRw2 ) )
+ SetComplRow( aCRD );
+
+ rRangeList.Append( aCRD, nTab );
+ }
+ }
+ break;
+ case 0x5C:
+ case 0x7C:
+ case 0x3C: // Deleted 3-D Cell Reference [ 277]
+ aIn.Ignore( 6 );
+ break;
+ case 0x5D:
+ case 0x7D:
+ case 0x3D: // Deleted 3-D Area Reference [ 277]
+ aIn.Ignore( 10 );
+ break;
+ default:
+ bError = sal_True;
+ }
+ bError |= !aIn.IsValid();
+ }
+
+ ConvErr eRet;
+
+ if( bError )
+ eRet = ConvErrNi;
+ else if( aIn.GetRecPos() != nEndPos )
+ eRet = ConvErrCount;
+ else if( bExternName )
+ eRet = ConvErrExternal;
+ else
+ eRet = ConvOK;
+
+ aIn.Seek( nEndPos );
+ return eRet;
+}
+
+ConvErr ExcelToSc8::ConvertExternName( const ScTokenArray*& rpArray, XclImpStream& rStrm, sal_Size nFormulaLen,
+ const String& rUrl, const vector<String>& rTabNames )
+{
+ if( !GetDocShell() )
+ return ConvErrNi;
+
+ String aFileUrl = ScGlobal::GetAbsDocName(rUrl, GetDocShell());
+
+ sal_uInt8 nOp, nByte;
+ bool bError = false;
+
+ ScSingleRefData aSRD;
+ ScComplexRefData aCRD;
+
+ if (eStatus != ConvOK)
+ {
+ rStrm.Ignore(nFormulaLen);
+ return eStatus;
+ }
+
+ if (nFormulaLen == 0)
+ {
+ aPool.Store(CREATE_STRING("-/-"));
+ aPool >> aStack;
+ rpArray = aPool[aStack.Get()];
+ return ConvOK;
+ }
+
+ ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
+ sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFileUrl);
+ sal_uInt16 nTabCount = static_cast< sal_uInt16 >( rTabNames.size() );
+
+ sal_Size nEndPos = rStrm.GetRecPos() + nFormulaLen;
+
+ while( (rStrm.GetRecPos() < nEndPos) && !bError )
+ {
+ rStrm >> nOp;
+
+ // always reset flags
+ aSRD.InitFlags();
+ aCRD.InitFlags();
+
+ switch( nOp )
+ {
+ case 0x1C: // Error Value
+ {
+ rStrm >> nByte;
+ DefTokenId eOc;
+ switch( nByte )
+ {
+ case EXC_ERR_NULL:
+ case EXC_ERR_DIV0:
+ case EXC_ERR_VALUE:
+ case EXC_ERR_REF:
+ case EXC_ERR_NAME:
+ case EXC_ERR_NUM: eOc = ocStop; break;
+ case EXC_ERR_NA: eOc = ocNotAvail; break;
+ default: eOc = ocNoName;
+ }
+ aPool << eOc;
+ if( eOc != ocStop )
+ aPool << ocOpen << ocClose;
+ aPool >> aStack;
+ }
+ break;
+ case 0x3A:
+ {
+ // cell reference in external range name
+ sal_uInt16 nExtTab1, nExtTab2, nRow, nGrbitCol;
+ rStrm >> nExtTab1 >> nExtTab2 >> nRow >> nGrbitCol;
+ if (nExtTab1 >= nTabCount || nExtTab2 >= nTabCount)
+ {
+ bError = true;
+ break;
+ }
+
+ aSRD.nTab = nExtTab1;
+ aSRD.SetFlag3D(true);
+ aSRD.SetTabRel(false);
+ ExcRelToScRel8(nRow, nGrbitCol, aSRD, true);
+ aCRD.Ref1 = aCRD.Ref2 = aSRD;
+ String aTabName = rTabNames[nExtTab1];
+
+ if (nExtTab1 == nExtTab2)
+ {
+ // single cell reference
+ aStack << aPool.StoreExtRef(nFileId, aTabName, aSRD);
+ }
+ else
+ {
+ // area reference
+ aCRD.Ref2.nTab = nExtTab2;
+ aStack << aPool.StoreExtRef(nFileId, aTabName, aCRD);
+ }
+ }
+ break;
+ case 0x3B:
+ {
+ // area reference
+ sal_uInt16 nExtTab1, nExtTab2, nRow1, nRow2, nGrbitCol1, nGrbitCol2;
+ rStrm >> nExtTab1 >> nExtTab2 >> nRow1 >> nRow2 >> nGrbitCol1 >> nGrbitCol2;
+ ScSingleRefData& rR1 = aCRD.Ref1;
+ ScSingleRefData& rR2 = aCRD.Ref2;
+
+ rR1.nTab = nExtTab1;
+ rR1.SetFlag3D(true);
+ rR1.SetTabRel(false);
+ ExcRelToScRel8(nRow1, nGrbitCol1, rR1, true);
+
+ rR2.nTab = nExtTab2;
+ rR2.SetFlag3D(true);
+ rR2.SetTabRel(false);
+ ExcRelToScRel8(nRow2, nGrbitCol2, rR2, true);
+
+ String aTabName = rTabNames[nExtTab1];
+ aStack << aPool.StoreExtRef(nFileId, aTabName, aCRD);
+ }
+ break;
+ default:
+ bError = true;
+ }
+ bError |= !rStrm.IsValid();
+ }
+
+ ConvErr eRet;
+
+ if( bError )
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ rpArray = aPool[ aStack.Get() ];
+ eRet = ConvErrNi;
+ }
+ else if( rStrm.GetRecPos() != nEndPos )
+ {
+ aPool << ocBad;
+ aPool >> aStack;
+ rpArray = aPool[ aStack.Get() ];
+ eRet = ConvErrCount;
+ }
+ else
+ {
+ rpArray = aPool[ aStack.Get() ];
+ eRet = ConvOK;
+ }
+
+ rStrm.Seek(nEndPos);
+ return eRet;
+}
+
+void ExcelToSc8::ExcRelToScRel8( sal_uInt16 nRow, sal_uInt16 nC, ScSingleRefData &rSRD, const sal_Bool bName )
+{
+ const sal_Bool bColRel = ( nC & 0x4000 ) != 0;
+ const sal_Bool bRowRel = ( nC & 0x8000 ) != 0;
+ const sal_uInt8 nCol = static_cast<sal_uInt8>(nC);
+
+ rSRD.SetColRel( bColRel );
+ rSRD.SetRowRel( bRowRel );
+
+ if( bName )
+ {
+ // C O L
+ if( bColRel )
+ // rel Col
+ rSRD.nRelCol = static_cast<SCsCOL>(static_cast<sal_Int8>(nC));
+ else
+ // abs Col
+ rSRD.nCol = static_cast<SCCOL>(nCol);
+
+ // R O W
+ if( bRowRel )
+ // rel Row
+ rSRD.nRelRow = static_cast<SCsROW>(static_cast<sal_Int16>(nRow));
+ else
+ // abs Row
+ rSRD.nRow = Min( static_cast<SCROW>(nRow), MAXROW);
+
+ // T A B
+ // abs needed if rel in shared formula for ScCompiler UpdateNameReference
+ if ( rSRD.IsTabRel() && !rSRD.IsFlag3D() )
+ rSRD.nTab = GetCurrScTab();
+ }
+ else
+ {
+ // C O L
+ if ( bColRel )
+ {
+ rSRD.nRelCol = static_cast<SCsCOL>(nCol) - aEingPos.Col();
+ rSRD.nCol = rSRD.nRelCol;
+ }
+ else
+ rSRD.nCol = static_cast<SCCOL>(nCol);
+
+ // R O W
+ if ( bRowRel )
+ {
+ rSRD.nRelRow = static_cast<SCsROW>(nRow) - aEingPos.Row();
+ rSRD.nRow = rSRD.nRelRow;
+ }
+ else
+ rSRD.nRow = static_cast<SCROW>(nRow);
+
+ // T A B
+ // #i10184# abs needed if rel in shared formula for ScCompiler UpdateNameReference
+ if ( rSRD.IsTabRel() && !rSRD.IsFlag3D() )
+ rSRD.nTab = GetCurrScTab() + rSRD.nRelTab;
+ }
+}
+
+
+// stream seeks to first byte after <nLen>
+sal_Bool ExcelToSc8::GetAbsRefs( ScRangeList& r, XclImpStream& aIn, sal_Size nLen )
+{
+ sal_uInt8 nOp;
+ sal_uInt16 nRow1, nRow2, nCol1, nCol2;
+ SCTAB nTab1, nTab2;
+ sal_uInt16 nIxti;
+
+ sal_Size nSeek;
+
+ sal_Size nEndPos = aIn.GetRecPos() + nLen;
+
+ while( aIn.IsValid() && (aIn.GetRecPos() < nEndPos) )
+ {
+ aIn >> nOp;
+ nSeek = 0;
+
+ switch( nOp )
+ {
+ case 0x44:
+ case 0x64:
+ case 0x24: // Cell Reference [319 270]
+ case 0x4C:
+ case 0x6C:
+ case 0x2C: // Cell Reference Within a Name [323 ]
+ // Cell Reference Within a Shared Formula[ 273]
+ aIn >> nRow1 >> nCol1;
+
+ nRow2 = nRow1;
+ nCol2 = nCol1;
+ nTab1 = nTab2 = GetCurrScTab();
+ goto _common;
+ case 0x45:
+ case 0x65:
+ case 0x25: // Area Reference [320 270]
+ case 0x4D:
+ case 0x6D:
+ case 0x2D: // Area Reference Within a Name [324 ]
+ // Area Reference Within a Shared Formula[ 274]
+ aIn >> nRow1 >> nRow2 >> nCol1 >> nCol2;
+
+ nTab1 = nTab2 = GetCurrScTab();
+ goto _common;
+ case 0x5A:
+ case 0x7A:
+ case 0x3A: // 3-D Cell Reference [ 275]
+ aIn >> nIxti >> nRow1 >> nCol1;
+
+ nRow2 = nRow1;
+ nCol2 = nCol1;
+
+ goto _3d_common;
+ case 0x5B:
+ case 0x7B:
+ case 0x3B: // 3-D Area Reference [ 276]
+ aIn >> nIxti >> nRow1 >> nRow2 >> nCol1 >> nCol2;
+
+ _3d_common:
+ // skip references to deleted sheets
+ if( !rLinkMan.GetScTabRange( nTab1, nTab2, nIxti ) || !ValidTab( nTab1 ) || !ValidTab( nTab2 ) )
+ break;
+
+ goto _common;
+ _common:
+ // do not check abs/rel flags, linked controls have set them!
+// if( !(( nCol1 & 0xC000 ) || ( nCol2 & 0xC000 )) )
+ {
+ ScRange aScRange;
+ nCol1 &= 0x3FFF;
+ nCol2 &= 0x3FFF;
+ if( GetAddressConverter().ConvertRange( aScRange, XclRange( nCol1, nRow1, nCol2, nRow2 ), nTab1, nTab2, true ) )
+ r.Append( aScRange );
+ }
+ break;
+ case 0x1C: // Error Value [314 266]
+ case 0x1D: // Boolean [315 266]
+ nSeek = 1;
+ break;
+ case 0x1E: // Integer [315 266]
+ case 0x41:
+ case 0x61:
+ case 0x21: // Function, Fixed Number of Arguments [333 282]
+ case 0x49:
+ case 0x69:
+ case 0x29: // Variable Reference Subexpression [331 281]
+ case 0x4E:
+ case 0x6E:
+ case 0x2E: // Reference Subexpression Within a Name [332 282]
+ case 0x4F:
+ case 0x6F:
+ case 0x2F: // Incomplete Reference Subexpression... [332 282]
+ case 0x58:
+ case 0x78:
+ case 0x38: // Command-Equivalent Function [333 ]
+ nSeek = 2;
+ break;
+ case 0x42:
+ case 0x62:
+ case 0x22: // Function, Variable Number of Arg. [333 283]
+ nSeek = 3;
+ break;
+ case 0x01: // Array Formula [325 ]
+ case 0x02: // Data Table [325 277]
+ case 0x43:
+ case 0x63:
+ case 0x23: // Name [318 269]
+ case 0x4A:
+ case 0x6A:
+ case 0x2A: // Deleted Cell Reference [323 273]
+ nSeek = 4;
+ break;
+ case 0x46:
+ case 0x66:
+ case 0x26: // Constant Reference Subexpression [321 271]
+ case 0x47:
+ case 0x67:
+ case 0x27: // Erroneous Constant Reference Subexpr. [322 272]
+ case 0x48:
+ case 0x68:
+ case 0x28: // Incomplete Constant Reference Subexpr.[331 281]
+ case 0x5C:
+ case 0x7C:
+ case 0x3C: // Deleted 3-D Cell Reference [ 277]
+ case 0x59:
+ case 0x79:
+ case 0x39: // Name or External Name [ 275]
+ nSeek = 6;
+ break;
+ case 0x40:
+ case 0x60:
+ case 0x20: // Array Constant [317 268]
+ nSeek = 7;
+ break;
+ case 0x1F: // Number [315 266]
+ case 0x4B:
+ case 0x6B:
+ case 0x2B: // Deleted Area Refernce [323 273]
+ nSeek = 8;
+ break;
+ case 0x5D:
+ case 0x7D:
+ case 0x3D: // Deleted 3-D Area Reference [ 277]
+ nSeek = 10;
+ break;
+ case 0x17: // String Constant [314 266]
+ {
+ sal_uInt8 nStrLen;
+ aIn >> nStrLen;
+ aIn.IgnoreUniString( nStrLen ); // reads Grbit even if nLen==0
+ nSeek = 0;
+ }
+ break;
+ case 0x19: // Special Attribute [327 279]
+ {
+ sal_uInt16 nData;
+ sal_uInt8 nOpt;
+ aIn >> nOpt >> nData;
+ if( nOpt & 0x04 )
+ {// nFakt -> Bytes oder Words ueberlesen AttrChoose
+ nData++;
+ nSeek = nData * 2;
+ }
+ }
+ break;
+ }
+
+ aIn.Ignore( nSeek );
+ }
+ aIn.Seek( nEndPos );
+
+ return !r.empty();
+}
+
+
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/excimp8.cxx b/sc/source/filter/excel/excimp8.cxx
new file mode 100644
index 000000000000..a1bbe57dbc0c
--- /dev/null
+++ b/sc/source/filter/excel/excimp8.cxx
@@ -0,0 +1,859 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "excimp8.hxx"
+
+#include <scitems.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/mediadescriptor.hxx>
+#include <unotools/fltrcfg.hxx>
+
+#include <svtools/wmf.hxx>
+
+#include <editeng/eeitem.hxx>
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/docinf.hxx>
+#include <sfx2/frame.hxx>
+
+#include <editeng/brshitem.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/crsditem.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/xflclit.hxx>
+
+#include <vcl/graph.hxx>
+#include <vcl/bmpacc.hxx>
+#include <sot/exchange.hxx>
+
+#include <svl/stritem.hxx>
+
+#include <tools/string.hxx>
+#include <tools/urlobj.hxx>
+#include <rtl/math.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/charclass.hxx>
+#include <drwlayer.hxx>
+
+#include <boost/scoped_array.hpp>
+
+#include "cell.hxx"
+#include "document.hxx"
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "attrib.hxx"
+#include "conditio.hxx"
+#include "dbcolect.hxx"
+#include "globalnames.hxx"
+#include "editutil.hxx"
+#include "markdata.hxx"
+#include "rangenam.hxx"
+#include "docoptio.hxx"
+#include "globstr.hrc"
+#include "fprogressbar.hxx"
+#include "xltracer.hxx"
+#include "xihelper.hxx"
+#include "xipage.hxx"
+#include "xicontent.hxx"
+#include "xilink.hxx"
+#include "xiescher.hxx"
+#include "xipivot.hxx"
+
+#include "excform.hxx"
+#include "scextopt.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "detfunc.hxx"
+#include "macromgr.hxx"
+
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/script/ModuleInfo.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <comphelper/mediadescriptor.hxx>
+#include <cppuhelper/component_context.hxx>
+#include <sfx2/app.hxx>
+#include "xltoolbar.hxx"
+
+
+using namespace com::sun::star;
+using namespace ::comphelper;
+using ::rtl::OUString;
+
+//OleNameOverrideContainer
+
+typedef ::cppu::WeakImplHelper1< container::XNameContainer > OleNameOverrideContainer_BASE;
+
+class OleNameOverrideContainer : public OleNameOverrideContainer_BASE
+{
+private:
+ typedef boost::unordered_map< rtl::OUString, uno::Reference< container::XIndexContainer >, ::rtl::OUStringHash,
+ ::std::equal_to< ::rtl::OUString > > NamedIndexToOleName;
+ NamedIndexToOleName IdToOleNameHash;
+ ::osl::Mutex m_aMutex;
+public:
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType( ) throw (uno::RuntimeException) { return container::XIndexContainer::static_type(0); }
+ virtual ::sal_Bool SAL_CALL hasElements( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return ( IdToOleNameHash.size() > 0 );
+ }
+ // XNameAcess
+ virtual uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !hasByName(aName) )
+ throw container::NoSuchElementException();
+ return uno::makeAny( IdToOleNameHash[ aName ] );
+ }
+ virtual uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ uno::Sequence< ::rtl::OUString > aResult( IdToOleNameHash.size() );
+ NamedIndexToOleName::iterator it = IdToOleNameHash.begin();
+ NamedIndexToOleName::iterator it_end = IdToOleNameHash.end();
+ rtl::OUString* pName = aResult.getArray();
+ for (; it != it_end; ++it, ++pName )
+ *pName = it->first;
+ return aResult;
+ }
+ virtual ::sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return ( IdToOleNameHash.find( aName ) != IdToOleNameHash.end() );
+ }
+
+ // XElementAccess
+ virtual ::sal_Int32 SAL_CALL getCount( ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return IdToOleNameHash.size();
+ }
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const ::rtl::OUString& aName, const uno::Any& aElement ) throw(lang::IllegalArgumentException, container::ElementExistException, lang::WrappedTargetException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( hasByName( aName ) )
+ throw container::ElementExistException();
+ uno::Reference< container::XIndexContainer > xElement;
+ if ( ! ( aElement >>= xElement ) )
+ throw lang::IllegalArgumentException();
+ IdToOleNameHash[ aName ] = xElement;
+ }
+ virtual void SAL_CALL removeByName( const ::rtl::OUString& aName ) throw(container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !hasByName( aName ) )
+ throw container::NoSuchElementException();
+ IdToOleNameHash.erase( IdToOleNameHash.find( aName ) );
+ }
+ virtual void SAL_CALL replaceByName( const ::rtl::OUString& aName, const uno::Any& aElement ) throw(lang::IllegalArgumentException, container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !hasByName( aName ) )
+ throw container::NoSuchElementException();
+ uno::Reference< container::XIndexContainer > xElement;
+ if ( ! ( aElement >>= xElement ) )
+ throw lang::IllegalArgumentException();
+ IdToOleNameHash[ aName ] = xElement;
+ }
+};
+
+// defined in docfunc.cxx ( really this needs a new name )
+script::ModuleInfo lcl_InitModuleInfo( SfxObjectShell& rDocSh, String& sModule );
+
+ImportExcel8::ImportExcel8( XclImpRootData& rImpData, SvStream& rStrm ) :
+ ImportExcel( rImpData, rStrm )
+{
+ // replace BIFF2-BIFF5 formula importer with BIFF8 formula importer
+ delete pFormConv;
+ pFormConv = pExcRoot->pFmlaConverter = new ExcelToSc8( GetRoot() );
+}
+
+
+ImportExcel8::~ImportExcel8()
+{
+}
+
+
+void ImportExcel8::Calccount( void )
+{
+ ScDocOptions aOpt = pD->GetDocOptions();
+ aOpt.SetIterCount( aIn.ReaduInt16() );
+ pD->SetDocOptions( aOpt );
+}
+
+
+void ImportExcel8::Precision( void )
+{
+ ScDocOptions aOpt = pD->GetDocOptions();
+ aOpt.SetCalcAsShown( aIn.ReaduInt16() == 0 );
+ pD->SetDocOptions( aOpt );
+}
+
+
+void ImportExcel8::Delta( void )
+{
+ ScDocOptions aOpt = pD->GetDocOptions();
+ aOpt.SetIterEps( aIn.ReadDouble() );
+ pD->SetDocOptions( aOpt );
+}
+
+
+void ImportExcel8::Iteration( void )
+{
+ ScDocOptions aOpt = pD->GetDocOptions();
+ aOpt.SetIter( aIn.ReaduInt16() == 1 );
+ pD->SetDocOptions( aOpt );
+}
+
+
+void ImportExcel8::Boundsheet( void )
+{
+ sal_uInt8 nLen;
+ sal_uInt16 nGrbit;
+
+ aIn.DisableDecryption();
+ maSheetOffsets.push_back( aIn.ReaduInt32() );
+ aIn.EnableDecryption();
+ aIn >> nGrbit >> nLen;
+
+ String aName( aIn.ReadUniString( nLen ) );
+ GetTabInfo().AppendXclTabName( aName, nBdshtTab );
+
+ SCTAB nScTab = static_cast< SCTAB >( nBdshtTab );
+ if( nScTab > 0 )
+ {
+ DBG_ASSERT( !pD->HasTable( nScTab ), "ImportExcel8::Boundsheet - sheet exists already" );
+ pD->MakeTable( nScTab );
+ }
+
+ if( ( nGrbit & 0x0001 ) || ( nGrbit & 0x0002 ) )
+ pD->SetVisible( nScTab, false );
+
+ if( !pD->RenameTab( nScTab, aName ) )
+ {
+ pD->CreateValidTabName( aName );
+ pD->RenameTab( nScTab, aName );
+ }
+
+ nBdshtTab++;
+}
+
+
+void ImportExcel8::Scenman( void )
+{
+ sal_uInt16 nLastDispl;
+
+ aIn.Ignore( 4 );
+ aIn >> nLastDispl;
+
+ aScenList.nLastScenario = nLastDispl;
+}
+
+
+void ImportExcel8::Scenario( void )
+{
+ aScenList.aEntries.push_back( new ExcScenario( aIn, *pExcRoot ) );
+}
+
+
+void ImportExcel8::Labelsst( void )
+{
+ XclAddress aXclPos;
+ sal_uInt16 nXF;
+ sal_uInt32 nSst;
+
+ aIn >> aXclPos >> nXF >> nSst;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
+ {
+ GetXFRangeBuffer().SetXF( aScPos, nXF );
+ if( ScBaseCell* pCell = GetSst().CreateCell( nSst, nXF ) )
+ GetDoc().PutCell( aScPos.Col(), aScPos.Row(), aScPos.Tab(), pCell );
+ }
+}
+
+
+void ImportExcel8::SheetProtection( void )
+{
+ GetSheetProtectBuffer().ReadOptions( aIn, GetCurrScTab() );
+}
+
+void ImportExcel8::ReadBasic( void )
+{
+ SfxObjectShell* pShell = GetDocShell();
+ SotStorageRef xRootStrg = GetRootStorage();
+ SvtFilterOptions* pFilterOpt = SvtFilterOptions::Get();
+ if( pShell && xRootStrg.Is() ) try
+ {
+ bool bLoadCode = pFilterOpt->IsLoadExcelBasicCode();
+ bool bLoadExecutable = pFilterOpt->IsLoadExcelBasicExecutable();
+ bool bLoadStrg = pFilterOpt->IsLoadExcelBasicStorage();
+ // #FIXME need to get rid of this, we can also do this from within oox
+ // via the "ooo.vba.VBAGlobals" service
+ if( bLoadCode || bLoadStrg )
+ {
+ bool bAsComment = !bLoadExecutable;
+
+ if ( !bAsComment )
+ {
+ // see if we have the XCB stream
+ SvStorageStreamRef xXCB = xRootStrg->OpenSotStream( String( RTL_CONSTASCII_USTRINGPARAM( "XCB" ) ), STREAM_STD_READ | STREAM_NOCREATE );
+ if ( xXCB.Is()|| SVSTREAM_OK == xXCB->GetError() )
+ {
+ CTBWrapper wrapper;
+ if ( wrapper.Read( xXCB ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ wrapper.Print( stderr );
+#endif
+ wrapper.ImportCustomToolBar( *pShell );
+ }
+ }
+ }
+ }
+ try
+ {
+ uno::Reference< lang::XComponent > xComponent( pShell->GetModel(), uno::UNO_QUERY_THROW );
+ uno::Sequence< beans::NamedValue > aArgSeq( 1 );
+
+ // collect names of embedded form controls, as specified in the VBA project
+ aArgSeq[ 0 ].Name = CREATE_OUSTRING( "OleNameOverrideInfo" );
+ uno::Reference< container::XNameContainer > xOleNameOverrideSink( new OleNameOverrideContainer );
+ aArgSeq[ 0 ].Value <<= xOleNameOverrideSink;
+
+ uno::Sequence< uno::Any > aArgs( 2 );
+ // framework calls filter objects with factory as first argument
+ aArgs[ 0 ] <<= getProcessServiceFactory();
+ aArgs[ 1 ] <<= aArgSeq;
+
+ uno::Reference< document::XImporter > xImporter( ScfApiHelper::CreateInstanceWithArgs( CREATE_OUSTRING( "com.sun.star.comp.oox.xls.ExcelVbaProjectFilter" ), aArgs ), uno::UNO_QUERY_THROW );
+ xImporter->setTargetDocument( xComponent );
+
+ MediaDescriptor aMediaDesc;
+ SfxMedium& rMedium = GetMedium();
+ SfxItemSet* pItemSet = rMedium.GetItemSet();
+ if( pItemSet )
+ {
+ if( const SfxStringItem* pItem = static_cast< const SfxStringItem* >( pItemSet->GetItem( SID_FILE_NAME ) ) )
+ aMediaDesc[ MediaDescriptor::PROP_URL() ] <<= ::rtl::OUString( pItem->GetValue() );
+ if( const SfxStringItem* pItem = static_cast< const SfxStringItem* >( pItemSet->GetItem( SID_PASSWORD ) ) )
+ aMediaDesc[ MediaDescriptor::PROP_PASSWORD() ] <<= ::rtl::OUString( pItem->GetValue() );
+ }
+ aMediaDesc[ MediaDescriptor::PROP_INPUTSTREAM() ] <<= rMedium.GetInputStream();
+ aMediaDesc[ MediaDescriptor::PROP_INTERACTIONHANDLER() ] <<= rMedium.GetInteractionHandler();
+
+ // call the filter
+ uno::Reference< document::XFilter > xFilter( xImporter, uno::UNO_QUERY_THROW );
+ xFilter->filter( aMediaDesc.getAsConstPropertyValueList() );
+ GetObjectManager().SetOleNameOverrideInfo( xOleNameOverrideSink );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+
+void ImportExcel8::EndSheet( void )
+{
+ ImportExcel::EndSheet();
+ GetCondFormatManager().Apply();
+ GetValidationManager().Apply();
+}
+
+
+void ImportExcel8::PostDocLoad( void )
+{
+ // reading basic has been delayed until sheet objects (codenames etc.) are read
+ if( HasBasic() )
+ ReadBasic();
+ // #i11776# filtered ranges before outlines and hidden rows
+ if( pExcRoot->pAutoFilterBuffer )
+ pExcRoot->pAutoFilterBuffer->Apply();
+
+ GetWebQueryBuffer().Apply(); //! test if extant
+ GetSheetProtectBuffer().Apply();
+ GetDocProtectBuffer().Apply();
+
+ ImportExcel::PostDocLoad();
+
+ // Scenarien bemachen! ACHTUNG: Hier wird Tabellen-Anzahl im Dokument erhoeht!!
+ if( !pD->IsClipboard() && aScenList.aEntries.size() )
+ {
+ pD->UpdateChartListenerCollection(); // references in charts must be updated
+
+ aScenList.Apply( GetRoot() );
+ }
+
+ // read doc info (no docshell while pasting from clipboard)
+ LoadDocumentProperties();
+
+ // #i45843# Pivot tables are now handled outside of PostDocLoad, so they are available
+ // when formula cells are calculated, for the GETPIVOTDATA function.
+}
+
+void ImportExcel8::LoadDocumentProperties()
+{
+ // no docshell while pasting from clipboard
+ if( SfxObjectShell* pShell = GetDocShell() )
+ {
+ // BIFF5+ without storage is possible
+ SotStorageRef xRootStrg = GetRootStorage();
+ if( xRootStrg.Is() ) try
+ {
+ uno::Reference< document::XDocumentPropertiesSupplier > xDPS( pShell->GetModel(), uno::UNO_QUERY_THROW );
+ uno::Reference< document::XDocumentProperties > xDocProps( xDPS->getDocumentProperties(), uno::UNO_SET_THROW );
+ sfx2::LoadOlePropertySet( xDocProps, xRootStrg );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+}
+
+//___________________________________________________________________
+// autofilter
+
+void ImportExcel8::FilterMode( void )
+{
+ // The FilterMode record exists: if either the AutoFilter
+ // record exists or an Advanced Filter is saved and stored
+ // in the sheet. Thus if the FilterMode records only exists
+ // then the latter is true..
+ if( !pExcRoot->pAutoFilterBuffer ) return;
+
+ XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
+ if( pData )
+ pData->SetAutoOrAdvanced();
+}
+
+void ImportExcel8::AutoFilterInfo( void )
+{
+ if( !pExcRoot->pAutoFilterBuffer ) return;
+
+ XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
+ if( pData )
+ {
+ pData->SetAdvancedRange( NULL );
+ pData->Activate();
+ }
+}
+
+void ImportExcel8::AutoFilter( void )
+{
+ if( !pExcRoot->pAutoFilterBuffer ) return;
+
+ XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
+ if( pData )
+ pData->ReadAutoFilter( aIn );
+}
+
+
+
+XclImpAutoFilterData::XclImpAutoFilterData( RootData* pRoot, const ScRange& rRange ) :
+ ExcRoot( pRoot ),
+ pCurrDBData(NULL),
+ nFirstEmpty( 0 ),
+ bActive( false ),
+ bHasConflict( false ),
+ bCriteria( false ),
+ bAutoOrAdvanced(false)
+{
+ aParam.nCol1 = rRange.aStart.Col();
+ aParam.nRow1 = rRange.aStart.Row();
+ aParam.nTab = rRange.aStart.Tab();
+ aParam.nCol2 = rRange.aEnd.Col();
+ aParam.nRow2 = rRange.aEnd.Row();
+
+ aParam.bInplace = sal_True;
+
+}
+
+void XclImpAutoFilterData::CreateFromDouble( String& rStr, double fVal )
+{
+ rStr += String( ::rtl::math::doubleToUString( fVal,
+ rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0), sal_True));
+}
+
+void XclImpAutoFilterData::SetCellAttribs()
+{
+ ScDocument& rDoc = pExcRoot->pIR->GetDoc();
+ for ( SCCOL nCol = StartCol(); nCol <= EndCol(); nCol++ )
+ {
+ sal_Int16 nFlag = ((ScMergeFlagAttr*) rDoc.GetAttr( nCol, StartRow(), Tab(), ATTR_MERGE_FLAG ))->GetValue();
+ rDoc.ApplyAttr( nCol, StartRow(), Tab(), ScMergeFlagAttr( nFlag | SC_MF_AUTO) );
+ }
+}
+
+void XclImpAutoFilterData::InsertQueryParam()
+{
+ if( pCurrDBData && !bHasConflict )
+ {
+ ScRange aAdvRange;
+ sal_Bool bHasAdv = pCurrDBData->GetAdvancedQuerySource( aAdvRange );
+ if( bHasAdv )
+ pExcRoot->pIR->GetDoc().CreateQueryParam( aAdvRange.aStart.Col(),
+ aAdvRange.aStart.Row(), aAdvRange.aEnd.Col(), aAdvRange.aEnd.Row(),
+ aAdvRange.aStart.Tab(), aParam );
+
+ pCurrDBData->SetQueryParam( aParam );
+ if( bHasAdv )
+ pCurrDBData->SetAdvancedQuerySource( &aAdvRange );
+ else
+ {
+ pCurrDBData->SetAutoFilter( sal_True );
+ SetCellAttribs();
+ }
+ }
+}
+
+static void ExcelQueryToOooQuery( ScQueryEntry& rEntry )
+{
+ if( ( rEntry.eOp != SC_EQUAL && rEntry.eOp != SC_NOT_EQUAL ) || rEntry.pStr == NULL )
+ return;
+ else
+ {
+ xub_StrLen nLen = rEntry.pStr->Len();
+ sal_Unicode nStart = rEntry.pStr->GetChar( 0 );
+ sal_Unicode nEnd = rEntry.pStr->GetChar( nLen-1 );
+ if( nLen >2 && nStart == '*' && nEnd == '*' )
+ {
+ rEntry.pStr->Erase( nLen-1, 1 );
+ rEntry.pStr->Erase( 0, 1 );
+ rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_CONTAINS : SC_DOES_NOT_CONTAIN;
+ }
+ else if( nLen > 1 && nStart == '*' && nEnd != '*' )
+ {
+ rEntry.pStr->Erase( 0, 1 );
+ rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_ENDS_WITH : SC_DOES_NOT_END_WITH;
+ }
+ else if( nLen > 1 && nStart != '*' && nEnd == '*' )
+ {
+ rEntry.pStr->Erase( nLen-1, 1 );
+ rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_BEGINS_WITH : SC_DOES_NOT_BEGIN_WITH;
+ }
+ else if( nLen == 2 && nStart == '*' && nEnd == '*' )
+ {
+ rEntry.pStr->Erase( 0, 1 );
+ }
+ }
+}
+
+void XclImpAutoFilterData::ReadAutoFilter( XclImpStream& rStrm )
+{
+ sal_uInt16 nCol, nFlags;
+ rStrm >> nCol >> nFlags;
+
+ ScQueryConnect eConn = ::get_flagvalue( nFlags, EXC_AFFLAG_ANDORMASK, SC_OR, SC_AND );
+ sal_Bool bTop10 = ::get_flag( nFlags, EXC_AFFLAG_TOP10 );
+ sal_Bool bTopOfTop10 = ::get_flag( nFlags, EXC_AFFLAG_TOP10TOP );
+ sal_Bool bPercent = ::get_flag( nFlags, EXC_AFFLAG_TOP10PERC );
+ sal_uInt16 nCntOfTop10 = nFlags >> 7;
+ SCSIZE nCount = aParam.GetEntryCount();
+
+ if( bTop10 )
+ {
+ if( nFirstEmpty < nCount )
+ {
+ ScQueryEntry& aEntry = aParam.GetEntry( nFirstEmpty );
+ aEntry.bDoQuery = sal_True;
+ aEntry.bQueryByString = sal_True;
+ aEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol));
+ aEntry.eOp = bTopOfTop10 ?
+ (bPercent ? SC_TOPPERC : SC_TOPVAL) : (bPercent ? SC_BOTPERC : SC_BOTVAL);
+ aEntry.eConnect = SC_AND;
+ aEntry.pStr->Assign( String::CreateFromInt32( (sal_Int32) nCntOfTop10 ) );
+
+ rStrm.Ignore( 20 );
+ nFirstEmpty++;
+ }
+ }
+ else
+ {
+ sal_uInt8 nE, nType, nOper, nBoolErr, nVal;
+ sal_Int32 nRK;
+ double fVal;
+ sal_Bool bIgnore;
+
+ sal_uInt8 nStrLen[ 2 ] = { 0, 0 };
+ ScQueryEntry *pQueryEntries[ 2 ] = { NULL, NULL };
+
+ for( nE = 0; nE < 2; nE++ )
+ {
+ if( nFirstEmpty < nCount )
+ {
+ ScQueryEntry& aEntry = aParam.GetEntry( nFirstEmpty );
+ pQueryEntries[ nE ] = &aEntry;
+ bIgnore = false;
+
+ rStrm >> nType >> nOper;
+ switch( nOper )
+ {
+ case EXC_AFOPER_LESS:
+ aEntry.eOp = SC_LESS;
+ break;
+ case EXC_AFOPER_EQUAL:
+ aEntry.eOp = SC_EQUAL;
+ break;
+ case EXC_AFOPER_LESSEQUAL:
+ aEntry.eOp = SC_LESS_EQUAL;
+ break;
+ case EXC_AFOPER_GREATER:
+ aEntry.eOp = SC_GREATER;
+ break;
+ case EXC_AFOPER_NOTEQUAL:
+ aEntry.eOp = SC_NOT_EQUAL;
+ break;
+ case EXC_AFOPER_GREATEREQUAL:
+ aEntry.eOp = SC_GREATER_EQUAL;
+ break;
+ default:
+ aEntry.eOp = SC_EQUAL;
+ }
+
+ switch( nType )
+ {
+ case EXC_AFTYPE_RK:
+ rStrm >> nRK;
+ rStrm.Ignore( 4 );
+ CreateFromDouble( *aEntry.pStr, XclTools::GetDoubleFromRK( nRK ) );
+ break;
+ case EXC_AFTYPE_DOUBLE:
+ rStrm >> fVal;
+ CreateFromDouble( *aEntry.pStr, fVal );
+ break;
+ case EXC_AFTYPE_STRING:
+ rStrm.Ignore( 4 );
+ rStrm >> nStrLen[ nE ];
+ rStrm.Ignore( 3 );
+ aEntry.pStr->Erase();
+ break;
+ case EXC_AFTYPE_BOOLERR:
+ rStrm >> nBoolErr >> nVal;
+ rStrm.Ignore( 6 );
+ aEntry.pStr->Assign( String::CreateFromInt32( (sal_Int32) nVal ) );
+ bIgnore = (sal_Bool) nBoolErr;
+ break;
+ case EXC_AFTYPE_EMPTY:
+ aEntry.bQueryByString = false;
+ aEntry.nVal = SC_EMPTYFIELDS;
+ aEntry.eOp = SC_EQUAL;
+ break;
+ case EXC_AFTYPE_NOTEMPTY:
+ aEntry.bQueryByString = false;
+ aEntry.nVal = SC_NONEMPTYFIELDS;
+ aEntry.eOp = SC_EQUAL;
+ break;
+ default:
+ rStrm.Ignore( 8 );
+ bIgnore = sal_True;
+ }
+
+ /* #i39464# conflict, if two conditions of one column are 'OR'ed,
+ and they follow conditions of other columns.
+ Example: Let A1 be a condition of column A, and B1 and B2
+ conditions of column B, connected with OR. Excel performs
+ 'A1 AND (B1 OR B2)' in this case, but Calc would do
+ '(A1 AND B1) OR B2' instead. */
+ if( (nFirstEmpty > 1) && nE && (eConn == SC_OR) && !bIgnore )
+ bHasConflict = sal_True;
+ if( !bHasConflict && !bIgnore )
+ {
+ aEntry.bDoQuery = sal_True;
+ aEntry.bQueryByString = sal_True;
+ aEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol));
+ aEntry.eConnect = nE ? eConn : SC_AND;
+ nFirstEmpty++;
+ }
+ }
+ else
+ rStrm.Ignore( 10 );
+ }
+
+ for( nE = 0; nE < 2; nE++ )
+ if( nStrLen[ nE ] && pQueryEntries[ nE ] )
+ {
+ pQueryEntries[ nE ]->pStr->Assign ( rStrm.ReadUniString( nStrLen[ nE ] ) );
+ ExcelQueryToOooQuery( *pQueryEntries[ nE ] );
+ }
+
+ }
+}
+
+void XclImpAutoFilterData::SetAdvancedRange( const ScRange* pRange )
+{
+ if (pRange)
+ {
+ aCriteriaRange = *pRange;
+ bCriteria = sal_True;
+ }
+ else
+ bCriteria = false;
+}
+
+void XclImpAutoFilterData::SetExtractPos( const ScAddress& rAddr )
+{
+ aParam.nDestCol = rAddr.Col();
+ aParam.nDestRow = rAddr.Row();
+ aParam.nDestTab = rAddr.Tab();
+ aParam.bInplace = false;
+ aParam.bDestPers = sal_True;
+}
+
+void XclImpAutoFilterData::Apply()
+{
+ CreateScDBData();
+
+ if( bActive )
+ {
+ InsertQueryParam();
+
+ // #i38093# rows hidden by filter need extra flag, but CR_FILTERED is not set here yet
+// SCROW nRow1 = StartRow();
+// SCROW nRow2 = EndRow();
+// size_t nRows = nRow2 - nRow1 + 1;
+// boost::scoped_array<sal_uInt8> pFlags( new sal_uInt8[nRows]);
+// pExcRoot->pDoc->GetRowFlagsArray( Tab()).FillDataArray( nRow1, nRow2,
+// pFlags.get());
+// for (size_t j=0; j<nRows; ++j)
+// {
+// if ((pFlags[j] & CR_HIDDEN) && !(pFlags[j] & CR_FILTERED))
+// pExcRoot->pDoc->SetRowFlags( nRow1 + j, Tab(),
+// pFlags[j] | CR_FILTERED );
+// }
+ }
+}
+
+void XclImpAutoFilterData::CreateScDBData()
+{
+
+ // Create the ScDBData() object if the AutoFilter is activated
+ // or if we need to create the Advanced Filter.
+ if( bActive || bCriteria)
+ {
+ ScDocument* pDoc = pExcRoot->pIR->GetDocPtr();
+ String aNewName = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(STR_DB_LOCAL_NONAME));
+ pCurrDBData = new ScDBData(aNewName , Tab(),
+ StartCol(),StartRow(), EndCol(),EndRow() );
+ if(bCriteria)
+ {
+ EnableRemoveFilter();
+
+ pCurrDBData->SetQueryParam( aParam );
+ pCurrDBData->SetAdvancedQuerySource(&aCriteriaRange);
+ }
+ else
+ pCurrDBData->SetAdvancedQuerySource(NULL);
+ pDoc->SetAnonymousDBData(Tab(), pCurrDBData);
+ }
+
+}
+
+void XclImpAutoFilterData::EnableRemoveFilter()
+{
+ // only if this is a saved Advanced filter
+ if( !bActive && bAutoOrAdvanced )
+ {
+ ScQueryEntry& aEntry = aParam.GetEntry( nFirstEmpty );
+ aEntry.bDoQuery = sal_True;
+ ++nFirstEmpty;
+ }
+
+ // TBD: force the automatic activation of the
+ // "Remove Filter" by setting a virtual mouse click
+ // inside the advanced range
+}
+
+XclImpAutoFilterBuffer::XclImpAutoFilterBuffer()
+{
+}
+
+XclImpAutoFilterBuffer::~XclImpAutoFilterBuffer()
+{
+ for( XclImpAutoFilterData* pData = _First(); pData; pData = _Next() )
+ delete pData;
+}
+
+void XclImpAutoFilterBuffer::Insert( RootData* pRoot, const ScRange& rRange)
+{
+ if( !GetByTab( rRange.aStart.Tab() ) )
+ Append( new XclImpAutoFilterData( pRoot, rRange) );
+}
+
+void XclImpAutoFilterBuffer::AddAdvancedRange( const ScRange& rRange )
+{
+ XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
+ if( pData )
+ pData->SetAdvancedRange( &rRange );
+}
+
+void XclImpAutoFilterBuffer::AddExtractPos( const ScRange& rRange )
+{
+ XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
+ if( pData )
+ pData->SetExtractPos( rRange.aStart );
+}
+
+void XclImpAutoFilterBuffer::Apply()
+{
+ for( XclImpAutoFilterData* pData = _First(); pData; pData = _Next() )
+ pData->Apply();
+}
+
+XclImpAutoFilterData* XclImpAutoFilterBuffer::GetByTab( SCTAB nTab )
+{
+ for( XclImpAutoFilterData* pData = _First(); pData; pData = _Next() )
+ if( pData->Tab() == nTab )
+ return pData;
+ return NULL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/excrecds.cxx b/sc/source/filter/excel/excrecds.cxx
new file mode 100644
index 000000000000..d3671b4d1cbe
--- /dev/null
+++ b/sc/source/filter/excel/excrecds.cxx
@@ -0,0 +1,1060 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------------
+
+#include "excrecds.hxx"
+
+#include <map>
+#include <filter/msfilter/countryid.hxx>
+
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <sfx2/objsh.hxx>
+
+#include <editeng/editdata.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+
+#include <editeng/flditem.hxx>
+#include <editeng/flstitem.hxx>
+
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/brshitem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/paperinf.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/escpitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <svtools/ctrltool.hxx>
+
+#define _SVSTDARR_USHORTS
+#include <svl/svstdarr.hxx>
+
+#include <string.h>
+
+#include "global.hxx"
+#include "globstr.hrc"
+#include "docpool.hxx"
+#include "patattr.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "scextopt.hxx"
+#include "patattr.hxx"
+#include "attrib.hxx"
+#include "progress.hxx"
+#include "dociter.hxx"
+#include "rangenam.hxx"
+#include "dbcolect.hxx"
+#include "stlsheet.hxx"
+#include "stlpool.hxx"
+#include "editutil.hxx"
+#include "formula/errorcodes.hxx"
+
+#include "excdoc.hxx"
+#include "xeescher.hxx"
+#include "xeformula.hxx"
+#include "xelink.hxx"
+#include "xename.hxx"
+#include "xecontent.hxx"
+
+#include "xcl97rec.hxx"
+
+using namespace ::oox;
+
+using ::com::sun::star::uno::Sequence;
+using ::rtl::OString;
+
+//--------------------------------------------------------- class ExcDummy_00 -
+const sal_uInt8 ExcDummy_00::pMyData[] = {
+ 0x5c, 0x00, 0x20, 0x00, 0x04, 'C', 'a', 'l', 'c', // WRITEACCESS
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
+};
+const sal_Size ExcDummy_00::nMyLen = sizeof( ExcDummy_00::pMyData );
+
+//-------------------------------------------------------- class ExcDummy_04x -
+const sal_uInt8 ExcDummy_040::pMyData[] = {
+ 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, // BACKUP
+ 0x8d, 0x00, 0x02, 0x00, 0x00, 0x00, // HIDEOBJ
+};
+const sal_Size ExcDummy_040::nMyLen = sizeof( ExcDummy_040::pMyData );
+
+const sal_uInt8 ExcDummy_041::pMyData[] = {
+ 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, // PRECISION
+ 0xda, 0x00, 0x02, 0x00, 0x00, 0x00 // BOOKBOOL
+};
+const sal_Size ExcDummy_041::nMyLen = sizeof( ExcDummy_041::pMyData );
+
+//-------------------------------------------------------- class ExcDummy_02a -
+const sal_uInt8 ExcDummy_02a::pMyData[] = {
+ 0x0d, 0x00, 0x02, 0x00, 0x01, 0x00, // CALCMODE
+ 0x0c, 0x00, 0x02, 0x00, 0x64, 0x00, // CALCCOUNT
+ 0x0f, 0x00, 0x02, 0x00, 0x01, 0x00, // REFMODE
+ 0x11, 0x00, 0x02, 0x00, 0x00, 0x00, // ITERATION
+ 0x10, 0x00, 0x08, 0x00, 0xfc, 0xa9, 0xf1, 0xd2, 0x4d, // DELTA
+ 0x62, 0x50, 0x3f,
+ 0x5f, 0x00, 0x02, 0x00, 0x01, 0x00 // SAVERECALC
+};
+const sal_Size ExcDummy_02a::nMyLen = sizeof( ExcDummy_02a::pMyData );
+
+//----------------------------------------------------------- class ExcRecord -
+
+void ExcRecord::Save( XclExpStream& rStrm )
+{
+ SetRecHeader( GetNum(), GetLen() );
+ XclExpRecord::Save( rStrm );
+}
+
+void ExcRecord::SaveCont( XclExpStream& /*rStrm*/ )
+{
+}
+
+void ExcRecord::WriteBody( XclExpStream& rStrm )
+{
+ SaveCont( rStrm );
+}
+
+void ExcRecord::SaveXml( XclExpXmlStream& /*rStrm*/ )
+{
+}
+
+
+//--------------------------------------------------------- class ExcEmptyRec -
+
+void ExcEmptyRec::Save( XclExpStream& /*rStrm*/ )
+{
+}
+
+
+sal_uInt16 ExcEmptyRec::GetNum() const
+{
+ return 0;
+}
+
+
+sal_Size ExcEmptyRec::GetLen() const
+{
+ return 0;
+}
+
+
+
+//------------------------------------------------------- class ExcRecordList -
+
+ExcRecordList::~ExcRecordList()
+{
+ for( ExcRecord* pRec = First(); pRec; pRec = Next() )
+ delete pRec;
+}
+
+
+void ExcRecordList::Save( XclExpStream& rStrm )
+{
+ for( ExcRecord* pRec = First(); pRec; pRec = Next() )
+ pRec->Save( rStrm );
+}
+
+
+
+//--------------------------------------------------------- class ExcDummyRec -
+
+void ExcDummyRec::Save( XclExpStream& rStrm )
+{
+ rStrm.Write( GetData(), GetLen() ); // raw write mode
+}
+
+
+sal_uInt16 ExcDummyRec::GetNum( void ) const
+{
+ return 0x0000;
+}
+
+
+
+//------------------------------------------------------- class ExcBoolRecord -
+
+void ExcBoolRecord::SaveCont( XclExpStream& rStrm )
+{
+ rStrm << (sal_uInt16)(bVal ? 0x0001 : 0x0000);
+}
+
+
+sal_Size ExcBoolRecord::GetLen( void ) const
+{
+ return 2;
+}
+
+
+
+
+//--------------------------------------------------------- class ExcBof_Base -
+
+ExcBof_Base::ExcBof_Base() :
+ nRupBuild( 0x096C ), // copied from Excel
+ nRupYear( 0x07C9 ) // copied from Excel
+{
+}
+
+
+
+//-------------------------------------------------------------- class ExcBof -
+
+ExcBof::ExcBof( void )
+{
+ nDocType = 0x0010;
+ nVers = 0x0500;
+}
+
+
+void ExcBof::SaveCont( XclExpStream& rStrm )
+{
+ rStrm << nVers << nDocType << nRupBuild << nRupYear;
+}
+
+
+sal_uInt16 ExcBof::GetNum( void ) const
+{
+ return 0x0809;
+}
+
+
+sal_Size ExcBof::GetLen( void ) const
+{
+ return 8;
+}
+
+
+
+//------------------------------------------------------------- class ExcBofW -
+
+ExcBofW::ExcBofW( void )
+{
+ nDocType = 0x0005;
+ nVers = 0x0500;
+}
+
+
+void ExcBofW::SaveCont( XclExpStream& rStrm )
+{
+ rStrm << nVers << nDocType << nRupBuild << nRupYear;
+}
+
+
+
+sal_uInt16 ExcBofW::GetNum( void ) const
+{
+ return 0x0809;
+}
+
+
+
+sal_Size ExcBofW::GetLen( void ) const
+{
+ return 8;
+}
+
+
+
+//-------------------------------------------------------------- class ExcEof -
+
+sal_uInt16 ExcEof::GetNum( void ) const
+{
+ return 0x000A;
+}
+
+
+sal_Size ExcEof::GetLen( void ) const
+{
+ return 0;
+}
+
+
+
+//--------------------------------------------------------- class ExcDummy_00 -
+
+sal_Size ExcDummy_00::GetLen( void ) const
+{
+ return nMyLen;
+}
+
+
+const sal_uInt8* ExcDummy_00::GetData( void ) const
+{
+ return pMyData;
+}
+
+
+
+//-------------------------------------------------------- class ExcDummy_04x -
+
+sal_Size ExcDummy_040::GetLen( void ) const
+{
+ return nMyLen;
+}
+
+
+const sal_uInt8* ExcDummy_040::GetData( void ) const
+{
+ return pMyData;
+}
+
+
+
+
+sal_Size ExcDummy_041::GetLen( void ) const
+{
+ return nMyLen;
+}
+
+
+const sal_uInt8* ExcDummy_041::GetData( void ) const
+{
+ return pMyData;
+}
+
+
+
+//------------------------------------------------------------- class Exc1904 -
+
+Exc1904::Exc1904( ScDocument& rDoc )
+{
+ Date* pDate = rDoc.GetFormatTable()->GetNullDate();
+ bVal = pDate ? (*pDate == Date( 1, 1, 1904 )) : false;
+ bDateCompatibility = pDate ? !( *pDate == Date( 30, 12, 1899 )) : false;
+}
+
+
+sal_uInt16 Exc1904::GetNum( void ) const
+{
+ return 0x0022;
+}
+
+
+void Exc1904::SaveXml( XclExpXmlStream& rStrm )
+{
+ bool bISOIEC = ( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 );
+
+ if( bISOIEC )
+ {
+ rStrm.WriteAttributes(
+ XML_dateCompatibility, XclXmlUtils::ToPsz( bDateCompatibility ),
+ FSEND );
+ }
+
+ if( !bISOIEC || bDateCompatibility )
+ {
+ rStrm.WriteAttributes(
+ XML_date1904, XclXmlUtils::ToPsz( bVal ),
+ FSEND );
+ }
+}
+
+
+
+//------------------------------------------------------ class ExcBundlesheet -
+
+ExcBundlesheetBase::ExcBundlesheetBase( RootData& rRootData, SCTAB nTabNum ) :
+ nStrPos( STREAM_SEEK_TO_END ),
+ nOwnPos( STREAM_SEEK_TO_END ),
+ nGrbit( rRootData.pER->GetTabInfo().IsVisibleTab( nTabNum ) ? 0x0000 : 0x0001 ),
+ nTab( nTabNum )
+{
+}
+
+
+ExcBundlesheetBase::ExcBundlesheetBase() :
+ nStrPos( STREAM_SEEK_TO_END ),
+ nOwnPos( STREAM_SEEK_TO_END ),
+ nGrbit( 0x0000 ),
+ nTab( SCTAB_GLOBAL )
+{
+}
+
+
+void ExcBundlesheetBase::UpdateStreamPos( XclExpStream& rStrm )
+{
+ rStrm.SetSvStreamPos( nOwnPos );
+ rStrm.DisableEncryption();
+ rStrm << static_cast<sal_uInt32>(nStrPos);
+ rStrm.EnableEncryption();
+}
+
+
+sal_uInt16 ExcBundlesheetBase::GetNum( void ) const
+{
+ return 0x0085;
+}
+
+
+
+
+ExcBundlesheet::ExcBundlesheet( RootData& rRootData, SCTAB _nTab ) :
+ ExcBundlesheetBase( rRootData, _nTab )
+{
+ String sTabName = rRootData.pER->GetTabInfo().GetScTabName( _nTab );
+ DBG_ASSERT( sTabName.Len() < 256, "ExcBundlesheet::ExcBundlesheet - table name too long" );
+ aName = ByteString( sTabName, rRootData.pER->GetTextEncoding() );
+}
+
+
+void ExcBundlesheet::SaveCont( XclExpStream& rStrm )
+{
+ nOwnPos = rStrm.GetSvStreamPos();
+ rStrm << (sal_uInt32) 0x00000000 // dummy (stream position of the sheet)
+ << nGrbit;
+ rStrm.WriteByteString( aName ); // 8 bit length, max 255 chars
+}
+
+
+sal_Size ExcBundlesheet::GetLen() const
+{
+ return 7 + Min( aName.Len(), (xub_StrLen) 255 );
+}
+
+
+//--------------------------------------------------------- class ExcDummy_02 -
+
+sal_Size ExcDummy_02a::GetLen( void ) const
+{
+ return nMyLen;
+}
+
+const sal_uInt8* ExcDummy_02a::GetData( void ) const
+{
+ return pMyData;
+}
+//--------------------------------------------------------- class ExcDummy_02 -
+
+XclExpCountry::XclExpCountry( const XclExpRoot& rRoot ) :
+ XclExpRecord( EXC_ID_COUNTRY, 4 )
+{
+ /* #i31530# set document country as UI country too -
+ needed for correct behaviour of number formats. */
+ mnUICountry = mnDocCountry = static_cast< sal_uInt16 >(
+ ::msfilter::ConvertLanguageToCountry( rRoot.GetDocLanguage() ) );
+}
+
+void XclExpCountry::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << mnUICountry << mnDocCountry;
+}
+
+// XclExpWsbool ===============================================================
+
+XclExpWsbool::XclExpWsbool( bool bFitToPages, SCTAB nScTab, XclExpFilterManager* pManager )
+ : XclExpUInt16Record( EXC_ID_WSBOOL, EXC_WSBOOL_DEFAULTFLAGS )
+ , mnScTab( nScTab )
+ , mpManager( pManager )
+{
+ if( bFitToPages )
+ SetValue( GetValue() | EXC_WSBOOL_FITTOPAGE );
+}
+
+void XclExpWsbool::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_sheetPr,
+ // OOXTODO: XML_syncHorizontal,
+ // OOXTODO: XML_syncVertical,
+ // OOXTODO: XML_syncRef,
+ // OOXTODO: XML_transitionEvaluation,
+ // OOXTODO: XML_transitionEntry,
+ // OOXTODO: XML_published,
+ // OOXTODO: XML_codeName,
+ XML_filterMode, mpManager ? XclXmlUtils::ToPsz( mpManager->HasFilterMode( mnScTab ) ) : NULL,
+ // OOXTODO: XML_enableFormatConditionsCalculation,
+ FSEND );
+ // OOXTODO: elements XML_tabColor, XML_outlinePr
+ rWorksheet->singleElement( XML_pageSetUpPr,
+ // OOXTODO: XML_autoPageBreaks,
+ XML_fitToPage, XclXmlUtils::ToPsz( GetValue() & EXC_WSBOOL_FITTOPAGE ),
+ FSEND );
+ rWorksheet->endElement( XML_sheetPr );
+}
+
+
+// XclExpWindowProtection ===============================================================
+
+XclExpWindowProtection::XclExpWindowProtection(bool bValue) :
+ XclExpBoolRecord(EXC_ID_WINDOWPROTECT, bValue)
+{
+}
+
+void XclExpWindowProtection::SaveXml( XclExpXmlStream& rStrm )
+{
+ rStrm.WriteAttributes(
+ XML_lockWindows, XclXmlUtils::ToPsz( GetBool() ),
+ FSEND );
+}
+
+// XclExpDocProtection ===============================================================
+
+XclExpProtection::XclExpProtection(bool bValue) :
+ XclExpBoolRecord(EXC_ID_PROTECT, bValue)
+{
+}
+
+// ============================================================================
+
+XclExpPassHash::XclExpPassHash(const Sequence<sal_Int8>& aHash) :
+ XclExpRecord(EXC_ID_PASSWORD, 2),
+ mnHash(0x0000)
+{
+ if (aHash.getLength() >= 2)
+ {
+ mnHash = ((aHash[0] << 8) & 0xFFFF);
+ mnHash |= (aHash[1] & 0xFF);
+ }
+}
+
+XclExpPassHash::~XclExpPassHash()
+{
+}
+
+void XclExpPassHash::WriteBody(XclExpStream& rStrm)
+{
+ rStrm << mnHash;
+}
+
+// ============================================================================
+
+XclExpFiltermode::XclExpFiltermode() :
+ XclExpEmptyRecord( EXC_ID_FILTERMODE )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpAutofilterinfo::XclExpAutofilterinfo( const ScAddress& rStartPos, SCCOL nScCol ) :
+ XclExpUInt16Record( EXC_ID_AUTOFILTERINFO, static_cast< sal_uInt16 >( nScCol ) ),
+ maStartPos( rStartPos )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ExcFilterCondition::ExcFilterCondition() :
+ nType( EXC_AFTYPE_NOTUSED ),
+ nOper( EXC_AFOPER_EQUAL ),
+ fVal( 0.0 ),
+ pText( NULL )
+{
+}
+
+ExcFilterCondition::~ExcFilterCondition()
+{
+ if( pText )
+ delete pText;
+}
+
+sal_Size ExcFilterCondition::GetTextBytes() const
+{
+ return pText ? (1 + pText->GetBufferSize()) : 0;
+}
+
+void ExcFilterCondition::SetCondition( sal_uInt8 nTp, sal_uInt8 nOp, double fV, String* pT )
+{
+ nType = nTp;
+ nOper = nOp;
+ fVal = fV;
+
+ delete pText;
+ pText = pT ? new XclExpString( *pT, EXC_STR_8BITLENGTH ) : NULL;
+}
+
+void ExcFilterCondition::Save( XclExpStream& rStrm )
+{
+ rStrm << nType << nOper;
+ switch( nType )
+ {
+ case EXC_AFTYPE_DOUBLE:
+ rStrm << fVal;
+ break;
+ case EXC_AFTYPE_STRING:
+ DBG_ASSERT( pText, "ExcFilterCondition::Save() -- pText is NULL!" );
+ rStrm << (sal_uInt32)0 << (sal_uInt8) pText->Len() << (sal_uInt16)0 << (sal_uInt8)0;
+ break;
+ case EXC_AFTYPE_BOOLERR:
+ rStrm << (sal_uInt8)0 << (sal_uInt8)((fVal != 0) ? 1 : 0) << (sal_uInt32)0 << (sal_uInt16)0;
+ break;
+ default:
+ rStrm << (sal_uInt32)0 << (sal_uInt32)0;
+ }
+}
+
+static const char* lcl_GetOperator( sal_uInt8 nOper )
+{
+ switch( nOper )
+ {
+ case EXC_AFOPER_EQUAL: return "equal";
+ case EXC_AFOPER_GREATER: return "greaterThan";
+ case EXC_AFOPER_GREATEREQUAL: return "greaterThanOrEqual";
+ case EXC_AFOPER_LESS: return "lessThan";
+ case EXC_AFOPER_LESSEQUAL: return "lessThanOrEqual";
+ case EXC_AFOPER_NOTEQUAL: return "notEqual";
+ case EXC_AFOPER_NONE:
+ default: return "**none**";
+ }
+}
+
+static OString lcl_GetValue( sal_uInt8 nType, double fVal, XclExpString* pStr )
+{
+ switch( nType )
+ {
+ case EXC_AFTYPE_STRING: return XclXmlUtils::ToOString( *pStr );
+ case EXC_AFTYPE_DOUBLE: return OString::valueOf( fVal );
+ case EXC_AFTYPE_BOOLERR: return OString::valueOf( (sal_Int32) ( fVal != 0 ? 1 : 0 ) );
+ default: return OString();
+ }
+}
+
+void ExcFilterCondition::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( IsEmpty() )
+ return;
+
+ rStrm.GetCurrentStream()->singleElement( XML_customFilter,
+ XML_operator, lcl_GetOperator( nOper ),
+ XML_val, lcl_GetValue( nType, fVal, pText ).getStr(),
+ FSEND );
+}
+
+void ExcFilterCondition::SaveText( XclExpStream& rStrm )
+{
+ if( nType == EXC_AFTYPE_STRING )
+ {
+ DBG_ASSERT( pText, "ExcFilterCondition::SaveText() -- pText is NULL!" );
+ pText->WriteFlagField( rStrm );
+ pText->WriteBuffer( rStrm );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpAutofilter::XclExpAutofilter( const XclExpRoot& rRoot, sal_uInt16 nC ) :
+ XclExpRecord( EXC_ID_AUTOFILTER, 24 ),
+ XclExpRoot( rRoot ),
+ nCol( nC ),
+ nFlags( 0 )
+{
+}
+
+sal_Bool XclExpAutofilter::AddCondition( ScQueryConnect eConn, sal_uInt8 nType, sal_uInt8 nOp,
+ double fVal, String* pText, sal_Bool bSimple )
+{
+ if( !aCond[ 1 ].IsEmpty() )
+ return false;
+
+ sal_uInt16 nInd = aCond[ 0 ].IsEmpty() ? 0 : 1;
+
+ if( nInd == 1 )
+ nFlags |= (eConn == SC_OR) ? EXC_AFFLAG_OR : EXC_AFFLAG_AND;
+ if( bSimple )
+ nFlags |= (nInd == 0) ? EXC_AFFLAG_SIMPLE1 : EXC_AFFLAG_SIMPLE2;
+
+ aCond[ nInd ].SetCondition( nType, nOp, fVal, pText );
+
+ AddRecSize( aCond[ nInd ].GetTextBytes() );
+
+ return sal_True;
+}
+
+sal_Bool XclExpAutofilter::AddEntry( const ScQueryEntry& rEntry )
+{
+ sal_Bool bConflict = false;
+ String sText;
+
+ if( rEntry.pStr )
+ {
+ sText.Assign( *rEntry.pStr );
+ switch( rEntry.eOp )
+ {
+ case SC_CONTAINS:
+ case SC_DOES_NOT_CONTAIN:
+ {
+ sText.InsertAscii( "*" , 0 );
+ sText.AppendAscii( "*" );
+ }
+ break;
+ case SC_BEGINS_WITH:
+ case SC_DOES_NOT_BEGIN_WITH:
+ sText.AppendAscii( "*" );
+ break;
+ case SC_ENDS_WITH:
+ case SC_DOES_NOT_END_WITH:
+ sText.InsertAscii( "*" , 0 );
+ break;
+ default:
+ {
+ //nothing
+ }
+ }
+ }
+
+ sal_Bool bLen = sText.Len() > 0;
+
+ // empty/nonempty fields
+ if( !bLen && (rEntry.nVal == SC_EMPTYFIELDS) )
+ bConflict = !AddCondition( rEntry.eConnect, EXC_AFTYPE_EMPTY, EXC_AFOPER_NONE, 0.0, NULL, sal_True );
+ else if( !bLen && (rEntry.nVal == SC_NONEMPTYFIELDS) )
+ bConflict = !AddCondition( rEntry.eConnect, EXC_AFTYPE_NOTEMPTY, EXC_AFOPER_NONE, 0.0, NULL, sal_True );
+ // other conditions
+ else
+ {
+ double fVal = 0.0;
+ sal_uInt32 nIndex = 0;
+ sal_Bool bIsNum = bLen ? GetFormatter().IsNumberFormat( sText, nIndex, fVal ) : sal_True;
+ String* pText = bIsNum ? NULL : &sText;
+
+ // top10 flags
+ sal_uInt16 nNewFlags = 0x0000;
+ switch( rEntry.eOp )
+ {
+ case SC_TOPVAL:
+ nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP);
+ break;
+ case SC_BOTVAL:
+ nNewFlags = EXC_AFFLAG_TOP10;
+ break;
+ case SC_TOPPERC:
+ nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP | EXC_AFFLAG_TOP10PERC);
+ break;
+ case SC_BOTPERC:
+ nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10PERC);
+ break;
+ default:;
+ }
+ sal_Bool bNewTop10 = ::get_flag( nNewFlags, EXC_AFFLAG_TOP10 );
+
+ bConflict = HasTop10() && bNewTop10;
+ if( !bConflict )
+ {
+ if( bNewTop10 )
+ {
+ if( fVal < 0 ) fVal = 0;
+ if( fVal >= 501 ) fVal = 500;
+ nFlags |= (nNewFlags | (sal_uInt16)(fVal) << 7);
+ }
+ // normal condition
+ else
+ {
+ sal_uInt8 nType = bIsNum ? EXC_AFTYPE_DOUBLE : EXC_AFTYPE_STRING;
+ sal_uInt8 nOper = EXC_AFOPER_NONE;
+
+ switch( rEntry.eOp )
+ {
+ case SC_EQUAL: nOper = EXC_AFOPER_EQUAL; break;
+ case SC_LESS: nOper = EXC_AFOPER_LESS; break;
+ case SC_GREATER: nOper = EXC_AFOPER_GREATER; break;
+ case SC_LESS_EQUAL: nOper = EXC_AFOPER_LESSEQUAL; break;
+ case SC_GREATER_EQUAL: nOper = EXC_AFOPER_GREATEREQUAL; break;
+ case SC_NOT_EQUAL: nOper = EXC_AFOPER_NOTEQUAL; break;
+ case SC_CONTAINS:
+ case SC_BEGINS_WITH:
+ case SC_ENDS_WITH:
+ nOper = EXC_AFOPER_EQUAL; break;
+ case SC_DOES_NOT_CONTAIN:
+ case SC_DOES_NOT_BEGIN_WITH:
+ case SC_DOES_NOT_END_WITH:
+ nOper = EXC_AFOPER_NOTEQUAL; break;
+ default:;
+ }
+ bConflict = !AddCondition( rEntry.eConnect, nType, nOper, fVal, pText );
+ }
+ }
+ }
+ return bConflict;
+}
+
+void XclExpAutofilter::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << nCol << nFlags;
+ aCond[ 0 ].Save( rStrm );
+ aCond[ 1 ].Save( rStrm );
+ aCond[ 0 ].SaveText( rStrm );
+ aCond[ 1 ].SaveText( rStrm );
+}
+
+void XclExpAutofilter::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( !HasCondition() )
+ return;
+
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+
+ rWorksheet->startElement( XML_filterColumn,
+ XML_colId, OString::valueOf( (sal_Int32) nCol ).getStr(),
+ // OOXTODO: XML_hiddenButton, AutoFilter12 fHideArrow?
+ // OOXTODO: XML_showButton,
+ FSEND );
+
+ if( HasTop10() )
+ {
+ rWorksheet->singleElement( XML_top10,
+ XML_top, XclXmlUtils::ToPsz( get_flag( nFlags, EXC_AFFLAG_TOP10TOP ) ),
+ XML_percent, XclXmlUtils::ToPsz( get_flag( nFlags, EXC_AFFLAG_TOP10PERC ) ),
+ XML_val, OString::valueOf( (sal_Int32) (nFlags >> 7 ) ).getStr(),
+ // OOXTODO: XML_filterVal,
+ FSEND );
+ }
+
+ rWorksheet->startElement( XML_customFilters,
+ XML_and, XclXmlUtils::ToPsz( (nFlags & EXC_AFFLAG_ANDORMASK) == EXC_AFFLAG_AND ),
+ FSEND );
+ aCond[ 0 ].SaveXml( rStrm );
+ aCond[ 1 ].SaveXml( rStrm );
+ rWorksheet->endElement( XML_customFilters );
+ // OOXTODO: XLM_colorFilter, XML_dynamicFilter,
+ // XML_extLst, XML_filters, XML_iconFilter, XML_top10
+ rWorksheet->endElement( XML_filterColumn );
+}
+
+// ----------------------------------------------------------------------------
+
+ExcAutoFilterRecs::ExcAutoFilterRecs( const XclExpRoot& rRoot, SCTAB nTab ) :
+ XclExpRoot( rRoot ),
+ pFilterMode( NULL ),
+ pFilterInfo( NULL )
+ , mbAutoFilter (false)
+{
+ XclExpNameManager& rNameMgr = GetNameManager();
+
+ sal_Bool bFound = false;
+ sal_Bool bAdvanced = false;
+ ScDBData* pData = rRoot.GetDoc().GetAnonymousDBData(nTab);
+ ScRange aAdvRange;
+ if (pData)
+ {
+ bAdvanced = pData->GetAdvancedQuerySource( aAdvRange );
+ bFound = (pData->HasQueryParam() || pData->HasAutoFilter() || bAdvanced);
+ }
+ if( bFound )
+ {
+ ScQueryParam aParam;
+ pData->GetQueryParam( aParam );
+
+ ScRange aRange( aParam.nCol1, aParam.nRow1, aParam.nTab,
+ aParam.nCol2, aParam.nRow2, aParam.nTab );
+ SCCOL nColCnt = aParam.nCol2 - aParam.nCol1 + 1;
+
+ maRef = aRange;
+
+ // #i2394# built-in defined names must be sorted by containing sheet name
+ rNameMgr.InsertBuiltInName( EXC_BUILTIN_FILTERDATABASE, aRange );
+
+ // advanced filter
+ if( bAdvanced )
+ {
+ // filter criteria, excel allows only same table
+ if( aAdvRange.aStart.Tab() == nTab )
+ rNameMgr.InsertBuiltInName( EXC_BUILTIN_CRITERIA, aAdvRange );
+
+ // filter destination range, excel allows only same table
+ if( !aParam.bInplace )
+ {
+ ScRange aDestRange( aParam.nDestCol, aParam.nDestRow, aParam.nDestTab );
+ aDestRange.aEnd.IncCol( nColCnt - 1 );
+ if( aDestRange.aStart.Tab() == nTab )
+ rNameMgr.InsertBuiltInName( EXC_BUILTIN_EXTRACT, aDestRange );
+ }
+
+ pFilterMode = new XclExpFiltermode;
+ }
+ // AutoFilter
+ else
+ {
+ sal_Bool bConflict = false;
+ sal_Bool bContLoop = sal_True;
+ sal_Bool bHasOr = false;
+ SCCOLROW nFirstField = aParam.GetEntry( 0 ).nField;
+
+ // create AUTOFILTER records for filtered columns
+ for( SCSIZE nEntry = 0; !bConflict && bContLoop && (nEntry < aParam.GetEntryCount()); nEntry++ )
+ {
+ const ScQueryEntry& rEntry = aParam.GetEntry( nEntry );
+
+ bContLoop = rEntry.bDoQuery;
+ if( bContLoop )
+ {
+ XclExpAutofilter* pFilter = GetByCol( static_cast<SCCOL>(rEntry.nField) - aRange.aStart.Col() );
+
+ if( nEntry > 0 )
+ bHasOr |= (rEntry.eConnect == SC_OR);
+
+ bConflict = (nEntry > 1) && bHasOr;
+ if( !bConflict )
+ bConflict = (nEntry == 1) && (rEntry.eConnect == SC_OR) &&
+ (nFirstField != rEntry.nField);
+ if( !bConflict )
+ bConflict = pFilter->AddEntry( rEntry );
+ }
+ }
+
+ // additional tests for conflicts
+ for( size_t nPos = 0, nSize = maFilterList.GetSize(); !bConflict && (nPos < nSize); ++nPos )
+ {
+ XclExpAutofilterRef xFilter = maFilterList.GetRecord( nPos );
+ bConflict = xFilter->HasCondition() && xFilter->HasTop10();
+ }
+
+ if( bConflict )
+ maFilterList.RemoveAllRecords();
+
+ if( !maFilterList.IsEmpty() )
+ pFilterMode = new XclExpFiltermode;
+ pFilterInfo = new XclExpAutofilterinfo( aRange.aStart, nColCnt );
+
+ if (maFilterList.IsEmpty () && !bConflict)
+ mbAutoFilter = true;
+ }
+ }
+}
+
+ExcAutoFilterRecs::~ExcAutoFilterRecs()
+{
+ delete pFilterMode;
+ delete pFilterInfo;
+}
+
+XclExpAutofilter* ExcAutoFilterRecs::GetByCol( SCCOL nCol )
+{
+ XclExpAutofilterRef xFilter;
+ for( size_t nPos = 0, nSize = maFilterList.GetSize(); nPos < nSize; ++nPos )
+ {
+ xFilter = maFilterList.GetRecord( nPos );
+ if( xFilter->GetCol() == static_cast<sal_uInt16>(nCol) )
+ return xFilter.get();
+ }
+ xFilter.reset( new XclExpAutofilter( GetRoot(), static_cast<sal_uInt16>(nCol) ) );
+ maFilterList.AppendRecord( xFilter );
+ return xFilter.get();
+}
+
+sal_Bool ExcAutoFilterRecs::IsFiltered( SCCOL nCol )
+{
+ for( size_t nPos = 0, nSize = maFilterList.GetSize(); nPos < nSize; ++nPos )
+ if( maFilterList.GetRecord( nPos )->GetCol() == static_cast<sal_uInt16>(nCol) )
+ return sal_True;
+ return false;
+}
+
+void ExcAutoFilterRecs::AddObjRecs()
+{
+ if( pFilterInfo )
+ {
+ ScAddress aAddr( pFilterInfo->GetStartPos() );
+ for( SCCOL nObj = 0, nCount = pFilterInfo->GetColCount(); nObj < nCount; nObj++ )
+ {
+ XclObj* pObjRec = new XclObjDropDown( GetObjectManager(), aAddr, IsFiltered( nObj ) );
+ GetObjectManager().AddObj( pObjRec );
+ aAddr.IncCol( 1 );
+ }
+ }
+}
+
+void ExcAutoFilterRecs::Save( XclExpStream& rStrm )
+{
+ if( pFilterMode )
+ pFilterMode->Save( rStrm );
+ if( pFilterInfo )
+ pFilterInfo->Save( rStrm );
+ maFilterList.Save( rStrm );
+}
+
+void ExcAutoFilterRecs::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( maFilterList.IsEmpty() && !mbAutoFilter )
+ return;
+
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_autoFilter,
+ XML_ref, XclXmlUtils::ToOString( maRef ).getStr(),
+ FSEND );
+ // OOXTODO: XML_extLst, XML_sortState
+ if( !maFilterList.IsEmpty() )
+ maFilterList.SaveXml( rStrm );
+ rWorksheet->endElement( XML_autoFilter );
+}
+
+bool ExcAutoFilterRecs::HasFilterMode() const
+{
+ return pFilterMode != NULL;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpFilterManager::XclExpFilterManager( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+void XclExpFilterManager::InitTabFilter( SCTAB nScTab )
+{
+ maFilterMap[ nScTab ].reset( new ExcAutoFilterRecs( GetRoot(), nScTab ) );
+}
+
+XclExpRecordRef XclExpFilterManager::CreateRecord( SCTAB nScTab )
+{
+ XclExpTabFilterRef xRec;
+ XclExpTabFilterMap::iterator aIt = maFilterMap.find( nScTab );
+ if( aIt != maFilterMap.end() )
+ {
+ xRec = aIt->second;
+ xRec->AddObjRecs();
+ }
+ return xRec;
+}
+
+bool XclExpFilterManager::HasFilterMode( SCTAB nScTab )
+{
+ XclExpTabFilterRef xRec;
+ XclExpTabFilterMap::iterator aIt = maFilterMap.find( nScTab );
+ if( aIt != maFilterMap.end() )
+ {
+ return aIt->second->HasFilterMode();
+ }
+ return false;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/exctools.cxx b/sc/source/filter/excel/exctools.cxx
new file mode 100644
index 000000000000..4cfedccea8f5
--- /dev/null
+++ b/sc/source/filter/excel/exctools.cxx
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <editeng/editdata.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+
+#include "document.hxx"
+#include "patattr.hxx"
+#include "attrib.hxx"
+#include "globstr.hrc"
+#include "scextopt.hxx"
+#include "progress.hxx"
+#include "rangenam.hxx"
+#include "editutil.hxx"
+
+#include "excrecds.hxx"
+#include "root.hxx"
+#include "imp_op.hxx"
+#include "excimp8.hxx"
+#include "otlnbuff.hxx"
+#include "xcl97rec.hxx"
+#include "formel.hxx"
+#include "xilink.hxx"
+#include "xecontent.hxx"
+
+#include <vector>
+
+RootData::RootData( void )
+{
+ eDateiTyp = BiffX;
+ pExtSheetBuff = NULL;
+ pShrfmlaBuff = NULL;
+ pExtNameBuff = NULL;
+ pFmlaConverter = NULL;
+
+ pAutoFilterBuffer = NULL;
+ pPrintRanges = new _ScRangeListTabs;
+ pPrintTitles = new _ScRangeListTabs;
+
+ pTabId = NULL;
+ pUserBViewList = NULL;
+
+ pIR = NULL;
+ pER = NULL;
+}
+
+RootData::~RootData()
+{
+ delete pExtSheetBuff;
+ delete pShrfmlaBuff;
+ delete pExtNameBuff;
+ delete pAutoFilterBuffer;
+ delete pPrintRanges;
+ delete pPrintTitles;
+}
+
+
+XclImpOutlineBuffer::XclImpOutlineBuffer( SCSIZE nNewSize ) :
+ maLevels(0, nNewSize, 0),
+ mpOutlineArray(NULL),
+ mnEndPos(nNewSize),
+ mnMaxLevel(0),
+ mbButtonAfter(true)
+{
+}
+
+XclImpOutlineBuffer::~XclImpOutlineBuffer()
+{
+}
+
+void XclImpOutlineBuffer::SetLevel( SCSIZE nIndex, sal_uInt8 nVal, bool bCollapsed )
+{
+ maLevels.insert_back(nIndex, nIndex+1, nVal);
+ if (nVal > mnMaxLevel)
+ mnMaxLevel = nVal;
+ if (bCollapsed)
+ maCollapsedPosSet.insert(nIndex);
+}
+
+void XclImpOutlineBuffer::SetOutlineArray( ScOutlineArray* pOArray )
+{
+ mpOutlineArray = pOArray;
+}
+
+void XclImpOutlineBuffer::MakeScOutline()
+{
+ if (!mpOutlineArray)
+ return;
+
+ ::std::vector<SCSIZE> aOutlineStack;
+ aOutlineStack.reserve(mnMaxLevel);
+ OutlineLevels::const_iterator itr = maLevels.begin(), itrEnd = maLevels.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ SCSIZE nPos = itr->first;
+ if (nPos >= mnEndPos)
+ {
+ // Don't go beyond the max allowed position.
+ DBG_ASSERT(aOutlineStack.empty(), "XclImpOutlineBuffer::MakeScOutline: outline stack not empty but expected to be.");
+ break;
+ }
+ sal_uInt8 nLevel = itr->second;
+ sal_uInt8 nCurLevel = static_cast<sal_uInt8>(aOutlineStack.size());
+ if (nLevel > nCurLevel)
+ {
+ for (sal_uInt8 i = 0; i < nLevel - nCurLevel; ++i)
+ aOutlineStack.push_back(nPos);
+ }
+ else
+ {
+ DBG_ASSERT(nLevel < nCurLevel, "XclImpOutlineBuffer::MakeScOutline: unexpected level!");
+ for (sal_uInt8 i = 0; i < nCurLevel - nLevel; ++i)
+ {
+ if (aOutlineStack.empty())
+ {
+ // Something is wrong.
+ return;
+ }
+ SCSIZE nFirstPos = aOutlineStack.back();
+ aOutlineStack.pop_back();
+ bool bCollapsed = false;
+ if (mbButtonAfter)
+ bCollapsed = maCollapsedPosSet.count(nPos) > 0;
+ else if (nFirstPos > 0)
+ bCollapsed = maCollapsedPosSet.count(nFirstPos-1) > 0;
+
+ sal_Bool bDummy;
+ mpOutlineArray->Insert(nFirstPos, nPos-1, bDummy, bCollapsed);
+ }
+ }
+ }
+}
+
+void XclImpOutlineBuffer::SetLevelRange( SCSIZE nF, SCSIZE nL, sal_uInt8 nVal, bool bCollapsed )
+{
+ if (nF > nL)
+ // invalid range
+ return;
+
+ maLevels.insert_back(nF, nL+1, nVal);
+
+ if (bCollapsed)
+ maCollapsedPosSet.insert(nF);
+}
+
+void XclImpOutlineBuffer::SetButtonMode( bool bRightOrUnder )
+{
+ mbButtonAfter = bRightOrUnder;
+}
+
+ExcScenarioCell::ExcScenarioCell( const sal_uInt16 nC, const sal_uInt16 nR )
+ : nCol( nC ), nRow( nR )
+{
+}
+
+ExcScenario::ExcScenario( XclImpStream& rIn, const RootData& rR )
+ : nTab( rR.pIR->GetCurrScTab() )
+{
+ sal_uInt16 nCref;
+ sal_uInt8 nName, nComment;
+
+ rIn >> nCref;
+ rIn >> nProtected;
+ rIn.Ignore( 1 ); // Hide
+ rIn >> nName >> nComment;
+ rIn.Ignore( 1 ); // statt nUser!
+
+ if( nName )
+ pName = new String( rIn.ReadUniString( nName ) );
+ else
+ {
+ pName = new String( RTL_CONSTASCII_USTRINGPARAM( "Scenery" ) );
+ rIn.Ignore( 1 );
+ }
+
+ pUserName = new String( rIn.ReadUniString() );
+
+ if( nComment )
+ pComment = new String( rIn.ReadUniString() );
+ else
+ pComment = new String;
+
+ sal_uInt16 n = nCref;
+ sal_uInt16 nC, nR;
+ while( n )
+ {
+ rIn >> nR >> nC;
+
+ aEntries.push_back(new ExcScenarioCell( nC, nR ));
+
+ n--;
+ }
+
+ n = nCref;
+
+ boost::ptr_vector<ExcScenarioCell>::iterator iter;
+ for (iter = aEntries.begin(); iter != aEntries.end(); ++iter)
+ iter->SetValue(rIn.ReadUniString());
+}
+
+ExcScenario::~ExcScenario()
+{
+ if( pName )
+ delete pName;
+ if( pComment )
+ delete pComment;
+ if( pUserName )
+ delete pUserName;
+}
+
+void ExcScenario::Apply( const XclImpRoot& rRoot, const sal_Bool bLast )
+{
+ ScDocument& r = rRoot.GetDoc();
+ String aSzenName( *pName );
+ sal_uInt16 nNewTab = nTab + 1;
+
+ if( !r.InsertTab( nNewTab, aSzenName ) )
+ return;
+
+ r.SetScenario( nNewTab, true );
+ // do not show scenario frames
+ r.SetScenarioData( nNewTab, *pComment, COL_LIGHTGRAY, /*SC_SCENARIO_SHOWFRAME|*/SC_SCENARIO_COPYALL|(nProtected ? SC_SCENARIO_PROTECT : 0) );
+
+ boost::ptr_vector<ExcScenarioCell>::const_iterator iter;
+ for (iter = aEntries.begin(); iter != aEntries.end(); ++iter)
+ {
+ sal_uInt16 nCol = iter->nCol;
+ sal_uInt16 nRow = iter->nRow;
+ String aVal = iter->GetValue();
+
+ r.ApplyFlagsTab( nCol, nRow, nCol, nRow, nNewTab, SC_MF_SCENARIO );
+
+ r.SetString( nCol, nRow, nNewTab, aVal );
+ }
+
+ if( bLast )
+ r.SetActiveScenario( nNewTab, sal_True );
+
+ // modify what the Active tab is set to if the new
+ // scenario tab occurs before the active tab.
+ ScExtDocSettings& rDocSett = rRoot.GetExtDocOptions().GetDocSettings();
+ if( (static_cast< SCCOL >( nTab ) < rDocSett.mnDisplTab) && (rDocSett.mnDisplTab < MAXTAB) )
+ ++rDocSett.mnDisplTab;
+ rRoot.GetTabInfo().InsertScTab( nNewTab );
+}
+
+void ExcScenarioList::Apply( const XclImpRoot& rRoot )
+{
+ sal_uInt16 n = static_cast<sal_uInt16>(aEntries.size());
+
+ boost::ptr_vector<ExcScenario>::reverse_iterator iter;
+ for (iter = aEntries.rbegin(); iter != aEntries.rend(); ++iter)
+ {
+ n--;
+ iter->Apply(rRoot, n == nLastScenario);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/expop2.cxx b/sc/source/filter/excel/expop2.cxx
new file mode 100644
index 000000000000..f52c0d7feec2
--- /dev/null
+++ b/sc/source/filter/excel/expop2.cxx
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------------
+
+#include <unotools/fltrcfg.hxx>
+
+#include <sfx2/objsh.hxx>
+#include <sfx2/docinf.hxx>
+#include <filter/msfilter/svxmsbas.hxx>
+
+#include "scerrors.hxx"
+#include "scextopt.hxx"
+
+#include "root.hxx"
+#include "excdoc.hxx"
+#include "exp_op.hxx"
+
+#include "xcl97esc.hxx"
+
+#include "document.hxx"
+#include "rangenam.hxx"
+#include "filtopt.hxx"
+#include "xltools.hxx"
+#include "xelink.hxx"
+
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+
+
+ExportBiff5::ExportBiff5( XclExpRootData& rExpData, SvStream& rStrm ):
+ ExportTyp( rStrm, &rExpData.mrDoc, rExpData.meTextEnc ),
+ XclExpRoot( rExpData )
+{
+ // nur Teil der Root-Daten gebraucht
+ pExcRoot = &GetOldRoot();
+ pExcRoot->pER = this; // ExcRoot -> XclExpRoot
+ pExcRoot->eDateiTyp = Biff5;
+ pExcDoc = new ExcDocument( *this );
+}
+
+
+ExportBiff5::~ExportBiff5()
+{
+ delete pExcDoc;
+}
+
+
+FltError ExportBiff5::Write()
+{
+ SfxObjectShell* pDocShell = GetDocShell();
+ DBG_ASSERT( pDocShell, "ExportBiff5::Write - no document shell" );
+
+ SotStorageRef xRootStrg = GetRootStorage();
+ DBG_ASSERT( xRootStrg.Is(), "ExportBiff5::Write - no root storage" );
+
+ bool bWriteBasicCode = false;
+ bool bWriteBasicStrg = false;
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ if( SvtFilterOptions* pFilterOpt = SvtFilterOptions::Get() )
+ {
+ bWriteBasicCode = pFilterOpt->IsLoadExcelBasicCode();
+ bWriteBasicStrg = pFilterOpt->IsLoadExcelBasicStorage();
+ }
+ }
+
+ if( pDocShell && xRootStrg.Is() && bWriteBasicStrg )
+ {
+ SvxImportMSVBasic aBasicImport( *pDocShell, *xRootStrg, bWriteBasicCode, bWriteBasicStrg );
+ sal_uLong nErr = aBasicImport.SaveOrDelMSVBAStorage( sal_True, EXC_STORAGE_VBA_PROJECT );
+ if( nErr != ERRCODE_NONE )
+ pDocShell->SetError( nErr, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
+ }
+
+ pExcDoc->ReadDoc(); // ScDoc -> ExcDoc
+ pExcDoc->Write( aOut ); // wechstreamen
+
+ if( pDocShell && xRootStrg.Is() )
+ {
+ // #i88642# update doc info (revision etc)
+ pDocShell->UpdateDocInfoForSave();
+
+ using namespace ::com::sun::star;
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ pDocShell->GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps
+ = xDPS->getDocumentProperties();
+ if ( SvtFilterOptions::Get()->IsEnableCalcPreview() )
+ {
+ ::boost::shared_ptr<GDIMetaFile> pMetaFile =
+ pDocShell->GetPreviewMetaFile (false);
+ uno::Sequence<sal_uInt8> metaFile(
+ sfx2::convertMetaFile(pMetaFile.get()));
+ sfx2::SaveOlePropertySet(xDocProps, xRootStrg, &metaFile);
+ }
+ else
+ sfx2::SaveOlePropertySet(xDocProps, xRootStrg );
+ }
+
+ //! TODO: separate warnings for columns and sheets
+ const XclExpAddressConverter& rAddrConv = GetAddressConverter();
+ if( rAddrConv.IsColTruncated() || rAddrConv.IsRowTruncated() || rAddrConv.IsTabTruncated() )
+ return SCWARN_EXPORT_MAXROW;
+
+ return eERR_OK;
+}
+
+
+
+ExportBiff8::ExportBiff8( XclExpRootData& rExpData, SvStream& rStrm ) :
+ ExportBiff5( rExpData, rStrm )
+{
+ pExcRoot->eDateiTyp = Biff8;
+}
+
+
+ExportBiff8::~ExportBiff8()
+{
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/fontbuff.cxx b/sc/source/filter/excel/fontbuff.cxx
new file mode 100644
index 000000000000..26db50f0166f
--- /dev/null
+++ b/sc/source/filter/excel/fontbuff.cxx
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "lotfntbf.hxx"
+
+#include "scitems.hxx"
+#include <editeng/cntritem.hxx>
+#include <editeng/crsditem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <sfx2/printer.hxx>
+
+#include "attrib.hxx"
+#include "document.hxx"
+#include "global.hxx"
+#include "docpool.hxx"
+#include "patattr.hxx"
+#include "ftools.hxx"
+
+const sal_uInt16 LotusFontBuffer::nSize = 8;
+
+void LotusFontBuffer::Fill( const sal_uInt8 nIndex, SfxItemSet& rItemSet )
+{
+ sal_uInt8 nIntIndex = nIndex & 0x07;
+
+ ENTRY* pAkt = pData + nIntIndex;
+
+ if( pAkt->pFont )
+ rItemSet.Put( *pAkt->pFont );
+
+ if( pAkt->pHeight )
+ rItemSet.Put( *pAkt->pHeight );
+
+ if( pAkt->pColor )
+ rItemSet.Put( *pAkt->pColor );
+
+ if( nIndex & 0x08 )
+ {
+ SvxWeightItem aWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT );
+ rItemSet.Put( aWeightItem );
+ }
+
+ if( nIndex & 0x10 )
+ {
+ SvxPostureItem aAttr( ITALIC_NORMAL, ATTR_FONT_POSTURE );
+ rItemSet.Put( aAttr );
+ }
+
+ FontUnderline eUnderline;
+ switch( nIndex & 0x60 ) // Bit 5+6
+ {
+ case 0x60:
+ case 0x20: eUnderline = UNDERLINE_SINGLE; break;
+ case 0x40: eUnderline = UNDERLINE_DOUBLE; break;
+ default: eUnderline = UNDERLINE_NONE;
+ }
+ if( eUnderline != UNDERLINE_NONE )
+ {
+ SvxUnderlineItem aUndItem( eUnderline, ATTR_FONT_UNDERLINE );
+ rItemSet.Put( aUndItem );
+ }
+}
+
+
+void LotusFontBuffer::SetName( const sal_uInt16 nIndex, const String& rName )
+{
+ DBG_ASSERT( nIndex < nSize, "*LotusFontBuffer::SetName(): Array zu klein!" );
+ if( nIndex < nSize )
+ {
+ register ENTRY* pEntry = pData + nIndex;
+ pEntry->TmpName( rName );
+
+ if( pEntry->nType >= 0 )
+ MakeFont( pEntry );
+ }
+}
+
+
+void LotusFontBuffer::SetHeight( const sal_uInt16 nIndex, const sal_uInt16 nHeight )
+{
+ DBG_ASSERT( nIndex < nSize, "*LotusFontBuffer::SetHeight(): Array zu klein!" );
+ if( nIndex < nSize )
+ pData[ nIndex ].Height( *( new SvxFontHeightItem( ( sal_uLong ) nHeight * 20, 100, ATTR_FONT_HEIGHT ) ) );
+}
+
+
+void LotusFontBuffer::SetType( const sal_uInt16 nIndex, const sal_uInt16 nType )
+{
+ DBG_ASSERT( nIndex < nSize, "*LotusFontBuffer::SetType(): Array zu klein!" );
+ if( nIndex < nSize )
+ {
+ register ENTRY* pEntry = pData + nIndex;
+ pEntry->Type( nType );
+
+ if( pEntry->pTmpName )
+ MakeFont( pEntry );
+ }
+}
+
+
+void LotusFontBuffer::MakeFont( ENTRY* pEntry )
+{
+ FontFamily eFamily = FAMILY_DONTKNOW;
+ FontPitch ePitch = PITCH_DONTKNOW;
+ CharSet eCharSet = RTL_TEXTENCODING_DONTKNOW;
+
+ switch( pEntry->nType )
+ {
+ case 0x00: // Helvetica
+ eFamily = FAMILY_SWISS;
+ ePitch = PITCH_VARIABLE;
+ break;
+ case 0x01: // Times Roman
+ eFamily = FAMILY_ROMAN;
+ ePitch = PITCH_VARIABLE;
+ break;
+ case 0x02: // Courier
+ ePitch = PITCH_FIXED;
+ break;
+ case 0x03: // Symbol
+ eCharSet = RTL_TEXTENCODING_SYMBOL;
+ break;
+ }
+
+ pEntry->pFont = new SvxFontItem( eFamily, *pEntry->pTmpName, EMPTY_STRING, ePitch, eCharSet, ATTR_FONT );
+
+ delete pEntry->pTmpName;
+ pEntry->pTmpName = NULL;
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/frmbase.cxx b/sc/source/filter/excel/frmbase.cxx
new file mode 100644
index 000000000000..81706ce5cb7d
--- /dev/null
+++ b/sc/source/filter/excel/frmbase.cxx
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "formel.hxx"
+
+_ScRangeListTabs::_ScRangeListTabs()
+{
+}
+
+_ScRangeListTabs::~_ScRangeListTabs()
+{
+}
+
+
+void _ScRangeListTabs::Append( ScSingleRefData a, SCTAB nTab, const bool b )
+{
+ if( b )
+ {
+ if( a.nTab > MAXTAB )
+ a.nTab = MAXTAB;
+
+ if( a.nCol > MAXCOL )
+ a.nCol = MAXCOL;
+
+ if( a.nRow > MAXROW )
+ a.nRow = MAXROW;
+ }
+ else
+ {
+ DBG_ASSERT( ValidTab(a.nTab), "-_ScRangeListTabs::Append(): Luegen haben kurze Abstuerze!" );
+ }
+
+ if( nTab == SCTAB_MAX)
+ return;
+ if( nTab < 0)
+ nTab = a.nTab;
+
+ if (nTab < 0 || MAXTAB < nTab)
+ return;
+
+ TabRangeType::iterator itr = maTabRanges.find(nTab);
+ if (itr == maTabRanges.end())
+ {
+ // No entry for this table yet. Insert a new one.
+ std::pair<TabRangeType::iterator, bool> r =
+ maTabRanges.insert(nTab, new RangeListType);
+
+ if (!r.second)
+ // Insertion failed.
+ return;
+
+ itr = r.first;
+ }
+ itr->second->push_back(ScRange(a.nCol,a.nRow,a.nTab));
+}
+
+void _ScRangeListTabs::Append( ScComplexRefData a, SCTAB nTab, bool b )
+{
+ if( b )
+ {
+ // ignore 3D ranges
+ if( a.Ref1.nTab != a.Ref2.nTab )
+ return;
+
+ SCsTAB& rTab = a.Ref1.nTab;
+ if( rTab > MAXTAB )
+ rTab = MAXTAB;
+ else if( rTab < 0 )
+ rTab = 0;
+
+ SCsCOL& rCol1 = a.Ref1.nCol;
+ if( rCol1 > MAXCOL )
+ rCol1 = MAXCOL;
+ else if( rCol1 < 0 )
+ rCol1 = 0;
+
+ SCsROW& rRow1 = a.Ref1.nRow;
+ if( rRow1 > MAXROW )
+ rRow1 = MAXROW;
+ else if( rRow1 < 0 )
+ rRow1 = 0;
+
+ SCsCOL& rCol2 = a.Ref2.nCol;
+ if( rCol2 > MAXCOL )
+ rCol2 = MAXCOL;
+ else if( rCol2 < 0 )
+ rCol2 = 0;
+
+ SCsROW& rRow2 = a.Ref2.nRow;
+ if( rRow2 > MAXROW )
+ rRow2 = MAXROW;
+ else if( rRow2 < 0 )
+ rRow2 = 0;
+ }
+ else
+ {
+ DBG_ASSERT( ValidTab(a.Ref1.nTab),
+ "-_ScRangeListTabs::Append(): Luegen haben kurze Abstuerze!" );
+ DBG_ASSERT( a.Ref1.nTab == a.Ref2.nTab,
+ "+_ScRangeListTabs::Append(): 3D-Ranges werden in SC nicht unterstuetzt!" );
+ }
+
+ if( nTab == SCTAB_MAX)
+ return;
+
+ if( nTab < -1)
+ nTab = a.Ref1.nTab;
+
+ if (nTab < 0 || MAXTAB < nTab)
+ return;
+
+ TabRangeType::iterator itr = maTabRanges.find(nTab);
+ if (itr == maTabRanges.end())
+ {
+ // No entry for this table yet. Insert a new one.
+ std::pair<TabRangeType::iterator, bool> r =
+ maTabRanges.insert(nTab, new RangeListType);
+
+ if (!r.second)
+ // Insertion failed.
+ return;
+
+ itr = r.first;
+ }
+ itr->second->push_back(
+ ScRange(a.Ref1.nCol,a.Ref1.nRow,a.Ref1.nTab,
+ a.Ref2.nCol,a.Ref2.nRow,a.Ref2.nTab));
+}
+
+const ScRange* _ScRangeListTabs::First( SCTAB n )
+{
+ DBG_ASSERT( ValidTab(n), "-_ScRangeListTabs::First(): Und tschuessssssss!" );
+
+ TabRangeType::iterator itr = maTabRanges.find(n);
+ if (itr == maTabRanges.end())
+ // No range list exists for this table.
+ return NULL;
+
+ const RangeListType& rList = *itr->second;
+ maItrCur = rList.begin();
+ maItrCurEnd = rList.end();
+ return rList.empty() ? NULL : &(*maItrCur);
+}
+
+const ScRange* _ScRangeListTabs::Next ()
+{
+ ++maItrCur;
+ if (maItrCur == maItrCurEnd)
+ return NULL;
+
+ return &(*maItrCur);
+}
+
+ConverterBase::ConverterBase( sal_uInt16 nNewBuffer ) :
+ aEingPos( 0, 0, 0 ),
+ eStatus( ConvOK ),
+ nBufferSize( nNewBuffer )
+{
+ DBG_ASSERT( nNewBuffer > 0, "ConverterBase::ConverterBase - nNewBuffer == 0!" );
+ pBuffer = new sal_Char[ nNewBuffer ];
+}
+
+ConverterBase::~ConverterBase()
+{
+ delete[] pBuffer;
+}
+
+void ConverterBase::Reset()
+{
+ eStatus = ConvOK;
+ aPool.Reset();
+ aStack.Reset();
+}
+
+
+
+
+ExcelConverterBase::ExcelConverterBase( sal_uInt16 nNewBuffer ) :
+ ConverterBase( nNewBuffer )
+{
+}
+
+ExcelConverterBase::~ExcelConverterBase()
+{
+}
+
+void ExcelConverterBase::Reset( const ScAddress& rEingPos )
+{
+ ConverterBase::Reset();
+ aEingPos = rEingPos;
+}
+
+void ExcelConverterBase::Reset()
+{
+ ConverterBase::Reset();
+ aEingPos.Set( 0, 0, 0 );
+}
+
+
+
+
+LotusConverterBase::LotusConverterBase( SvStream &rStr, sal_uInt16 nNewBuffer ) :
+ ConverterBase( nNewBuffer ),
+ aIn( rStr ),
+ nBytesLeft( 0 )
+{
+}
+
+LotusConverterBase::~LotusConverterBase()
+{
+}
+
+void LotusConverterBase::Reset( const ScAddress& rEingPos )
+{
+ ConverterBase::Reset();
+ nBytesLeft = 0;
+ aEingPos = rEingPos;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/impop.cxx b/sc/source/filter/excel/impop.cxx
new file mode 100644
index 000000000000..9ad703da3b0e
--- /dev/null
+++ b/sc/source/filter/excel/impop.cxx
@@ -0,0 +1,1336 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "imp_op.hxx"
+
+#include <filter/msfilter/countryid.hxx>
+
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <editeng/editdata.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/colritem.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/docfile.hxx>
+#include <svl/zforlist.hxx>
+
+#include <sfx2/objsh.hxx>
+#include "tools/urlobj.hxx"
+#include "docuno.hxx"
+
+#include "cell.hxx"
+#include "document.hxx"
+#include "rangenam.hxx"
+#include "compiler.hxx"
+#include "patattr.hxx"
+#include "attrib.hxx"
+#include "globstr.hrc"
+#include "global.hxx"
+#include "markdata.hxx"
+#include "olinetab.hxx"
+#include "stlsheet.hxx"
+#include "stlpool.hxx"
+#include "compiler.hxx"
+#include "viewopti.hxx"
+#include "docoptio.hxx"
+#include "scextopt.hxx"
+#include "editutil.hxx"
+#include "filtopt.hxx"
+#include "scerrors.hxx"
+#include "unonames.hxx"
+#include "paramisc.hxx"
+#include "postit.hxx"
+
+#include "fapihelper.hxx"
+#include "xltools.hxx"
+#include "xltable.hxx"
+#include "xlview.hxx"
+#include "xltracer.hxx"
+#include "xihelper.hxx"
+#include "xipage.hxx"
+#include "xiview.hxx"
+#include "xilink.hxx"
+#include "xiescher.hxx"
+#include "xicontent.hxx"
+
+#include "excimp8.hxx"
+#include "excform.hxx"
+
+#if defined( WNT )
+#include <math.h>
+#else
+#include <stdlib.h>
+#endif
+
+using namespace ::com::sun::star;
+
+
+const double ImportExcel::fExcToTwips =
+ ( double ) TWIPS_PER_CHAR / 256.0;
+
+
+ImportTyp::ImportTyp( ScDocument* pDoc, CharSet eQ )
+{
+ eQuellChar = eQ;
+ pD = pDoc;
+}
+
+
+ImportTyp::~ImportTyp()
+{
+}
+
+
+FltError ImportTyp::Read()
+{
+ return eERR_INTERN;
+}
+
+
+ImportExcel::ImportExcel( XclImpRootData& rImpData, SvStream& rStrm ):
+ ImportTyp( &rImpData.mrDoc, rImpData.meTextEnc ),
+ XclImpRoot( rImpData ),
+ maStrm( rStrm, GetRoot() ),
+ aIn( maStrm ),
+ maScOleSize( ScAddress::INITIALIZE_INVALID )
+{
+ mnLastRefIdx = 0;
+ nBdshtTab = 0;
+ nIxfeIndex = 0; // zur Sicherheit auf 0
+
+ // Root-Daten fuellen - nach new's ohne Root als Parameter
+ pExcRoot = &GetOldRoot();
+ pExcRoot->pIR = this; // ExcRoot -> XclImpRoot
+ pExcRoot->eDateiTyp = BiffX;
+ pExcRoot->pExtSheetBuff = new ExtSheetBuffer( pExcRoot ); //&aExtSheetBuff;
+ pExcRoot->pShrfmlaBuff = new ShrfmlaBuffer( pExcRoot ); //&aShrfrmlaBuff;
+ pExcRoot->pExtNameBuff = new ExtNameBuff ( *this );
+
+ pExtNameBuff = new NameBuffer( pExcRoot ); //prevent empty rootdata
+ pExtNameBuff->SetBase( 1 );
+
+ pOutlineListBuffer = new XclImpOutlineListBuffer( );
+
+ // ab Biff8
+ pFormConv = pExcRoot->pFmlaConverter = new ExcelToSc( GetRoot() );
+
+ bTabTruncated = false;
+
+ // Excel-Dokument per Default auf 31.12.1899, entspricht Excel-Einstellungen mit 1.1.1900
+ ScDocOptions aOpt = pD->GetDocOptions();
+ aOpt.SetDate( 30, 12, 1899 );
+ pD->SetDocOptions( aOpt );
+ pD->GetFormatTable()->ChangeNullDate( 30, 12, 1899 );
+
+ ScDocOptions aDocOpt( pD->GetDocOptions() );
+ aDocOpt.SetIgnoreCase( sal_True ); // always in Excel
+ aDocOpt.SetFormulaRegexEnabled( false ); // regular expressions? what's that?
+ aDocOpt.SetLookUpColRowNames( false ); // default: no natural language refs
+ pD->SetDocOptions( aDocOpt );
+}
+
+
+ImportExcel::~ImportExcel( void )
+{
+ GetDoc().SetSrcCharSet( GetTextEncoding() );
+
+ delete pExtNameBuff;
+
+ delete pOutlineListBuffer;
+
+ delete pFormConv;
+}
+
+
+void ImportExcel::ReadFileSharing()
+{
+ sal_uInt16 nRecommendReadOnly, nPasswordHash;
+ maStrm >> nRecommendReadOnly >> nPasswordHash;
+
+ if( (nRecommendReadOnly != 0) || (nPasswordHash != 0) )
+ {
+ if( SfxItemSet* pItemSet = GetMedium().GetItemSet() )
+ pItemSet->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) );
+
+ if( SfxObjectShell* pShell = GetDocShell() )
+ {
+ if( nRecommendReadOnly != 0 )
+ pShell->SetLoadReadonly( sal_True );
+ if( nPasswordHash != 0 )
+ pShell->SetModifyPasswordHash( nPasswordHash );
+ }
+ }
+}
+
+sal_uInt16 ImportExcel::ReadXFIndex( bool bBiff2 )
+{
+ sal_uInt16 nXFIdx = 0;
+ if( bBiff2 )
+ {
+ sal_uInt8 nXFIdx2;
+ maStrm >> nXFIdx2;
+ maStrm.Ignore( 2 );
+ nXFIdx = nXFIdx2 & 0x3F;
+ if( nXFIdx == 63 )
+ nXFIdx = nIxfeIndex;
+ }
+ else
+ aIn >> nXFIdx;
+ return nXFIdx;
+}
+
+void ImportExcel::ReadDimensions()
+{
+ XclRange aXclUsedArea( ScAddress::UNINITIALIZED );
+ if( (maStrm.GetRecId() == EXC_ID2_DIMENSIONS) || (GetBiff() <= EXC_BIFF5) )
+ {
+ maStrm >> aXclUsedArea;
+ if( (aXclUsedArea.GetColCount() > 1) && (aXclUsedArea.GetRowCount() > 1) )
+ {
+ // Excel stores first unused row/column index
+ --aXclUsedArea.maLast.mnCol;
+ --aXclUsedArea.maLast.mnRow;
+ // create the Calc range
+ SCTAB nScTab = GetCurrScTab();
+ ScRange& rScUsedArea = GetExtDocOptions().GetOrCreateTabSettings( nScTab ).maUsedArea;
+ GetAddressConverter().ConvertRange( rScUsedArea, aXclUsedArea, nScTab, nScTab, false );
+ // if any error occurs in ConvertRange(), rScUsedArea keeps untouched
+ }
+ }
+ else
+ {
+ sal_uInt32 nXclRow1, nXclRow2;
+ maStrm >> nXclRow1 >> nXclRow2 >> aXclUsedArea.maFirst.mnCol >> aXclUsedArea.maLast.mnCol;
+ if( (nXclRow1 < nXclRow2) && (aXclUsedArea.GetColCount() > 1) &&
+ (nXclRow1 <= static_cast< sal_uInt32 >( GetScMaxPos().Row() )) )
+ {
+ // Excel stores first unused row/column index
+ --nXclRow2;
+ --aXclUsedArea.maLast.mnCol;
+ // convert row indexes to 16-bit values
+ aXclUsedArea.maFirst.mnRow = static_cast< sal_uInt16 >( nXclRow1 );
+ aXclUsedArea.maLast.mnRow = limit_cast< sal_uInt16 >( nXclRow2, aXclUsedArea.maFirst.mnRow, SAL_MAX_UINT16 );
+ // create the Calc range
+ SCTAB nScTab = GetCurrScTab();
+ ScRange& rScUsedArea = GetExtDocOptions().GetOrCreateTabSettings( nScTab ).maUsedArea;
+ GetAddressConverter().ConvertRange( rScUsedArea, aXclUsedArea, nScTab, nScTab, false );
+ // if any error occurs in ConvertRange(), rScUsedArea keeps untouched
+ }
+ }
+}
+
+void ImportExcel::ReadBlank()
+{
+ XclAddress aXclPos;
+ aIn >> aXclPos;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
+ {
+ sal_uInt16 nXFIdx = ReadXFIndex( maStrm.GetRecId() == EXC_ID2_BLANK );
+
+ GetXFRangeBuffer().SetBlankXF( aScPos, nXFIdx );
+ }
+}
+
+void ImportExcel::ReadInteger()
+{
+ XclAddress aXclPos;
+ maStrm >> aXclPos;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
+ {
+ sal_uInt16 nXFIdx = ReadXFIndex( true );
+ sal_uInt16 nValue;
+ maStrm >> nValue;
+
+ GetXFRangeBuffer().SetXF( aScPos, nXFIdx );
+ GetDoc().PutCell( aScPos, new ScValueCell( nValue ) );
+ }
+}
+
+void ImportExcel::ReadNumber()
+{
+ XclAddress aXclPos;
+ maStrm >> aXclPos;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
+ {
+ sal_uInt16 nXFIdx = ReadXFIndex( maStrm.GetRecId() == EXC_ID2_NUMBER );
+ double fValue;
+ maStrm >> fValue;
+
+ GetXFRangeBuffer().SetXF( aScPos, nXFIdx );
+ GetDoc().PutCell( aScPos, new ScValueCell( fValue ) );
+ }
+}
+
+void ImportExcel::ReadLabel()
+{
+ XclAddress aXclPos;
+ maStrm >> aXclPos;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
+ {
+ /* Record ID BIFF XF type String type
+ 0x0004 2-7 3 byte 8-bit length, byte string
+ 0x0004 8 3 byte 16-bit length, unicode string
+ 0x0204 2-7 2 byte 16-bit length, byte string
+ 0x0204 8 2 byte 16-bit length, unicode string */
+ bool bBiff2 = maStrm.GetRecId() == EXC_ID2_LABEL;
+ sal_uInt16 nXFIdx = ReadXFIndex( bBiff2 );
+ XclStrFlags nFlags = (bBiff2 && (GetBiff() <= EXC_BIFF5)) ? EXC_STR_8BITLENGTH : EXC_STR_DEFAULT;
+ XclImpString aString;
+
+ // #i63105# use text encoding from FONT record
+ rtl_TextEncoding eOldTextEnc = GetTextEncoding();
+ if( const XclImpFont* pFont = GetXFBuffer().GetFont( nXFIdx ) )
+ SetTextEncoding( pFont->GetFontEncoding() );
+ aString.Read( maStrm, nFlags );
+ SetTextEncoding( eOldTextEnc );
+
+ GetXFRangeBuffer().SetXF( aScPos, nXFIdx );
+ if( ScBaseCell* pCell = XclImpStringHelper::CreateCell( GetRoot(), aString, nXFIdx ) )
+ GetDoc().PutCell( aScPos, pCell );
+ }
+}
+
+void ImportExcel::ReadBoolErr()
+{
+ XclAddress aXclPos;
+ maStrm >> aXclPos;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
+ {
+ sal_uInt16 nXFIdx = ReadXFIndex( maStrm.GetRecId() == EXC_ID2_BOOLERR );
+ sal_uInt8 nValue, nType;
+ maStrm >> nValue >> nType;
+
+ if( nType == EXC_BOOLERR_BOOL )
+ GetXFRangeBuffer().SetBoolXF( aScPos, nXFIdx );
+ else
+ GetXFRangeBuffer().SetXF( aScPos, nXFIdx );
+
+ double fValue;
+ const ScTokenArray* pScTokArr = ErrorToFormula( nType, nValue, fValue );
+ ScFormulaCell* pCell = new ScFormulaCell( pD, aScPos, pScTokArr );
+ pCell->SetHybridDouble( fValue );
+ GetDoc().PutCell( aScPos, pCell );
+ }
+}
+
+void ImportExcel::ReadRk()
+{
+ XclAddress aXclPos;
+ maStrm >> aXclPos;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
+ {
+ sal_uInt16 nXFIdx = ReadXFIndex( false );
+ sal_Int32 nRk;
+ maStrm >> nRk;
+
+ GetXFRangeBuffer().SetXF( aScPos, nXFIdx );
+ GetDoc().PutCell( aScPos, new ScValueCell( XclTools::GetDoubleFromRK( nRk ) ) );
+ }
+}
+
+
+void ImportExcel::Window1()
+{
+ GetDocViewSettings().ReadWindow1( maStrm );
+}
+
+
+
+
+void ImportExcel::Row25( void )
+{
+ sal_uInt16 nRow, nRowHeight;
+
+ aIn >> nRow;
+ aIn.Ignore( 4 ); // Mic und Mac ueberspringen
+
+ if( ValidRow( nRow ) )
+ {
+ aIn >> nRowHeight; // direkt in Twips angegeben
+ aIn.Ignore( 2 );
+
+ if( GetBiff() == EXC_BIFF2 )
+ {// -------------------- BIFF2
+ pColRowBuff->SetHeight( nRow, nRowHeight );
+ }
+ else
+ {// -------------------- BIFF5
+ sal_uInt16 nGrbit;
+
+ aIn.Ignore( 2 ); // reserved
+ aIn >> nGrbit;
+
+ sal_uInt8 nLevel = ::extract_value< sal_uInt8 >( nGrbit, 0, 3 );
+ pRowOutlineBuff->SetLevel( nRow, nLevel, ::get_flag( nGrbit, EXC_ROW_COLLAPSED ) );
+ pColRowBuff->SetRowSettings( nRow, nRowHeight, nGrbit );
+ }
+ }
+}
+
+
+void ImportExcel::Bof2( void )
+{
+ sal_uInt16 nSubType;
+ maStrm.DisableDecryption();
+ maStrm.Ignore( 2 );
+ maStrm >> nSubType;
+
+ if( nSubType == 0x0020 ) // Chart
+ pExcRoot->eDateiTyp = Biff2C;
+ else if( nSubType == 0x0040 ) // Macro
+ pExcRoot->eDateiTyp = Biff2M;
+ else // #i51490# Excel interprets invalid indexes as worksheet
+ pExcRoot->eDateiTyp = Biff2;
+}
+
+
+void ImportExcel::Eof( void )
+{
+ // POST: darf nur nach einer GUELTIGEN Tabelle gerufen werden!
+ EndSheet();
+ IncCurrScTab();
+}
+
+
+void ImportExcel::SheetPassword( void )
+{
+ if (GetRoot().GetBiff() != EXC_BIFF8)
+ return;
+
+ GetRoot().GetSheetProtectBuffer().ReadPasswordHash( aIn, GetCurrScTab() );
+}
+
+
+void ImportExcel::Externsheet( void )
+{
+ String aUrl, aTabName;
+ bool bSameWorkBook;
+ String aEncodedUrl( aIn.ReadByteString( false ) );
+ XclImpUrlHelper::DecodeUrl( aUrl, aTabName, bSameWorkBook, *pExcRoot->pIR, aEncodedUrl );
+ mnLastRefIdx = pExcRoot->pExtSheetBuff->Add( aUrl, aTabName, bSameWorkBook );
+}
+
+
+void ImportExcel:: WinProtection( void )
+{
+ if (GetRoot().GetBiff() != EXC_BIFF8)
+ return;
+
+ GetRoot().GetDocProtectBuffer().ReadWinProtect( aIn );
+}
+
+
+void ImportExcel::Columndefault( void )
+{// Default Cell Attributes
+ sal_uInt16 nColMic, nColMac;
+ sal_uInt8 nOpt0;
+
+ aIn >> nColMic >> nColMac;
+
+ DBG_ASSERT( aIn.GetRecLeft() == (sal_Size)(nColMac - nColMic) * 3 + 2,
+ "ImportExcel::Columndefault - wrong record size" );
+
+ nColMac--;
+
+ if( nColMac > MAXCOL )
+ nColMac = static_cast<sal_uInt16>(MAXCOL);
+
+ for( sal_uInt16 nCol = nColMic ; nCol <= nColMac ; nCol++ )
+ {
+ aIn >> nOpt0;
+ aIn.Ignore( 2 ); // nur 0. Attribut-Byte benutzt
+
+ if( nOpt0 & 0x80 ) // Col hidden?
+ pColRowBuff->HideCol( nCol );
+ }
+}
+
+
+void ImportExcel::Array25( void )
+{
+ sal_uInt16 nFirstRow, nLastRow, nFormLen;
+ sal_uInt8 nFirstCol, nLastCol;
+
+ aIn >> nFirstRow >> nLastRow >> nFirstCol >> nLastCol;
+
+ if( GetBiff() == EXC_BIFF2 )
+ {// BIFF2
+ aIn.Ignore( 1 );
+ nFormLen = aIn.ReaduInt8();
+ }
+ else
+ {// BIFF5
+ aIn.Ignore( 6 );
+ aIn >> nFormLen;
+ }
+
+ if( ValidColRow( nLastCol, nLastRow ) )
+ {
+ // jetzt steht Lesemarke auf Formel, Laenge in nFormLen
+ const ScTokenArray* pErgebnis;
+
+ pFormConv->Reset( ScAddress( static_cast<SCCOL>(nFirstCol),
+ static_cast<SCROW>(nFirstRow), GetCurrScTab() ) );
+ pFormConv->Convert( pErgebnis, maStrm, nFormLen, true, FT_CellFormula);
+
+ DBG_ASSERT( pErgebnis, "*ImportExcel::Array25(): ScTokenArray ist NULL!" );
+
+ ScMarkData aMarkData;
+ aMarkData.SelectOneTable( GetCurrScTab() );
+ pD->InsertMatrixFormula( static_cast<SCCOL>(nFirstCol),
+ static_cast<SCROW>(nFirstRow), static_cast<SCCOL>(nLastCol),
+ static_cast<SCROW>(nLastRow), aMarkData, EMPTY_STRING,
+ pErgebnis );
+ }
+}
+
+
+void ImportExcel::Rec1904( void )
+{
+ sal_uInt16 n1904;
+
+ aIn >> n1904;
+
+ if( n1904 )
+ {// 1904 date system
+ ScDocOptions aOpt = pD->GetDocOptions();
+ aOpt.SetDate( 1, 1, 1904 );
+ pD->SetDocOptions( aOpt );
+ pD->GetFormatTable()->ChangeNullDate( 1, 1, 1904 );
+ }
+}
+
+
+void ImportExcel::Externname25( void )
+{
+ sal_uInt32 nRes;
+ sal_uInt16 nOpt;
+
+ aIn >> nOpt >> nRes;
+
+ String aName( aIn.ReadByteString( false ) );
+
+ if( ( nOpt & 0x0001 ) || ( ( nOpt & 0xFFFE ) == 0x0000 ) )
+ {// external name
+ ScfTools::ConvertToScDefinedName( aName );
+ pExcRoot->pExtNameBuff->AddName( aName, mnLastRefIdx );
+ }
+ else if( nOpt & 0x0010 )
+ {// ole link
+ pExcRoot->pExtNameBuff->AddOLE( aName, mnLastRefIdx, nRes ); // nRes is storage ID
+ }
+ else
+ {// dde link
+ pExcRoot->pExtNameBuff->AddDDE( aName, mnLastRefIdx );
+ }
+}
+
+
+void ImportExcel::Colwidth( void )
+{// Column Width
+ sal_uInt8 nColFirst, nColLast;
+ sal_uInt16 nColWidth;
+
+ aIn >> nColFirst >> nColLast >> nColWidth;
+
+//! TODO: add a check for the unlikely case of changed MAXCOL (-> XclImpAddressConverter)
+// if( nColLast > MAXCOL )
+// nColLast = static_cast<sal_uInt16>(MAXCOL);
+
+ sal_uInt16 nScWidth = XclTools::GetScColumnWidth( nColWidth, GetCharWidth() );
+ pColRowBuff->SetWidthRange( nColFirst, nColLast, nScWidth );
+}
+
+
+void ImportExcel::Defrowheight2( void )
+{
+ sal_uInt16 nDefHeight;
+ maStrm >> nDefHeight;
+ nDefHeight &= 0x7FFF;
+ pColRowBuff->SetDefHeight( nDefHeight, EXC_DEFROW_UNSYNCED );
+}
+
+
+void ImportExcel::SheetProtect( void )
+{
+ if (GetRoot().GetBiff() != EXC_BIFF8)
+ return;
+
+ GetRoot().GetSheetProtectBuffer().ReadProtect( aIn, GetCurrScTab() );
+}
+
+void ImportExcel::DocProtect( void )
+{
+ if (GetRoot().GetBiff() != EXC_BIFF8)
+ return;
+
+ GetRoot().GetDocProtectBuffer().ReadDocProtect( aIn );
+}
+
+void ImportExcel::DocPasssword( void )
+{
+ if (GetRoot().GetBiff() != EXC_BIFF8)
+ return;
+
+ GetRoot().GetDocProtectBuffer().ReadPasswordHash( aIn );
+}
+
+void ImportExcel::Codepage( void )
+{
+ SetCodePage( maStrm.ReaduInt16() );
+}
+
+
+void ImportExcel::Ixfe( void )
+{
+ aIn >> nIxfeIndex;
+}
+
+
+void ImportExcel::DefColWidth( void )
+{
+ // stored as entire characters -> convert to 1/256 of characters (as in COLINFO)
+ double fDefWidth = 256.0 * maStrm.ReaduInt16();
+
+ // #i3006# additional space for default width - Excel adds space depending on font size
+ long nFontHt = GetFontBuffer().GetAppFontData().mnHeight;
+ fDefWidth += XclTools::GetXclDefColWidthCorrection( nFontHt );
+
+ sal_uInt16 nScWidth = XclTools::GetScColumnWidth( limit_cast< sal_uInt16 >( fDefWidth ), GetCharWidth() );
+ pColRowBuff->SetDefWidth( nScWidth );
+}
+
+
+void ImportExcel::Builtinfmtcnt( void )
+{
+}
+
+
+void ImportExcel::Colinfo( void )
+{// Column Formatting Information
+ sal_uInt16 nColFirst, nColLast, nColWidth, nXF;
+ sal_uInt16 nOpt;
+
+ aIn >> nColFirst >> nColLast >> nColWidth >> nXF >> nOpt;
+
+ if( nColFirst > MAXCOL )
+ return;
+
+ if( nColLast > MAXCOL )
+ nColLast = static_cast<sal_uInt16>(MAXCOL);
+
+ bool bHidden = ::get_flag( nOpt, EXC_COLINFO_HIDDEN );
+ bool bCollapsed = ::get_flag( nOpt, EXC_COLINFO_COLLAPSED );
+ sal_uInt8 nLevel = ::extract_value< sal_uInt8 >( nOpt, 8, 3 );
+ pColOutlineBuff->SetLevelRange( nColFirst, nColLast, nLevel, bCollapsed );
+
+ if( bHidden )
+ pColRowBuff->HideColRange( nColFirst, nColLast );
+
+ sal_uInt16 nScWidth = XclTools::GetScColumnWidth( nColWidth, GetCharWidth() );
+ pColRowBuff->SetWidthRange( nColFirst, nColLast, nScWidth );
+ pColRowBuff->SetDefaultXF( nColFirst, nColLast, nXF );
+}
+
+
+void ImportExcel::Wsbool( void )
+{
+ sal_uInt16 nFlags;
+ aIn >> nFlags;
+
+ pRowOutlineBuff->SetButtonMode( ::get_flag( nFlags, EXC_WSBOOL_ROWBELOW ) );
+ pColOutlineBuff->SetButtonMode( ::get_flag( nFlags, EXC_WSBOOL_COLBELOW ) );
+
+ GetPageSettings().SetFitToPages( ::get_flag( nFlags, EXC_WSBOOL_FITTOPAGE ) );
+}
+
+
+void ImportExcel::Boundsheet( void )
+{
+ sal_uInt16 nGrbit = 0;
+
+ if( GetBiff() == EXC_BIFF5 )
+ {
+ aIn.DisableDecryption();
+ maSheetOffsets.push_back( aIn.ReaduInt32() );
+ aIn.EnableDecryption();
+ aIn >> nGrbit;
+ }
+
+ String aName( aIn.ReadByteString( false ) );
+
+ SCTAB nScTab = static_cast< SCTAB >( nBdshtTab );
+ if( nScTab > 0 )
+ {
+ DBG_ASSERT( !pD->HasTable( nScTab ), "ImportExcel::Boundsheet - sheet exists already" );
+ pD->MakeTable( nScTab );
+ }
+
+ if( ( nGrbit & 0x0001 ) || ( nGrbit & 0x0002 ) )
+ pD->SetVisible( nScTab, false );
+
+ if( !pD->RenameTab( nScTab, aName ) )
+ {
+ pD->CreateValidTabName( aName );
+ pD->RenameTab( nScTab, aName );
+ }
+
+ nBdshtTab++;
+}
+
+
+void ImportExcel::Country( void )
+{
+ sal_uInt16 nUICountry, nDocCountry;
+ maStrm >> nUICountry >> nDocCountry;
+
+ // Store system language in XclRoot
+ LanguageType eLanguage = ::msfilter::ConvertCountryToLanguage( static_cast< ::msfilter::CountryId >( nDocCountry ) );
+ if( eLanguage != LANGUAGE_DONTKNOW )
+ SetDocLanguage( eLanguage );
+
+ // Set Excel UI language in add-in name translator
+ eLanguage = ::msfilter::ConvertCountryToLanguage( static_cast< ::msfilter::CountryId >( nUICountry ) );
+ if( eLanguage != LANGUAGE_DONTKNOW )
+ SetUILanguage( eLanguage );
+}
+
+
+void ImportExcel::ReadUsesElfs()
+{
+ if( maStrm.ReaduInt16() != 0 )
+ {
+ ScDocOptions aDocOpt = GetDoc().GetDocOptions();
+ aDocOpt.SetLookUpColRowNames( sal_True );
+ GetDoc().SetDocOptions( aDocOpt );
+ }
+}
+
+
+void ImportExcel::Hideobj( void )
+{
+ sal_uInt16 nHide;
+ ScVObjMode eOle, eChart, eDraw;
+
+ aIn >> nHide;
+
+ ScViewOptions aOpts( pD->GetViewOptions() );
+
+ switch( nHide )
+ {
+ case 1: // Placeholders
+ eOle = VOBJ_MODE_SHOW; // in Excel 97 werden nur Charts als Platzhalter angezeigt
+ eChart = VOBJ_MODE_SHOW; //#i80528# VOBJ_MODE_DUMMY replaced by VOBJ_MODE_SHOW now
+ eDraw = VOBJ_MODE_SHOW;
+ break;
+ case 2: // Hide all
+ eOle = VOBJ_MODE_HIDE;
+ eChart = VOBJ_MODE_HIDE;
+ eDraw = VOBJ_MODE_HIDE;
+ break;
+ default: // Show all
+ eOle = VOBJ_MODE_SHOW;
+ eChart = VOBJ_MODE_SHOW;
+ eDraw = VOBJ_MODE_SHOW;
+ break;
+ }
+
+ aOpts.SetObjMode( VOBJ_TYPE_OLE, eOle );
+ aOpts.SetObjMode( VOBJ_TYPE_CHART, eChart );
+ aOpts.SetObjMode( VOBJ_TYPE_DRAW, eDraw );
+
+ pD->SetViewOptions( aOpts );
+}
+
+
+void ImportExcel::Bundleheader( void )
+{
+}
+
+
+void ImportExcel::Standardwidth( void )
+{
+ sal_uInt16 nScWidth = XclTools::GetScColumnWidth( maStrm.ReaduInt16(), GetCharWidth() );
+ pColRowBuff->SetDefWidth( nScWidth, sal_True );
+}
+
+
+void ImportExcel::Shrfmla( void )
+{
+ sal_uInt16 nFirstRow, nLastRow, nLenExpr;
+ sal_uInt8 nFirstCol, nLastCol;
+
+ aIn >> nFirstRow >> nLastRow >> nFirstCol >> nLastCol;
+ aIn.Ignore( 2 );
+ aIn >> nLenExpr;
+
+ // jetzt steht Lesemarke an der Formel
+
+ const ScTokenArray* pErgebnis;
+
+ pFormConv->Reset();
+ pFormConv->Convert( pErgebnis, maStrm, nLenExpr, true, FT_SharedFormula );
+
+
+ DBG_ASSERT( pErgebnis, "+ImportExcel::Shrfmla(): ScTokenArray ist NULL!" );
+
+ pExcRoot->pShrfmlaBuff->Store( ScRange( static_cast<SCCOL>(nFirstCol),
+ static_cast<SCROW>(nFirstRow), GetCurrScTab(),
+ static_cast<SCCOL>(nLastCol), static_cast<SCROW>(nLastRow),
+ GetCurrScTab()), *pErgebnis );
+}
+
+
+void ImportExcel::Mulrk( void )
+{
+ XclAddress aXclPos;
+ sal_uInt16 nXF;
+ sal_Int32 nRkNum;
+
+ aIn >> aXclPos;
+
+ for( XclAddress aCurrXclPos( aXclPos ); (aXclPos.mnCol <= aCurrXclPos.mnCol) && (aIn.GetRecLeft() > 2); ++aCurrXclPos.mnCol )
+ {
+ aIn >> nXF >> nRkNum;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aCurrXclPos, GetCurrScTab(), true ) )
+ {
+ GetXFRangeBuffer().SetXF( aScPos, nXF );
+ GetDoc().PutCell( aScPos, new ScValueCell( XclTools::GetDoubleFromRK( nRkNum ) ) );
+ }
+ }
+}
+
+
+void ImportExcel::Mulblank( void )
+{
+ XclAddress aXclPos;
+ sal_uInt16 nXF;
+
+ aIn >> aXclPos;
+
+ for( XclAddress aCurrXclPos( aXclPos ); (aXclPos.mnCol <= aCurrXclPos.mnCol) && (aIn.GetRecLeft() > 2); ++aCurrXclPos.mnCol )
+ {
+ aIn >> nXF;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aCurrXclPos, GetCurrScTab(), true ) )
+ GetXFRangeBuffer().SetBlankXF( aScPos, nXF );
+ }
+}
+
+
+void ImportExcel::Rstring( void )
+{
+ XclAddress aXclPos;
+ sal_uInt16 nXFIdx;
+ aIn >> aXclPos >> nXFIdx;
+
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
+ {
+ // unformatted Unicode string with separate formatting information
+ XclImpString aString;
+
+ // #i63105# use text encoding from FONT record
+ rtl_TextEncoding eOldTextEnc = GetTextEncoding();
+ if( const XclImpFont* pFont = GetXFBuffer().GetFont( nXFIdx ) )
+ SetTextEncoding( pFont->GetFontEncoding() );
+ aString.Read( maStrm );
+ SetTextEncoding( eOldTextEnc );
+
+ // character formatting runs
+ if( !aString.IsRich() )
+ aString.ReadFormats( maStrm );
+
+ GetXFRangeBuffer().SetXF( aScPos, nXFIdx );
+ if( ScBaseCell* pCell = XclImpStringHelper::CreateCell( *this, aString, nXFIdx ) )
+ GetDoc().PutCell( aScPos, pCell );
+ }
+}
+
+
+void ImportExcel::Cellmerging()
+{
+ XclImpAddressConverter& rAddrConv = GetAddressConverter();
+ SCTAB nScTab = GetCurrScTab();
+
+ sal_uInt16 nCount;
+ maStrm >> nCount;
+ for( sal_uInt16 nIdx = 0; (nIdx < nCount) && (maStrm.GetRecLeft() >= 8); ++nIdx )
+ {
+ XclRange aXclRange;
+ maStrm >> aXclRange; // 16-bit rows and columns
+ ScRange aScRange( ScAddress::UNINITIALIZED );
+ if( rAddrConv.ConvertRange( aScRange, aXclRange, nScTab, nScTab, true ) )
+ GetXFRangeBuffer().SetMerge( aScRange.aStart.Col(), aScRange.aStart.Row(), aScRange.aEnd.Col(), aScRange.aEnd.Row() );
+ }
+}
+
+
+void ImportExcel::Olesize( void )
+{
+ XclRange aXclOleSize( ScAddress::UNINITIALIZED );
+ maStrm.Ignore( 2 );
+ aXclOleSize.Read( maStrm, false );
+
+ SCTAB nScTab = GetCurrScTab();
+ GetAddressConverter().ConvertRange( maScOleSize, aXclOleSize, nScTab, nScTab, false );
+}
+
+
+void ImportExcel::Row34( void )
+{
+ sal_uInt16 nRow, nRowHeight, nGrbit, nXF;
+
+ aIn >> nRow;
+ aIn.Ignore( 4 ); // Mic und Mac ueberspringen
+
+ SCROW nScRow = static_cast< SCROW >( nRow );
+
+ if( ValidRow( nScRow ) )
+ {
+ aIn >> nRowHeight; // direkt in Twips angegeben
+ aIn.Ignore( 4 );
+
+ aIn >> nGrbit >> nXF;
+
+ sal_uInt8 nLevel = ::extract_value< sal_uInt8 >( nGrbit, 0, 3 );
+ pRowOutlineBuff->SetLevel( nScRow, nLevel, ::get_flag( nGrbit, EXC_ROW_COLLAPSED ) );
+ pColRowBuff->SetRowSettings( nScRow, nRowHeight, nGrbit );
+
+ if( nGrbit & EXC_ROW_USEDEFXF )
+ GetXFRangeBuffer().SetRowDefXF( nScRow, nXF & EXC_ROW_XFMASK );
+ }
+}
+
+
+void ImportExcel::Bof3( void )
+{
+ sal_uInt16 nSubType;
+ maStrm.DisableDecryption();
+ maStrm.Ignore( 2 );
+ maStrm >> nSubType;
+
+ DBG_ASSERT( nSubType != 0x0100, "*ImportExcel::Bof3(): Biff3 als Workbook?!" );
+ if( nSubType == 0x0100 ) // Book
+ pExcRoot->eDateiTyp = Biff3W;
+ else if( nSubType == 0x0020 ) // Chart
+ pExcRoot->eDateiTyp = Biff3C;
+ else if( nSubType == 0x0040 ) // Macro
+ pExcRoot->eDateiTyp = Biff3M;
+ else // #i51490# Excel interprets invalid indexes as worksheet
+ pExcRoot->eDateiTyp = Biff3;
+}
+
+
+void ImportExcel::Array34( void )
+{
+ sal_uInt16 nFirstRow, nLastRow, nFormLen;
+ sal_uInt8 nFirstCol, nLastCol;
+
+ aIn >> nFirstRow >> nLastRow >> nFirstCol >> nLastCol;
+ aIn.Ignore( (GetBiff() >= EXC_BIFF5) ? 6 : 2 );
+ aIn >> nFormLen;
+
+ if( ValidColRow( nLastCol, nLastRow ) )
+ {
+ // jetzt steht Lesemarke auf Formel, Laenge in nFormLen
+ const ScTokenArray* pErgebnis;
+
+ pFormConv->Reset( ScAddress( static_cast<SCCOL>(nFirstCol),
+ static_cast<SCROW>(nFirstRow), GetCurrScTab() ) );
+ pFormConv->Convert( pErgebnis, maStrm, nFormLen, true, FT_CellFormula);
+
+ DBG_ASSERT( pErgebnis, "+ImportExcel::Array34(): ScTokenArray ist NULL!" );
+
+ ScMarkData aMarkData;
+ aMarkData.SelectOneTable( GetCurrScTab() );
+ pD->InsertMatrixFormula( static_cast<SCCOL>(nFirstCol),
+ static_cast<SCROW>(nFirstRow), static_cast<SCCOL>(nLastCol),
+ static_cast<SCROW>(nLastRow), aMarkData, EMPTY_STRING,
+ pErgebnis);
+ }
+}
+
+
+void ImportExcel::Externname34( void )
+{
+}
+
+
+void ImportExcel::Defrowheight345( void )
+{
+ sal_uInt16 nFlags, nDefHeight;
+ maStrm >> nFlags >> nDefHeight;
+ pColRowBuff->SetDefHeight( nDefHeight, nFlags );
+}
+
+
+void ImportExcel::TableOp( void )
+{
+ sal_uInt16 nFirstRow, nLastRow;
+ sal_uInt8 nFirstCol, nLastCol;
+ sal_uInt16 nGrbit;
+ sal_uInt16 nInpRow, nInpCol, nInpRow2, nInpCol2;
+
+ aIn >> nFirstRow >> nLastRow >> nFirstCol >> nLastCol >> nGrbit
+ >> nInpRow >> nInpCol >> nInpRow2 >> nInpCol2;
+
+ if( ValidColRow( nLastCol, nLastRow ) )
+ {
+ if( nFirstCol && nFirstRow )
+ {
+ ScTabOpParam aTabOpParam;
+ aTabOpParam.nMode = (nGrbit & EXC_TABLEOP_BOTH) ? 2 : ((nGrbit & EXC_TABLEOP_ROW) ? 1 : 0 );
+ sal_uInt16 nCol = nFirstCol - 1;
+ sal_uInt16 nRow = nFirstRow - 1;
+ SCTAB nTab = GetCurrScTab();
+ switch( aTabOpParam.nMode )
+ {
+ case 0: // COL
+ aTabOpParam.aRefFormulaCell.Set(
+ static_cast<SCCOL>(nFirstCol),
+ static_cast<SCROW>(nFirstRow - 1), nTab, false,
+ false, false );
+ aTabOpParam.aRefFormulaEnd.Set(
+ static_cast<SCCOL>(nLastCol),
+ static_cast<SCROW>(nFirstRow - 1), nTab, false,
+ false, false );
+ aTabOpParam.aRefColCell.Set( static_cast<SCCOL>(nInpCol),
+ static_cast<SCROW>(nInpRow), nTab, false, false,
+ false );
+ nRow++;
+ break;
+ case 1: // ROW
+ aTabOpParam.aRefFormulaCell.Set(
+ static_cast<SCCOL>(nFirstCol - 1),
+ static_cast<SCROW>(nFirstRow), nTab, false, false,
+ false );
+ aTabOpParam.aRefFormulaEnd.Set(
+ static_cast<SCCOL>(nFirstCol - 1),
+ static_cast<SCROW>(nLastRow), nTab, false, false,
+ false );
+ aTabOpParam.aRefRowCell.Set( static_cast<SCCOL>(nInpCol),
+ static_cast<SCROW>(nInpRow), nTab, false, false,
+ false );
+ nCol++;
+ break;
+ case 2: // TWO-INPUT
+ aTabOpParam.aRefFormulaCell.Set(
+ static_cast<SCCOL>(nFirstCol - 1),
+ static_cast<SCROW>(nFirstRow - 1), nTab, false,
+ false, false );
+ aTabOpParam.aRefRowCell.Set( static_cast<SCCOL>(nInpCol),
+ static_cast<SCROW>(nInpRow), nTab, false, false,
+ false );
+ aTabOpParam.aRefColCell.Set( static_cast<SCCOL>(nInpCol2),
+ static_cast<SCROW>(nInpRow2), nTab, false, false,
+ false );
+ break;
+ }
+
+ ScMarkData aMarkData;
+ aMarkData.SelectOneTable( nTab );
+ pD->InsertTableOp( aTabOpParam, static_cast<SCCOL>(nCol),
+ static_cast<SCROW>(nRow), static_cast<SCCOL>(nLastCol),
+ static_cast<SCROW>(nLastRow), aMarkData );
+ }
+ }
+ else
+ {
+ bTabTruncated = sal_True;
+ GetTracer().TraceInvalidRow(GetCurrScTab(), nLastRow, MAXROW);
+ }
+}
+
+
+void ImportExcel::Bof4( void )
+{
+ sal_uInt16 nSubType;
+ maStrm.DisableDecryption();
+ maStrm.Ignore( 2 );
+ maStrm >> nSubType;
+
+ if( nSubType == 0x0100 ) // Book
+ pExcRoot->eDateiTyp = Biff4W;
+ else if( nSubType == 0x0020 ) // Chart
+ pExcRoot->eDateiTyp = Biff4C;
+ else if( nSubType == 0x0040 ) // Macro
+ pExcRoot->eDateiTyp = Biff4M;
+ else // #i51490# Excel interprets invalid indexes as worksheet
+ pExcRoot->eDateiTyp = Biff4;
+}
+
+
+void ImportExcel::Bof5( void )
+{
+ //POST: eDateiTyp = Typ der zu lesenden Datei
+ sal_uInt16 nSubType, nVers;
+ BiffTyp eDatei;
+
+ maStrm.DisableDecryption();
+ maStrm >> nVers >> nSubType;
+
+ switch( nSubType )
+ {
+ case 0x0005: eDatei = Biff5W; break; // workbook globals
+ case 0x0006: eDatei = Biff5V; break; // VB module
+ case 0x0010: eDatei = Biff5; break; // worksheet
+ case 0x0020: eDatei = Biff5C; break; // chart
+ case 0x0040: eDatei = Biff5M4; break; // macro sheet
+ default:
+ pExcRoot->eDateiTyp = BiffX;
+ return;
+ }
+
+ if( nVers == 0x0600 && (GetBiff() == EXC_BIFF8) )
+ eDatei = ( BiffTyp ) ( eDatei - Biff5 + Biff8 );
+
+ pExcRoot->eDateiTyp = eDatei;
+}
+
+void ImportExcel::EndSheet( void )
+{
+ pExcRoot->pExtSheetBuff->Reset();
+
+ if( GetBiff() <= EXC_BIFF5 )
+ {
+ pExcRoot->pExtNameBuff->Reset();
+ mnLastRefIdx = 0;
+ }
+
+ FinalizeTable();
+}
+
+
+void ImportExcel::NeueTabelle( void )
+{
+ SCTAB nTab = GetCurrScTab();
+ if( nTab > 0 && !pD->HasTable( nTab ) )
+ pD->MakeTable( nTab );
+
+ if (nTab == 0 && GetBiff() == EXC_BIFF2)
+ {
+ // For Excel 2.1 Worksheet file, we need to set the file name as the
+ // sheet name.
+ INetURLObject aURL(GetDocUrl());
+ pD->RenameTab(0, aURL.getBase(), false);
+ }
+
+ pExcRoot->pShrfmlaBuff->Clear();
+
+ InitializeTable( nTab );
+
+ XclImpOutlineDataBuffer* pNewItem = new XclImpOutlineDataBuffer( GetRoot(), nTab );
+ pOutlineListBuffer->push_back( pNewItem );
+ pExcRoot->pColRowBuff = pColRowBuff = pNewItem->GetColRowBuff();
+ pColOutlineBuff = pNewItem->GetColOutline();
+ pRowOutlineBuff = pNewItem->GetRowOutline();
+}
+
+
+const ScTokenArray* ImportExcel::ErrorToFormula( sal_uInt8 bErrOrVal, sal_uInt8 nError, double& rVal )
+{
+ return pFormConv->GetBoolErr( XclTools::ErrorToEnum( rVal, bErrOrVal, nError ) );
+}
+
+
+void ImportExcel::AdjustRowHeight()
+{
+ /* Speed up chart import: import all sheets without charts, then
+ update row heights (here), last load all charts -> do not any longer
+ update inside of ScDocShell::ConvertFrom() (causes update of existing
+ charts during each and every change of row height). */
+ if( ScModelObj* pDocObj = GetDocModelObj() )
+ pDocObj->UpdateAllRowHeights();
+}
+
+
+void ImportExcel::PostDocLoad( void )
+{
+ /* Set automatic page numbering in Default page style (default is "page number = 1").
+ Otherwise hidden tables (i.e. for scenarios) which have Default page style will
+ break automatic page numbering. */
+ if( SfxStyleSheetBase* pStyleSheet = GetStyleSheetPool().Find( ScGlobal::GetRscString( STR_STYLENAME_STANDARD ), SFX_STYLE_FAMILY_PAGE ) )
+ pStyleSheet->GetItemSet().Put( SfxUInt16Item( ATTR_PAGE_FIRSTPAGENO, 0 ) );
+
+ // outlines for all sheets, sets hidden rows and columns (#i11776# after filtered ranges)
+ for (XclImpOutlineListBuffer::iterator itBuffer = pOutlineListBuffer->begin(); itBuffer != pOutlineListBuffer->end(); ++itBuffer)
+ itBuffer->Convert();
+
+ // document view settings (before visible OLE area)
+ GetDocViewSettings().Finalize();
+
+ // process all drawing objects (including OLE, charts, controls; after hiding rows/columns; before visible OLE area)
+ GetObjectManager().ConvertObjects();
+
+ // visible area (used if this document is an embedded OLE object)
+ if( SfxObjectShell* pDocShell = GetDocShell() )
+ {
+ // visible area if embedded
+ const ScExtDocSettings& rDocSett = GetExtDocOptions().GetDocSettings();
+ SCTAB nDisplScTab = rDocSett.mnDisplTab;
+
+ /* #i44077# If a new OLE object is inserted from file, there is no
+ OLESIZE record in the Excel file. Calculate used area from file
+ contents (used cells and drawing objects). */
+ if( !maScOleSize.IsValid() )
+ {
+ // used area of displayed sheet (cell contents)
+ if( const ScExtTabSettings* pTabSett = GetExtDocOptions().GetTabSettings( nDisplScTab ) )
+ maScOleSize = pTabSett->maUsedArea;
+ // add all valid drawing objects
+ ScRange aScObjArea = GetObjectManager().GetUsedArea( nDisplScTab );
+ if( aScObjArea.IsValid() )
+ maScOleSize.ExtendTo( aScObjArea );
+ }
+
+ // valid size found - set it at the document
+ if( maScOleSize.IsValid() )
+ {
+ pDocShell->SetVisArea( GetDoc().GetMMRect(
+ maScOleSize.aStart.Col(), maScOleSize.aStart.Row(),
+ maScOleSize.aEnd.Col(), maScOleSize.aEnd.Row(), nDisplScTab ) );
+ GetDoc().SetVisibleTab( nDisplScTab );
+ }
+ }
+
+ // open forms in alive mode (has no effect, if no controls in document)
+ if( ScModelObj* pDocObj = GetDocModelObj() )
+ pDocObj->setPropertyValue( CREATE_OUSTRING( SC_UNO_APPLYFMDES ), uno::Any( false ) );
+
+ // enables extended options to be set to the view after import
+ GetExtDocOptions().SetChanged( true );
+
+ // root data owns the extended document options -> create a new object
+ GetDoc().SetExtDocOptions( new ScExtDocOptions( GetExtDocOptions() ) );
+
+ const SCTAB nLast = pD->GetTableCount();
+ const ScRange* p;
+
+ if( pExcRoot->pPrintRanges->HasRanges() )
+ {
+ for( SCTAB n = 0 ; n < nLast ; n++ )
+ {
+ p = pExcRoot->pPrintRanges->First(n);
+ if( p )
+ {
+ pD->ClearPrintRanges( n );
+ while( p )
+ {
+ pD->AddPrintRange( n, *p );
+ p = pExcRoot->pPrintRanges->Next();
+ }
+ }
+ else
+ {
+ // #i4063# no print ranges -> print entire sheet
+ pD->SetPrintEntireSheet( n );
+ }
+ }
+ GetTracer().TracePrintRange();
+ }
+
+ if( pExcRoot->pPrintTitles->HasRanges() )
+ {
+ for( SCTAB n = 0 ; n < nLast ; n++ )
+ {
+ p = pExcRoot->pPrintTitles->First(n);
+ if( p )
+ {
+ sal_Bool bRowVirgin = sal_True;
+ sal_Bool bColVirgin = sal_True;
+
+ while( p )
+ {
+ if( p->aStart.Col() == 0 && p->aEnd.Col() == MAXCOL && bRowVirgin )
+ {
+ pD->SetRepeatRowRange( n, p );
+ bRowVirgin = false;
+ }
+
+ if( p->aStart.Row() == 0 && p->aEnd.Row() == MAXROW && bColVirgin )
+ {
+ pD->SetRepeatColRange( n, p );
+ bColVirgin = false;
+ }
+
+ p = pExcRoot->pPrintTitles->Next();
+ }
+ }
+ }
+ }
+}
+
+XclImpOutlineDataBuffer::XclImpOutlineDataBuffer( const XclImpRoot& rRoot, SCTAB nScTab ) :
+ XclImpRoot( rRoot ),
+ mxColOutlineBuff( new XclImpOutlineBuffer( MAXCOLCOUNT ) ),
+ mxRowOutlineBuff( new XclImpOutlineBuffer( MAXROWCOUNT ) ),
+ mxColRowBuff( new XclImpColRowSettings( rRoot ) ),
+ mnScTab( nScTab )
+{
+}
+
+XclImpOutlineDataBuffer::~XclImpOutlineDataBuffer()
+{
+}
+
+void XclImpOutlineDataBuffer::Convert()
+{
+ mxColOutlineBuff->SetOutlineArray( GetDoc().GetOutlineTable( mnScTab, sal_True )->GetColArray() );
+ mxColOutlineBuff->MakeScOutline();
+
+ mxRowOutlineBuff->SetOutlineArray( GetDoc().GetOutlineTable( mnScTab, sal_True )->GetRowArray() );
+ mxRowOutlineBuff->MakeScOutline();
+
+ mxColRowBuff->ConvertHiddenFlags( mnScTab );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/namebuff.cxx b/sc/source/filter/excel/namebuff.cxx
new file mode 100644
index 000000000000..fe388a218e95
--- /dev/null
+++ b/sc/source/filter/excel/namebuff.cxx
@@ -0,0 +1,346 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "namebuff.hxx"
+
+#include <tools/urlobj.hxx>
+#include <string.h>
+
+#include "rangenam.hxx"
+#include "document.hxx"
+#include "compiler.hxx"
+#include "scextopt.hxx"
+
+#include "root.hxx"
+#include "tokstack.hxx"
+#include "xltools.hxx"
+#include "xiroot.hxx"
+
+
+sal_uInt32 StringHashEntry::MakeHashCode( const String& r )
+{
+ register sal_uInt32 n = 0;
+ const sal_Unicode* pAkt = r.GetBuffer();
+ register sal_Unicode cAkt = *pAkt;
+
+ while( cAkt )
+ {
+ n *= 70;
+ n += ( sal_uInt32 ) cAkt;
+ pAkt++;
+ cAkt = *pAkt;
+ }
+
+ return n;
+}
+
+
+
+
+NameBuffer::~NameBuffer()
+{
+ register StringHashEntry* pDel = ( StringHashEntry* ) List::First();
+ while( pDel )
+ {
+ delete pDel;
+ pDel = ( StringHashEntry* ) List::Next();
+ }
+}
+
+
+//void NameBuffer::operator <<( const SpString &rNewString )
+void NameBuffer::operator <<( const String &rNewString )
+{
+ DBG_ASSERT( Count() + nBase < 0xFFFF,
+ "*NameBuffer::GetLastIndex(): Ich hab' die Nase voll!" );
+
+ List::Insert( new StringHashEntry( rNewString ), LIST_APPEND );
+}
+
+
+#ifdef DBG_UTIL
+sal_uInt16 nShrCnt;
+#endif
+
+
+size_t ShrfmlaBuffer::ScAddressHashFunc::operator() (const ScAddress &addr) const
+{
+ // Use something simple, it is just a hash.
+ return static_cast< sal_uInt16 >( addr.Row() ) | (static_cast< sal_uInt8 >( addr.Col() ) << 16);
+}
+
+const size_t nBase = 16384; // Range~ und Shared~ Dingens mit jeweils der Haelfte Ids
+ShrfmlaBuffer::ShrfmlaBuffer( RootData* pRD ) :
+ ExcRoot( pRD ),
+ mnCurrIdx (nBase)
+{
+#ifdef DBG_UTIL
+ nShrCnt = 0;
+#endif
+}
+
+ShrfmlaBuffer::~ShrfmlaBuffer()
+{
+}
+
+void ShrfmlaBuffer::Clear()
+{
+ index_hash.clear();
+ // do not clear index_list, index calculation depends on complete list size...
+ // do not change mnCurrIdx
+}
+
+void ShrfmlaBuffer::Store( const ScRange& rRange, const ScTokenArray& rToken )
+{
+ String aName( CreateName( rRange.aStart ) );
+
+ DBG_ASSERT( mnCurrIdx <= 0xFFFF, "*ShrfmlaBuffer::Store(): Gleich wird mir schlecht...!" );
+
+ ScRangeData* pData = new ScRangeData( pExcRoot->pIR->GetDocPtr(), aName, rToken, rRange.aStart, RT_SHARED );
+ const ScAddress& rMaxPos = pExcRoot->pIR->GetMaxPos();
+ pData->SetMaxCol(rMaxPos.Col());
+ pData->SetMaxRow(rMaxPos.Row());
+ pData->SetIndex( static_cast< sal_uInt16 >( mnCurrIdx ) );
+ pExcRoot->pIR->GetNamedRanges().insert( pData );
+ index_hash[rRange.aStart] = static_cast< sal_uInt16 >( mnCurrIdx );
+ index_list.push_front (rRange);
+ ++mnCurrIdx;
+}
+
+
+sal_uInt16 ShrfmlaBuffer::Find( const ScAddress & aAddr ) const
+{
+ ShrfmlaHash::const_iterator hash = index_hash.find (aAddr);
+ if (hash != index_hash.end())
+ return hash->second;
+
+ // It was not hashed on the top left corner ? do a brute force search
+ unsigned int ind = nBase;
+ for (ShrfmlaList::const_iterator ptr = index_list.end(); ptr != index_list.begin() ; ind++)
+ if ((--ptr)->In (aAddr))
+ return static_cast< sal_uInt16 >( ind );
+ return static_cast< sal_uInt16 >( mnCurrIdx );
+}
+
+
+#define SHRFMLA_BASENAME "SHARED_FORMULA_"
+
+String ShrfmlaBuffer::CreateName( const ScRange& r )
+{
+ String aName( RTL_CONSTASCII_USTRINGPARAM( SHRFMLA_BASENAME ) );
+ aName += String::CreateFromInt32( r.aStart.Col() );
+ aName.Append( '_' );
+ aName += String::CreateFromInt32( r.aStart.Row() );
+ aName.Append( '_' );
+ aName += String::CreateFromInt32( r.aEnd.Col() );
+ aName.Append( '_' );
+ aName += String::CreateFromInt32( r.aEnd.Row() );
+ aName.Append( '_' );
+ aName += String::CreateFromInt32( r.aStart.Tab() );
+
+ return aName;
+}
+
+
+ExtSheetBuffer::~ExtSheetBuffer()
+{
+ Cont *pAkt = ( Cont * ) List::First();
+ while( pAkt )
+ {
+ delete pAkt;
+ pAkt = ( Cont * ) List::Next();
+ }
+}
+
+
+sal_Int16 ExtSheetBuffer::Add( const String& rFPAN, const String& rTN, const sal_Bool bSWB )
+{
+ List::Insert( new Cont( rFPAN, rTN, bSWB ), LIST_APPEND );
+ // return 1-based index of EXTERNSHEET
+ return static_cast< sal_Int16 >( List::Count() );
+}
+
+
+sal_Bool ExtSheetBuffer::GetScTabIndex( sal_uInt16 nExcIndex, sal_uInt16& rScIndex )
+{
+ DBG_ASSERT( nExcIndex,
+ "*ExtSheetBuffer::GetScTabIndex(): Sheet-Index == 0!" );
+
+ nExcIndex--;
+ Cont* pCur = ( Cont * ) List::GetObject( nExcIndex );
+ sal_uInt16& rTabNum = pCur->nTabNum;
+
+ if( pCur )
+ {
+ if( rTabNum < 0xFFFD )
+ {
+ rScIndex = rTabNum;
+ return sal_True;
+ }
+
+ if( rTabNum == 0xFFFF )
+ {// neue Tabelle erzeugen
+ SCTAB nNewTabNum;
+ if( pCur->bSWB )
+ {// Tabelle ist im selben Workbook!
+ if( pExcRoot->pIR->GetDoc().GetTable( pCur->aTab, nNewTabNum ) )
+ {
+ rScIndex = rTabNum = static_cast<sal_uInt16>(nNewTabNum);
+ return sal_True;
+ }
+ else
+ rTabNum = 0xFFFD;
+ }
+ else if( pExcRoot->pIR->GetDocShell() )
+ {// Tabelle ist 'echt' extern
+ if( pExcRoot->pIR->GetExtDocOptions().GetDocSettings().mnLinkCnt == 0 )
+ {
+ String aURL( ScGlobal::GetAbsDocName( pCur->aFile,
+ pExcRoot->pIR->GetDocShell() ) );
+ String aTabName( ScGlobal::GetDocTabName( aURL, pCur->aTab ) );
+ if( pExcRoot->pIR->GetDoc().LinkExternalTab( nNewTabNum, aTabName, aURL, pCur->aTab ) )
+ {
+ rScIndex = rTabNum = static_cast<sal_uInt16>(nNewTabNum);
+ return sal_True;
+ }
+ else
+ rTabNum = 0xFFFE; // Tabelle einmal nicht angelegt -> wird
+ // wohl auch nicht mehr gehen...
+ }
+ else
+ rTabNum = 0xFFFE;
+
+ }
+ }
+ }
+
+ return false;
+}
+
+
+sal_Bool ExtSheetBuffer::IsLink( const sal_uInt16 nExcIndex ) const
+{
+ DBG_ASSERT( nExcIndex > 0, "*ExtSheetBuffer::IsLink(): Index muss >0 sein!" );
+ Cont* pRet = ( Cont * ) List::GetObject( nExcIndex - 1 );
+
+ if( pRet )
+ return pRet->bLink;
+ else
+ return false;
+}
+
+
+sal_Bool ExtSheetBuffer::GetLink( const sal_uInt16 nExcIndex, String& rAppl, String& rDoc ) const
+{
+ DBG_ASSERT( nExcIndex > 0, "*ExtSheetBuffer::GetLink(): Index muss >0 sein!" );
+ Cont* pRet = ( Cont * ) List::GetObject( nExcIndex - 1 );
+
+ if( pRet )
+ {
+ rAppl = pRet->aFile;
+ rDoc = pRet->aTab;
+ return sal_True;
+ }
+ else
+ return false;
+}
+
+
+void ExtSheetBuffer::Reset( void )
+{
+ Cont *pAkt = ( Cont * ) List::First();
+ while( pAkt )
+ {
+ delete pAkt;
+ pAkt = ( Cont * ) List::Next();
+ }
+
+ List::Clear();
+}
+
+
+
+
+sal_Bool ExtName::IsDDE( void ) const
+{
+ return ( nFlags & 0x0001 ) != 0;
+}
+
+
+sal_Bool ExtName::IsOLE( void ) const
+{
+ return ( nFlags & 0x0002 ) != 0;
+}
+
+
+ExtNameBuff::ExtNameBuff( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+
+void ExtNameBuff::AddDDE( const String& rName, sal_Int16 nRefIdx )
+{
+ ExtName aNew( rName, 0x0001 );
+ maExtNames[ nRefIdx ].push_back( aNew );
+}
+
+
+void ExtNameBuff::AddOLE( const String& rName, sal_Int16 nRefIdx, sal_uInt32 nStorageId )
+{
+ ExtName aNew( rName, 0x0002 );
+ aNew.nStorageId = nStorageId;
+ maExtNames[ nRefIdx ].push_back( aNew );
+}
+
+
+void ExtNameBuff::AddName( const String& rName, sal_Int16 nRefIdx )
+{
+ ExtName aNew( GetScAddInName( rName ), 0x0004 );
+ maExtNames[ nRefIdx ].push_back( aNew );
+}
+
+
+const ExtName* ExtNameBuff::GetNameByIndex( sal_Int16 nRefIdx, sal_uInt16 nNameIdx ) const
+{
+ DBG_ASSERT( nNameIdx > 0, "ExtNameBuff::GetNameByIndex() - invalid name index" );
+ ExtNameMap::const_iterator aIt = maExtNames.find( nRefIdx );
+ return ((aIt != maExtNames.end()) && (0 < nNameIdx) && (nNameIdx <= aIt->second.size())) ? &aIt->second[ nNameIdx - 1 ] : 0;
+}
+
+
+void ExtNameBuff::Reset( void )
+{
+ maExtNames.clear();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/ooxml-export-TODO.txt b/sc/source/filter/excel/ooxml-export-TODO.txt
new file mode 100644
index 000000000000..5b04efb97007
--- /dev/null
+++ b/sc/source/filter/excel/ooxml-export-TODO.txt
@@ -0,0 +1,148 @@
+TODO/Unimplemented Calc OOXML Export Features:
+=============================================
+
+Partially implemented features are not mentioned here; grep for OOXTODO within
+sc/source/filter/*.
+
+In updated OfficeFileFormatsProtocols.zip [MS-XLS].pdf,
+Section §2.3.1 (p.154) provides the record name :: record number mapping, and
+Section §2.3.2 (p.165) provides the record number :: record name mapping.
+
+Elements:
+ - Workbook (§3.2):
+ - customWorkbookViews (§3.2.3)
+ - ext (§3.2.7)
+ - externalReference (§3.2.8)
+ - externalReferences (§3.2.9)
+ - extLst (§3.2.10)
+ - fileRecoveryPr (§3.2.11) [ CRASHRECERR? 865h ]
+ - fileSharing (§3.2.12) [ FILESHARING 5Bh ]
+ - functionGroup (§3.2.14) [ FNGRP12 898h; FNGROUPNAME 9Ah ]
+ - functionGroups (§3.2.15) [ FNGROUPCOUNT: 9Ch ]
+ - oleSize (§3.2.16) [ OLESIZE DEh ]
+ - smartTagPr (§3.2.21) [ BOOKEXT 863h ]
+ - smartTagType (§3.2.22) [ unknown record ]
+ - smartTagTypes (§3.2.23) [ unknown record ]
+ - webPublishing (§3.2.24) [ WOPT 80Bh ]
+ - webPublishObject (§3.2.25) [ WEBPUB 801h ]
+ - webPublishObjects (§3.2.26) [ unsupported ]
+ - Worksheets (§3.3.1):
+ - autoFilter (§3.3.1.1) [ AutoFilter 9Eh ]
+ - cellSmartTag (§3.3.1.4) [ FEAT 868h ]
+ - cellSmartTagPr (§3.3.1.5) [ FEAT? 868h ]
+ - cellSmartTags (§3.3.1.6) [ FEAT 868h ]
+ - cellWatch (§3.3.1.7) [ CELLWATCH 86Ch ]
+ - cellWatches (§3.3.1.8) [ CELLWATCH 86Ch ]
+ - cfRule (§3.3.1.9) [ CF 1B1h ]
+ - cfvo (§3.3.1.10) [ CF12 87Ah ]
+ - chartsheet (§3.3.1.11) [ CHARTFRTINFO 850h, FRTWRAPPER 851h...]
+ - color (§3.3.1.14) [ DXF 88Dh xfpropBorder?
+ XFEXT 87Dh xclrType? ]
+ - colorScale (§3.3.1.15) [ DXF 88Dh? ]
+ - control (§3.3.1.18) [ ??? ]
+ - controls (§3.3.1.19) [ ??? ]
+ - customPr (§3.3.1.20) [ ??? ]
+ - customProperties (§3.3.1.21) [ ??? ]
+ - customSheetView (§3.3.1.22) [ ???; for charts; see chartsheet? ]
+ - customSheetView (§3.3.1.23) [ ??? ]
+ - customSheetViews (§3.3.1.24) [ ???; for charts; see chartsheet? ]
+ - customSheetViews (§3.3.1.25) [ ??? ]
+ - dataBar (§3.3.1.26) [ CF12 87Ah ct=Databar ]
+ - dataConsolidate (§3.3.1.27) [ DCON 50h ]
+ - dataRef (§3.3.1.28) [ DCONBIN 1B5h ]
+ - dataRefs (§3.3.1.29) [ ??? ]
+ - dialogsheet (§3.3.1.32) [ ??? ]
+ - drawing (§3.3.1.34) [ ??? ]
+ - evenFooter (§3.3.1.35) [ HeaderFooter 89Ch ]
+ - evenHeader (§3.3.1.36) [ HeaderFooter 89Ch ]
+ - firstFooter (§3.3.1.38) [ HeaderFooter 89Ch ]
+ - firstHeader (§3.3.1.39) [ HeaderFooter 89Ch ]
+ - formula (§3.3.1.40) [ CF 1B1h ]
+ - iconSet (§3.3.1.46) [ CF12 87Ah ct=CFMultistate ]
+ - ignoredError (§3.3.1.47) [ Feat/FeatForumulaErr2/FFErrorCheck 868h ]
+ - ignoredErrors (§3.3.1.48) [ Feat 868h ]
+ - legacyDrawing (§3.3.1.51) [ MsoDrawing ECh ]
+ - legacyDrawingHF (§3.3.1.52) [ ??? ]
+ - oleObject (§3.3.1.57) [ ??? ]
+ - oleObjects (§3.3.1.58) [ ??? ]
+ - outlinePr (§3.3.1.59) [ ??? ]
+ - pageSetup (§3.3.1.62) [ ???; for charts; see chartsheet? ]
+ - picture (§3.3.1.65) [ BkHim E9h; see XclExpBitmap ]
+ - pivotArea (§3.3.1.66) [ ??? ]
+ - pivotSelection (§3.3.1.67) [ ??? ]
+ - protectedRange (§3.3.1.69) [ ??? ]
+ - protectedRanges (§3.3.1.70) [ ??? ]
+ - sheetCalcPr (§3.3.1.76) [ REFRESHALL?? ]
+ - sheetFormatPr (§3.3.1.78) [ lots of records? ]
+ @defaultColWidth: DefColWidth
+ @defaultRowHeight: DEFROWHEIGHT
+ @baseColWidth: ColInfo/coldx?
+ @customHeight: ColInfo/fUserSet?
+ @zeroHeight: ColInfo/fHidden?
+ @thickTop: ?
+ @thickBottom: ?
+ @outlineLevelRow: ?
+ @outlineLevelCol: ColInfo/iOutLevel?
+ - sheetPr (§3.3.1.80) [ ??? ; for charts ]
+ - sheetView (§3.3.1.84) [ ??? ; for charts ]
+ - sheetViews (§3.3.1.86) [ ??? ; for charts ]
+ - smartTags (§3.3.1.87) [ FEAT 868h; isf=ISFFACTOID ]
+ - sortCondition (§3.3.1.88) [ SortData 895h? ]
+ - sortState (§3.3.1.89) [ Sort 90h ]
+ - tabColor (§3.3.1.90) [ SheetExt 862h ]
+ - tablePart (§3.3.1.91) [ ??? ]
+ - tableParts (§3.3.1.92) [ ??? ]
+ - webPublishItem (§3.3.1.94) [ WebPub 801h ]
+ - webPublishItems (§3.3.1.95)
+ - AutoFilter Settings (§3.3.2):
+ - colorFilter (§3.3.2.1) [ AutoFilter12 87Eh,
+ DXFN12NoCB struct ]
+ - dateGroupItem (§3.3.2.4) [ AutoFilter12 87Eh,
+ AF12DateInfo struct ]
+ - dynamicFilter (§3.3.2.5) [ AutoFilter12 87Eh, cft field ]
+ - filter (§3.3.2.6) [ AutoFilter12 87Eh, rgCriteria? ]
+ - filters (§3.3.2.9) [ AutoFilter12 87Eh, rgCriteria? ]
+ - iconFilter (§3.3.2.9) [ AutoFilter12 87Eh,
+ AF12CellIcon struct ]
+ - Shared String Table (§3.4):
+ - phoneticPr (§3.4.3)
+ - rPh (§3.4.6)
+ - Tables (§3.5.1):
+ - calculatedColumnFormula (§3.5.1.1)
+ [ ??? ]
+ - table (§3.5.1.2) [ ??? ]
+ - tableColumn (§3.5.1.3) [ ??? ]
+ - tableColumns (§3.5.1.4) [ ??? ]
+ - tableStyleInfo (§3.5.1.5) [ ??? ]
+ - totalRowFormula (§3.5.1.6) [ ??? ]
+ - xmlColumnPr (§3.5.1.7) [ ??? ]
+ - Single Cell Tables (§3.5.2):
+ - singleXmlCell (§3.5.2.1) [ ??? ]
+ - singleXmlCells (§3.5.2.2) [ ??? ]
+ - xmlCellPr (§3.5.2.3) [ ??? ]
+ - xmlPr (§3.5.2.4) [ ??? ]
+ - Calculation Chain (§3.6):
+ - c (§3.6.1) [ ??? ]
+ - calcChain (§3.6.2) [ ??? ]
+ - Comments (§3.7):
+ - Note: Excel *requires* that there be a drawing object associated
+ with the comment before it will show it. If you _just_ generate the
+ <comments/> XML part and create a <Relationship/> for it, Excell
+ will NOT display the comment.
+ - As drawing is not currently implemented, comments support is
+ incomplete.
+ - TODO: text formatting. Currently we only write unformatted text
+ into comments?.xml, as I'm not sure how formatted text is handled.
+ - Styles (§3.8):
+ - dxf (§3.8.14): [ DXF 88Dh; unsupported ]
+ - dxfs (§3.8.15): [ DXF 88Dh ]
+ - gradientFill (§3.8.23): [ ??? ]
+ - horizontal (§3.8.24): [ DXF 88Dh fNewBorder, xfprops ]
+ - mruColors (§3.8.28): [ ??? ]
+ - scheme (§3.8.36): [ ??? ]
+ - stop (§3.8.38): [ ??? ]
+ - tableStyle (§3.8.40): [ TableStyle 88Fh; unsupported ]
+ - tableStyleElement (§3.8.41): [ TableStyleElement 890h; unsupported ]
+ - tableStyles (§3.8.42): [ TableStyles 88Eh; unsupported ]
+ - vertical (§3.8.44): [ DXF 88Dh fNewBorder, xfprops ]
+
diff --git a/sc/source/filter/excel/read.cxx b/sc/source/filter/excel/read.cxx
new file mode 100644
index 000000000000..96e68a9df01f
--- /dev/null
+++ b/sc/source/filter/excel/read.cxx
@@ -0,0 +1,1307 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "document.hxx"
+#include "scerrors.hxx"
+#include "fprogressbar.hxx"
+#include "xltracer.hxx"
+#include "xltable.hxx"
+#include "xihelper.hxx"
+#include "xipage.hxx"
+#include "xiview.hxx"
+#include "xilink.hxx"
+#include "xiname.hxx"
+#include "xicontent.hxx"
+#include "xiescher.hxx"
+#include "xipivot.hxx"
+#include "XclImpChangeTrack.hxx"
+
+#include "root.hxx"
+#include "imp_op.hxx"
+#include "excimp8.hxx"
+
+FltError ImportExcel::Read( void )
+{
+ XclImpPageSettings& rPageSett = GetPageSettings();
+ XclImpTabViewSettings& rTabViewSett = GetTabViewSettings();
+ XclImpPalette& rPal = GetPalette();
+ XclImpFontBuffer& rFontBfr = GetFontBuffer();
+ XclImpNumFmtBuffer& rNumFmtBfr = GetNumFmtBuffer();
+ XclImpXFBuffer& rXFBfr = GetXFBuffer();
+ XclImpNameManager& rNameMgr = GetNameManager();
+ XclImpObjectManager& rObjMgr = GetObjectManager();
+ (void)rObjMgr;
+ // call to GetCurrSheetDrawing() cannot be cached (changes in new sheets)
+
+ enum Zustand {
+ Z_BiffNull, // Nicht in gueltigem Biff-Format
+ Z_Biff2, // Biff2: nur eine Tabelle
+
+ Z_Biff3, // Biff3: nur eine Tabelle
+
+ Z_Biff4, // Biff4: nur eine Tabelle
+ Z_Biff4W, // Biff4 Workbook: Globals
+ Z_Biff4T, // Biff4 Workbook: eine Tabelle selbst
+ Z_Biff4E, // Biff4 Workbook: zwischen den Tabellen
+
+ Z_Biff5WPre,// Biff5: Prefetch Workbook
+ Z_Biff5W, // Biff5: Globals
+ Z_Biff5TPre,// Biff5: Prefetch fuer Shrfmla/Array Formula
+ Z_Biff5T, // Biff5: eine Tabelle selbst
+ Z_Biff5E, // Biff5: zwischen den Tabellen
+ Z_Biffn0, // Alle Biffs: Tabelle bis naechstesss EOF ueberlesen
+ Z_Ende };
+
+ Zustand eAkt = Z_BiffNull, ePrev = Z_BiffNull;
+
+ FltError eLastErr = eERR_OK;
+ sal_uInt16 nOpcode;
+ sal_uInt16 nBofLevel = 0;
+
+ DBG_ASSERT( &aIn != NULL, "-ImportExcel::Read(): Kein Stream - wie dass?!" );
+
+ ::std::auto_ptr< ScfSimpleProgressBar > pProgress( new ScfSimpleProgressBar(
+ aIn.GetSvStreamSize(), GetDocShell(), STR_LOAD_DOC ) );
+
+ /* #i104057# Need to track a base position for progress bar calculation,
+ because sheet substreams may not be in order of sheets. */
+ sal_Size nProgressBasePos = 0;
+ sal_Size nProgressBaseSize = 0;
+
+ while( eAkt != Z_Ende )
+ {
+ if( eAkt == Z_Biff5E )
+ {
+ sal_uInt16 nScTab = GetCurrScTab();
+ if( nScTab < maSheetOffsets.size() )
+ {
+ nProgressBaseSize += (aIn.GetSvStreamPos() - nProgressBasePos);
+ nProgressBasePos = maSheetOffsets[ nScTab ];
+ aIn.StartNextRecord( nProgressBasePos );
+ }
+ else
+ eAkt = Z_Ende;
+ }
+ else
+ aIn.StartNextRecord();
+
+ nOpcode = aIn.GetRecId();
+
+ if( !aIn.IsValid() )
+ {
+ // finalize table if EOF is missing
+ switch( eAkt )
+ {
+ case Z_Biff2:
+ case Z_Biff3:
+ case Z_Biff4:
+ case Z_Biff4T:
+ case Z_Biff5TPre:
+ case Z_Biff5T:
+ rNumFmtBfr.CreateScFormats();
+ Eof();
+ break;
+ default:;
+ };
+ eAkt = Z_Ende;
+ break;
+ }
+
+ if( eAkt == Z_Ende )
+ break;
+
+ if( eAkt != Z_Biff5TPre && eAkt != Z_Biff5WPre )
+ pProgress->ProgressAbs( nProgressBaseSize + aIn.GetSvStreamPos() - nProgressBasePos );
+
+ switch( eAkt )
+ {
+ // ----------------------------------------------------------------
+ case Z_BiffNull: // ------------------------------- Z_BiffNull -
+ {
+ switch( nOpcode )
+ {
+ case EXC_ID2_BOF:
+ case EXC_ID3_BOF:
+ case EXC_ID4_BOF:
+ case EXC_ID5_BOF:
+ {
+ // #i23425# don't rely on the record ID, but on the detected BIFF version
+ switch( GetBiff() )
+ {
+ case EXC_BIFF2:
+ Bof2();
+ if( pExcRoot->eDateiTyp == Biff2 )
+ {
+ eAkt = Z_Biff2;
+ NeueTabelle();
+ }
+ break;
+ case EXC_BIFF3:
+ Bof3();
+ if( pExcRoot->eDateiTyp == Biff3 )
+ {
+ eAkt = Z_Biff3;
+ NeueTabelle();
+ }
+ break;
+ case EXC_BIFF4:
+ Bof4();
+ if( pExcRoot->eDateiTyp == Biff4 )
+ {
+ eAkt = Z_Biff4;
+ NeueTabelle();
+ }
+ else if( pExcRoot->eDateiTyp == Biff4W )
+ eAkt = Z_Biff4W;
+ break;
+ case EXC_BIFF5:
+ Bof5();
+ if( pExcRoot->eDateiTyp == Biff5W )
+ {
+ eAkt = Z_Biff5WPre;
+
+ nBdshtTab = 0;
+
+ aIn.StoreGlobalPosition(); // und Position merken
+ }
+ else if( pExcRoot->eDateiTyp == Biff5 )
+ {
+ // #i62752# possible to have BIFF5 sheet without globals
+ NeueTabelle();
+ eAkt = Z_Biff5TPre; // Shrfmla Prefetch, Row-Prefetch
+ nBofLevel = 0;
+ aIn.StoreGlobalPosition(); // und Position merken
+ }
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+ }
+ break;
+ }
+ }
+ break;
+ // ----------------------------------------------------------------
+ case Z_Biff2: // ---------------------------------- Z_Biff2 -
+ {
+ switch( nOpcode )
+ {
+ case EXC_ID2_DIMENSIONS:
+ case EXC_ID3_DIMENSIONS: ReadDimensions(); break;
+ case EXC_ID2_BLANK:
+ case EXC_ID3_BLANK: ReadBlank(); break;
+ case EXC_ID2_INTEGER: ReadInteger(); break;
+ case EXC_ID2_NUMBER:
+ case EXC_ID3_NUMBER: ReadNumber(); break;
+ case EXC_ID2_LABEL:
+ case EXC_ID3_LABEL: ReadLabel(); break;
+ case EXC_ID2_BOOLERR:
+ case EXC_ID3_BOOLERR: ReadBoolErr(); break;
+ case EXC_ID_RK: ReadRk(); break;
+
+ case 0x06: Formula25(); break; // FORMULA [ 2 5]
+ case 0x08: Row25(); break; // ROW [ 2 5]
+ case 0x0A: // EOF [ 2345]
+ rNumFmtBfr.CreateScFormats();
+ Eof();
+ eAkt = Z_Ende;
+ break;
+ case 0x14:
+ case 0x15: rPageSett.ReadHeaderFooter( maStrm ); break;
+ case 0x17: Externsheet(); break; // EXTERNSHEET [ 2345]
+ case 0x18: rNameMgr.ReadName( maStrm ); break;
+ case 0x1C: GetCurrSheetDrawing().ReadNote( maStrm );break;
+ case 0x1D: rTabViewSett.ReadSelection( maStrm ); break;
+ case 0x1E: rNumFmtBfr.ReadFormat( maStrm ); break;
+ case 0x20: Columndefault(); break; // COLUMNDEFAULT[ 2 ]
+ case 0x21: Array25(); break; // ARRAY [ 2 5]
+ case 0x23: Externname25(); break; // EXTERNNAME [ 2 5]
+ case 0x24: Colwidth(); break; // COLWIDTH [ 2 ]
+ case 0x25: Defrowheight2(); break; // DEFAULTROWHEI[ 2 ]
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29: rPageSett.ReadMargin( maStrm ); break;
+ case 0x2A: rPageSett.ReadPrintHeaders( maStrm ); break;
+ case 0x2B: rPageSett.ReadPrintGridLines( maStrm ); break;
+ case 0x2F: // FILEPASS [ 2345]
+ eLastErr = XclImpDecryptHelper::ReadFilepass( maStrm );
+ if( eLastErr != ERRCODE_NONE )
+ eAkt = Z_Ende;
+ break;
+ case EXC_ID2_FONT: rFontBfr.ReadFont( maStrm ); break;
+ case EXC_ID_EFONT: rFontBfr.ReadEfont( maStrm ); break;
+ case 0x3E: rTabViewSett.ReadWindow2( maStrm, false );break;
+ case 0x41: rTabViewSett.ReadPane( maStrm ); break;
+ case 0x42: Codepage(); break; // CODEPAGE [ 2345]
+ case 0x43: rXFBfr.ReadXF( maStrm ); break;
+ case 0x44: Ixfe(); break; // IXFE [ 2 ]
+ }
+ }
+ break;
+ // ----------------------------------------------------------------
+ case Z_Biff3: // ---------------------------------- Z_Biff3 -
+ {
+ switch( nOpcode )
+ {
+ // skip chart substream
+ case EXC_ID2_BOF:
+ case EXC_ID3_BOF:
+ case EXC_ID4_BOF:
+ case EXC_ID5_BOF: XclTools::SkipSubStream( maStrm ); break;
+
+ case EXC_ID2_DIMENSIONS:
+ case EXC_ID3_DIMENSIONS: ReadDimensions(); break;
+ case EXC_ID2_BLANK:
+ case EXC_ID3_BLANK: ReadBlank(); break;
+ case EXC_ID2_INTEGER: ReadInteger(); break;
+ case EXC_ID2_NUMBER:
+ case EXC_ID3_NUMBER: ReadNumber(); break;
+ case EXC_ID2_LABEL:
+ case EXC_ID3_LABEL: ReadLabel(); break;
+ case EXC_ID2_BOOLERR:
+ case EXC_ID3_BOOLERR: ReadBoolErr(); break;
+ case EXC_ID_RK: ReadRk(); break;
+
+ case 0x0A: // EOF [ 2345]
+ rNumFmtBfr.CreateScFormats();
+ Eof();
+ eAkt = Z_Ende;
+ break;
+ case 0x14:
+ case 0x15: rPageSett.ReadHeaderFooter( maStrm ); break;
+ case 0x17: Externsheet(); break; // EXTERNSHEET [ 2345]
+ case 0x1A:
+ case 0x1B: rPageSett.ReadPageBreaks( maStrm ); break;
+ case 0x1C: GetCurrSheetDrawing().ReadNote( maStrm );break;
+ case 0x1D: rTabViewSett.ReadSelection( maStrm ); break;
+ case 0x1E: rNumFmtBfr.ReadFormat( maStrm ); break;
+ case 0x22: Rec1904(); break; // 1904 [ 2345]
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29: rPageSett.ReadMargin( maStrm ); break;
+ case 0x2A: rPageSett.ReadPrintHeaders( maStrm ); break;
+ case 0x2B: rPageSett.ReadPrintGridLines( maStrm ); break;
+ case 0x2F: // FILEPASS [ 2345]
+ eLastErr = XclImpDecryptHelper::ReadFilepass( maStrm );
+ if( eLastErr != ERRCODE_NONE )
+ eAkt = Z_Ende;
+ break;
+ case EXC_ID_FILESHARING: ReadFileSharing(); break;
+ case 0x41: rTabViewSett.ReadPane( maStrm ); break;
+ case 0x42: Codepage(); break; // CODEPAGE [ 2345]
+ case 0x56: Builtinfmtcnt(); break; // BUILTINFMTCNT[ 34 ]
+ case 0x5D: GetCurrSheetDrawing().ReadObj( maStrm );break;
+ case 0x7D: Colinfo(); break; // COLINFO [ 345]
+ case 0x8C: Country(); break; // COUNTRY [ 345]
+ case 0x92: rPal.ReadPalette( maStrm ); break;
+ case 0x0206: Formula3(); break; // FORMULA [ 3 ]
+ case 0x0208: Row34(); break; // ROW [ 34 ]
+ case 0x0218: rNameMgr.ReadName( maStrm ); break;
+ case 0x0221: Array34(); break; // ARRAY [ 34 ]
+ case 0x0223: Externname34(); break; // EXTERNNAME [ 34 ]
+ case 0x0225: Defrowheight345();break;//DEFAULTROWHEI[ 345]
+ case 0x0231: rFontBfr.ReadFont( maStrm ); break;
+ case 0x023E: rTabViewSett.ReadWindow2( maStrm, false );break;
+ case 0x0243: rXFBfr.ReadXF( maStrm ); break;
+ case 0x0293: rXFBfr.ReadStyle( maStrm ); break;
+ }
+ }
+ break;
+ // ----------------------------------------------------------------
+ case Z_Biff4: // ---------------------------------- Z_Biff4 -
+ {
+ switch( nOpcode )
+ {
+ // skip chart substream
+ case EXC_ID2_BOF:
+ case EXC_ID3_BOF:
+ case EXC_ID4_BOF:
+ case EXC_ID5_BOF: XclTools::SkipSubStream( maStrm ); break;
+
+ case EXC_ID2_DIMENSIONS:
+ case EXC_ID3_DIMENSIONS: ReadDimensions(); break;
+ case EXC_ID2_BLANK:
+ case EXC_ID3_BLANK: ReadBlank(); break;
+ case EXC_ID2_INTEGER: ReadInteger(); break;
+ case EXC_ID2_NUMBER:
+ case EXC_ID3_NUMBER: ReadNumber(); break;
+ case EXC_ID2_LABEL:
+ case EXC_ID3_LABEL: ReadLabel(); break;
+ case EXC_ID2_BOOLERR:
+ case EXC_ID3_BOOLERR: ReadBoolErr(); break;
+ case EXC_ID_RK: ReadRk(); break;
+
+ case 0x0A: // EOF [ 2345]
+ rNumFmtBfr.CreateScFormats();
+ Eof();
+ eAkt = Z_Ende;
+ break;
+ case 0x12: SheetProtect(); break; // SHEET PROTECTION
+ case 0x14:
+ case 0x15: rPageSett.ReadHeaderFooter( maStrm ); break;
+ case 0x17: Externsheet(); break; // EXTERNSHEET [ 2345]
+ case 0x1A:
+ case 0x1B: rPageSett.ReadPageBreaks( maStrm ); break;
+ case 0x1C: GetCurrSheetDrawing().ReadNote( maStrm );break;
+ case 0x1D: rTabViewSett.ReadSelection( maStrm ); break;
+ case 0x22: Rec1904(); break; // 1904 [ 2345]
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29: rPageSett.ReadMargin( maStrm ); break;
+ case 0x2A: rPageSett.ReadPrintHeaders( maStrm ); break;
+ case 0x2B: rPageSett.ReadPrintGridLines( maStrm ); break;
+ case 0x2F: // FILEPASS [ 2345]
+ eLastErr = XclImpDecryptHelper::ReadFilepass( maStrm );
+ if( eLastErr != ERRCODE_NONE )
+ eAkt = Z_Ende;
+ break;
+ case EXC_ID_FILESHARING: ReadFileSharing(); break;
+ case 0x41: rTabViewSett.ReadPane( maStrm ); break;
+ case 0x42: Codepage(); break; // CODEPAGE [ 2345]
+ case 0x55: DefColWidth(); break;
+ case 0x56: Builtinfmtcnt(); break; // BUILTINFMTCNT[ 34 ]
+ case 0x5D: GetCurrSheetDrawing().ReadObj( maStrm );break;
+ case 0x7D: Colinfo(); break; // COLINFO [ 345]
+ case 0x8C: Country(); break; // COUNTRY [ 345]
+ case 0x92: rPal.ReadPalette( maStrm ); break;
+ case 0x99: Standardwidth(); break; // STANDARDWIDTH[ 45]
+ case 0xA1: rPageSett.ReadSetup( maStrm ); break;
+ case 0x0208: Row34(); break; // ROW [ 34 ]
+ case 0x0218: rNameMgr.ReadName( maStrm ); break;
+ case 0x0221: Array34(); break; // ARRAY [ 34 ]
+ case 0x0223: Externname34(); break; // EXTERNNAME [ 34 ]
+ case 0x0225: Defrowheight345();break;//DEFAULTROWHEI[ 345]
+ case 0x0231: rFontBfr.ReadFont( maStrm ); break;
+ case 0x023E: rTabViewSett.ReadWindow2( maStrm, false );break;
+ case 0x0406: Formula4(); break; // FORMULA [ 4 ]
+ case 0x041E: rNumFmtBfr.ReadFormat( maStrm ); break;
+ case 0x0443: rXFBfr.ReadXF( maStrm ); break;
+ case 0x0293: rXFBfr.ReadStyle( maStrm ); break;
+ }
+ }
+ break;
+ // ----------------------------------------------------------------
+ case Z_Biff4W: // --------------------------------- Z_Biff4W -
+ {
+ switch( nOpcode )
+ {
+ case 0x0A: // EOF [ 2345]
+ eAkt = Z_Ende;
+ break;
+ case 0x12: DocProtect(); break; // PROTECT [ 5]
+ case 0x2F: // FILEPASS [ 2345]
+ eLastErr = XclImpDecryptHelper::ReadFilepass( maStrm );
+ if( eLastErr != ERRCODE_NONE )
+ eAkt = Z_Ende;
+ break;
+ case EXC_ID_FILESHARING: ReadFileSharing(); break;
+ case 0x17: Externsheet(); break; // EXTERNSHEET [ 2345]
+ case 0x42: Codepage(); break; // CODEPAGE [ 2345]
+ case 0x55: DefColWidth(); break;
+ case 0x56: Builtinfmtcnt(); break; // BUILTINFMTCNT[ 34 ]
+ case 0x8C: Country(); break; // COUNTRY [ 345]
+ case 0x8F: Bundleheader(); break; // BUNDLEHEADER [ 4 ]
+ case 0x92: rPal.ReadPalette( maStrm ); break;
+ case 0x99: Standardwidth(); break; // STANDARDWIDTH[ 45]
+ case 0x0218: rNameMgr.ReadName( maStrm ); break;
+ case 0x0223: Externname34(); break; // EXTERNNAME [ 34 ]
+ case 0x0225: Defrowheight345();break;//DEFAULTROWHEI[ 345]
+ case 0x0231: rFontBfr.ReadFont( maStrm ); break;
+ case 0x0409: // BOF [ 4 ]
+ Bof4();
+ if( pExcRoot->eDateiTyp == Biff4 )
+ {
+ eAkt = Z_Biff4T;
+ NeueTabelle();
+ }
+ else
+ eAkt = Z_Ende;
+ break;
+ case 0x041E: rNumFmtBfr.ReadFormat( maStrm ); break;
+ case 0x0443: rXFBfr.ReadXF( maStrm ); break;
+ case 0x0293: rXFBfr.ReadStyle( maStrm ); break;
+ }
+
+ }
+ break;
+ // ----------------------------------------------------------------
+ case Z_Biff4T: // --------------------------------- Z_Biff4T -
+ {
+ switch( nOpcode )
+ {
+ // skip chart substream
+ case EXC_ID2_BOF:
+ case EXC_ID3_BOF:
+ case EXC_ID4_BOF:
+ case EXC_ID5_BOF: XclTools::SkipSubStream( maStrm ); break;
+
+ case EXC_ID2_DIMENSIONS:
+ case EXC_ID3_DIMENSIONS: ReadDimensions(); break;
+ case EXC_ID2_BLANK:
+ case EXC_ID3_BLANK: ReadBlank(); break;
+ case EXC_ID2_INTEGER: ReadInteger(); break;
+ case EXC_ID2_NUMBER:
+ case EXC_ID3_NUMBER: ReadNumber(); break;
+ case EXC_ID2_LABEL:
+ case EXC_ID3_LABEL: ReadLabel(); break;
+ case EXC_ID2_BOOLERR:
+ case EXC_ID3_BOOLERR: ReadBoolErr(); break;
+ case EXC_ID_RK: ReadRk(); break;
+
+ case 0x0A: // EOF [ 2345]
+ Eof();
+ eAkt = Z_Biff4E;
+ break;
+ case 0x12: SheetProtect(); break; // SHEET PROTECTION
+ case 0x14:
+ case 0x15: rPageSett.ReadHeaderFooter( maStrm ); break;
+ case 0x1A:
+ case 0x1B: rPageSett.ReadPageBreaks( maStrm ); break;
+ case 0x1C: GetCurrSheetDrawing().ReadNote( maStrm );break;
+ case 0x1D: rTabViewSett.ReadSelection( maStrm ); break;
+ case 0x2F: // FILEPASS [ 2345]
+ eLastErr = XclImpDecryptHelper::ReadFilepass( maStrm );
+ if( eLastErr != ERRCODE_NONE )
+ eAkt = Z_Ende;
+ break;
+ case 0x41: rTabViewSett.ReadPane( maStrm ); break;
+ case 0x42: Codepage(); break; // CODEPAGE [ 2345]
+ case 0x55: DefColWidth(); break;
+ case 0x56: Builtinfmtcnt(); break; // BUILTINFMTCNT[ 34 ]
+ case 0x5D: GetCurrSheetDrawing().ReadObj( maStrm );break;
+ case 0x7D: Colinfo(); break; // COLINFO [ 345]
+ case 0x8C: Country(); break; // COUNTRY [ 345]
+ case 0x8F: Bundleheader(); break; // BUNDLEHEADER [ 4 ]
+ case 0x92: rPal.ReadPalette( maStrm ); break;
+ case 0x99: Standardwidth(); break; // STANDARDWIDTH[ 45]
+ case 0xA1: rPageSett.ReadSetup( maStrm ); break;
+ case 0x0208: Row34(); break; // ROW [ 34 ]
+ case 0x0218: rNameMgr.ReadName( maStrm ); break;
+ case 0x0221: Array34(); break;
+ case 0x0225: Defrowheight345();break;//DEFAULTROWHEI[ 345]
+ case 0x0231: rFontBfr.ReadFont( maStrm ); break;
+ case 0x023E: rTabViewSett.ReadWindow2( maStrm, false );break;
+ case 0x0406: Formula4(); break;
+ case 0x041E: rNumFmtBfr.ReadFormat( maStrm ); break;
+ case 0x0443: rXFBfr.ReadXF( maStrm ); break;
+ case 0x0293: rXFBfr.ReadStyle( maStrm ); break;
+ }
+
+ }
+ break;
+ // ----------------------------------------------------------------
+ case Z_Biff4E: // --------------------------------- Z_Biff4E -
+ {
+ switch( nOpcode )
+ {
+ case 0x0A: // EOF [ 2345]
+ eAkt = Z_Ende;
+ break;
+ case 0x8F: break; // BUNDLEHEADER [ 4 ]
+ case 0x0409: // BOF [ 4 ]
+ Bof4();
+ NeueTabelle();
+ if( pExcRoot->eDateiTyp == Biff4 )
+ {
+ eAkt = Z_Biff4T;
+ }
+ else
+ {
+ ePrev = eAkt;
+ eAkt = Z_Biffn0;
+ }
+ break;
+ }
+
+ }
+ break;
+ case Z_Biff5WPre: // ------------------------------ Z_Biff5WPre -
+ {
+ switch( nOpcode )
+ {
+ case 0x0A: // EOF [ 2345]
+ eAkt = Z_Biff5W;
+ aIn.SeekGlobalPosition(); // und zurueck an alte Position
+ break;
+ case 0x12: DocProtect(); break; // PROTECT [ 5]
+ case 0x2F: // FILEPASS [ 2345]
+ eLastErr = XclImpDecryptHelper::ReadFilepass( maStrm );
+ if( eLastErr != ERRCODE_NONE )
+ eAkt = Z_Ende;
+ break;
+ case EXC_ID_FILESHARING: ReadFileSharing(); break;
+ case 0x3D: Window1(); break;
+ case 0x42: Codepage(); break; // CODEPAGE [ 2345]
+ case 0x85: Boundsheet(); break; // BOUNDSHEET [ 5]
+ case 0x8C: Country(); break; // COUNTRY [ 345]
+ // PALETTE follows XFs, but already needed while reading the XFs
+ case 0x92: rPal.ReadPalette( maStrm ); break;
+ }
+ }
+ break;
+ case Z_Biff5W: // --------------------------------- Z_Biff5W -
+ {
+ switch( nOpcode )
+ {
+ case 0x0A: // EOF [ 2345]
+ rNumFmtBfr.CreateScFormats();
+ rXFBfr.CreateUserStyles();
+ eAkt = Z_Biff5E;
+ break;
+ case 0x18: rNameMgr.ReadName( maStrm ); break;
+ case 0x1E: rNumFmtBfr.ReadFormat( maStrm ); break;
+ case 0x22: Rec1904(); break; // 1904 [ 2345]
+ case 0x31: rFontBfr.ReadFont( maStrm ); break;
+ case 0x56: Builtinfmtcnt(); break; // BUILTINFMTCNT[ 34 ]
+ case 0x8D: Hideobj(); break; // HIDEOBJ [ 345]
+ case 0xDE: Olesize(); break;
+ case 0xE0: rXFBfr.ReadXF( maStrm ); break;
+ case 0x0293: rXFBfr.ReadStyle( maStrm ); break;
+ case 0x041E: rNumFmtBfr.ReadFormat( maStrm ); break;
+ }
+
+ }
+ break;
+ // ----------------------------------------------------------------
+ case Z_Biff5TPre: // ------------------------------- Z_Biff5Pre -
+ {
+ if( nOpcode == 0x0809 )
+ nBofLevel++;
+ else if( (nOpcode == 0x000A) && nBofLevel )
+ nBofLevel--;
+ else if( !nBofLevel ) // don't read chart records
+ {
+ switch( nOpcode )
+ {
+ case EXC_ID2_DIMENSIONS:
+ case EXC_ID3_DIMENSIONS: ReadDimensions(); break;
+ case 0x08: Row25(); break; // ROW [ 2 5]
+ case 0x0A: // EOF [ 2345]
+ eAkt = Z_Biff5T;
+ aIn.SeekGlobalPosition(); // und zurueck an alte Position
+ break;
+ case 0x12: SheetProtect(); break; // SHEET PROTECTION
+ case 0x1A:
+ case 0x1B: rPageSett.ReadPageBreaks( maStrm ); break;
+ case 0x1D: rTabViewSett.ReadSelection( maStrm ); break;
+ case 0x17: Externsheet(); break; // EXTERNSHEET [ 2345]
+ case 0x21: Array25(); break; // ARRAY [ 2 5]
+ case 0x23: Externname25(); break; // EXTERNNAME [ 2 5]
+ case 0x41: rTabViewSett.ReadPane( maStrm ); break;
+ case 0x42: Codepage(); break; // CODEPAGE [ 2345]
+ case 0x55: DefColWidth(); break;
+ case 0x7D: Colinfo(); break; // COLINFO [ 345]
+ case 0x81: Wsbool(); break; // WSBOOL [ 2345]
+ case 0x8C: Country(); break; // COUNTRY [ 345]
+ case 0x99: Standardwidth(); break; // STANDARDWIDTH[ 45]
+ case 0x0208: Row34(); break; // ROW [ 34 ]
+ case 0x0221: Array34(); break; // ARRAY [ 34 ]
+ case 0x0223: Externname34(); break; // EXTERNNAME [ 34 ]
+ case 0x0225: Defrowheight345();break;//DEFAULTROWHEI[ 345]
+ case 0x023E: rTabViewSett.ReadWindow2( maStrm, false );break;
+ case 0x04BC: Shrfmla(); break; // SHRFMLA [ 5]
+ }
+ }
+ }
+ break;
+ // ----------------------------------------------------------------
+ case Z_Biff5T: // --------------------------------- Z_Biff5T -
+ {
+ switch( nOpcode )
+ {
+ case EXC_ID2_BLANK:
+ case EXC_ID3_BLANK: ReadBlank(); break;
+ case EXC_ID2_INTEGER: ReadInteger(); break;
+ case EXC_ID2_NUMBER:
+ case EXC_ID3_NUMBER: ReadNumber(); break;
+ case EXC_ID2_LABEL:
+ case EXC_ID3_LABEL: ReadLabel(); break;
+ case EXC_ID2_BOOLERR:
+ case EXC_ID3_BOOLERR: ReadBoolErr(); break;
+ case EXC_ID_RK: ReadRk(); break;
+
+ case 0x0006:
+ case 0x0206:
+ case 0x0406: Formula25(); break;
+ case 0x0A: Eof(); eAkt = Z_Biff5E; break;
+ case 0x14:
+ case 0x15: rPageSett.ReadHeaderFooter( maStrm ); break;
+ case 0x17: Externsheet(); break; // EXTERNSHEET [ 2345]
+ case 0x1C: GetCurrSheetDrawing().ReadNote( maStrm );break;
+ case 0x1D: rTabViewSett.ReadSelection( maStrm ); break;
+ case 0x23: Externname25(); break; // EXTERNNAME [ 2 5]
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29: rPageSett.ReadMargin( maStrm ); break;
+ case 0x2A: rPageSett.ReadPrintHeaders( maStrm ); break;
+ case 0x2B: rPageSett.ReadPrintGridLines( maStrm ); break;
+ case 0x2F: // FILEPASS [ 2345]
+ eLastErr = XclImpDecryptHelper::ReadFilepass( maStrm );
+ if( eLastErr != ERRCODE_NONE )
+ eAkt = Z_Ende;
+ break;
+ case 0x5D: GetCurrSheetDrawing().ReadObj( maStrm );break;
+ case 0x83:
+ case 0x84: rPageSett.ReadCenter( maStrm ); break;
+ case 0xA0: rTabViewSett.ReadScl( maStrm ); break;
+ case 0xA1: rPageSett.ReadSetup( maStrm ); break;
+ case 0xBD: Mulrk(); break; // MULRK [ 5]
+ case 0xBE: Mulblank(); break; // MULBLANK [ 5]
+ case 0xD6: Rstring(); break; // RSTRING [ 5]
+ case 0x00E5: Cellmerging(); break; // #i62300#
+ case 0x0236: TableOp(); break; // TABLE [ 5]
+ case 0x0809: // BOF [ 5]
+ XclTools::SkipSubStream( maStrm );
+ break;
+ }
+
+ }
+ break;
+ // ----------------------------------------------------------------
+ case Z_Biff5E: // --------------------------------- Z_Biff5E -
+ {
+ switch( nOpcode )
+ {
+ case 0x0809: // BOF [ 5]
+ Bof5();
+ NeueTabelle();
+ switch( pExcRoot->eDateiTyp )
+ {
+ case Biff5:
+ case Biff5M4:
+ eAkt = Z_Biff5TPre; // Shrfmla Prefetch, Row-Prefetch
+ nBofLevel = 0;
+ aIn.StoreGlobalPosition(); // und Position merken
+ break;
+ case Biff5C: // chart sheet
+ GetCurrSheetDrawing().ReadTabChart( maStrm );
+ Eof();
+ GetTracer().TraceChartOnlySheet();
+ break;
+ case Biff5V:
+ default:
+ pD->SetVisible( GetCurrScTab(), false );
+ ePrev = eAkt;
+ eAkt = Z_Biffn0;
+ }
+ DBG_ASSERT( pExcRoot->eDateiTyp != Biff5W,
+ "+ImportExcel::Read(): Doppel-Whopper-Workbook!" );
+
+ break;
+ }
+
+ }
+ break;
+ case Z_Biffn0: // --------------------------------- Z_Biffn0 -
+ {
+ switch( nOpcode )
+ {
+ case 0x0A: // EOF [ 2345]
+ eAkt = ePrev;
+ IncCurrScTab();
+ break;
+ }
+
+ }
+ break;
+ // ----------------------------------------------------------------
+ case Z_Ende: // ----------------------------------- Z_Ende -
+ OSL_FAIL( "*ImportExcel::Read(): Not possible state!" );
+ break;
+ default: OSL_FAIL( "-ImportExcel::Read(): Zustand vergessen!" );
+ }
+ }
+
+ if( eLastErr == eERR_OK )
+ {
+ pProgress.reset();
+
+ AdjustRowHeight();
+ PostDocLoad();
+
+ pD->CalcAfterLoad();
+
+ const XclImpAddressConverter& rAddrConv = GetAddressConverter();
+ if( rAddrConv.IsTabTruncated() )
+ eLastErr = SCWARN_IMPORT_SHEET_OVERFLOW;
+ else if( bTabTruncated || rAddrConv.IsRowTruncated() )
+ eLastErr = SCWARN_IMPORT_ROW_OVERFLOW;
+ else if( rAddrConv.IsColTruncated() )
+ eLastErr = SCWARN_IMPORT_COLUMN_OVERFLOW;
+ }
+
+ return eLastErr;
+}
+
+
+//___________________________________________________________________
+
+FltError ImportExcel8::Read( void )
+{
+#if EXC_INCL_DUMPER
+ {
+ Biff8RecDumper aDumper( GetRoot(), sal_True );
+ if( aDumper.Dump( aIn ) )
+ return ERRCODE_ABORT;
+ }
+#endif
+ // read the entire BIFF8 stream
+ // don't look too close - this stuff seriously needs to be reworked
+
+ XclImpPageSettings& rPageSett = GetPageSettings();
+ XclImpTabViewSettings& rTabViewSett = GetTabViewSettings();
+ XclImpPalette& rPal = GetPalette();
+ XclImpFontBuffer& rFontBfr = GetFontBuffer();
+ XclImpNumFmtBuffer& rNumFmtBfr = GetNumFmtBuffer();
+ XclImpXFBuffer& rXFBfr = GetXFBuffer();
+ XclImpSst& rSst = GetSst();
+ XclImpTabInfo& rTabInfo = GetTabInfo();
+ XclImpNameManager& rNameMgr = GetNameManager();
+ XclImpLinkManager& rLinkMgr = GetLinkManager();
+ XclImpObjectManager& rObjMgr = GetObjectManager();
+ // call to GetCurrSheetDrawing() cannot be cached (changes in new sheets)
+ XclImpCondFormatManager& rCondFmtMgr = GetCondFormatManager();
+ XclImpValidationManager& rValidMgr = GetValidationManager();
+ XclImpPivotTableManager& rPTableMgr = GetPivotTableManager();
+ XclImpWebQueryBuffer& rWQBfr = GetWebQueryBuffer();
+
+ bool bInUserView = false; // true = In USERSVIEW(BEGIN|END) record block.
+
+ enum XclImpReadState
+ {
+ EXC_STATE_BEFORE_GLOBALS, /// Before workbook globals (wait for initial BOF).
+ EXC_STATE_GLOBALS_PRE, /// Prefetch for workbook globals.
+ EXC_STATE_GLOBALS, /// Workbook globals.
+ EXC_STATE_BEFORE_SHEET, /// Before worksheet (wait for new worksheet BOF).
+ EXC_STATE_SHEET_PRE, /// Prefetch for worksheet.
+ EXC_STATE_SHEET, /// Worksheet.
+ EXC_STATE_END /// Stop reading.
+ };
+
+ XclImpReadState eAkt = EXC_STATE_BEFORE_GLOBALS;
+
+ FltError eLastErr = eERR_OK;
+
+ ::std::auto_ptr< ScfSimpleProgressBar > pProgress( new ScfSimpleProgressBar(
+ aIn.GetSvStreamSize(), GetDocShell(), STR_LOAD_DOC ) );
+
+ /* #i104057# Need to track a base position for progress bar calculation,
+ because sheet substreams may not be in order of sheets. */
+ sal_Size nProgressBasePos = 0;
+ sal_Size nProgressBaseSize = 0;
+
+ bool bSheetHasCodeName = false;
+
+ std::vector< String > CodeNames;
+
+ std::vector < SCTAB > nTabsWithNoCodeName;
+
+ while( eAkt != EXC_STATE_END )
+ {
+ if( eAkt == EXC_STATE_BEFORE_SHEET )
+ {
+ sal_uInt16 nScTab = GetCurrScTab();
+ if( nScTab < maSheetOffsets.size() )
+ {
+ nProgressBaseSize += (aIn.GetSvStreamPos() - nProgressBasePos);
+ nProgressBasePos = maSheetOffsets[ nScTab ];
+ aIn.StartNextRecord( nProgressBasePos );
+ }
+ else
+ eAkt = EXC_STATE_END;
+ }
+ else
+ aIn.StartNextRecord();
+
+ if( !aIn.IsValid() )
+ {
+ // #i63591# finalize table if EOF is missing
+ switch( eAkt )
+ {
+ case EXC_STATE_SHEET_PRE:
+ eAkt = EXC_STATE_SHEET;
+ aIn.SeekGlobalPosition();
+ continue; // next iteration in while loop
+ case EXC_STATE_SHEET:
+ Eof();
+ eAkt = EXC_STATE_END;
+ break;
+ default:
+ eAkt = EXC_STATE_END;
+ }
+ }
+
+ if( eAkt == EXC_STATE_END )
+ break;
+
+ if( eAkt != EXC_STATE_SHEET_PRE && eAkt != EXC_STATE_GLOBALS_PRE )
+ pProgress->ProgressAbs( nProgressBaseSize + aIn.GetSvStreamPos() - nProgressBasePos );
+
+ sal_uInt16 nRecId = aIn.GetRecId();
+
+ /* #i39464# Ignore records between USERSVIEWBEGIN and USERSVIEWEND
+ completely (user specific view settings). Otherwise view settings
+ and filters are loaded multiple times, which at least causes
+ problems in auto-filters. */
+ switch( nRecId )
+ {
+ case EXC_ID_USERSVIEWBEGIN:
+ DBG_ASSERT( !bInUserView, "ImportExcel8::Read - nested user view settings" );
+ bInUserView = true;
+ break;
+ case EXC_ID_USERSVIEWEND:
+ DBG_ASSERT( bInUserView, "ImportExcel8::Read - not in user view settings" );
+ bInUserView = false;
+ break;
+ }
+
+ if( !bInUserView ) switch( eAkt )
+ {
+ // ----------------------------------------------------------------
+ // before workbook globals: wait for initial workbook globals BOF
+ case EXC_STATE_BEFORE_GLOBALS:
+ {
+ if( nRecId == EXC_ID5_BOF )
+ {
+ DBG_ASSERT( GetBiff() == EXC_BIFF8, "ImportExcel8::Read - wrong BIFF version" );
+ Bof5();
+ if( pExcRoot->eDateiTyp == Biff8W )
+ {
+ eAkt = EXC_STATE_GLOBALS_PRE;
+ maStrm.StoreGlobalPosition();
+ nBdshtTab = 0;
+ }
+ else if( pExcRoot->eDateiTyp == Biff8 )
+ {
+ // #i62752# possible to have BIFF8 sheet without globals
+ NeueTabelle();
+ eAkt = EXC_STATE_SHEET_PRE; // Shrfmla Prefetch, Row-Prefetch
+ bSheetHasCodeName = false; // reset
+ aIn.StoreGlobalPosition();
+ }
+ }
+ }
+ break;
+
+ // ----------------------------------------------------------------
+ // prefetch for workbook globals
+ case EXC_STATE_GLOBALS_PRE:
+ {
+ switch( nRecId )
+ {
+ case EXC_ID_EOF:
+ case EXC_ID_EXTSST:
+ /* #i56376# evil hack: if EOF for globals is missing,
+ simulate it. This hack works only for the bugdoc
+ given in the issue, where the sheet substreams
+ start directly after the EXTSST record. A future
+ implementation should be more robust against
+ missing EOFs. */
+ if( (nRecId == EXC_ID_EOF) ||
+ ((nRecId == EXC_ID_EXTSST) && (maStrm.GetNextRecId() == EXC_ID5_BOF)) )
+ {
+ eAkt = EXC_STATE_GLOBALS;
+ aIn.SeekGlobalPosition();
+ }
+ break;
+ case 0x12: DocProtect(); break; // PROTECT [ 5678]
+ case 0x13: DocPasssword(); break;
+ case 0x19: WinProtection(); break;
+ case 0x2F: // FILEPASS [ 2345 ]
+ eLastErr = XclImpDecryptHelper::ReadFilepass( maStrm );
+ if( eLastErr != ERRCODE_NONE )
+ eAkt = EXC_STATE_END;
+ break;
+ case EXC_ID_FILESHARING: ReadFileSharing(); break;
+ case 0x3D: Window1(); break;
+ case 0x42: Codepage(); break; // CODEPAGE [ 2345 ]
+ case 0x85: Boundsheet(); break; // BOUNDSHEET [ 5 ]
+ case 0x8C: Country(); break; // COUNTRY [ 345 ]
+
+ // PALETTE follows XFs, but already needed while reading the XFs
+ case EXC_ID_PALETTE: rPal.ReadPalette( maStrm ); break;
+ }
+ }
+ break;
+
+ // ----------------------------------------------------------------
+ // workbook globals
+ case EXC_STATE_GLOBALS:
+ {
+ switch( nRecId )
+ {
+ case EXC_ID_EOF:
+ case EXC_ID_EXTSST:
+ /* #i56376# evil hack: if EOF for globals is missing,
+ simulate it. This hack works only for the bugdoc
+ given in the issue, where the sheet substreams
+ start directly after the EXTSST record. A future
+ implementation should be more robust against
+ missing EOFs. */
+ if( (nRecId == EXC_ID_EOF) ||
+ ((nRecId == EXC_ID_EXTSST) && (maStrm.GetNextRecId() == EXC_ID5_BOF)) )
+ {
+ rNumFmtBfr.CreateScFormats();
+ rXFBfr.CreateUserStyles();
+ rPTableMgr.ReadPivotCaches( maStrm );
+ eAkt = EXC_STATE_BEFORE_SHEET;
+ }
+ break;
+ case 0x0E: Precision(); break; // PRECISION
+ case 0x22: Rec1904(); break; // 1904 [ 2345 ]
+ case 0x56: Builtinfmtcnt(); break; // BUILTINFMTCNT[ 34 ]
+ case 0x8D: Hideobj(); break; // HIDEOBJ [ 345 ]
+ case 0xD3: SetHasBasic(); break;
+ case 0xDE: Olesize(); break;
+
+ case EXC_ID_CODENAME: ReadCodeName( aIn, true ); break;
+ case EXC_ID_USESELFS: ReadUsesElfs(); break;
+
+ case EXC_ID2_FONT: rFontBfr.ReadFont( maStrm ); break;
+ case EXC_ID4_FORMAT: rNumFmtBfr.ReadFormat( maStrm ); break;
+ case EXC_ID5_XF: rXFBfr.ReadXF( maStrm ); break;
+ case EXC_ID_STYLE: rXFBfr.ReadStyle( maStrm ); break;
+
+ case EXC_ID_SST: rSst.ReadSst( maStrm ); break;
+ case EXC_ID_TABID: rTabInfo.ReadTabid( maStrm ); break;
+ case EXC_ID_NAME: rNameMgr.ReadName( maStrm ); break;
+
+ case EXC_ID_EXTERNSHEET: rLinkMgr.ReadExternsheet( maStrm ); break;
+ case EXC_ID_SUPBOOK: rLinkMgr.ReadSupbook( maStrm ); break;
+ case EXC_ID_XCT: rLinkMgr.ReadXct( maStrm ); break;
+ case EXC_ID_CRN: rLinkMgr.ReadCrn( maStrm ); break;
+ case EXC_ID_EXTERNNAME: rLinkMgr.ReadExternname( maStrm, pFormConv ); break;
+
+ case EXC_ID_MSODRAWINGGROUP:rObjMgr.ReadMsoDrawingGroup( maStrm ); break;
+
+ case EXC_ID_SXIDSTM: rPTableMgr.ReadSxidstm( maStrm ); break;
+ case EXC_ID_SXVS: rPTableMgr.ReadSxvs( maStrm ); break;
+ case EXC_ID_DCONREF: rPTableMgr.ReadDconref( maStrm ); break;
+ case EXC_ID_DCONNAME: rPTableMgr.ReadDConName( maStrm ); break;
+ }
+
+ }
+ break;
+
+ // ----------------------------------------------------------------
+ // before worksheet: wait for new worksheet BOF
+ case EXC_STATE_BEFORE_SHEET:
+ {
+ if( nRecId == EXC_ID5_BOF )
+ {
+ // import only 256 sheets
+ if( GetCurrScTab() > GetScMaxPos().Tab() )
+ {
+ XclTools::SkipSubStream( maStrm );
+ // #i29930# show warning box
+ GetAddressConverter().CheckScTab( GetCurrScTab(), true );
+ eAkt = EXC_STATE_END;
+ }
+ else
+ {
+ Bof5();
+ NeueTabelle();
+ switch( pExcRoot->eDateiTyp )
+ {
+ case Biff8: // worksheet
+ case Biff8M4: // macro sheet
+ eAkt = EXC_STATE_SHEET_PRE; // Shrfmla Prefetch, Row-Prefetch
+ aIn.StoreGlobalPosition();
+ break;
+ case Biff8C: // chart sheet
+ GetCurrSheetDrawing().ReadTabChart( maStrm );
+ Eof();
+ GetTracer().TraceChartOnlySheet();
+ break;
+ case Biff8W: // workbook
+ DBG_ERRORFILE( "ImportExcel8::Read - double workbook globals" );
+ // run through
+ case Biff8V: // VB module
+ default:
+ // TODO: do not create a sheet in the Calc document
+ pD->SetVisible( GetCurrScTab(), false );
+ XclTools::SkipSubStream( maStrm );
+ IncCurrScTab();
+ }
+ }
+ }
+ }
+ break;
+
+ // ----------------------------------------------------------------
+ // prefetch for worksheet
+ case EXC_STATE_SHEET_PRE:
+ {
+ switch( nRecId )
+ {
+ // skip chart substream
+ case EXC_ID2_BOF:
+ case EXC_ID3_BOF:
+ case EXC_ID4_BOF:
+ case EXC_ID5_BOF: XclTools::SkipSubStream( maStrm ); break;
+
+ case EXC_ID_WINDOW2: rTabViewSett.ReadWindow2( maStrm, false );break;
+ case EXC_ID_SCL: rTabViewSett.ReadScl( maStrm ); break;
+ case EXC_ID_PANE: rTabViewSett.ReadPane( maStrm ); break;
+ case EXC_ID_SELECTION: rTabViewSett.ReadSelection( maStrm ); break;
+
+ case EXC_ID2_DIMENSIONS:
+ case EXC_ID3_DIMENSIONS: ReadDimensions(); break;
+
+ case EXC_ID_CODENAME: ReadCodeName( aIn, false ); bSheetHasCodeName = true; break;
+
+ case 0x0A: // EOF [ 2345 ]
+ {
+ eAkt = EXC_STATE_SHEET;
+ String sName;
+ GetDoc().GetName( GetCurrScTab(), sName );
+ if ( !bSheetHasCodeName )
+ {
+ nTabsWithNoCodeName.push_back( GetCurrScTab() );
+ OSL_TRACE("No Codename for %d", GetCurrScTab() );
+ }
+ else
+ {
+ String sCodeName;
+ GetDoc().GetCodeName( GetCurrScTab(), sCodeName );
+ OSL_TRACE("Have CodeName %s for SheetName %s",
+ rtl::OUStringToOString( sCodeName, RTL_TEXTENCODING_UTF8 ).getStr(), rtl::OUStringToOString( sName, RTL_TEXTENCODING_UTF8 ).getStr() );
+ CodeNames.push_back( sCodeName );
+ }
+
+ bSheetHasCodeName = false; // reset
+
+ aIn.SeekGlobalPosition(); // und zurueck an alte Position
+ break;
+ }
+ case 0x12: SheetProtect(); break;
+ case 0x13: SheetPassword(); break;
+ case 0x42: Codepage(); break; // CODEPAGE [ 2345 ]
+ case 0x55: DefColWidth(); break;
+ case 0x7D: Colinfo(); break; // COLINFO [ 345 ]
+ case 0x81: Wsbool(); break; // WSBOOL [ 2345 ]
+ case 0x8C: Country(); break; // COUNTRY [ 345 ]
+ case 0x99: Standardwidth(); break; // STANDARDWIDTH[ 45 ]
+ case 0x9B: FilterMode(); break; // FILTERMODE
+ case 0x9D: AutoFilterInfo(); break;// AUTOFILTERINFO
+ case 0x9E: AutoFilter(); break; // AUTOFILTER
+ case 0x0208: Row34(); break; // ROW [ 34 ]
+ case EXC_ID2_ARRAY:
+ case EXC_ID3_ARRAY: Array34(); break; // ARRAY [ 34 ]
+ case 0x0225: Defrowheight345();break;//DEFAULTROWHEI[ 345 ]
+ case 0x04BC: Shrfmla(); break; // SHRFMLA [ 5 ]
+ case 0x0867: SheetProtection(); break; // SHEETPROTECTION
+ }
+ }
+ break;
+
+ // ----------------------------------------------------------------
+ // worksheet
+ case EXC_STATE_SHEET:
+ {
+ switch( nRecId )
+ {
+ // skip unknown substreams
+ case EXC_ID2_BOF:
+ case EXC_ID3_BOF:
+ case EXC_ID4_BOF:
+ case EXC_ID5_BOF: XclTools::SkipSubStream( maStrm ); break;
+
+ case EXC_ID_EOF: Eof(); eAkt = EXC_STATE_BEFORE_SHEET; break;
+
+ case EXC_ID2_BLANK:
+ case EXC_ID3_BLANK: ReadBlank(); break;
+ case EXC_ID2_INTEGER: ReadInteger(); break;
+ case EXC_ID2_NUMBER:
+ case EXC_ID3_NUMBER: ReadNumber(); break;
+ case EXC_ID2_LABEL:
+ case EXC_ID3_LABEL: ReadLabel(); break;
+ case EXC_ID2_BOOLERR:
+ case EXC_ID3_BOOLERR: ReadBoolErr(); break;
+ case EXC_ID_RK: ReadRk(); break;
+
+ case 0x0006:
+ case 0x0206:
+ case 0x0406: Formula25(); break; // FORMULA [ 2 5 ]
+ case 0x000C: Calccount(); break; // CALCCOUNT
+ case 0x0010: Delta(); break; // DELTA
+ case 0x0011: Iteration(); break; // ITERATION
+ case 0x007E:
+ case 0x00AE: Scenman(); break; // SCENMAN
+ case 0x00AF: Scenario(); break; // SCENARIO
+ case 0x00BD: Mulrk(); break; // MULRK [ 5 ]
+ case 0x00BE: Mulblank(); break; // MULBLANK [ 5 ]
+ case 0x00D6: Rstring(); break; // RSTRING [ 5 ]
+ case 0x00E5: Cellmerging(); break; // CELLMERGING
+ case 0x00FD: Labelsst(); break; // LABELSST [ 8 ]
+ case 0x0236: TableOp(); break; // TABLE
+
+ case EXC_ID_HORPAGEBREAKS:
+ case EXC_ID_VERPAGEBREAKS: rPageSett.ReadPageBreaks( maStrm ); break;
+ case EXC_ID_HEADER:
+ case EXC_ID_FOOTER: rPageSett.ReadHeaderFooter( maStrm ); break;
+ case EXC_ID_LEFTMARGIN:
+ case EXC_ID_RIGHTMARGIN:
+ case EXC_ID_TOPMARGIN:
+ case EXC_ID_BOTTOMMARGIN: rPageSett.ReadMargin( maStrm ); break;
+ case EXC_ID_PRINTHEADERS: rPageSett.ReadPrintHeaders( maStrm ); break;
+ case EXC_ID_PRINTGRIDLINES: rPageSett.ReadPrintGridLines( maStrm ); break;
+ case EXC_ID_HCENTER:
+ case EXC_ID_VCENTER: rPageSett.ReadCenter( maStrm ); break;
+ case EXC_ID_SETUP: rPageSett.ReadSetup( maStrm ); break;
+ case EXC_ID8_IMGDATA: rPageSett.ReadImgData( maStrm ); break;
+
+ case EXC_ID_MSODRAWING: GetCurrSheetDrawing().ReadMsoDrawing( maStrm ); break;
+ // #i61786# weird documents: OBJ without MSODRAWING -> read in BIFF5 format
+ case EXC_ID_OBJ: GetCurrSheetDrawing().ReadObj( maStrm ); break;
+ case EXC_ID_NOTE: GetCurrSheetDrawing().ReadNote( maStrm ); break;
+
+ case EXC_ID_HLINK: XclImpHyperlink::ReadHlink( maStrm ); break;
+ case EXC_ID_LABELRANGES: XclImpLabelranges::ReadLabelranges( maStrm ); break;
+
+ case EXC_ID_CONDFMT: rCondFmtMgr.ReadCondfmt( maStrm ); break;
+ case EXC_ID_CF: rCondFmtMgr.ReadCF( maStrm ); break;
+
+ case EXC_ID_DVAL: rValidMgr.ReadDval( maStrm ); break;
+ case EXC_ID_DV: rValidMgr.ReadDV( maStrm ); break;
+
+ case EXC_ID_QSI: rWQBfr.ReadQsi( maStrm ); break;
+ case EXC_ID_WQSTRING: rWQBfr.ReadWqstring( maStrm ); break;
+ case EXC_ID_PQRY: rWQBfr.ReadParamqry( maStrm ); break;
+ case EXC_ID_WQSETT: rWQBfr.ReadWqsettings( maStrm ); break;
+ case EXC_ID_WQTABLES: rWQBfr.ReadWqtables( maStrm ); break;
+
+ case EXC_ID_SXVIEW: rPTableMgr.ReadSxview( maStrm ); break;
+ case EXC_ID_SXVD: rPTableMgr.ReadSxvd( maStrm ); break;
+ case EXC_ID_SXVI: rPTableMgr.ReadSxvi( maStrm ); break;
+ case EXC_ID_SXIVD: rPTableMgr.ReadSxivd( maStrm ); break;
+ case EXC_ID_SXPI: rPTableMgr.ReadSxpi( maStrm ); break;
+ case EXC_ID_SXDI: rPTableMgr.ReadSxdi( maStrm ); break;
+ case EXC_ID_SXVDEX: rPTableMgr.ReadSxvdex( maStrm ); break;
+ case EXC_ID_SXEX: rPTableMgr.ReadSxex( maStrm ); break;
+ case EXC_ID_SHEETEXT: rTabViewSett.ReadTabBgColor( maStrm, rPal ); break;
+ case EXC_ID_SXVIEWEX9: rPTableMgr.ReadSxViewEx9( maStrm ); break;
+ }
+ }
+ break;
+
+ // ----------------------------------------------------------------
+ default:;
+ }
+ }
+
+ if( eLastErr == eERR_OK )
+ {
+ // In some strange circumstances a the codename might be missing
+ // # Create any missing Sheet CodeNames
+ std::vector < SCTAB >::iterator it_end = nTabsWithNoCodeName.end();
+ for ( std::vector < SCTAB >::iterator it = nTabsWithNoCodeName.begin(); it != it_end; ++it )
+ {
+ SCTAB nTab = 1;
+ OSL_TRACE("Trying to find suitable codename for %d", *it );
+ while ( true )
+ {
+ String sTmpName( RTL_CONSTASCII_USTRINGPARAM("Sheet" ) );
+ sTmpName += String::CreateFromInt32( sal_Int32(nTab++) );
+ std::vector< String >::iterator codeName_It = CodeNames.begin();
+ std::vector< String >::iterator codeName_It_end = CodeNames.end();
+ // search for codename
+ for ( ; codeName_It != codeName_It_end; ++codeName_It )
+ {
+ if ( *codeName_It == sTmpName )
+ break;
+ }
+
+ if ( codeName_It == codeName_It_end ) // generated codename not found
+ {
+ OSL_TRACE("Using generated codename %s", rtl::OUStringToOString( sTmpName, RTL_TEXTENCODING_UTF8 ).getStr() );
+ // Set new codename
+ GetDoc().SetCodeName( *it, sTmpName );
+ // Record newly used codename
+ CodeNames.push_back( sTmpName );
+ // Record those we have created so they can be created in
+ // basic
+ AutoGeneratedCodeNames.push_back( sTmpName );
+ break;
+ }
+ }
+
+ }
+ // #i45843# Convert pivot tables before calculation, so they are available
+ // for the GETPIVOTDATA function.
+ if( GetBiff() == EXC_BIFF8 )
+ GetPivotTableManager().ConvertPivotTables();
+
+ pProgress.reset();
+#if 0
+ // Excel documents look much better without this call; better in the
+ // sense that the row heights are identical to the original heights in
+ // Excel.
+ if (pD->IsAdjustHeightEnabled())
+ AdjustRowHeight();
+#endif
+ PostDocLoad();
+
+ pD->CalcAfterLoad();
+
+ // import change tracking data
+ XclImpChangeTrack aImpChTr( GetRoot(), maStrm );
+ aImpChTr.Apply();
+
+ const XclImpAddressConverter& rAddrConv = GetAddressConverter();
+ if( rAddrConv.IsTabTruncated() )
+ eLastErr = SCWARN_IMPORT_SHEET_OVERFLOW;
+ else if( bTabTruncated || rAddrConv.IsRowTruncated() )
+ eLastErr = SCWARN_IMPORT_ROW_OVERFLOW;
+ else if( rAddrConv.IsColTruncated() )
+ eLastErr = SCWARN_IMPORT_COLUMN_OVERFLOW;
+
+ if( GetBiff() == EXC_BIFF8 )
+ GetPivotTableManager().MaybeRefreshPivotTables();
+ }
+
+ return eLastErr;
+}
+
+//___________________________________________________________________
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/tokstack.cxx b/sc/source/filter/excel/tokstack.cxx
new file mode 100644
index 000000000000..36c46e04b15e
--- /dev/null
+++ b/sc/source/filter/excel/tokstack.cxx
@@ -0,0 +1,881 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+#ifndef PCH
+#include <string.h>
+#endif
+
+#include "compiler.hxx"
+#include "tokstack.hxx"
+#include "global.hxx"
+#include "scmatrix.hxx"
+
+#include <stdio.h> // printf
+
+const sal_uInt16 TokenPool::nScTokenOff = 8192;
+
+
+TokenStack::TokenStack( sal_uInt16 nNewSize )
+{
+ pStack = new TokenId[ nNewSize ];
+
+ Reset();
+ nSize = nNewSize;
+}
+
+
+TokenStack::~TokenStack()
+{
+ delete[] pStack;
+}
+
+
+
+
+//------------------------------------------------------------------------
+
+// !ACHTUNG!: nach Aussen hin beginnt die Nummerierung mit 1!
+// !ACHTUNG!: SC-Token werden mit einem Offset nScTokenOff abgelegt
+// -> Unterscheidung von anderen Token
+
+
+TokenPool::TokenPool( void )
+{
+ sal_uInt16 nLauf = nScTokenOff;
+
+ // Sammelstelle fuer Id-Folgen
+ nP_Id = 256;
+ pP_Id = new sal_uInt16[ nP_Id ];
+
+ // Sammelstelle fuer Ids
+ nElement = 32;
+ pElement = new sal_uInt16[ nElement ];
+ pType = new E_TYPE[ nElement ];
+ pSize = new sal_uInt16[ nElement ];
+ nP_IdLast = 0;
+
+ // Sammelstelle fuer Strings
+ nP_Str = 4;
+ ppP_Str = new String *[ nP_Str ];
+ for( nLauf = 0 ; nLauf < nP_Str ; nLauf++ )
+ ppP_Str[ nLauf ] = NULL;
+
+ // Sammelstelle fuer double
+ nP_Dbl = 8;
+ pP_Dbl = new double[ nP_Dbl ];
+
+ // Sammelstelle fuer error codes
+ nP_Err = 8;
+ pP_Err = new sal_uInt16[ nP_Err ];
+
+ // Sammelstellen fuer Referenzen
+ nP_RefTr = 32;
+ ppP_RefTr = new ScSingleRefData *[ nP_RefTr ];
+ for( nLauf = 0 ; nLauf < nP_RefTr ; nLauf++ )
+ ppP_RefTr[ nLauf ] = NULL;
+
+ nP_Ext = 32;
+ ppP_Ext = new EXTCONT*[ nP_Ext ];
+ memset( ppP_Ext, 0, sizeof( EXTCONT* ) * nP_Ext );
+
+ nP_Nlf = 16;
+ ppP_Nlf = new NLFCONT*[ nP_Nlf ];
+ memset( ppP_Nlf, 0, sizeof( NLFCONT* ) * nP_Nlf );
+
+ nP_Matrix = 16;
+ ppP_Matrix = new ScMatrix*[ nP_Matrix ];
+ memset( ppP_Matrix, 0, sizeof( ScMatrix* ) * nP_Matrix );
+
+ pScToken = new ScTokenArray;
+
+ Reset();
+}
+
+
+TokenPool::~TokenPool()
+{
+ sal_uInt16 n;
+
+ delete[] pP_Id;
+ delete[] pElement;
+ delete[] pType;
+ delete[] pSize;
+ delete[] pP_Dbl;
+ delete[] pP_Err;
+
+ for( n = 0 ; n < nP_RefTr ; n++/*, pAktTr++*/ )
+ {
+ if( ppP_RefTr[ n ] )
+ delete ppP_RefTr[ n ];
+ }
+ delete[] ppP_RefTr;
+
+ for( n = 0 ; n < nP_Str ; n++/*, pAktStr++*/ )
+ {
+ if( ppP_Str[ n ] )
+ delete ppP_Str[ n ];
+ }
+ delete[] ppP_Str;
+
+ for( n = 0 ; n < nP_Ext ; n++ )
+ {
+ if( ppP_Ext[ n ] )
+ delete ppP_Ext[ n ];
+ }
+ delete[] ppP_Ext;
+
+ for( n = 0 ; n < nP_Nlf ; n++ )
+ {
+ if( ppP_Nlf[ n ] )
+ delete ppP_Nlf[ n ];
+ }
+ delete[] ppP_Nlf;
+
+ for( n = 0 ; n < nP_Matrix ; n++ )
+ {
+ if( ppP_Matrix[ n ] )
+ ppP_Matrix[ n ]->DecRef( );
+ }
+ delete[] ppP_Matrix;
+
+ delete pScToken;
+}
+
+
+void TokenPool::GrowString( void )
+{
+ sal_uInt16 nP_StrNew = nP_Str * 2;
+ sal_uInt16 nL;
+
+ String** ppP_StrNew = new String *[ nP_StrNew ];
+
+ for( nL = 0 ; nL < nP_Str ; nL++ )
+ ppP_StrNew[ nL ] = ppP_Str[ nL ];
+ for( nL = nP_Str ; nL < nP_StrNew ; nL++ )
+ ppP_StrNew[ nL ] = NULL;
+
+ nP_Str = nP_StrNew;
+
+ delete[] ppP_Str;
+ ppP_Str = ppP_StrNew;
+}
+
+
+void TokenPool::GrowDouble( void )
+{
+ sal_uInt16 nP_DblNew = nP_Dbl * 2;
+
+ double* pP_DblNew = new double[ nP_DblNew ];
+
+ for( sal_uInt16 nL = 0 ; nL < nP_Dbl ; nL++ )
+ pP_DblNew[ nL ] = pP_Dbl[ nL ];
+
+ nP_Dbl = nP_DblNew;
+
+ delete[] pP_Dbl;
+ pP_Dbl = pP_DblNew;
+}
+
+void TokenPool::GrowTripel( void )
+{
+ sal_uInt16 nP_RefTrNew = nP_RefTr * 2;
+ sal_uInt16 nL;
+
+ ScSingleRefData** ppP_RefTrNew = new ScSingleRefData *[ nP_RefTrNew ];
+
+ for( nL = 0 ; nL < nP_RefTr ; nL++ )
+ ppP_RefTrNew[ nL ] = ppP_RefTr[ nL ];
+ for( nL = nP_RefTr ; nL < nP_RefTrNew ; nL++ )
+ ppP_RefTrNew[ nL ] = NULL;
+
+ nP_RefTr = nP_RefTrNew;
+
+ delete[] ppP_RefTr;
+ ppP_RefTr = ppP_RefTrNew;
+}
+
+
+void TokenPool::GrowId( void )
+{
+ sal_uInt16 nP_IdNew = nP_Id * 2;
+
+ sal_uInt16* pP_IdNew = new sal_uInt16[ nP_IdNew ];
+
+ for( sal_uInt16 nL = 0 ; nL < nP_Id ; nL++ )
+ pP_IdNew[ nL ] = pP_Id[ nL ];
+
+ nP_Id = nP_IdNew;
+
+ delete[] pP_Id;
+ pP_Id = pP_IdNew;
+}
+
+
+void TokenPool::GrowElement( void )
+{
+ sal_uInt16 nElementNew = nElement * 2;
+
+ sal_uInt16* pElementNew = new sal_uInt16[ nElementNew ];
+ E_TYPE* pTypeNew = new E_TYPE[ nElementNew ];
+ sal_uInt16* pSizeNew = new sal_uInt16[ nElementNew ];
+
+ for( sal_uInt16 nL = 0 ; nL < nElement ; nL++ )
+ {
+ pElementNew[ nL ] = pElement[ nL ];
+ pTypeNew[ nL ] = pType[ nL ];
+ pSizeNew[ nL ] = pSize[ nL ];
+ }
+
+ nElement = nElementNew;
+
+ delete[] pElement;
+ delete[] pType;
+ delete[] pSize;
+ pElement = pElementNew;
+ pType = pTypeNew;
+ pSize = pSizeNew;
+}
+
+
+void TokenPool::GrowExt( void )
+{
+ sal_uInt16 nNewSize = nP_Ext * 2;
+
+ EXTCONT** ppNew = new EXTCONT*[ nNewSize ];
+
+ memset( ppNew, 0, sizeof( EXTCONT* ) * nNewSize );
+ memcpy( ppNew, ppP_Ext, sizeof( EXTCONT* ) * nP_Ext );
+
+ delete[] ppP_Ext;
+ ppP_Ext = ppNew;
+ nP_Ext = nNewSize;
+}
+
+
+void TokenPool::GrowNlf( void )
+{
+ sal_uInt16 nNewSize = nP_Nlf * 2;
+
+ NLFCONT** ppNew = new NLFCONT*[ nNewSize ];
+
+ memset( ppNew, 0, sizeof( NLFCONT* ) * nNewSize );
+ memcpy( ppNew, ppP_Nlf, sizeof( NLFCONT* ) * nP_Nlf );
+
+ delete[] ppP_Nlf;
+ ppP_Nlf = ppNew;
+ nP_Nlf = nNewSize;
+}
+
+
+void TokenPool::GrowMatrix( void )
+{
+ sal_uInt16 nNewSize = nP_Matrix * 2;
+
+ ScMatrix** ppNew = new ScMatrix*[ nNewSize ];
+
+ memset( ppNew, 0, sizeof( ScMatrix* ) * nNewSize );
+ memcpy( ppNew, ppP_Matrix, sizeof( ScMatrix* ) * nP_Matrix );
+
+ delete[] ppP_Matrix;
+ ppP_Matrix = ppNew;
+ nP_Matrix = nNewSize;
+}
+
+void TokenPool::GetElement( const sal_uInt16 nId )
+{
+ DBG_ASSERT( nId < nElementAkt, "*TokenPool::GetElement(): Id zu gross!?" );
+
+ if( pType[ nId ] == T_Id )
+ GetElementRek( nId );
+ else
+ {
+ switch( pType[ nId ] )
+ {
+#ifdef DBG_UTIL
+ case T_Id:
+ OSL_FAIL( "-TokenPool::GetElement(): hier hast Du nichts zu suchen!" );
+ break;
+#endif
+ case T_Str:
+ pScToken->AddString( ppP_Str[ pElement[ nId ] ]->GetBuffer() );
+ break;
+ case T_D:
+ pScToken->AddDouble( pP_Dbl[ pElement[ nId ] ] );
+ break;
+ case T_Err:
+ break;
+ case T_RefC:
+ pScToken->AddSingleReference( *ppP_RefTr[ pElement[ (sal_uInt16) nId ] ] );
+ break;
+ case T_RefA:
+ {
+ ScComplexRefData aScComplexRefData;
+ aScComplexRefData.Ref1 = *ppP_RefTr[ pElement[ nId ] ];
+ aScComplexRefData.Ref2 = *ppP_RefTr[ pElement[ nId ] + 1 ];
+ pScToken->AddDoubleReference( aScComplexRefData );
+ }
+ break;
+ case T_RN:
+ {
+ sal_uInt16 n = pElement[nId];
+ if (n < maRangeNames.size())
+ {
+ const RangeName& r = maRangeNames[n];
+ pScToken->AddRangeName(r.mnIndex, r.mbGlobal);
+ }
+ }
+ break;
+ case T_Ext:
+ {
+ sal_uInt16 n = pElement[ nId ];
+ EXTCONT* p = ( n < nP_Ext )? ppP_Ext[ n ] : NULL;
+
+ if( p )
+ {
+ if( p->eId == ocEuroConvert )
+ pScToken->AddOpCode( p->eId );
+ else
+ pScToken->AddExternal( p->aText, p->eId );
+ }
+ }
+ break;
+ case T_Nlf:
+ {
+ sal_uInt16 n = pElement[ nId ];
+ NLFCONT* p = ( n < nP_Nlf )? ppP_Nlf[ n ] : NULL;
+
+ if( p )
+ pScToken->AddColRowName( p->aRef );
+ }
+ break;
+ case T_Matrix:
+ {
+ sal_uInt16 n = pElement[ nId ];
+ ScMatrix* p = ( n < nP_Matrix )? ppP_Matrix[ n ] : NULL;
+
+ if( p )
+ pScToken->AddMatrix( p );
+ }
+ break;
+ case T_ExtName:
+ {
+ sal_uInt16 n = pElement[nId];
+ if (n < maExtNames.size())
+ {
+ const ExtName& r = maExtNames[n];
+ pScToken->AddExternalName(r.mnFileId, r.maName);
+ }
+ }
+ break;
+ case T_ExtRefC:
+ {
+ sal_uInt16 n = pElement[nId];
+ if (n < maExtCellRefs.size())
+ {
+ const ExtCellRef& r = maExtCellRefs[n];
+ pScToken->AddExternalSingleReference(r.mnFileId, r.maTabName, r.maRef);
+ }
+ }
+ break;
+ case T_ExtRefA:
+ {
+ sal_uInt16 n = pElement[nId];
+ if (n < maExtAreaRefs.size())
+ {
+ const ExtAreaRef& r = maExtAreaRefs[n];
+ pScToken->AddExternalDoubleReference(r.mnFileId, r.maTabName, r.maRef);
+ }
+ }
+ break;
+ default:
+ OSL_FAIL("-TokenPool::GetElement(): Zustand undefiniert!?");
+ }
+ }
+}
+
+
+void TokenPool::GetElementRek( const sal_uInt16 nId )
+{
+#ifdef DBG_UTIL
+ nRek++;
+ DBG_ASSERT( nRek <= nP_Id, "*TokenPool::GetElement(): Rekursion loopt!?" );
+#endif
+
+ DBG_ASSERT( nId < nElementAkt, "*TokenPool::GetElementRek(): Id zu gross!?" );
+
+ DBG_ASSERT( pType[ nId ] == T_Id, "-TokenPool::GetElementRek(): nId nicht Id-Folge!" );
+
+
+ sal_uInt16 nAnz = pSize[ nId ];
+ sal_uInt16* pAkt = &pP_Id[ pElement[ nId ] ];
+ for( ; nAnz > 0 ; nAnz--, pAkt++ )
+ {
+ if( *pAkt < nScTokenOff )
+ {// Rekursion oder nicht?
+ switch( pType[ *pAkt ] )
+ {
+ case T_Id:
+ GetElementRek( *pAkt );
+ break;
+ case T_Str:
+ pScToken->AddString( ppP_Str[ pElement[ *pAkt ] ]->GetBuffer() );
+ break;
+ case T_D:
+ pScToken->AddDouble( pP_Dbl[ pElement[ *pAkt ] ] );
+ break;
+ case T_Err:
+ break;
+ case T_RefC:
+ pScToken->AddSingleReference( *ppP_RefTr[ pElement[ *pAkt ] ] );
+ break;
+ case T_RefA:
+ {
+ ScComplexRefData aScComplexRefData;
+ aScComplexRefData.Ref1 = *ppP_RefTr[ pElement[ *pAkt ] ];
+ aScComplexRefData.Ref2 = *ppP_RefTr[ pElement[ *pAkt ] + 1 ];
+ pScToken->AddDoubleReference( aScComplexRefData );
+ }
+ break;
+ case T_RN:
+ {
+ sal_uInt16 n = pElement[*pAkt];
+ if (n < maRangeNames.size())
+ {
+ const RangeName& r = maRangeNames[n];
+ pScToken->AddRangeName(r.mnIndex, r.mbGlobal);
+ }
+ }
+ break;
+ case T_Ext:
+ {
+ sal_uInt16 n = pElement[ *pAkt ];
+ EXTCONT* p = ( n < nP_Ext )? ppP_Ext[ n ] : NULL;
+
+ if( p )
+ pScToken->AddExternal( p->aText, p->eId );
+ }
+ break;
+ case T_Nlf:
+ {
+ sal_uInt16 n = pElement[ *pAkt ];
+ NLFCONT* p = ( n < nP_Nlf )? ppP_Nlf[ n ] : NULL;
+
+ if( p )
+ pScToken->AddColRowName( p->aRef );
+ }
+ break;
+ case T_Matrix:
+ {
+ sal_uInt16 n = pElement[ *pAkt ];
+ ScMatrix* p = ( n < nP_Matrix )? ppP_Matrix[ n ] : NULL;
+
+ if( p )
+ pScToken->AddMatrix( p );
+ }
+ break;
+ case T_ExtName:
+ {
+ sal_uInt16 n = pElement[*pAkt];
+ if (n < maExtNames.size())
+ {
+ const ExtName& r = maExtNames[n];
+ pScToken->AddExternalName(r.mnFileId, r.maName);
+ }
+ }
+ break;
+ case T_ExtRefC:
+ {
+ sal_uInt16 n = pElement[*pAkt];
+ if (n < maExtCellRefs.size())
+ {
+ const ExtCellRef& r = maExtCellRefs[n];
+ pScToken->AddExternalSingleReference(r.mnFileId, r.maTabName, r.maRef);
+ }
+ }
+ break;
+ case T_ExtRefA:
+ {
+ sal_uInt16 n = pElement[*pAkt];
+ if (n < maExtAreaRefs.size())
+ {
+ const ExtAreaRef& r = maExtAreaRefs[n];
+ pScToken->AddExternalDoubleReference(r.mnFileId, r.maTabName, r.maRef);
+ }
+ }
+ break;
+ default:
+ OSL_FAIL("-TokenPool::GetElementRek(): Zustand undefiniert!?");
+ }
+ }
+ else // elementarer SC_Token
+ pScToken->AddOpCode( ( DefTokenId ) ( *pAkt - nScTokenOff ) );
+ }
+
+
+#ifdef DBG_UTIL
+ nRek--;
+#endif
+}
+
+
+void TokenPool::operator >>( TokenId& rId )
+{
+ rId = ( TokenId ) ( nElementAkt + 1 );
+
+ if( nElementAkt >= nElement )
+ GrowElement();
+
+ pElement[ nElementAkt ] = nP_IdLast; // Start der Token-Folge
+ pType[ nElementAkt ] = T_Id; // Typinfo eintragen
+ pSize[ nElementAkt ] = nP_IdAkt - nP_IdLast;
+ // von nP_IdLast bis nP_IdAkt-1 geschrieben -> Laenge der Folge
+
+ nElementAkt++; // Startwerte fuer naechste Folge
+ nP_IdLast = nP_IdAkt;
+}
+
+
+const TokenId TokenPool::Store( const double& rDouble )
+{
+ if( nElementAkt >= nElement )
+ GrowElement();
+
+ if( nP_DblAkt >= nP_Dbl )
+ GrowDouble();
+
+ pElement[ nElementAkt ] = nP_DblAkt; // Index in Double-Array
+ pType[ nElementAkt ] = T_D; // Typinfo Double eintragen
+
+ pP_Dbl[ nP_DblAkt ] = rDouble;
+
+ pSize[ nElementAkt ] = 1; // eigentlich Banane
+
+ nElementAkt++;
+ nP_DblAkt++;
+
+ return ( const TokenId ) nElementAkt; // Ausgabe von altem Wert + 1!
+}
+
+
+const TokenId TokenPool::Store( const sal_uInt16 nIndex )
+{
+ return StoreName(nIndex, true);
+}
+
+
+const TokenId TokenPool::Store( const String& rString )
+{
+ // weitgehend nach Store( const sal_Char* ) kopiert, zur Vermeidung
+ // eines temporaeren Strings in "
+ if( nElementAkt >= nElement )
+ GrowElement();
+
+ if( nP_StrAkt >= nP_Str )
+ GrowString();
+
+ pElement[ nElementAkt ] = nP_StrAkt; // Index in String-Array
+ pType[ nElementAkt ] = T_Str; // Typinfo String eintragen
+
+ // String anlegen
+ if( !ppP_Str[ nP_StrAkt ] )
+ //...aber nur, wenn noch nicht vorhanden
+ ppP_Str[ nP_StrAkt ] = new String( rString );
+ else
+ //...ansonsten nur kopieren
+ *ppP_Str[ nP_StrAkt ] = rString;
+
+ DBG_ASSERT( sizeof( xub_StrLen ) <= 2, "*TokenPool::Store(): StrLen doesn't match!" );
+
+ pSize[ nElementAkt ] = ( sal_uInt16 ) ppP_Str[ nP_StrAkt ]->Len();
+
+ nElementAkt++;
+ nP_StrAkt++;
+
+ return ( const TokenId ) nElementAkt; // Ausgabe von altem Wert + 1!
+}
+
+
+const TokenId TokenPool::Store( const ScSingleRefData& rTr )
+{
+ if( nElementAkt >= nElement )
+ GrowElement();
+
+ if( nP_RefTrAkt >= nP_RefTr )
+ GrowTripel();
+
+ pElement[ nElementAkt ] = nP_RefTrAkt;
+ pType[ nElementAkt ] = T_RefC; // Typinfo Cell-Reff eintragen
+
+ if( !ppP_RefTr[ nP_RefTrAkt ] )
+ ppP_RefTr[ nP_RefTrAkt ] = new ScSingleRefData( rTr );
+ else
+ *ppP_RefTr[ nP_RefTrAkt ] = rTr;
+
+ nElementAkt++;
+ nP_RefTrAkt++;
+
+ return ( const TokenId ) nElementAkt; // Ausgabe von altem Wert + 1!
+}
+
+
+const TokenId TokenPool::Store( const ScComplexRefData& rTr )
+{
+ if( nElementAkt >= nElement )
+ GrowElement();
+
+ if( nP_RefTrAkt + 1 >= nP_RefTr )
+ GrowTripel();
+
+ pElement[ nElementAkt ] = nP_RefTrAkt;
+ pType[ nElementAkt ] = T_RefA; // Typinfo Area-Reff eintragen
+
+ if( !ppP_RefTr[ nP_RefTrAkt ] )
+ ppP_RefTr[ nP_RefTrAkt ] = new ScSingleRefData( rTr.Ref1 );
+ else
+ *ppP_RefTr[ nP_RefTrAkt ] = rTr.Ref1;
+ nP_RefTrAkt++;
+
+ if( !ppP_RefTr[ nP_RefTrAkt ] )
+ ppP_RefTr[ nP_RefTrAkt ] = new ScSingleRefData( rTr.Ref2 );
+ else
+ *ppP_RefTr[ nP_RefTrAkt ] = rTr.Ref2;
+ nP_RefTrAkt++;
+
+ nElementAkt++;
+
+ return ( const TokenId ) nElementAkt; // Ausgabe von altem Wert + 1!
+}
+
+
+const TokenId TokenPool::Store( const DefTokenId e, const String& r )
+{
+ if( nElementAkt >= nElement )
+ GrowElement();
+
+ if( nP_ExtAkt >= nP_Ext )
+ GrowExt();
+
+ pElement[ nElementAkt ] = nP_ExtAkt;
+ pType[ nElementAkt ] = T_Ext; // Typinfo String eintragen
+
+ if( ppP_Ext[ nP_ExtAkt ] )
+ {
+ ppP_Ext[ nP_ExtAkt ]->eId = e;
+ ppP_Ext[ nP_ExtAkt ]->aText = r;
+ }
+ else
+ ppP_Ext[ nP_ExtAkt ] = new EXTCONT( e, r );
+
+ nElementAkt++;
+ nP_ExtAkt++;
+
+ return ( const TokenId ) nElementAkt; // Ausgabe von altem Wert + 1!
+}
+
+
+const TokenId TokenPool::StoreNlf( const ScSingleRefData& rTr )
+{
+ if( nElementAkt >= nElement )
+ GrowElement();
+
+ if( nP_NlfAkt >= nP_Nlf )
+ GrowNlf();
+
+ pElement[ nElementAkt ] = nP_NlfAkt;
+ pType[ nElementAkt ] = T_Nlf;
+
+ if( ppP_Nlf[ nP_NlfAkt ] )
+ {
+ ppP_Nlf[ nP_NlfAkt ]->aRef = rTr;
+ }
+ else
+ ppP_Nlf[ nP_NlfAkt ] = new NLFCONT( rTr );
+
+ nElementAkt++;
+ nP_NlfAkt++;
+
+ return ( const TokenId ) nElementAkt;
+}
+
+const TokenId TokenPool::StoreMatrix()
+{
+ ScMatrix* pM;
+
+ if( nElementAkt >= nElement )
+ GrowElement();
+
+ if( nP_MatrixAkt >= nP_Matrix )
+ GrowMatrix();
+
+ pElement[ nElementAkt ] = nP_MatrixAkt;
+ pType[ nElementAkt ] = T_Matrix;
+
+ pM = new ScMatrix( 0, 0 );
+ pM->IncRef( );
+ ppP_Matrix[ nP_MatrixAkt ] = pM;
+
+ nElementAkt++;
+ nP_MatrixAkt++;
+
+ return ( const TokenId ) nElementAkt;
+}
+
+const TokenId TokenPool::StoreName( sal_uInt16 nIndex, bool bGlobal )
+{
+ if ( nElementAkt >= nElement )
+ GrowElement();
+
+ pElement[nElementAkt] = static_cast<sal_uInt16>(maRangeNames.size());
+ pType[nElementAkt] = T_RN;
+
+ maRangeNames.push_back(RangeName());
+ RangeName& r = maRangeNames.back();
+ r.mnIndex = nIndex;
+ r.mbGlobal = bGlobal;
+
+ ++nElementAkt;
+
+ return static_cast<const TokenId>(nElementAkt);
+}
+
+const TokenId TokenPool::StoreExtName( sal_uInt16 nFileId, const String& rName )
+{
+ if ( nElementAkt >= nElement )
+ GrowElement();
+
+ pElement[nElementAkt] = static_cast<sal_uInt16>(maExtNames.size());
+ pType[nElementAkt] = T_ExtName;
+
+ maExtNames.push_back(ExtName());
+ ExtName& r = maExtNames.back();
+ r.mnFileId = nFileId;
+ r.maName = rName;
+
+ ++nElementAkt;
+
+ return static_cast<const TokenId>(nElementAkt);
+}
+
+const TokenId TokenPool::StoreExtRef( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
+{
+ if ( nElementAkt >= nElement )
+ GrowElement();
+
+ pElement[nElementAkt] = static_cast<sal_uInt16>(maExtCellRefs.size());
+ pType[nElementAkt] = T_ExtRefC;
+
+ maExtCellRefs.push_back(ExtCellRef());
+ ExtCellRef& r = maExtCellRefs.back();
+ r.mnFileId = nFileId;
+ r.maTabName = rTabName;
+ r.maRef = rRef;
+
+ ++nElementAkt;
+
+ return static_cast<const TokenId>(nElementAkt);
+}
+
+const TokenId TokenPool::StoreExtRef( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef )
+{
+ if ( nElementAkt >= nElement )
+ GrowElement();
+
+ pElement[nElementAkt] = static_cast<sal_uInt16>(maExtAreaRefs.size());
+ pType[nElementAkt] = T_ExtRefA;
+
+ maExtAreaRefs.push_back(ExtAreaRef());
+ ExtAreaRef& r = maExtAreaRefs.back();
+ r.mnFileId = nFileId;
+ r.maTabName = rTabName;
+ r.maRef = rRef;
+
+ ++nElementAkt;
+
+ return static_cast<const TokenId>(nElementAkt);
+}
+
+void TokenPool::Reset( void )
+{
+ nP_IdAkt = nP_IdLast = nElementAkt = nP_StrAkt = nP_DblAkt = nP_ErrAkt = nP_RefTrAkt = nP_ExtAkt = nP_NlfAkt = nP_MatrixAkt = 0;
+ maRangeNames.clear();
+ maExtNames.clear();
+ maExtCellRefs.clear();
+ maExtAreaRefs.clear();
+}
+
+
+sal_Bool TokenPool::IsSingleOp( const TokenId& rId, const DefTokenId eId ) const
+{
+ sal_uInt16 nId = (sal_uInt16) rId;
+ if( nId && nId <= nElementAkt )
+ {// existent?
+ nId--;
+ if( T_Id == pType[ nId ] )
+ {// Tokenfolge?
+ if( pSize[ nId ] == 1 )
+ {// GENAU 1 Token
+ sal_uInt16 nSecId = pP_Id[ pElement[ nId ] ];
+ if( nSecId >= nScTokenOff )
+ {// Default-Token?
+ return ( DefTokenId ) ( nSecId - nScTokenOff ) == eId; // Gesuchter?
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+const String* TokenPool::GetExternal( const TokenId& rId ) const
+{
+ const String* p = NULL;
+ sal_uInt16 n = (sal_uInt16) rId;
+ if( n && n <= nElementAkt )
+ {
+ n--;
+ if( (pType[ n ] == T_Ext) && ppP_Ext[ pElement[ n ] ] )
+ p = &ppP_Ext[ pElement[ n ] ]->aText;
+ }
+
+ return p;
+}
+
+ScMatrix* TokenPool::GetMatrix( unsigned int n ) const
+{
+ if( n < nP_MatrixAkt )
+ return ppP_Matrix[ n ];
+ else
+ printf ("GETMATRIX %d >= %d\n", n, nP_MatrixAkt);
+ return NULL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xechart.cxx b/sc/source/filter/excel/xechart.cxx
new file mode 100644
index 000000000000..5a37893da6cc
--- /dev/null
+++ b/sc/source/filter/excel/xechart.cxx
@@ -0,0 +1,3525 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "xechart.hxx"
+
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/chart/XChartDocument.hpp>
+#include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
+#include <com/sun/star/chart/ChartAxisPosition.hpp>
+#include <com/sun/star/chart/ChartLegendExpansion.hpp>
+#include <com/sun/star/chart/DataLabelPlacement.hpp>
+#include <com/sun/star/chart/ErrorBarStyle.hpp>
+#include <com/sun/star/chart/MissingValueTreatment.hpp>
+#include <com/sun/star/chart/TimeInterval.hpp>
+#include <com/sun/star/chart/TimeUnit.hpp>
+#include <com/sun/star/chart/XAxisSupplier.hpp>
+#include <com/sun/star/chart/XChartDocument.hpp>
+#include <com/sun/star/chart/XDiagramPositioning.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart2/XDiagram.hpp>
+#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
+#include <com/sun/star/chart2/XChartTypeContainer.hpp>
+#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
+#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
+#include <com/sun/star/chart2/XTitled.hpp>
+#include <com/sun/star/chart2/XColorScheme.hpp>
+#include <com/sun/star/chart2/data/XDataSource.hpp>
+#include <com/sun/star/chart2/AxisType.hpp>
+#include <com/sun/star/chart2/CurveStyle.hpp>
+#include <com/sun/star/chart2/DataPointGeometry3D.hpp>
+#include <com/sun/star/chart2/DataPointLabel.hpp>
+#include <com/sun/star/chart2/LegendPosition.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
+#include <com/sun/star/chart2/RelativeSize.hpp>
+#include <com/sun/star/chart2/StackingDirection.hpp>
+#include <com/sun/star/chart2/TickmarkStyle.hpp>
+
+#include <vcl/outdev.hxx>
+#include <filter/msfilter/escherex.hxx>
+
+#include "document.hxx"
+#include "rangelst.hxx"
+#include "rangeutl.hxx"
+#include "compiler.hxx"
+#include "tokenarray.hxx"
+#include "token.hxx"
+#include "xeescher.hxx"
+#include "xeformula.hxx"
+#include "xehelper.hxx"
+#include "xepage.hxx"
+#include "xestyle.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::UNO_SET_THROW;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::i18n::XBreakIterator;
+using ::com::sun::star::frame::XModel;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::drawing::XShapes;
+
+using ::com::sun::star::chart2::IncrementData;
+using ::com::sun::star::chart2::RelativePosition;
+using ::com::sun::star::chart2::RelativeSize;
+using ::com::sun::star::chart2::ScaleData;
+using ::com::sun::star::chart2::SubIncrement;
+using ::com::sun::star::chart2::XAxis;
+using ::com::sun::star::chart2::XChartDocument;
+using ::com::sun::star::chart2::XChartTypeContainer;
+using ::com::sun::star::chart2::XColorScheme;
+using ::com::sun::star::chart2::XCoordinateSystem;
+using ::com::sun::star::chart2::XCoordinateSystemContainer;
+using ::com::sun::star::chart2::XChartType;
+using ::com::sun::star::chart2::XDataSeries;
+using ::com::sun::star::chart2::XDataSeriesContainer;
+using ::com::sun::star::chart2::XDiagram;
+using ::com::sun::star::chart2::XFormattedString;
+using ::com::sun::star::chart2::XLegend;
+using ::com::sun::star::chart2::XRegressionCurve;
+using ::com::sun::star::chart2::XRegressionCurveContainer;
+using ::com::sun::star::chart2::XScaling;
+using ::com::sun::star::chart2::XTitle;
+using ::com::sun::star::chart2::XTitled;
+
+using ::com::sun::star::chart2::data::XDataSequence;
+using ::com::sun::star::chart2::data::XDataSource;
+using ::com::sun::star::chart2::data::XLabeledDataSequence;
+
+using ::formula::FormulaGrammar;
+using ::formula::FormulaToken;
+
+namespace cssc = ::com::sun::star::chart;
+namespace cssc2 = ::com::sun::star::chart2;
+
+// Helpers ====================================================================
+
+namespace {
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclChRectangle& rRect )
+{
+ return rStrm << rRect.mnX << rRect.mnY << rRect.mnWidth << rRect.mnHeight;
+}
+
+inline void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec )
+{
+ if( xRec )
+ xRec->Save( rStrm );
+}
+
+/** Saves the passed record (group) together with a leading value record. */
+template< typename Type >
+void lclSaveRecord( XclExpStream& rStrm, XclExpRecordRef xRec, sal_uInt16 nRecId, Type nValue )
+{
+ if( xRec )
+ {
+ XclExpValueRecord< Type >( nRecId, nValue ).Save( rStrm );
+ xRec->Save( rStrm );
+ }
+}
+
+template<typename ValueType, typename KeyType>
+void lclSaveRecord(XclExpStream& rStrm, ValueType* pRec, sal_uInt16 nRecId, KeyType nValue)
+{
+ if (pRec)
+ {
+ XclExpValueRecord<KeyType>(nRecId, nValue).Save(rStrm);
+ pRec->Save(rStrm);
+ }
+}
+
+void lclWriteChFrBlockRecord( XclExpStream& rStrm, const XclChFrBlock& rFrBlock, bool bBegin )
+{
+ sal_uInt16 nRecId = bBegin ? EXC_ID_CHFRBLOCKBEGIN : EXC_ID_CHFRBLOCKEND;
+ rStrm.StartRecord( nRecId, 12 );
+ rStrm << nRecId << EXC_FUTUREREC_EMPTYFLAGS << rFrBlock.mnType << rFrBlock.mnContext << rFrBlock.mnValue1 << rFrBlock.mnValue2;
+ rStrm.EndRecord();
+}
+
+template< typename Type >
+inline bool lclIsAutoAnyOrGetValue( Type& rValue, const Any& rAny )
+{
+ return !rAny.hasValue() || !(rAny >>= rValue);
+}
+
+bool lclIsAutoAnyOrGetScaledValue( double& rfValue, const Any& rAny, bool bLogScale )
+{
+ bool bIsAuto = lclIsAutoAnyOrGetValue( rfValue, rAny );
+ if( !bIsAuto && bLogScale )
+ rfValue = log( rfValue ) / log( 10.0 );
+ return bIsAuto;
+}
+
+sal_uInt16 lclGetTimeValue( const XclExpRoot& rRoot, double fSerialDate, sal_uInt16 nTimeUnit )
+{
+ DateTime aDateTime = rRoot.GetDateTimeFromDouble( fSerialDate );
+ switch( nTimeUnit )
+ {
+ case EXC_CHDATERANGE_DAYS:
+ return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16 );
+ case EXC_CHDATERANGE_MONTHS:
+ return ::limit_cast< sal_uInt16, sal_uInt16 >( 12 * (aDateTime.GetYear() - rRoot.GetBaseYear()) + aDateTime.GetMonth() - 1, 0, SAL_MAX_INT16 );
+ case EXC_CHDATERANGE_YEARS:
+ return ::limit_cast< sal_uInt16, sal_uInt16 >( aDateTime.GetYear() - rRoot.GetBaseYear(), 0, SAL_MAX_INT16 );
+ default:
+ OSL_ENSURE( false, "lclGetTimeValue - unexpected time unit" );
+ }
+ return ::limit_cast< sal_uInt16, double >( fSerialDate, 0, SAL_MAX_UINT16 );
+}
+
+bool lclConvertTimeValue( const XclExpRoot& rRoot, sal_uInt16& rnValue, const Any& rAny, sal_uInt16 nTimeUnit )
+{
+ double fSerialDate = 0;
+ bool bAuto = lclIsAutoAnyOrGetValue( fSerialDate, rAny );
+ if( !bAuto )
+ rnValue = lclGetTimeValue( rRoot, fSerialDate, nTimeUnit );
+ return bAuto;
+}
+
+sal_uInt16 lclGetTimeUnit( sal_Int32 nApiTimeUnit )
+{
+ switch( nApiTimeUnit )
+ {
+ case cssc::TimeUnit::DAY: return EXC_CHDATERANGE_DAYS;
+ case cssc::TimeUnit::MONTH: return EXC_CHDATERANGE_MONTHS;
+ case cssc::TimeUnit::YEAR: return EXC_CHDATERANGE_YEARS;
+ default: OSL_ENSURE( false, "lclGetTimeUnit - unexpected time unit" );
+ }
+ return EXC_CHDATERANGE_DAYS;
+}
+
+bool lclConvertTimeInterval( sal_uInt16& rnValue, sal_uInt16& rnTimeUnit, const Any& rAny )
+{
+ cssc::TimeInterval aInterval;
+ bool bAuto = lclIsAutoAnyOrGetValue( aInterval, rAny );
+ if( !bAuto )
+ {
+ rnValue = ::limit_cast< sal_uInt16, sal_Int32 >( aInterval.Number, 1, SAL_MAX_UINT16 );
+ rnTimeUnit = lclGetTimeUnit( aInterval.TimeUnit );
+ }
+ return bAuto;
+}
+
+} // namespace
+
+// Common =====================================================================
+
+/** Stores global data needed in various classes of the Chart export filter. */
+struct XclExpChRootData : public XclChRootData
+{
+ typedef ::std::vector< XclChFrBlock > XclChFrBlockVector;
+
+ XclExpChChart& mrChartData; /// The chart data object.
+ XclChFrBlockVector maWrittenFrBlocks; /// Stack of future record levels already written out.
+ XclChFrBlockVector maUnwrittenFrBlocks; /// Stack of future record levels not yet written out.
+
+ inline explicit XclExpChRootData( XclExpChChart& rChartData ) : mrChartData( rChartData ) {}
+
+ /** Registers a new future record level. */
+ void RegisterFutureRecBlock( const XclChFrBlock& rFrBlock );
+ /** Initializes the current future record level (writes all unwritten CHFRBLOCKBEGIN records). */
+ void InitializeFutureRecBlock( XclExpStream& rStrm );
+ /** Finalizes the current future record level (writes CHFRBLOCKEND record if needed). */
+ void FinalizeFutureRecBlock( XclExpStream& rStrm );
+};
+
+// ----------------------------------------------------------------------------
+
+void XclExpChRootData::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
+{
+ maUnwrittenFrBlocks.push_back( rFrBlock );
+}
+
+void XclExpChRootData::InitializeFutureRecBlock( XclExpStream& rStrm )
+{
+ // first call from a future record writes all missing CHFRBLOCKBEGIN records
+ if( !maUnwrittenFrBlocks.empty() )
+ {
+ // write the leading CHFRINFO record
+ if( maWrittenFrBlocks.empty() )
+ {
+ rStrm.StartRecord( EXC_ID_CHFRINFO, 20 );
+ rStrm << EXC_ID_CHFRINFO << EXC_FUTUREREC_EMPTYFLAGS << EXC_CHFRINFO_EXCELXP2003 << EXC_CHFRINFO_EXCELXP2003 << sal_uInt16( 3 );
+ rStrm << sal_uInt16( 0x0850 ) << sal_uInt16( 0x085A ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x0861 ) << sal_uInt16( 0x086A ) << sal_uInt16( 0x086B );
+ rStrm.EndRecord();
+ }
+ // write all unwritten CHFRBLOCKBEGIN records
+ for( XclChFrBlockVector::const_iterator aIt = maUnwrittenFrBlocks.begin(), aEnd = maUnwrittenFrBlocks.end(); aIt != aEnd; ++aIt )
+ {
+ DBG_ASSERT( aIt->mnType != EXC_CHFRBLOCK_TYPE_UNKNOWN, "XclExpChRootData::InitializeFutureRecBlock - unknown future record block type" );
+ lclWriteChFrBlockRecord( rStrm, *aIt, true );
+ }
+ // move all record infos to vector of written blocks
+ maWrittenFrBlocks.insert( maWrittenFrBlocks.end(), maUnwrittenFrBlocks.begin(), maUnwrittenFrBlocks.end() );
+ maUnwrittenFrBlocks.clear();
+ }
+}
+
+void XclExpChRootData::FinalizeFutureRecBlock( XclExpStream& rStrm )
+{
+ DBG_ASSERT( !maUnwrittenFrBlocks.empty() || !maWrittenFrBlocks.empty(), "XclExpChRootData::FinalizeFutureRecBlock - no future record level found" );
+ if( !maUnwrittenFrBlocks.empty() )
+ {
+ // no future record has been written, just forget the topmost level
+ maUnwrittenFrBlocks.pop_back();
+ }
+ else if( !maWrittenFrBlocks.empty() )
+ {
+ // write the CHFRBLOCKEND record for the topmost block and delete it
+ lclWriteChFrBlockRecord( rStrm, maWrittenFrBlocks.back(), false );
+ maWrittenFrBlocks.pop_back();
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChRoot::XclExpChRoot( const XclExpRoot& rRoot, XclExpChChart& rChartData ) :
+ XclExpRoot( rRoot ),
+ mxChData( new XclExpChRootData( rChartData ) )
+{
+}
+
+XclExpChRoot::~XclExpChRoot()
+{
+}
+
+Reference< XChartDocument > XclExpChRoot::GetChartDocument() const
+{
+ return mxChData->mxChartDoc;
+}
+
+XclExpChChart& XclExpChRoot::GetChartData() const
+{
+ return mxChData->mrChartData;
+}
+
+const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
+{
+ return mxChData->mxTypeInfoProv->GetTypeInfo( eType );
+}
+
+const XclChTypeInfo& XclExpChRoot::GetChartTypeInfo( const OUString& rServiceName ) const
+{
+ return mxChData->mxTypeInfoProv->GetTypeInfoFromService( rServiceName );
+}
+
+const XclChFormatInfo& XclExpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
+{
+ return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType );
+}
+
+void XclExpChRoot::InitConversion( XChartDocRef xChartDoc, const Rectangle& rChartRect ) const
+{
+ mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect );
+}
+
+void XclExpChRoot::FinishConversion() const
+{
+ mxChData->FinishConversion();
+}
+
+bool XclExpChRoot::IsSystemColor( const Color& rColor, sal_uInt16 nSysColorIdx ) const
+{
+ XclExpPalette& rPal = GetPalette();
+ return rPal.IsSystemColor( nSysColorIdx ) && (rColor == rPal.GetDefColor( nSysColorIdx ));
+}
+
+void XclExpChRoot::SetSystemColor( Color& rColor, sal_uInt32& rnColorId, sal_uInt16 nSysColorIdx ) const
+{
+ DBG_ASSERT( GetPalette().IsSystemColor( nSysColorIdx ), "XclExpChRoot::SetSystemColor - invalid color index" );
+ rColor = GetPalette().GetDefColor( nSysColorIdx );
+ rnColorId = XclExpPalette::GetColorIdFromIndex( nSysColorIdx );
+}
+
+sal_Int32 XclExpChRoot::CalcChartXFromHmm( sal_Int32 nPosX ) const
+{
+ return ::limit_cast< sal_Int32, double >( (nPosX - mxChData->mnBorderGapX) / mxChData->mfUnitSizeX, 0, EXC_CHART_TOTALUNITS );
+}
+
+sal_Int32 XclExpChRoot::CalcChartYFromHmm( sal_Int32 nPosY ) const
+{
+ return ::limit_cast< sal_Int32, double >( (nPosY - mxChData->mnBorderGapY) / mxChData->mfUnitSizeY, 0, EXC_CHART_TOTALUNITS );
+}
+
+XclChRectangle XclExpChRoot::CalcChartRectFromHmm( const ::com::sun::star::awt::Rectangle& rRect ) const
+{
+ XclChRectangle aRect;
+ aRect.mnX = CalcChartXFromHmm( rRect.X );
+ aRect.mnY = CalcChartYFromHmm( rRect.Y );
+ aRect.mnWidth = CalcChartXFromHmm( rRect.Width );
+ aRect.mnHeight = CalcChartYFromHmm( rRect.Height );
+ return aRect;
+}
+
+void XclExpChRoot::ConvertLineFormat( XclChLineFormat& rLineFmt,
+ const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
+{
+ GetChartPropSetHelper().ReadLineProperties(
+ rLineFmt, *mxChData->mxLineDashTable, rPropSet, ePropMode );
+}
+
+bool XclExpChRoot::ConvertAreaFormat( XclChAreaFormat& rAreaFmt,
+ const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
+{
+ return GetChartPropSetHelper().ReadAreaProperties( rAreaFmt, rPropSet, ePropMode );
+}
+
+void XclExpChRoot::ConvertEscherFormat(
+ XclChEscherFormat& rEscherFmt, XclChPicFormat& rPicFmt,
+ const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode ) const
+{
+ GetChartPropSetHelper().ReadEscherProperties( rEscherFmt, rPicFmt,
+ *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable, rPropSet, ePropMode );
+}
+
+sal_uInt16 XclExpChRoot::ConvertFont( const ScfPropertySet& rPropSet, sal_Int16 nScript ) const
+{
+ XclFontData aFontData;
+ GetFontPropSetHelper().ReadFontProperties( aFontData, rPropSet, EXC_FONTPROPSET_CHART, nScript );
+ return GetFontBuffer().Insert( aFontData, EXC_COLOR_CHARTTEXT );
+}
+
+sal_uInt16 XclExpChRoot::ConvertPieRotation( const ScfPropertySet& rPropSet )
+{
+ sal_Int32 nApiRot = 0;
+ rPropSet.GetProperty( nApiRot, EXC_CHPROP_STARTINGANGLE );
+ return static_cast< sal_uInt16 >( (450 - (nApiRot % 360)) % 360 );
+}
+
+void XclExpChRoot::RegisterFutureRecBlock( const XclChFrBlock& rFrBlock )
+{
+ mxChData->RegisterFutureRecBlock( rFrBlock );
+}
+
+void XclExpChRoot::InitializeFutureRecBlock( XclExpStream& rStrm )
+{
+ mxChData->InitializeFutureRecBlock( rStrm );
+}
+
+void XclExpChRoot::FinalizeFutureRecBlock( XclExpStream& rStrm )
+{
+ mxChData->FinalizeFutureRecBlock( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChGroupBase::XclExpChGroupBase( const XclExpChRoot& rRoot,
+ sal_uInt16 nFrType, sal_uInt16 nRecId, sal_Size nRecSize ) :
+ XclExpRecord( nRecId, nRecSize ),
+ XclExpChRoot( rRoot ),
+ maFrBlock( nFrType )
+{
+}
+
+XclExpChGroupBase::~XclExpChGroupBase()
+{
+}
+
+void XclExpChGroupBase::Save( XclExpStream& rStrm )
+{
+ // header record
+ XclExpRecord::Save( rStrm );
+ // group records
+ if( HasSubRecords() )
+ {
+ // register the future record context corresponding to this record group
+ RegisterFutureRecBlock( maFrBlock );
+ // CHBEGIN record
+ XclExpEmptyRecord( EXC_ID_CHBEGIN ).Save( rStrm );
+ // embedded records
+ WriteSubRecords( rStrm );
+ // finalize the future records, must be done before the closing CHEND
+ FinalizeFutureRecBlock( rStrm );
+ // CHEND record
+ XclExpEmptyRecord( EXC_ID_CHEND ).Save( rStrm );
+ }
+}
+
+bool XclExpChGroupBase::HasSubRecords() const
+{
+ return true;
+}
+
+void XclExpChGroupBase::SetFutureRecordContext( sal_uInt16 nFrContext, sal_uInt16 nFrValue1, sal_uInt16 nFrValue2 )
+{
+ maFrBlock.mnContext = nFrContext;
+ maFrBlock.mnValue1 = nFrValue1;
+ maFrBlock.mnValue2 = nFrValue2;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChFutureRecordBase::XclExpChFutureRecordBase( const XclExpChRoot& rRoot,
+ XclFutureRecType eRecType, sal_uInt16 nRecId, sal_Size nRecSize ) :
+ XclExpFutureRecord( eRecType, nRecId, nRecSize ),
+ XclExpChRoot( rRoot )
+{
+}
+
+void XclExpChFutureRecordBase::Save( XclExpStream& rStrm )
+{
+ InitializeFutureRecBlock( rStrm );
+ XclExpFutureRecord::Save( rStrm );
+}
+
+// Frame formatting ===========================================================
+
+XclExpChFramePos::XclExpChFramePos( sal_uInt16 nTLMode, sal_uInt16 nBRMode ) :
+ XclExpRecord( EXC_ID_CHFRAMEPOS, 20 )
+{
+ maData.mnTLMode = nTLMode;
+ maData.mnBRMode = nBRMode;
+}
+
+void XclExpChFramePos::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnTLMode << maData.mnBRMode << maData.maRect;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChLineFormat::XclExpChLineFormat( const XclExpChRoot& rRoot ) :
+ XclExpRecord( EXC_ID_CHLINEFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 10 ),
+ mnColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
+{
+}
+
+void XclExpChLineFormat::SetDefault( XclChFrameType eDefFrameType )
+{
+ switch( eDefFrameType )
+ {
+ case EXC_CHFRAMETYPE_AUTO:
+ SetAuto( true );
+ break;
+ case EXC_CHFRAMETYPE_INVISIBLE:
+ SetAuto( false );
+ maData.mnPattern = EXC_CHLINEFORMAT_NONE;
+ break;
+ default:
+ DBG_ERRORFILE( "XclExpChLineFormat::SetDefault - unknown frame type" );
+ }
+}
+
+void XclExpChLineFormat::Convert( const XclExpChRoot& rRoot,
+ const ScfPropertySet& rPropSet, XclChObjectType eObjType )
+{
+ const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
+ rRoot.ConvertLineFormat( maData, rPropSet, rFmtInfo.mePropMode );
+ if( HasLine() )
+ {
+ // detect system color, set color identifier (TODO: detect automatic series line)
+ if( (eObjType != EXC_CHOBJTYPE_LINEARSERIES) && rRoot.IsSystemColor( maData.maColor, rFmtInfo.mnAutoLineColorIdx ) )
+ {
+ // store color index from automatic format data
+ mnColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoLineColorIdx );
+ // try to set automatic mode
+ bool bAuto = (maData.mnPattern == EXC_CHLINEFORMAT_SOLID) && (maData.mnWeight == rFmtInfo.mnAutoLineWeight);
+ ::set_flag( maData.mnFlags, EXC_CHLINEFORMAT_AUTO, bAuto );
+ }
+ else
+ {
+ // user defined color - register in palette
+ mnColorId = rRoot.GetPalette().InsertColor( maData.maColor, EXC_COLOR_CHARTLINE );
+ }
+ }
+ else
+ {
+ // no line - set default system color
+ rRoot.SetSystemColor( maData.maColor, mnColorId, EXC_COLOR_CHWINDOWTEXT );
+ }
+}
+
+bool XclExpChLineFormat::IsDefault( XclChFrameType eDefFrameType ) const
+{
+ return
+ ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasLine()) ||
+ ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
+}
+
+void XclExpChLineFormat::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.maColor << maData.mnPattern << maData.mnWeight << maData.mnFlags;
+ if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
+ rStrm << rStrm.GetRoot().GetPalette().GetColorIndex( mnColorId );
+}
+
+namespace {
+
+/** Creates a CHLINEFORMAT record from the passed property set. */
+XclExpChLineFormatRef lclCreateLineFormat( const XclExpChRoot& rRoot,
+ const ScfPropertySet& rPropSet, XclChObjectType eObjType )
+{
+ XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( rRoot ) );
+ xLineFmt->Convert( rRoot, rPropSet, eObjType );
+ const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
+ if( rFmtInfo.mbDeleteDefFrame && xLineFmt->IsDefault( rFmtInfo.meDefFrameType ) )
+ xLineFmt.reset();
+ return xLineFmt;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpChAreaFormat::XclExpChAreaFormat( const XclExpChRoot& rRoot ) :
+ XclExpRecord( EXC_ID_CHAREAFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 16 : 12 ),
+ mnPattColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
+ mnBackColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
+{
+}
+
+bool XclExpChAreaFormat::Convert( const XclExpChRoot& rRoot,
+ const ScfPropertySet& rPropSet, XclChObjectType eObjType )
+{
+ const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
+ bool bComplexFill = rRoot.ConvertAreaFormat( maData, rPropSet, rFmtInfo.mePropMode );
+ if( HasArea() )
+ {
+ bool bSolid = maData.mnPattern == EXC_PATT_SOLID;
+ // detect system color, set color identifier (TODO: detect automatic series area)
+ if( (eObjType != EXC_CHOBJTYPE_FILLEDSERIES) && rRoot.IsSystemColor( maData.maPattColor, rFmtInfo.mnAutoPattColorIdx ) )
+ {
+ // store color index from automatic format data
+ mnPattColorId = XclExpPalette::GetColorIdFromIndex( rFmtInfo.mnAutoPattColorIdx );
+ // set automatic mode
+ ::set_flag( maData.mnFlags, EXC_CHAREAFORMAT_AUTO, bSolid );
+ }
+ else
+ {
+ // user defined color - register color in palette
+ mnPattColorId = rRoot.GetPalette().InsertColor( maData.maPattColor, EXC_COLOR_CHARTAREA );
+ }
+ // background color (default system color for solid fills)
+ if( bSolid )
+ rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
+ else
+ mnBackColorId = rRoot.GetPalette().InsertColor( maData.maBackColor, EXC_COLOR_CHARTAREA );
+ }
+ else
+ {
+ // no area - set default system colors
+ rRoot.SetSystemColor( maData.maPattColor, mnPattColorId, EXC_COLOR_CHWINDOWBACK );
+ rRoot.SetSystemColor( maData.maBackColor, mnBackColorId, EXC_COLOR_CHWINDOWTEXT );
+ }
+ return bComplexFill;
+}
+
+void XclExpChAreaFormat::SetDefault( XclChFrameType eDefFrameType )
+{
+ switch( eDefFrameType )
+ {
+ case EXC_CHFRAMETYPE_AUTO:
+ SetAuto( true );
+ break;
+ case EXC_CHFRAMETYPE_INVISIBLE:
+ SetAuto( false );
+ maData.mnPattern = EXC_PATT_NONE;
+ break;
+ default:
+ DBG_ERRORFILE( "XclExpChAreaFormat::SetDefault - unknown frame type" );
+ }
+}
+
+bool XclExpChAreaFormat::IsDefault( XclChFrameType eDefFrameType ) const
+{
+ return
+ ((eDefFrameType == EXC_CHFRAMETYPE_INVISIBLE) && !HasArea()) ||
+ ((eDefFrameType == EXC_CHFRAMETYPE_AUTO) && IsAuto());
+}
+
+void XclExpChAreaFormat::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.maPattColor << maData.maBackColor << maData.mnPattern << maData.mnFlags;
+ if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
+ {
+ const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
+ rStrm << rPal.GetColorIndex( mnPattColorId ) << rPal.GetColorIndex( mnBackColorId );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChEscherFormat::XclExpChEscherFormat( const XclExpChRoot& rRoot ) :
+ XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_UNKNOWN, EXC_ID_CHESCHERFORMAT ),
+ mnColor1Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) ),
+ mnColor2Id( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
+{
+ DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF8 );
+}
+
+void XclExpChEscherFormat::Convert( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
+{
+ const XclChFormatInfo& rFmtInfo = GetFormatInfo( eObjType );
+ ConvertEscherFormat( maData, maPicFmt, rPropSet, rFmtInfo.mePropMode );
+ // register colors in palette
+ mnColor1Id = RegisterColor( ESCHER_Prop_fillColor );
+ mnColor2Id = RegisterColor( ESCHER_Prop_fillBackColor );
+}
+
+bool XclExpChEscherFormat::IsValid() const
+{
+ return maData.mxEscherSet;
+}
+
+void XclExpChEscherFormat::Save( XclExpStream& rStrm )
+{
+ if( maData.mxEscherSet )
+ {
+ // replace RGB colors with palette indexes in the Escher container
+ const XclExpPalette& rPal = GetPalette();
+ maData.mxEscherSet->AddOpt( ESCHER_Prop_fillColor, 0x08000000 | rPal.GetColorIndex( mnColor1Id ) );
+ maData.mxEscherSet->AddOpt( ESCHER_Prop_fillBackColor, 0x08000000 | rPal.GetColorIndex( mnColor2Id ) );
+
+ // save the record group
+ XclExpChGroupBase::Save( rStrm );
+ }
+}
+
+bool XclExpChEscherFormat::HasSubRecords() const
+{
+ // no subrecords for gradients
+ return maPicFmt.mnBmpMode != EXC_CHPICFORMAT_NONE;
+}
+
+void XclExpChEscherFormat::WriteSubRecords( XclExpStream& rStrm )
+{
+ rStrm.StartRecord( EXC_ID_CHPICFORMAT, 14 );
+ rStrm << maPicFmt.mnBmpMode << maPicFmt.mnFormat << maPicFmt.mnFlags << maPicFmt.mfScale;
+ rStrm.EndRecord();
+}
+
+sal_uInt32 XclExpChEscherFormat::RegisterColor( sal_uInt16 nPropId )
+{
+ sal_uInt32 nBGRValue;
+ if( maData.mxEscherSet && maData.mxEscherSet->GetOpt( nPropId, nBGRValue ) )
+ {
+ // swap red and blue
+ Color aColor( RGB_COLORDATA(
+ COLORDATA_BLUE( nBGRValue ),
+ COLORDATA_GREEN( nBGRValue ),
+ COLORDATA_RED( nBGRValue ) ) );
+ return GetPalette().InsertColor( aColor, EXC_COLOR_CHARTAREA );
+ }
+ return XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK );
+}
+
+void XclExpChEscherFormat::WriteBody( XclExpStream& rStrm )
+{
+ DBG_ASSERT( maData.mxEscherSet, "XclExpChEscherFormat::WriteBody - missing property container" );
+ // write Escher property container via temporary memory stream
+ SvMemoryStream aMemStrm;
+ maData.mxEscherSet->Commit( aMemStrm );
+ aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
+ rStrm.CopyFromStream( aMemStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChFrameBase::XclExpChFrameBase()
+{
+}
+
+XclExpChFrameBase::~XclExpChFrameBase()
+{
+}
+
+void XclExpChFrameBase::ConvertFrameBase( const XclExpChRoot& rRoot,
+ const ScfPropertySet& rPropSet, XclChObjectType eObjType )
+{
+ // line format
+ mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
+ mxLineFmt->Convert( rRoot, rPropSet, eObjType );
+ // area format (only for frame objects)
+ if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
+ {
+ mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
+ bool bComplexFill = mxAreaFmt->Convert( rRoot, rPropSet, eObjType );
+ if( (rRoot.GetBiff() == EXC_BIFF8) && bComplexFill )
+ {
+ mxEscherFmt.reset( new XclExpChEscherFormat( rRoot ) );
+ mxEscherFmt->Convert( rPropSet, eObjType );
+ if( mxEscherFmt->IsValid() )
+ mxAreaFmt->SetAuto( false );
+ else
+ mxEscherFmt.reset();
+ }
+ }
+}
+
+void XclExpChFrameBase::SetDefaultFrameBase( const XclExpChRoot& rRoot,
+ XclChFrameType eDefFrameType, bool bIsFrame )
+{
+ // line format
+ mxLineFmt.reset( new XclExpChLineFormat( rRoot ) );
+ mxLineFmt->SetDefault( eDefFrameType );
+ // area format (only for frame objects)
+ if( bIsFrame )
+ {
+ mxAreaFmt.reset( new XclExpChAreaFormat( rRoot ) );
+ mxAreaFmt->SetDefault( eDefFrameType );
+ mxEscherFmt.reset();
+ }
+}
+
+bool XclExpChFrameBase::IsDefaultFrameBase( XclChFrameType eDefFrameType ) const
+{
+ return
+ (!mxLineFmt || mxLineFmt->IsDefault( eDefFrameType )) &&
+ (!mxAreaFmt || mxAreaFmt->IsDefault( eDefFrameType ));
+}
+
+void XclExpChFrameBase::WriteFrameRecords( XclExpStream& rStrm )
+{
+ lclSaveRecord( rStrm, mxLineFmt );
+ lclSaveRecord( rStrm, mxAreaFmt );
+ lclSaveRecord( rStrm, mxEscherFmt );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChFrame::XclExpChFrame( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
+ XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_FRAME, EXC_ID_CHFRAME, 4 ),
+ meObjType( eObjType )
+{
+}
+
+void XclExpChFrame::Convert( const ScfPropertySet& rPropSet )
+{
+ ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
+}
+
+void XclExpChFrame::SetAutoFlags( bool bAutoPos, bool bAutoSize )
+{
+ ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOPOS, bAutoPos );
+ ::set_flag( maData.mnFlags, EXC_CHFRAME_AUTOSIZE, bAutoSize );
+}
+
+bool XclExpChFrame::IsDefault() const
+{
+ return IsDefaultFrameBase( GetFormatInfo( meObjType ).meDefFrameType );
+}
+
+bool XclExpChFrame::IsDeleteable() const
+{
+ return IsDefault() && GetFormatInfo( meObjType ).mbDeleteDefFrame;
+}
+
+void XclExpChFrame::Save( XclExpStream& rStrm )
+{
+ switch( meObjType )
+ {
+ // wall/floor frame without CHFRAME header record
+ case EXC_CHOBJTYPE_WALL3D:
+ case EXC_CHOBJTYPE_FLOOR3D:
+ WriteFrameRecords( rStrm );
+ break;
+ default:
+ XclExpChGroupBase::Save( rStrm );
+ }
+}
+
+void XclExpChFrame::WriteSubRecords( XclExpStream& rStrm )
+{
+ WriteFrameRecords( rStrm );
+}
+
+void XclExpChFrame::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnFormat << maData.mnFlags;
+}
+
+namespace {
+
+/** Creates a CHFRAME record from the passed property set. */
+XclExpChFrameRef lclCreateFrame( const XclExpChRoot& rRoot,
+ const ScfPropertySet& rPropSet, XclChObjectType eObjType )
+{
+ XclExpChFrameRef xFrame( new XclExpChFrame( rRoot, eObjType ) );
+ xFrame->Convert( rPropSet );
+ if( xFrame->IsDeleteable() )
+ xFrame.reset();
+ return xFrame;
+}
+
+} // namespace
+
+// Source links ===============================================================
+
+namespace {
+
+void lclAddDoubleRefData(
+ ScTokenArray& orArray, const FormulaToken& rToken,
+ SCsTAB nScTab1, SCsCOL nScCol1, SCsROW nScRow1,
+ SCsTAB nScTab2, SCsCOL nScCol2, SCsROW nScRow2 )
+{
+ ScComplexRefData aComplexRef;
+ aComplexRef.InitFlags();
+ aComplexRef.Ref1.SetFlag3D( true );
+ aComplexRef.Ref1.nTab = nScTab1;
+ aComplexRef.Ref1.nCol = nScCol1;
+ aComplexRef.Ref1.nRow = nScRow1;
+ aComplexRef.Ref2.nTab = nScTab2;
+ aComplexRef.Ref2.nCol = nScCol2;
+ aComplexRef.Ref2.nRow = nScRow2;
+
+ if( orArray.GetLen() > 0 )
+ orArray.AddOpCode( ocUnion );
+
+ DBG_ASSERT( (rToken.GetType() == ::formula::svDoubleRef) || (rToken.GetType() == ::formula::svExternalDoubleRef),
+ "lclAddDoubleRefData - double reference token expected");
+ if( rToken.GetType() == ::formula::svExternalDoubleRef )
+ orArray.AddExternalDoubleReference( rToken.GetIndex(), rToken.GetString(), aComplexRef );
+ else
+ orArray.AddDoubleReference( aComplexRef );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot& rRoot, sal_uInt8 nDestType ) :
+ XclExpRecord( EXC_ID_CHSOURCELINK ),
+ XclExpChRoot( rRoot )
+{
+ maData.mnDestType = nDestType;
+ maData.mnLinkType = EXC_CHSRCLINK_DIRECTLY;
+}
+
+sal_uInt16 XclExpChSourceLink::ConvertDataSequence( Reference< XDataSequence > xDataSeq, bool bSplitToColumns, sal_uInt16 nDefCount )
+{
+ mxLinkFmla.reset();
+ maData.mnLinkType = EXC_CHSRCLINK_DEFAULT;
+
+ if( !xDataSeq.is() )
+ return nDefCount;
+
+ // Compile the range representation string into token array. Note that the
+ // source range text depends on the current grammar.
+ OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation();
+ ScCompiler aComp( GetDocPtr(), ScAddress() );
+ aComp.SetGrammar( GetDocPtr()->GetGrammar() );
+ ScTokenArray* pArray = aComp.CompileString( aRangeRepr );
+ if( !pArray )
+ return nDefCount;
+
+ ScTokenArray aArray;
+ sal_uInt32 nValueCount = 0;
+ pArray->Reset();
+ for( const FormulaToken* pToken = pArray->First(); pToken; pToken = pArray->Next() )
+ {
+ switch( pToken->GetType() )
+ {
+ case ::formula::svSingleRef:
+ case ::formula::svExternalSingleRef:
+ // for a single ref token, just add it to the new token array as is
+ if( aArray.GetLen() > 0 )
+ aArray.AddOpCode( ocUnion );
+ aArray.AddToken( *pToken );
+ ++nValueCount;
+ break;
+
+ case ::formula::svDoubleRef:
+ case ::formula::svExternalDoubleRef:
+ {
+ // split 3-dimensional ranges into single sheets
+ const ScComplexRefData& rComplexRef = static_cast< const ScToken* >( pToken )->GetDoubleRef();
+ const ScSingleRefData& rRef1 = rComplexRef.Ref1;
+ const ScSingleRefData& rRef2 = rComplexRef.Ref2;
+ for( SCsTAB nScTab = rRef1.nTab; nScTab <= rRef2.nTab; ++nScTab )
+ {
+ // split 2-dimensional ranges into single columns
+ if( bSplitToColumns && (rRef1.nCol < rRef2.nCol) && (rRef1.nRow < rRef2.nRow) )
+ for( SCsCOL nScCol = rRef1.nCol; nScCol <= rRef2.nCol; ++nScCol )
+ lclAddDoubleRefData( aArray, *pToken, nScTab, nScCol, rRef1.nRow, nScTab, nScCol, rRef2.nRow );
+ else
+ lclAddDoubleRefData( aArray, *pToken, nScTab, rRef1.nCol, rRef1.nRow, nScTab, rRef2.nCol, rRef2.nRow );
+ }
+ sal_uInt32 nTabs = static_cast< sal_uInt32 >( rRef2.nTab - rRef1.nTab + 1 );
+ sal_uInt32 nCols = static_cast< sal_uInt32 >( rRef2.nCol - rRef1.nCol + 1 );
+ sal_uInt32 nRows = static_cast< sal_uInt32 >( rRef2.nRow - rRef1.nRow + 1 );
+ nValueCount += nCols * nRows * nTabs;
+ }
+ break;
+
+ default:;
+ }
+ }
+
+ const ScAddress aBaseCell;
+ mxLinkFmla = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aArray, &aBaseCell );
+ maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET;
+ return ulimit_cast< sal_uInt16 >( nValueCount, EXC_CHDATAFORMAT_MAXPOINTCOUNT );
+}
+
+sal_uInt16 XclExpChSourceLink::ConvertStringSequence( const Sequence< Reference< XFormattedString > >& rStringSeq )
+{
+ mxString.reset();
+ sal_uInt16 nFontIdx = EXC_FONT_APP;
+ if( rStringSeq.hasElements() )
+ {
+ mxString = XclExpStringHelper::CreateString( GetRoot(), String::EmptyString(), EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
+ Reference< XBreakIterator > xBreakIt = GetDoc().GetBreakIterator();
+ namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
+
+ // convert all formatted string entries from the sequence
+ const Reference< XFormattedString >* pBeg = rStringSeq.getConstArray();
+ const Reference< XFormattedString >* pEnd = pBeg + rStringSeq.getLength();
+ for( const Reference< XFormattedString >* pIt = pBeg; pIt != pEnd; ++pIt )
+ {
+ if( pIt->is() )
+ {
+ sal_uInt16 nWstrnFontIdx = EXC_FONT_NOTFOUND;
+ sal_uInt16 nAsianFontIdx = EXC_FONT_NOTFOUND;
+ sal_uInt16 nCmplxFontIdx = EXC_FONT_NOTFOUND;
+ OUString aText = (*pIt)->getString();
+ ScfPropertySet aStrProp( *pIt );
+
+ // #i63255# get script type for leading weak characters
+ sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( GetRoot(), aText );
+
+ // process all script portions
+ sal_Int32 nPortionPos = 0;
+ sal_Int32 nTextLen = aText.getLength();
+ while( nPortionPos < nTextLen )
+ {
+ // get script type and end position of next script portion
+ sal_Int16 nScript = xBreakIt->getScriptType( aText, nPortionPos );
+ sal_Int32 nPortionEnd = xBreakIt->endOfScript( aText, nPortionPos, nScript );
+
+ // reuse previous script for following weak portions
+ if( nScript == ApiScriptType::WEAK )
+ nScript = nLastScript;
+
+ // Excel start position of this portion
+ sal_uInt16 nXclPortionStart = mxString->Len();
+ // add portion text to Excel string
+ XclExpStringHelper::AppendString( *mxString, GetRoot(), aText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
+ if( nXclPortionStart < mxString->Len() )
+ {
+ // find font index variable dependent on script type
+ sal_uInt16& rnFontIdx = (nScript == ApiScriptType::COMPLEX) ? nCmplxFontIdx :
+ ((nScript == ApiScriptType::ASIAN) ? nAsianFontIdx : nWstrnFontIdx);
+
+ // insert font into buffer (if not yet done)
+ if( rnFontIdx == EXC_FONT_NOTFOUND )
+ rnFontIdx = ConvertFont( aStrProp, nScript );
+
+ // insert font index into format run vector
+ mxString->AppendFormat( nXclPortionStart, rnFontIdx );
+ }
+
+ // go to next script portion
+ nLastScript = nScript;
+ nPortionPos = nPortionEnd;
+ }
+ }
+ }
+ if( !mxString->IsEmpty() )
+ {
+ // get leading font index
+ const XclFormatRunVec& rFormats = mxString->GetFormats();
+ DBG_ASSERT( !rFormats.empty() && (rFormats.front().mnChar == 0),
+ "XclExpChSourceLink::ConvertStringSequenc - missing leading format" );
+ // remove leading format run, if entire string is equally formatted
+ if( rFormats.size() == 1 )
+ nFontIdx = mxString->RemoveLeadingFont();
+ else if( !rFormats.empty() )
+ nFontIdx = rFormats.front().mnFontIdx;
+ // add trailing format run, if string is rich-formatted
+ if( mxString->IsRich() )
+ mxString->AppendTrailingFormat( EXC_FONT_APP );
+ }
+ }
+ return nFontIdx;
+}
+
+void XclExpChSourceLink::ConvertNumFmt( const ScfPropertySet& rPropSet, bool bPercent )
+{
+ sal_Int32 nApiNumFmt = 0;
+ if( bPercent ? rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_PERCENTAGENUMFMT ) : rPropSet.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
+ {
+ ::set_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
+ maData.mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
+ }
+}
+
+void XclExpChSourceLink::AppendString( const String& rStr )
+{
+ if (!mxString)
+ return;
+ XclExpStringHelper::AppendString( *mxString, GetRoot(), rStr );
+}
+
+void XclExpChSourceLink::Save( XclExpStream& rStrm )
+{
+ // CHFORMATRUNS record
+ if( mxString && mxString->IsRich() )
+ {
+ sal_Size nRecSize = (1 + mxString->GetFormatsCount()) * ((GetBiff() == EXC_BIFF8) ? 2 : 1);
+ rStrm.StartRecord( EXC_ID_CHFORMATRUNS, nRecSize );
+ mxString->WriteFormats( rStrm, true );
+ rStrm.EndRecord();
+ }
+ // CHSOURCELINK record
+ XclExpRecord::Save( rStrm );
+ // CHSTRING record
+ if( mxString && !mxString->IsEmpty() )
+ {
+ rStrm.StartRecord( EXC_ID_CHSTRING, 2 + mxString->GetSize() );
+ rStrm << sal_uInt16( 0 ) << *mxString;
+ rStrm.EndRecord();
+ }
+}
+
+void XclExpChSourceLink::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnDestType
+ << maData.mnLinkType
+ << maData.mnFlags
+ << maData.mnNumFmtIdx
+ << mxLinkFmla;
+}
+
+// Text =======================================================================
+
+XclExpChFont::XclExpChFont( sal_uInt16 nFontIdx ) :
+ XclExpUInt16Record( EXC_ID_CHFONT, nFontIdx )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChObjectLink::XclExpChObjectLink( sal_uInt16 nLinkTarget, const XclChDataPointPos& rPointPos ) :
+ XclExpRecord( EXC_ID_CHOBJECTLINK, 6 )
+{
+ maData.mnTarget = nLinkTarget;
+ maData.maPointPos = rPointPos;
+}
+
+void XclExpChObjectLink::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnTarget << maData.maPointPos.mnSeriesIdx << maData.maPointPos.mnPointIdx;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChFrLabelProps::XclExpChFrLabelProps( const XclExpChRoot& rRoot ) :
+ XclExpChFutureRecordBase( rRoot, EXC_FUTUREREC_UNUSEDREF, EXC_ID_CHFRLABELPROPS, 4 )
+{
+}
+
+void XclExpChFrLabelProps::Convert( const ScfPropertySet& rPropSet, bool bShowSeries,
+ bool bShowCateg, bool bShowValue, bool bShowPercent, bool bShowBubble )
+{
+ // label value flags
+ ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWSERIES, bShowSeries );
+ ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWCATEG, bShowCateg );
+ ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWVALUE, bShowValue );
+ ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWPERCENT, bShowPercent );
+ ::set_flag( maData.mnFlags, EXC_CHFRLABELPROPS_SHOWBUBBLE, bShowBubble );
+
+ // label value separator
+ rPropSet.GetStringProperty( maData.maSeparator, EXC_CHPROP_LABELSEPARATOR );
+ if( maData.maSeparator.Len() == 0 )
+ maData.maSeparator = String( sal_Unicode( ' ' ) );
+}
+
+void XclExpChFrLabelProps::WriteBody( XclExpStream& rStrm )
+{
+ XclExpString aXclSep( maData.maSeparator, EXC_STR_FORCEUNICODE | EXC_STR_SMARTFLAGS );
+ rStrm << maData.mnFlags << aXclSep;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChFontBase::~XclExpChFontBase()
+{
+}
+
+void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, sal_uInt16 nFontIdx )
+{
+ if( const XclExpFont* pFont = rRoot.GetFontBuffer().GetFont( nFontIdx ) )
+ {
+ XclExpChFontRef xFont( new XclExpChFont( nFontIdx ) );
+ SetFont( xFont, pFont->GetFontData().maColor, pFont->GetFontColorId() );
+ }
+}
+
+void XclExpChFontBase::ConvertFontBase( const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet )
+{
+ ConvertFontBase( rRoot, rRoot.ConvertFont( rPropSet, rRoot.GetDefApiScript() ) );
+}
+
+void XclExpChFontBase::ConvertRotationBase(
+ const XclExpChRoot& rRoot, const ScfPropertySet& rPropSet, bool bSupportsStacked )
+{
+ sal_uInt16 nRotation = rRoot.GetChartPropSetHelper().ReadRotationProperties( rPropSet, bSupportsStacked );
+ SetRotation( nRotation );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChText::XclExpChText( const XclExpChRoot& rRoot ) :
+ XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TEXT, EXC_ID_CHTEXT, (rRoot.GetBiff() == EXC_BIFF8) ? 32 : 26 ),
+ mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
+{
+}
+
+void XclExpChText::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
+{
+ mxFont = xFont;
+ maData.maTextColor = rColor;
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, rColor == COL_AUTO );
+ mnTextColorId = nColorId;
+}
+
+void XclExpChText::SetRotation( sal_uInt16 nRotation )
+{
+ maData.mnRotation = nRotation;
+ ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 8, 3 );
+}
+
+void XclExpChText::ConvertTitle( Reference< XTitle > xTitle, sal_uInt16 nTarget, const String* pSubTitle )
+{
+ switch( nTarget )
+ {
+ case EXC_CHOBJLINK_TITLE: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_TITLE ); break;
+ case EXC_CHOBJLINK_YAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 1 ); break;
+ case EXC_CHOBJLINK_XAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 0 ); break;
+ case EXC_CHOBJLINK_ZAXIS: SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_AXISTITLE, 2 ); break;
+ }
+
+ mxSrcLink.reset();
+ mxObjLink.reset( new XclExpChObjectLink( nTarget, XclChDataPointPos( 0, 0 ) ) );
+
+ if( xTitle.is() )
+ {
+ // title frame formatting
+ ScfPropertySet aTitleProp( xTitle );
+ mxFrame = lclCreateFrame( GetChRoot(), aTitleProp, EXC_CHOBJTYPE_TEXT );
+
+ // string sequence
+ mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
+ sal_uInt16 nFontIdx = mxSrcLink->ConvertStringSequence( xTitle->getText() );
+ if (pSubTitle)
+ {
+ // append subtitle as the 2nd line of the title.
+ String aSubTitle = String::CreateFromAscii("\n");
+ aSubTitle.Append(*pSubTitle);
+ mxSrcLink->AppendString(aSubTitle);
+ }
+
+ ConvertFontBase( GetChRoot(), nFontIdx );
+
+ // rotation
+ ConvertRotationBase( GetChRoot(), aTitleProp, true );
+
+ // manual text position - only for main title
+ mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT, EXC_CHFRAMEPOS_PARENT ) );
+ if( nTarget == EXC_CHOBJLINK_TITLE )
+ {
+ Any aRelPos;
+ if( aTitleProp.GetAnyProperty( aRelPos, EXC_CHPROP_RELATIVEPOSITION ) && aRelPos.has< RelativePosition >() ) try
+ {
+ // calculate absolute position for CHTEXT record
+ Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
+ Reference< XShape > xTitleShape( xChart1Doc->getTitle(), UNO_SET_THROW );
+ ::com::sun::star::awt::Point aPos = xTitleShape->getPosition();
+ ::com::sun::star::awt::Size aSize = xTitleShape->getSize();
+ ::com::sun::star::awt::Rectangle aRect( aPos.X, aPos.Y, aSize.Width, aSize.Height );
+ maData.maRect = CalcChartRectFromHmm( aRect );
+ ::insert_value( maData.mnFlags2, EXC_CHTEXT_POS_MOVED, 0, 4 );
+ // manual title position implies manual plot area
+ GetChartData().SetManualPlotArea();
+ // calculate the default title position in chart units
+ sal_Int32 nDefPosX = ::std::max< sal_Int32 >( (EXC_CHART_TOTALUNITS - maData.maRect.mnWidth) / 2, 0 );
+ sal_Int32 nDefPosY = 85;
+ // set the position relative to the standard position
+ XclChRectangle& rFrameRect = mxFramePos->GetFramePosData().maRect;
+ rFrameRect.mnX = maData.maRect.mnX - nDefPosX;
+ rFrameRect.mnY = maData.maRect.mnY - nDefPosY;
+ }
+ catch( Exception& )
+ {
+ }
+ }
+ }
+ else
+ {
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED );
+ }
+}
+
+void XclExpChText::ConvertLegend( const ScfPropertySet& rPropSet )
+{
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOGEN );
+ ConvertFontBase( GetChRoot(), rPropSet );
+}
+
+bool XclExpChText::ConvertDataLabel( const ScfPropertySet& rPropSet,
+ const XclChTypeInfo& rTypeInfo, const XclChDataPointPos& rPointPos )
+{
+ SetFutureRecordContext( EXC_CHFRBLOCK_TEXT_DATALABEL, rPointPos.mnPointIdx, rPointPos.mnSeriesIdx );
+
+ cssc2::DataPointLabel aPointLabel;
+ if( !rPropSet.GetProperty( aPointLabel, EXC_CHPROP_LABEL ) )
+ return false;
+
+ // percentage only allowed in pie and donut charts
+ bool bIsPie = rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE;
+ // bubble sizes only allowed in bubble charts
+ bool bIsBubble = rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES;
+ DBG_ASSERT( (GetBiff() == EXC_BIFF8) || !bIsBubble, "XclExpChText::ConvertDataLabel - bubble charts only in BIFF8" );
+
+ // raw show flags
+ bool bShowValue = !bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
+ bool bShowPercent = bIsPie && aPointLabel.ShowNumberInPercent; // percentage only in pie/donut charts
+ bool bShowCateg = aPointLabel.ShowCategoryName;
+ bool bShowBubble = bIsBubble && aPointLabel.ShowNumber; // Chart2 uses 'ShowNumber' for bubble size
+ bool bShowAny = bShowValue || bShowPercent || bShowCateg || bShowBubble;
+
+ // create the CHFRLABELPROPS record for extended settings in BIFF8
+ if( bShowAny && (GetBiff() == EXC_BIFF8) )
+ {
+ mxLabelProps.reset( new XclExpChFrLabelProps( GetChRoot() ) );
+ mxLabelProps->Convert( rPropSet, false, bShowCateg, bShowValue, bShowPercent, bShowBubble );
+ }
+
+ // restrict to combinations allowed in CHTEXT
+ if( bShowPercent ) bShowValue = false; // percent wins over value
+ if( bShowValue ) bShowCateg = false; // value wins over category
+ if( bShowValue || bShowCateg ) bShowBubble = false; // value or category wins over bubble size
+
+ // set all flags
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bShowValue );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bShowPercent );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bShowCateg );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bShowPercent && bShowCateg );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWBUBBLE, bShowBubble );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL, bShowAny && aPointLabel.ShowLegendSymbol );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bShowAny );
+
+ if( bShowAny )
+ {
+ // font settings
+ ConvertFontBase( GetChRoot(), rPropSet );
+ ConvertRotationBase( GetChRoot(), rPropSet, false );
+ // label placement
+ sal_Int32 nPlacement = 0;
+ sal_uInt16 nLabelPos = EXC_CHTEXT_POS_AUTO;
+ if( rPropSet.GetProperty( nPlacement, EXC_CHPROP_LABELPLACEMENT ) )
+ {
+ using namespace cssc::DataLabelPlacement;
+ if( nPlacement == rTypeInfo.mnDefaultLabelPos )
+ {
+ nLabelPos = EXC_CHTEXT_POS_DEFAULT;
+ }
+ else switch( nPlacement )
+ {
+ case AVOID_OVERLAP: nLabelPos = EXC_CHTEXT_POS_AUTO; break;
+ case CENTER: nLabelPos = EXC_CHTEXT_POS_CENTER; break;
+ case TOP: nLabelPos = EXC_CHTEXT_POS_ABOVE; break;
+ case TOP_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
+ case LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
+ case BOTTOM_LEFT: nLabelPos = EXC_CHTEXT_POS_LEFT; break;
+ case BOTTOM: nLabelPos = EXC_CHTEXT_POS_BELOW; break;
+ case BOTTOM_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
+ case RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
+ case TOP_RIGHT: nLabelPos = EXC_CHTEXT_POS_RIGHT; break;
+ case INSIDE: nLabelPos = EXC_CHTEXT_POS_INSIDE; break;
+ case OUTSIDE: nLabelPos = EXC_CHTEXT_POS_OUTSIDE; break;
+ case NEAR_ORIGIN: nLabelPos = EXC_CHTEXT_POS_AXIS; break;
+ default: DBG_ERRORFILE( "XclExpChText::ConvertDataLabel - unknown label placement type" );
+ }
+ }
+ ::insert_value( maData.mnFlags2, nLabelPos, 0, 4 );
+ // source link (contains number format)
+ mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
+ if( bShowValue || bShowPercent )
+ // percentage format wins over value format
+ mxSrcLink->ConvertNumFmt( rPropSet, bShowPercent );
+ // object link
+ mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
+ }
+
+ /* Return true to indicate valid label settings:
+ - for existing labels at entire series
+ - for any settings at single data point (to be able to delete a point label) */
+ return bShowAny || (rPointPos.mnPointIdx != EXC_CHDATAFORMAT_ALLPOINTS);
+}
+
+void XclExpChText::ConvertTrendLineEquation( const ScfPropertySet& rPropSet, const XclChDataPointPos& rPointPos )
+{
+ // required flags
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOTEXT );
+ if( GetBiff() == EXC_BIFF8 )
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ); // must set this to make equation visible in Excel
+ // frame formatting
+ mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_TEXT );
+ // font settings
+ maData.mnHAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
+ maData.mnVAlign = EXC_CHTEXT_ALIGN_TOPLEFT;
+ ConvertFontBase( GetChRoot(), rPropSet );
+ // source link (contains number format)
+ mxSrcLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
+ mxSrcLink->ConvertNumFmt( rPropSet, false );
+ // object link
+ mxObjLink.reset( new XclExpChObjectLink( EXC_CHOBJLINK_DATA, rPointPos ) );
+}
+
+sal_uInt16 XclExpChText::GetAttLabelFlags() const
+{
+ sal_uInt16 nFlags = 0;
+ ::set_flag( nFlags, EXC_CHATTLABEL_SHOWVALUE, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE ) );
+ ::set_flag( nFlags, EXC_CHATTLABEL_SHOWPERCENT, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT ) );
+ ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEGPERC, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC ) );
+ ::set_flag( nFlags, EXC_CHATTLABEL_SHOWCATEG, ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG ) );
+ return nFlags;
+}
+
+void XclExpChText::WriteSubRecords( XclExpStream& rStrm )
+{
+ // CHFRAMEPOS record
+ lclSaveRecord( rStrm, mxFramePos );
+ // CHFONT record
+ lclSaveRecord( rStrm, mxFont );
+ // CHSOURCELINK group
+ lclSaveRecord( rStrm, mxSrcLink );
+ // CHFRAME group
+ lclSaveRecord( rStrm, mxFrame );
+ // CHOBJECTLINK record
+ lclSaveRecord( rStrm, mxObjLink );
+ // CHFRLABELPROPS record
+ lclSaveRecord( rStrm, mxLabelProps );
+}
+
+void XclExpChText::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnHAlign
+ << maData.mnVAlign
+ << maData.mnBackMode
+ << maData.maTextColor
+ << maData.maRect
+ << maData.mnFlags;
+
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ rStrm << GetPalette().GetColorIndex( mnTextColorId )
+ << maData.mnFlags2
+ << maData.mnRotation;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+/** Creates and returns an Excel text object from the passed title. */
+XclExpChTextRef lclCreateTitle( const XclExpChRoot& rRoot, Reference< XTitled > xTitled, sal_uInt16 nTarget,
+ const String* pSubTitle = NULL )
+{
+ Reference< XTitle > xTitle;
+ if( xTitled.is() )
+ xTitle = xTitled->getTitleObject();
+
+ XclExpChTextRef xText( new XclExpChText( rRoot ) );
+ xText->ConvertTitle( xTitle, nTarget, pSubTitle );
+ /* Do not delete the CHTEXT group for the main title. A missing CHTEXT
+ will be interpreted as auto-generated title showing the series title in
+ charts that contain exactly one data series. */
+ if( (nTarget != EXC_CHOBJLINK_TITLE) && !xText->HasString() )
+ xText.reset();
+
+ return xText;
+}
+
+}
+
+// Data series ================================================================
+
+XclExpChMarkerFormat::XclExpChMarkerFormat( const XclExpChRoot& rRoot ) :
+ XclExpRecord( EXC_ID_CHMARKERFORMAT, (rRoot.GetBiff() == EXC_BIFF8) ? 20 : 12 ),
+ mnLineColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) ),
+ mnFillColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWBACK ) )
+{
+}
+
+void XclExpChMarkerFormat::Convert( const XclExpChRoot& rRoot,
+ const ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx )
+{
+ rRoot.GetChartPropSetHelper().ReadMarkerProperties( maData, rPropSet, nFormatIdx );
+ /* Set marker line/fill color to series line color.
+ TODO: remove this if OOChart supports own colors in markers. */
+ Color aLineColor;
+ if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
+ maData.maLineColor = maData.maFillColor = aLineColor;
+ // register colors in palette
+ RegisterColors( rRoot );
+}
+
+void XclExpChMarkerFormat::ConvertStockSymbol( const XclExpChRoot& rRoot,
+ const ScfPropertySet& rPropSet, bool bCloseSymbol )
+{
+ // clear the automatic flag
+ ::set_flag( maData.mnFlags, EXC_CHMARKERFORMAT_AUTO, false );
+ // symbol type and color
+ if( bCloseSymbol )
+ {
+ // set symbol type for the 'close' data series
+ maData.mnMarkerType = EXC_CHMARKERFORMAT_DOWJ;
+ maData.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE;
+ // set symbol line/fill color to series line color
+ Color aLineColor;
+ if( rPropSet.GetColorProperty( aLineColor, EXC_CHPROP_COLOR ) )
+ {
+ maData.maLineColor = maData.maFillColor = aLineColor;
+ RegisterColors( rRoot );
+ }
+ }
+ else
+ {
+ // set invisible symbol
+ maData.mnMarkerType = EXC_CHMARKERFORMAT_NOSYMBOL;
+ }
+}
+
+void XclExpChMarkerFormat::RegisterColors( const XclExpChRoot& rRoot )
+{
+ if( HasMarker() )
+ {
+ if( HasLineColor() )
+ mnLineColorId = rRoot.GetPalette().InsertColor( maData.maLineColor, EXC_COLOR_CHARTLINE );
+ if( HasFillColor() )
+ mnFillColorId = rRoot.GetPalette().InsertColor( maData.maFillColor, EXC_COLOR_CHARTAREA );
+ }
+}
+
+void XclExpChMarkerFormat::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.maLineColor << maData.maFillColor << maData.mnMarkerType << maData.mnFlags;
+ if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
+ {
+ const XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
+ rStrm << rPal.GetColorIndex( mnLineColorId ) << rPal.GetColorIndex( mnFillColorId ) << maData.mnMarkerSize;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChPieFormat::XclExpChPieFormat() :
+ XclExpUInt16Record( EXC_ID_CHPIEFORMAT, 0 )
+{
+}
+
+void XclExpChPieFormat::Convert( const ScfPropertySet& rPropSet )
+{
+ double fApiDist(0.0);
+ if( rPropSet.GetProperty( fApiDist, EXC_CHPROP_OFFSET ) )
+ SetValue( limit_cast< sal_uInt16 >( fApiDist * 100.0, 0, 100 ) );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpCh3dDataFormat::XclExpCh3dDataFormat() :
+ XclExpRecord( EXC_ID_CH3DDATAFORMAT, 2 )
+{
+}
+
+void XclExpCh3dDataFormat::Convert( const ScfPropertySet& rPropSet )
+{
+ sal_Int32 nApiType(0);
+ if( rPropSet.GetProperty( nApiType, EXC_CHPROP_GEOMETRY3D ) )
+ {
+ using namespace cssc2::DataPointGeometry3D;
+ switch( nApiType )
+ {
+ case CUBOID:
+ maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
+ maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
+ break;
+ case PYRAMID:
+ maData.mnBase = EXC_CH3DDATAFORMAT_RECT;
+ maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
+ break;
+ case CYLINDER:
+ maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
+ maData.mnTop = EXC_CH3DDATAFORMAT_STRAIGHT;
+ break;
+ case CONE:
+ maData.mnBase = EXC_CH3DDATAFORMAT_CIRC;
+ maData.mnTop = EXC_CH3DDATAFORMAT_SHARP;
+ break;
+ default:
+ DBG_ERRORFILE( "XclExpCh3dDataFormat::Convert - unknown 3D bar format" );
+ }
+ }
+}
+
+void XclExpCh3dDataFormat::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnBase << maData.mnTop;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChAttachedLabel::XclExpChAttachedLabel( sal_uInt16 nFlags ) :
+ XclExpUInt16Record( EXC_ID_CHATTACHEDLABEL, nFlags )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChDataFormat::XclExpChDataFormat( const XclExpChRoot& rRoot,
+ const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx ) :
+ XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DATAFORMAT, EXC_ID_CHDATAFORMAT, 8 )
+{
+ maData.maPointPos = rPointPos;
+ maData.mnFormatIdx = nFormatIdx;
+}
+
+void XclExpChDataFormat::ConvertDataSeries( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo )
+{
+ // line and area formatting
+ ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType() );
+
+ // data point symbols
+ bool bIsFrame = rTypeInfo.IsSeriesFrameFormat();
+ if( !bIsFrame )
+ {
+ mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
+ mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx );
+ }
+
+ // pie segments
+ if( rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE )
+ {
+ mxPieFmt.reset( new XclExpChPieFormat );
+ mxPieFmt->Convert( rPropSet );
+ }
+
+ // 3D bars (only allowed for entire series in BIFF8)
+ if( IsSeriesFormat() && (GetBiff() == EXC_BIFF8) && rTypeInfo.mb3dChart && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR) )
+ {
+ mx3dDataFmt.reset( new XclExpCh3dDataFormat );
+ mx3dDataFmt->Convert( rPropSet );
+ }
+
+ // spline
+ if( IsSeriesFormat() && rTypeInfo.mbSpline && !bIsFrame )
+ mxSeriesFmt.reset( new XclExpUInt16Record( EXC_ID_CHSERIESFORMAT, EXC_CHSERIESFORMAT_SMOOTHED ) );
+
+ // data point labels
+ XclExpChTextRef xLabel( new XclExpChText( GetChRoot() ) );
+ if( xLabel->ConvertDataLabel( rPropSet, rTypeInfo, maData.maPointPos ) )
+ {
+ // CHTEXT groups for data labels are stored in global CHCHART group
+ GetChartData().SetDataLabel( xLabel );
+ mxAttLabel.reset( new XclExpChAttachedLabel( xLabel->GetAttLabelFlags() ) );
+ }
+}
+
+void XclExpChDataFormat::ConvertStockSeries( const ScfPropertySet& rPropSet, bool bCloseSymbol )
+{
+ // set line format to invisible
+ SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, false );
+ // set symbols to invisible or to 'close' series symbol
+ mxMarkerFmt.reset( new XclExpChMarkerFormat( GetChRoot() ) );
+ mxMarkerFmt->ConvertStockSymbol( GetChRoot(), rPropSet, bCloseSymbol );
+}
+
+void XclExpChDataFormat::ConvertLine( const ScfPropertySet& rPropSet, XclChObjectType eObjType )
+{
+ ConvertFrameBase( GetChRoot(), rPropSet, eObjType );
+}
+
+void XclExpChDataFormat::WriteSubRecords( XclExpStream& rStrm )
+{
+ lclSaveRecord( rStrm, mx3dDataFmt );
+ WriteFrameRecords( rStrm );
+ lclSaveRecord( rStrm, mxPieFmt );
+ lclSaveRecord( rStrm, mxMarkerFmt );
+ lclSaveRecord( rStrm, mxSeriesFmt );
+ lclSaveRecord( rStrm, mxAttLabel );
+}
+
+void XclExpChDataFormat::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.maPointPos.mnPointIdx
+ << maData.maPointPos.mnSeriesIdx
+ << maData.mnFormatIdx
+ << maData.mnFlags;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChSerTrendLine::XclExpChSerTrendLine( const XclExpChRoot& rRoot ) :
+ XclExpRecord( EXC_ID_CHSERTRENDLINE, 28 ),
+ XclExpChRoot( rRoot )
+{
+}
+
+bool XclExpChSerTrendLine::Convert( Reference< XRegressionCurve > xRegCurve, sal_uInt16 nSeriesIdx )
+{
+ if( !xRegCurve.is() )
+ return false;
+
+ // trend line type
+ ScfPropertySet aCurveProp( xRegCurve );
+ OUString aService = aCurveProp.GetServiceName();
+ if( aService == SERVICE_CHART2_LINEARREGCURVE )
+ {
+ maData.mnLineType = EXC_CHSERTREND_POLYNOMIAL;
+ maData.mnOrder = 1;
+ }
+ else if( aService == SERVICE_CHART2_EXPREGCURVE )
+ maData.mnLineType = EXC_CHSERTREND_EXPONENTIAL;
+ else if( aService == SERVICE_CHART2_LOGREGCURVE )
+ maData.mnLineType = EXC_CHSERTREND_LOGARITHMIC;
+ else if( aService == SERVICE_CHART2_POTREGCURVE )
+ maData.mnLineType = EXC_CHSERTREND_POWER;
+ else
+ return false;
+
+ // line formatting
+ XclChDataPointPos aPointPos( nSeriesIdx );
+ mxDataFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, 0 ) );
+ mxDataFmt->ConvertLine( aCurveProp, EXC_CHOBJTYPE_TRENDLINE );
+
+ // #i83100# show equation and correlation coefficient
+ ScfPropertySet aEquationProp( xRegCurve->getEquationProperties() );
+ maData.mnShowEquation = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWEQUATION ) ? 1 : 0;
+ maData.mnShowRSquared = aEquationProp.GetBoolProperty( EXC_CHPROP_SHOWCORRELATION ) ? 1 : 0;
+
+ // #i83100# formatting of the equation text box
+ if( (maData.mnShowEquation != 0) || (maData.mnShowRSquared != 0) )
+ {
+ mxLabel.reset( new XclExpChText( GetChRoot() ) );
+ mxLabel->ConvertTrendLineEquation( aEquationProp, aPointPos );
+ }
+
+ // missing features
+ // #i20819# polynomial trend lines
+ // #i66819# moving average trend lines
+ // #i5085# manual trend line size
+ // #i34093# manual crossing point
+ return true;
+}
+
+void XclExpChSerTrendLine::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnLineType
+ << maData.mnOrder
+ << maData.mfIntercept
+ << maData.mnShowEquation
+ << maData.mnShowRSquared
+ << maData.mfForecastFor
+ << maData.mfForecastBack;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChSerErrorBar::XclExpChSerErrorBar( const XclExpChRoot& rRoot, sal_uInt8 nBarType ) :
+ XclExpRecord( EXC_ID_CHSERERRORBAR, 14 ),
+ XclExpChRoot( rRoot )
+{
+ maData.mnBarType = nBarType;
+}
+
+bool XclExpChSerErrorBar::Convert( XclExpChSourceLink& rValueLink, sal_uInt16& rnValueCount, const ScfPropertySet& rPropSet )
+{
+ sal_Int32 nBarStyle = 0;
+ bool bOk = rPropSet.GetProperty( nBarStyle, EXC_CHPROP_ERRORBARSTYLE );
+ if( bOk )
+ {
+ switch( nBarStyle )
+ {
+ case cssc::ErrorBarStyle::ABSOLUTE:
+ maData.mnSourceType = EXC_CHSERERR_FIXED;
+ rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
+ break;
+ case cssc::ErrorBarStyle::RELATIVE:
+ maData.mnSourceType = EXC_CHSERERR_PERCENT;
+ rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_POSITIVEERROR );
+ break;
+ case cssc::ErrorBarStyle::STANDARD_DEVIATION:
+ maData.mnSourceType = EXC_CHSERERR_STDDEV;
+ rPropSet.GetProperty( maData.mfValue, EXC_CHPROP_WEIGHT );
+ break;
+ case cssc::ErrorBarStyle::STANDARD_ERROR:
+ maData.mnSourceType = EXC_CHSERERR_STDERR;
+ break;
+ case cssc::ErrorBarStyle::FROM_DATA:
+ {
+ bOk = false;
+ maData.mnSourceType = EXC_CHSERERR_CUSTOM;
+ Reference< XDataSource > xDataSource( rPropSet.GetApiPropertySet(), UNO_QUERY );
+ if( xDataSource.is() )
+ {
+ // find first sequence with current role
+ OUString aRole = XclChartHelper::GetErrorBarValuesRole( maData.mnBarType );
+ Reference< XDataSequence > xValueSeq;
+
+ Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
+ const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
+ const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
+ for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xValueSeq.is() && (pIt != pEnd); ++pIt )
+ {
+ Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
+ ScfPropertySet aValueProp( xTmpValueSeq );
+ OUString aCurrRole;
+ if( aValueProp.GetProperty( aCurrRole, EXC_CHPROP_ROLE ) && (aCurrRole == aRole) )
+ xValueSeq = xTmpValueSeq;
+ }
+ if( xValueSeq.is() )
+ {
+ // #i86465# pass value count back to series
+ rnValueCount = maData.mnValueCount = rValueLink.ConvertDataSequence( xValueSeq, true );
+ bOk = maData.mnValueCount > 0;
+ }
+ }
+ }
+ break;
+ default:
+ bOk = false;
+ }
+ }
+ return bOk;
+}
+
+void XclExpChSerErrorBar::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnBarType
+ << maData.mnSourceType
+ << maData.mnLineEnd
+ << sal_uInt8( 1 ) // must be 1 to make line visible
+ << maData.mfValue
+ << maData.mnValueCount;
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+/** Returns the property set of the specified data point. */
+ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_Int32 nPointIdx )
+{
+ ScfPropertySet aPropSet;
+ try
+ {
+ aPropSet.Set( xDataSeries->getDataPointByIndex( nPointIdx ) );
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "lclGetPointPropSet - no data point property set" );
+ }
+ return aPropSet;
+}
+
+} // namespace
+
+XclExpChSeries::XclExpChSeries( const XclExpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
+ XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_SERIES, EXC_ID_CHSERIES, (rRoot.GetBiff() == EXC_BIFF8) ? 12 : 8 ),
+ mnGroupIdx( EXC_CHSERGROUP_NONE ),
+ mnSeriesIdx( nSeriesIdx ),
+ mnParentIdx( EXC_CHSERIES_INVALID )
+{
+ // CHSOURCELINK records are always required, even if unused
+ mxTitleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_TITLE ) );
+ mxValueLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_VALUES ) );
+ mxCategLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_CATEGORY ) );
+ if( GetBiff() == EXC_BIFF8 )
+ mxBubbleLink.reset( new XclExpChSourceLink( GetChRoot(), EXC_CHSRCLINK_BUBBLES ) );
+}
+
+bool XclExpChSeries::ConvertDataSeries(
+ Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries,
+ const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx )
+{
+ bool bOk = false;
+ Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
+ if( xDataSource.is() )
+ {
+ Reference< XDataSequence > xYValueSeq, xTitleSeq, xXValueSeq, xBubbleSeq;
+
+ // find first sequence with role 'values-y'
+ Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
+ const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
+ const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
+ for( const Reference< XLabeledDataSequence >* pIt = pBeg; pIt != pEnd; ++pIt )
+ {
+ Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
+ ScfPropertySet aValueProp( xTmpValueSeq );
+ OUString aRole;
+ if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) )
+ {
+ if( !xYValueSeq.is() && (aRole == EXC_CHPROP_ROLE_YVALUES) )
+ {
+ xYValueSeq = xTmpValueSeq;
+ if( !xTitleSeq.is() )
+ xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
+ }
+ else if( !xXValueSeq.is() && !rTypeInfo.mbCategoryAxis && (aRole == EXC_CHPROP_ROLE_XVALUES) )
+ {
+ xXValueSeq = xTmpValueSeq;
+ }
+ else if( !xBubbleSeq.is() && (rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES) && (aRole == EXC_CHPROP_ROLE_SIZEVALUES) )
+ {
+ xBubbleSeq = xTmpValueSeq;
+ xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
+ }
+ }
+ }
+
+ bOk = xYValueSeq.is();
+ if( bOk )
+ {
+ // chart type group index
+ mnGroupIdx = nGroupIdx;
+
+ // convert source links
+ maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
+ mxTitleLink->ConvertDataSequence( xTitleSeq, true );
+
+ // X values of XY charts
+ maData.mnCategCount = mxCategLink->ConvertDataSequence( xXValueSeq, false, maData.mnValueCount );
+
+ // size values of bubble charts
+ if( mxBubbleLink )
+ mxBubbleLink->ConvertDataSequence( xBubbleSeq, false, maData.mnValueCount );
+
+ // series formatting
+ XclChDataPointPos aPointPos( mnSeriesIdx );
+ ScfPropertySet aSeriesProp( xDataSeries );
+ mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
+ mxSeriesFmt->ConvertDataSeries( aSeriesProp, rTypeInfo );
+
+ // trend lines
+ CreateTrendLines( xDataSeries );
+
+ // error bars
+ CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARX, EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
+ CreateErrorBars( aSeriesProp, EXC_CHPROP_ERRORBARY, EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
+
+ if( maData.mnValueCount > 0 )
+ {
+ const sal_Int32 nMaxPointCount = maData.mnValueCount;
+
+ /* #i91063# Create missing fill properties in pie/doughnut charts.
+ If freshly created (never saved to ODF), these charts show
+ varying point colors but do not return these points via API. */
+ if( xDiagram.is() && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE) )
+ {
+ Reference< XColorScheme > xColorScheme = xDiagram->getDefaultColorScheme();
+ if( xColorScheme.is() )
+ {
+ const OUString aFillStyleName = CREATE_OUSTRING( "FillStyle" );
+ const OUString aColorName = CREATE_OUSTRING( "Color" );
+ namespace cssd = ::com::sun::star::drawing;
+ for( sal_Int32 nPointIdx = 0; nPointIdx < nMaxPointCount; ++nPointIdx )
+ {
+ aPointPos.mnPointIdx = static_cast< sal_uInt16 >( nPointIdx );
+ ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
+ // test that the point fill style is solid, but no color is set
+ cssd::FillStyle eFillStyle = cssd::FillStyle_NONE;
+ if( aPointProp.GetProperty( eFillStyle, aFillStyleName ) &&
+ (eFillStyle == cssd::FillStyle_SOLID) &&
+ !aPointProp.HasProperty( aColorName ) )
+ {
+ aPointProp.SetProperty( aColorName, xColorScheme->getColorByIndex( nPointIdx ) );
+ }
+ }
+ }
+ }
+
+ // data point formatting
+ Sequence< sal_Int32 > aPointIndexes;
+ if( aSeriesProp.GetProperty( aPointIndexes, EXC_CHPROP_ATTRIBDATAPOINTS ) && aPointIndexes.hasElements() )
+ {
+ const sal_Int32* pnBeg = aPointIndexes.getConstArray();
+ const sal_Int32* pnEnd = pnBeg + aPointIndexes.getLength();
+ for( const sal_Int32* pnIt = pnBeg; (pnIt != pnEnd) && (*pnIt < nMaxPointCount); ++pnIt )
+ {
+ aPointPos.mnPointIdx = static_cast< sal_uInt16 >( *pnIt );
+ ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, *pnIt );
+ XclExpChDataFormatRef xPointFmt( new XclExpChDataFormat( GetChRoot(), aPointPos, nFormatIdx ) );
+ xPointFmt->ConvertDataSeries( aPointProp, rTypeInfo );
+ maPointFmts.AppendRecord( xPointFmt );
+ }
+ }
+ }
+ }
+ }
+ return bOk;
+}
+
+bool XclExpChSeries::ConvertStockSeries( XDataSeriesRef xDataSeries,
+ const OUString& rValueRole, sal_uInt16 nGroupIdx, sal_uInt16 nFormatIdx, bool bCloseSymbol )
+{
+ bool bOk = false;
+ Reference< XDataSource > xDataSource( xDataSeries, UNO_QUERY );
+ if( xDataSource.is() )
+ {
+ Reference< XDataSequence > xYValueSeq, xTitleSeq;
+
+ // find first sequence with passed role
+ Sequence< Reference< XLabeledDataSequence > > aLabeledSeqVec = xDataSource->getDataSequences();
+ const Reference< XLabeledDataSequence >* pBeg = aLabeledSeqVec.getConstArray();
+ const Reference< XLabeledDataSequence >* pEnd = pBeg + aLabeledSeqVec.getLength();
+ for( const Reference< XLabeledDataSequence >* pIt = pBeg; !xYValueSeq.is() && (pIt != pEnd); ++pIt )
+ {
+ Reference< XDataSequence > xTmpValueSeq = (*pIt)->getValues();
+ ScfPropertySet aValueProp( xTmpValueSeq );
+ OUString aRole;
+ if( aValueProp.GetProperty( aRole, EXC_CHPROP_ROLE ) && (aRole == rValueRole) )
+ {
+ xYValueSeq = xTmpValueSeq;
+ xTitleSeq = (*pIt)->getLabel(); // ignore role of label sequence
+ }
+ }
+
+ bOk = xYValueSeq.is();
+ if( bOk )
+ {
+ // chart type group index
+ mnGroupIdx = nGroupIdx;
+ // convert source links
+ maData.mnValueCount = mxValueLink->ConvertDataSequence( xYValueSeq, true );
+ mxTitleLink->ConvertDataSequence( xTitleSeq, true );
+ // series formatting
+ ScfPropertySet aSeriesProp( xDataSeries );
+ mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), nFormatIdx ) );
+ mxSeriesFmt->ConvertStockSeries( aSeriesProp, bCloseSymbol );
+ }
+ }
+ return bOk;
+}
+
+bool XclExpChSeries::ConvertTrendLine( const XclExpChSeries& rParent, Reference< XRegressionCurve > xRegCurve )
+{
+ InitFromParent( rParent );
+ mxTrendLine.reset( new XclExpChSerTrendLine( GetChRoot() ) );
+ bool bOk = mxTrendLine->Convert( xRegCurve, mnSeriesIdx );
+ if( bOk )
+ {
+ mxSeriesFmt = mxTrendLine->GetDataFormat();
+ GetChartData().SetDataLabel( mxTrendLine->GetDataLabel() );
+ }
+ return bOk;
+}
+
+bool XclExpChSeries::ConvertErrorBar( const XclExpChSeries& rParent, const ScfPropertySet& rPropSet, sal_uInt8 nBarId )
+{
+ InitFromParent( rParent );
+ // error bar settings
+ mxErrorBar.reset( new XclExpChSerErrorBar( GetChRoot(), nBarId ) );
+ bool bOk = mxErrorBar->Convert( *mxValueLink, maData.mnValueCount, rPropSet );
+ if( bOk )
+ {
+ // error bar formatting
+ mxSeriesFmt.reset( new XclExpChDataFormat( GetChRoot(), XclChDataPointPos( mnSeriesIdx ), 0 ) );
+ mxSeriesFmt->ConvertLine( rPropSet, EXC_CHOBJTYPE_ERRORBAR );
+ }
+ return bOk;
+}
+
+void XclExpChSeries::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
+{
+ if( xCategSeq.is() )
+ maData.mnCategCount = mxCategLink->ConvertDataSequence( xCategSeq->getValues(), false );
+}
+
+void XclExpChSeries::WriteSubRecords( XclExpStream& rStrm )
+{
+ lclSaveRecord( rStrm, mxTitleLink );
+ lclSaveRecord( rStrm, mxValueLink );
+ lclSaveRecord( rStrm, mxCategLink );
+ lclSaveRecord( rStrm, mxBubbleLink );
+ lclSaveRecord( rStrm, mxSeriesFmt );
+ maPointFmts.Save( rStrm );
+ if( mnGroupIdx != EXC_CHSERGROUP_NONE )
+ XclExpUInt16Record( EXC_ID_CHSERGROUP, mnGroupIdx ).Save( rStrm );
+ if( mnParentIdx != EXC_CHSERIES_INVALID )
+ XclExpUInt16Record( EXC_ID_CHSERPARENT, mnParentIdx ).Save( rStrm );
+ lclSaveRecord( rStrm, mxTrendLine );
+ lclSaveRecord( rStrm, mxErrorBar );
+}
+
+void XclExpChSeries::InitFromParent( const XclExpChSeries& rParent )
+{
+ // index to parent series is stored 1-based
+ mnParentIdx = rParent.mnSeriesIdx + 1;
+ /* #i86465# MSO2007 SP1 expects correct point counts in child series
+ (there was no problem in Excel2003 or Excel2007 without SP1...) */
+ maData.mnCategCount = rParent.maData.mnCategCount;
+ maData.mnValueCount = rParent.maData.mnValueCount;
+}
+
+void XclExpChSeries::CreateTrendLines( XDataSeriesRef xDataSeries )
+{
+ Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
+ if( xRegCurveCont.is() )
+ {
+ Sequence< Reference< XRegressionCurve > > aRegCurveSeq = xRegCurveCont->getRegressionCurves();
+ const Reference< XRegressionCurve >* pBeg = aRegCurveSeq.getConstArray();
+ const Reference< XRegressionCurve >* pEnd = pBeg + aRegCurveSeq.getLength();
+ for( const Reference< XRegressionCurve >* pIt = pBeg; pIt != pEnd; ++pIt )
+ {
+ XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
+ if( xSeries && !xSeries->ConvertTrendLine( *this, *pIt ) )
+ GetChartData().RemoveLastSeries();
+ }
+ }
+}
+
+void XclExpChSeries::CreateErrorBars( const ScfPropertySet& rPropSet,
+ const OUString& rBarPropName, sal_uInt8 nPosBarId, sal_uInt8 nNegBarId )
+{
+ Reference< XPropertySet > xErrorBar;
+ if( rPropSet.GetProperty( xErrorBar, rBarPropName ) && xErrorBar.is() )
+ {
+ ScfPropertySet aErrorProp( xErrorBar );
+ CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWPOSITIVEERROR, nPosBarId );
+ CreateErrorBar( aErrorProp, EXC_CHPROP_SHOWNEGATIVEERROR, nNegBarId );
+ }
+}
+
+void XclExpChSeries::CreateErrorBar( const ScfPropertySet& rPropSet,
+ const OUString& rShowPropName, sal_uInt8 nBarId )
+{
+ if( rPropSet.GetBoolProperty( rShowPropName ) )
+ {
+ XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
+ if( xSeries && !xSeries->ConvertErrorBar( *this, rPropSet, nBarId ) )
+ GetChartData().RemoveLastSeries();
+ }
+}
+
+void XclExpChSeries::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnCategType << maData.mnValueType << maData.mnCategCount << maData.mnValueCount;
+ if( GetBiff() == EXC_BIFF8 )
+ rStrm << maData.mnBubbleType << maData.mnBubbleCount;
+}
+
+// Chart type groups ==========================================================
+
+XclExpChType::XclExpChType( const XclExpChRoot& rRoot ) :
+ XclExpRecord( EXC_ID_CHUNKNOWN ),
+ XclExpChRoot( rRoot ),
+ maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
+{
+}
+
+void XclExpChType::Convert( Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
+ sal_Int32 nApiAxesSetIdx, bool bSwappedAxesSet, bool bHasXLabels )
+{
+ if( xChartType.is() )
+ {
+ maTypeInfo = GetChartTypeInfo( xChartType->getChartType() );
+ // special handling for some chart types
+ switch( maTypeInfo.meTypeCateg )
+ {
+ case EXC_CHTYPECATEG_BAR:
+ {
+ maTypeInfo = GetChartTypeInfo( bSwappedAxesSet ? EXC_CHTYPEID_HORBAR : EXC_CHTYPEID_BAR );
+ ::set_flag( maData.mnFlags, EXC_CHBAR_HORIZONTAL, bSwappedAxesSet );
+ ScfPropertySet aTypeProp( xChartType );
+ Sequence< sal_Int32 > aInt32Seq;
+ maData.mnOverlap = 0;
+ if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_OVERLAPSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
+ maData.mnOverlap = limit_cast< sal_Int16 >( -aInt32Seq[ nApiAxesSetIdx ], -100, 100 );
+ maData.mnGap = 150;
+ if( aTypeProp.GetProperty( aInt32Seq, EXC_CHPROP_GAPWIDTHSEQ ) && (nApiAxesSetIdx < aInt32Seq.getLength()) )
+ maData.mnGap = limit_cast< sal_uInt16 >( aInt32Seq[ nApiAxesSetIdx ], 0, 500 );
+ }
+ break;
+ case EXC_CHTYPECATEG_RADAR:
+ ::set_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS, bHasXLabels );
+ break;
+ case EXC_CHTYPECATEG_PIE:
+ {
+ ScfPropertySet aTypeProp( xChartType );
+ bool bDonut = aTypeProp.GetBoolProperty( EXC_CHPROP_USERINGS );
+ maTypeInfo = GetChartTypeInfo( bDonut ? EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
+ maData.mnPieHole = bDonut ? 50 : 0;
+ // #i85166# starting angle of first pie slice
+ ScfPropertySet aDiaProp( xDiagram );
+ maData.mnRotation = XclExpChRoot::ConvertPieRotation( aDiaProp );
+ }
+ break;
+ case EXC_CHTYPECATEG_SCATTER:
+ if( GetBiff() == EXC_BIFF8 )
+ ::set_flag( maData.mnFlags, EXC_CHSCATTER_BUBBLES, maTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES );
+ break;
+ default:;
+ }
+ SetRecId( maTypeInfo.mnRecId );
+ }
+}
+
+void XclExpChType::SetStacked( bool bPercent )
+{
+ switch( maTypeInfo.meTypeCateg )
+ {
+ case EXC_CHTYPECATEG_LINE:
+ ::set_flag( maData.mnFlags, EXC_CHLINE_STACKED );
+ ::set_flag( maData.mnFlags, EXC_CHLINE_PERCENT, bPercent );
+ break;
+ case EXC_CHTYPECATEG_BAR:
+ ::set_flag( maData.mnFlags, EXC_CHBAR_STACKED );
+ ::set_flag( maData.mnFlags, EXC_CHBAR_PERCENT, bPercent );
+ maData.mnOverlap = -100;
+ break;
+ default:;
+ }
+}
+
+void XclExpChType::WriteBody( XclExpStream& rStrm )
+{
+ switch( GetRecId() )
+ {
+ case EXC_ID_CHBAR:
+ rStrm << maData.mnOverlap << maData.mnGap << maData.mnFlags;
+ break;
+
+ case EXC_ID_CHLINE:
+ case EXC_ID_CHAREA:
+ case EXC_ID_CHRADARLINE:
+ case EXC_ID_CHRADARAREA:
+ rStrm << maData.mnFlags;
+ break;
+
+ case EXC_ID_CHPIE:
+ rStrm << maData.mnRotation << maData.mnPieHole;
+ if( GetBiff() == EXC_BIFF8 )
+ rStrm << maData.mnFlags;
+ break;
+
+ case EXC_ID_CHSCATTER:
+ if( GetBiff() == EXC_BIFF8 )
+ rStrm << maData.mnBubbleSize << maData.mnBubbleType << maData.mnFlags;
+ break;
+
+ default:
+ DBG_ERRORFILE( "XclExpChType::WriteBody - unknown chart type" );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChChart3d::XclExpChChart3d() :
+ XclExpRecord( EXC_ID_CHCHART3D, 14 )
+{
+}
+
+void XclExpChChart3d::Convert( const ScfPropertySet& rPropSet, bool b3dWallChart )
+{
+ sal_Int32 nRotationY = 0;
+ rPropSet.GetProperty( nRotationY, EXC_CHPROP_ROTATIONVERTICAL );
+ sal_Int32 nRotationX = 0;
+ rPropSet.GetProperty( nRotationX, EXC_CHPROP_ROTATIONHORIZONTAL );
+ sal_Int32 nPerspective = 15;
+ rPropSet.GetProperty( nPerspective, EXC_CHPROP_PERSPECTIVE );
+
+ if( b3dWallChart )
+ {
+ // Y rotation (Excel [0..359], Chart2 [-179,180])
+ if( nRotationY < 0 ) nRotationY += 360;
+ maData.mnRotation = static_cast< sal_uInt16 >( nRotationY );
+ // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
+ maData.mnElevation = limit_cast< sal_Int16 >( nRotationX, -90, 90 );
+ // perspective (Excel and Chart2 [0,100])
+ maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
+ // flags
+ maData.mnFlags = 0;
+ ::set_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D, !rPropSet.GetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES ) );
+ ::set_flag( maData.mnFlags, EXC_CHCHART3D_AUTOHEIGHT );
+ ::set_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS );
+ }
+ else
+ {
+ // Y rotation not used in pie charts, but 'first pie slice angle'
+ maData.mnRotation = XclExpChRoot::ConvertPieRotation( rPropSet );
+ // X rotation a.k.a. elevation (map Chart2 [-80,-10] to Excel [10..80])
+ maData.mnElevation = limit_cast< sal_Int16 >( (nRotationX + 270) % 180, 10, 80 );
+ // perspective (Excel and Chart2 [0,100])
+ maData.mnEyeDist = limit_cast< sal_uInt16 >( nPerspective, 0, 100 );
+ // flags
+ maData.mnFlags = 0;
+ }
+}
+
+void XclExpChChart3d::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnRotation
+ << maData.mnElevation
+ << maData.mnEyeDist
+ << maData.mnRelHeight
+ << maData.mnRelDepth
+ << maData.mnDepthGap
+ << maData.mnFlags;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChLegend::XclExpChLegend( const XclExpChRoot& rRoot ) :
+ XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_LEGEND, EXC_ID_CHLEGEND, 20 )
+{
+}
+
+void XclExpChLegend::Convert( const ScfPropertySet& rPropSet )
+{
+ // frame properties
+ mxFrame = lclCreateFrame( GetChRoot(), rPropSet, EXC_CHOBJTYPE_LEGEND );
+ // text properties
+ mxText.reset( new XclExpChText( GetChRoot() ) );
+ mxText->ConvertLegend( rPropSet );
+
+ // legend position and size
+ Any aRelPosAny, aRelSizeAny;
+ rPropSet.GetAnyProperty( aRelPosAny, EXC_CHPROP_RELATIVEPOSITION );
+ rPropSet.GetAnyProperty( aRelSizeAny, EXC_CHPROP_RELATIVESIZE );
+ cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
+ rPropSet.GetProperty( eApiExpand, EXC_CHPROP_EXPANSION );
+ if( aRelPosAny.has< RelativePosition >() || ((eApiExpand == cssc::ChartLegendExpansion_CUSTOM) && aRelSizeAny.has< RelativeSize >()) )
+ {
+ try
+ {
+ /* The 'RelativePosition' or 'RelativeSize' properties are used as
+ indicator of manually changed legend position/size, but due to
+ the different anchor modes used by this property (in the
+ RelativePosition.Anchor member) it cannot be used to calculate
+ the position easily. For this, the Chart1 API will be used
+ instead. */
+ Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
+ Reference< XShape > xChart1Legend( xChart1Doc->getLegend(), UNO_SET_THROW );
+ // coordinates in CHLEGEND record written but not used by Excel
+ mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_CHARTSIZE, EXC_CHFRAMEPOS_PARENT ) );
+ XclChFramePos& rFramePos = mxFramePos->GetFramePosData();
+ rFramePos.mnTLMode = EXC_CHFRAMEPOS_CHARTSIZE;
+ ::com::sun::star::awt::Point aLegendPos = xChart1Legend->getPosition();
+ rFramePos.maRect.mnX = maData.maRect.mnX = CalcChartXFromHmm( aLegendPos.X );
+ rFramePos.maRect.mnY = maData.maRect.mnY = CalcChartYFromHmm( aLegendPos.Y );
+ // legend size, Excel expects points in CHFRAMEPOS record
+ rFramePos.mnBRMode = EXC_CHFRAMEPOS_ABSSIZE_POINTS;
+ ::com::sun::star::awt::Size aLegendSize = xChart1Legend->getSize();
+ rFramePos.maRect.mnWidth = static_cast< sal_uInt16 >( aLegendSize.Width * EXC_POINTS_PER_HMM + 0.5 );
+ rFramePos.maRect.mnHeight = static_cast< sal_uInt16 >( aLegendSize.Height * EXC_POINTS_PER_HMM + 0.5 );
+ maData.maRect.mnWidth = CalcChartXFromHmm( aLegendSize.Width );
+ maData.maRect.mnHeight = CalcChartYFromHmm( aLegendSize.Height );
+ eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
+ // manual legend position implies manual plot area
+ GetChartData().SetManualPlotArea();
+ maData.mnDockMode = EXC_CHLEGEND_NOTDOCKED;
+ // a CHFRAME record with cleared auto flags is needed
+ if( !mxFrame )
+ mxFrame.reset( new XclExpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
+ mxFrame->SetAutoFlags( false, false );
+ }
+ catch( Exception& )
+ {
+ OSL_FAIL( "XclExpChLegend::Convert - cannot get legend shape" );
+ maData.mnDockMode = EXC_CHLEGEND_RIGHT;
+ eApiExpand = cssc::ChartLegendExpansion_HIGH;
+ }
+ }
+ else
+ {
+ cssc2::LegendPosition eApiPos = cssc2::LegendPosition_CUSTOM;
+ rPropSet.GetProperty( eApiPos, EXC_CHPROP_ANCHORPOSITION );
+ switch( eApiPos )
+ {
+ case cssc2::LegendPosition_LINE_START: maData.mnDockMode = EXC_CHLEGEND_LEFT; break;
+ case cssc2::LegendPosition_LINE_END: maData.mnDockMode = EXC_CHLEGEND_RIGHT; break;
+ case cssc2::LegendPosition_PAGE_START: maData.mnDockMode = EXC_CHLEGEND_TOP; break;
+ case cssc2::LegendPosition_PAGE_END: maData.mnDockMode = EXC_CHLEGEND_BOTTOM; break;
+ default:
+ OSL_FAIL( "XclExpChLegend::Convert - unrecognized legend position" );
+ maData.mnDockMode = EXC_CHLEGEND_RIGHT;
+ eApiExpand = cssc::ChartLegendExpansion_HIGH;
+ }
+ }
+ ::set_flag( maData.mnFlags, EXC_CHLEGEND_STACKED, eApiExpand == cssc::ChartLegendExpansion_HIGH );
+
+ // other flags
+ ::set_flag( maData.mnFlags, EXC_CHLEGEND_AUTOSERIES );
+ const sal_uInt16 nAutoFlags = EXC_CHLEGEND_DOCKED | EXC_CHLEGEND_AUTOPOSX | EXC_CHLEGEND_AUTOPOSY;
+ ::set_flag( maData.mnFlags, nAutoFlags, maData.mnDockMode != EXC_CHLEGEND_NOTDOCKED );
+}
+
+void XclExpChLegend::WriteSubRecords( XclExpStream& rStrm )
+{
+ lclSaveRecord( rStrm, mxFramePos );
+ lclSaveRecord( rStrm, mxText );
+ lclSaveRecord( rStrm, mxFrame );
+}
+
+void XclExpChLegend::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.maRect << maData.mnDockMode << maData.mnSpacing << maData.mnFlags;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChDropBar::XclExpChDropBar( const XclExpChRoot& rRoot, XclChObjectType eObjType ) :
+ XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_DROPBAR, EXC_ID_CHDROPBAR, 2 ),
+ meObjType( eObjType ),
+ mnBarDist( 100 )
+{
+}
+
+void XclExpChDropBar::Convert( const ScfPropertySet& rPropSet )
+{
+ if( rPropSet.Is() )
+ ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
+ else
+ SetDefaultFrameBase( GetChRoot(), EXC_CHFRAMETYPE_INVISIBLE, true );
+}
+
+void XclExpChDropBar::WriteSubRecords( XclExpStream& rStrm )
+{
+ WriteFrameRecords( rStrm );
+}
+
+void XclExpChDropBar::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << mnBarDist;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChTypeGroup::XclExpChTypeGroup( const XclExpChRoot& rRoot, sal_uInt16 nGroupIdx ) :
+ XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_TYPEGROUP, EXC_ID_CHTYPEGROUP, 20 ),
+ maType( rRoot ),
+ maTypeInfo( maType.GetTypeInfo() )
+{
+ maData.mnGroupIdx = nGroupIdx;
+}
+
+void XclExpChTypeGroup::ConvertType(
+ Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
+ sal_Int32 nApiAxesSetIdx, bool b3dChart, bool bSwappedAxesSet, bool bHasXLabels )
+{
+ // chart type settings
+ maType.Convert( xDiagram, xChartType, nApiAxesSetIdx, bSwappedAxesSet, bHasXLabels );
+
+ // spline - TODO: get from single series (#i66858#)
+ ScfPropertySet aTypeProp( xChartType );
+ cssc2::CurveStyle eCurveStyle;
+ bool bSpline = aTypeProp.GetProperty( eCurveStyle, EXC_CHPROP_CURVESTYLE ) &&
+ (eCurveStyle != cssc2::CurveStyle_LINES);
+
+ // extended type info
+ maTypeInfo.Set( maType.GetTypeInfo(), b3dChart, bSpline );
+
+ // 3d chart settings
+ if( maTypeInfo.mb3dChart ) // only true, if Excel chart supports 3d mode
+ {
+ mxChart3d.reset( new XclExpChChart3d );
+ ScfPropertySet aDiaProp( xDiagram );
+ mxChart3d->Convert( aDiaProp, Is3dWallChart() );
+ }
+}
+
+void XclExpChTypeGroup::ConvertSeries(
+ Reference< XDiagram > xDiagram, Reference< XChartType > xChartType,
+ sal_Int32 nGroupAxesSetIdx, bool bPercent, bool bConnectBars )
+{
+ Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
+ if( xSeriesCont.is() )
+ {
+ typedef ::std::vector< Reference< XDataSeries > > XDataSeriesVec;
+ XDataSeriesVec aSeriesVec;
+
+ // copy data series attached to the current axes set to the vector
+ Sequence< Reference< XDataSeries > > aSeriesSeq = xSeriesCont->getDataSeries();
+ const Reference< XDataSeries >* pBeg = aSeriesSeq.getConstArray();
+ const Reference< XDataSeries >* pEnd = pBeg + aSeriesSeq.getLength();
+ for( const Reference< XDataSeries >* pIt = pBeg; pIt != pEnd; ++pIt )
+ {
+ ScfPropertySet aSeriesProp( *pIt );
+ sal_Int32 nSeriesAxesSetIdx(0);
+ if( aSeriesProp.GetProperty( nSeriesAxesSetIdx, EXC_CHPROP_ATTAXISINDEX ) && (nSeriesAxesSetIdx == nGroupAxesSetIdx) )
+ aSeriesVec.push_back( *pIt );
+ }
+
+ // Are there any series in the current axes set?
+ if( !aSeriesVec.empty() )
+ {
+ // stacking direction (stacked/percent/deep 3d) from first series
+ ScfPropertySet aSeriesProp( aSeriesVec.front() );
+ cssc2::StackingDirection eStacking;
+ if( !aSeriesProp.GetProperty( eStacking, EXC_CHPROP_STACKINGDIR ) )
+ eStacking = cssc2::StackingDirection_NO_STACKING;
+
+ // stacked or percent chart
+ if( maTypeInfo.mbSupportsStacking && (eStacking == cssc2::StackingDirection_Y_STACKING) )
+ {
+ // percent overrides simple stacking
+ maType.SetStacked( bPercent );
+
+ // connected data points (only in stacked bar charts)
+ if (bConnectBars && (maTypeInfo.meTypeCateg == EXC_CHTYPECATEG_BAR))
+ {
+ sal_uInt16 nKey = EXC_CHCHARTLINE_CONNECT;
+ maChartLines.insert(nKey, new XclExpChLineFormat(GetChRoot()));
+ }
+ }
+ else
+ {
+ // reverse series order for some unstacked 2D chart types
+ if( maTypeInfo.mbReverseSeries && !Is3dChart() )
+ ::std::reverse( aSeriesVec.begin(), aSeriesVec.end() );
+ }
+
+ // deep 3d chart or clustered 3d chart (stacked is not clustered)
+ if( (eStacking == cssc2::StackingDirection_NO_STACKING) && Is3dWallChart() )
+ mxChart3d->SetClustered();
+
+ // varied point colors
+ ::set_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS, aSeriesProp.GetBoolProperty( EXC_CHPROP_VARYCOLORSBY ) );
+
+ // process all series
+ for( XDataSeriesVec::const_iterator aIt = aSeriesVec.begin(), aEnd = aSeriesVec.end(); aIt != aEnd; ++aIt )
+ {
+ // create Excel series object, stock charts need special processing
+ if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
+ CreateAllStockSeries( xChartType, *aIt );
+ else
+ CreateDataSeries( xDiagram, *aIt );
+ }
+ }
+ }
+}
+
+void XclExpChTypeGroup::ConvertCategSequence( Reference< XLabeledDataSequence > xCategSeq )
+{
+ for( size_t nIdx = 0, nSize = maSeries.GetSize(); nIdx < nSize; ++nIdx )
+ maSeries.GetRecord( nIdx )->ConvertCategSequence( xCategSeq );
+}
+
+void XclExpChTypeGroup::ConvertLegend( const ScfPropertySet& rPropSet )
+{
+ if( rPropSet.GetBoolProperty( EXC_CHPROP_SHOW ) )
+ {
+ mxLegend.reset( new XclExpChLegend( GetChRoot() ) );
+ mxLegend->Convert( rPropSet );
+ }
+}
+
+void XclExpChTypeGroup::WriteSubRecords( XclExpStream& rStrm )
+{
+ maType.Save( rStrm );
+ lclSaveRecord( rStrm, mxChart3d );
+ lclSaveRecord( rStrm, mxLegend );
+ lclSaveRecord( rStrm, mxUpBar );
+ lclSaveRecord( rStrm, mxDownBar );
+ for( XclExpChLineFormatMap::iterator aLIt = maChartLines.begin(), aLEnd = maChartLines.end(); aLIt != aLEnd; ++aLIt )
+ lclSaveRecord( rStrm, aLIt->second, EXC_ID_CHCHARTLINE, aLIt->first );
+}
+
+sal_uInt16 XclExpChTypeGroup::GetFreeFormatIdx() const
+{
+ return static_cast< sal_uInt16 >( maSeries.GetSize() );
+}
+
+void XclExpChTypeGroup::CreateDataSeries(
+ Reference< XDiagram > xDiagram, Reference< XDataSeries > xDataSeries )
+{
+ // let chart create series object with correct series index
+ XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
+ if( xSeries )
+ {
+ if( xSeries->ConvertDataSeries( xDiagram, xDataSeries, maTypeInfo, GetGroupIdx(), GetFreeFormatIdx() ) )
+ maSeries.AppendRecord( xSeries );
+ else
+ GetChartData().RemoveLastSeries();
+ }
+}
+
+void XclExpChTypeGroup::CreateAllStockSeries(
+ Reference< XChartType > xChartType, Reference< XDataSeries > xDataSeries )
+{
+ // create existing series objects
+ bool bHasOpen = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_OPENVALUES, false );
+ bool bHasHigh = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_HIGHVALUES, false );
+ bool bHasLow = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_LOWVALUES, false );
+ bool bHasClose = CreateStockSeries( xDataSeries, EXC_CHPROP_ROLE_CLOSEVALUES, !bHasOpen );
+
+ // formatting of special stock chart elements
+ ScfPropertySet aTypeProp( xChartType );
+ // hi-lo lines
+ if( bHasHigh && bHasLow && aTypeProp.GetBoolProperty( EXC_CHPROP_SHOWHIGHLOW ) )
+ {
+ ScfPropertySet aSeriesProp( xDataSeries );
+ XclExpChLineFormatRef xLineFmt( new XclExpChLineFormat( GetChRoot() ) );
+ xLineFmt->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
+ sal_uInt16 nKey = EXC_CHCHARTLINE_HILO;
+ maChartLines.insert(nKey, new XclExpChLineFormat(GetChRoot()));
+ }
+ // dropbars
+ if( bHasOpen && bHasClose )
+ {
+ // dropbar type is dependent on position in the file - always create both
+ Reference< XPropertySet > xWhitePropSet, xBlackPropSet;
+ // white dropbar format
+ aTypeProp.GetProperty( xWhitePropSet, EXC_CHPROP_WHITEDAY );
+ ScfPropertySet aWhiteProp( xWhitePropSet );
+ mxUpBar.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_WHITEDROPBAR ) );
+ mxUpBar->Convert( aWhiteProp );
+ // black dropbar format
+ aTypeProp.GetProperty( xBlackPropSet, EXC_CHPROP_BLACKDAY );
+ ScfPropertySet aBlackProp( xBlackPropSet );
+ mxDownBar.reset( new XclExpChDropBar( GetChRoot(), EXC_CHOBJTYPE_BLACKDROPBAR ) );
+ mxDownBar->Convert( aBlackProp );
+ }
+}
+
+bool XclExpChTypeGroup::CreateStockSeries( Reference< XDataSeries > xDataSeries,
+ const OUString& rValueRole, bool bCloseSymbol )
+{
+ bool bOk = false;
+ // let chart create series object with correct series index
+ XclExpChSeriesRef xSeries = GetChartData().CreateSeries();
+ if( xSeries )
+ {
+ bOk = xSeries->ConvertStockSeries( xDataSeries,
+ rValueRole, GetGroupIdx(), GetFreeFormatIdx(), bCloseSymbol );
+ if( bOk )
+ maSeries.AppendRecord( xSeries );
+ else
+ GetChartData().RemoveLastSeries();
+ }
+ return bOk;
+}
+
+void XclExpChTypeGroup::WriteBody( XclExpStream& rStrm )
+{
+ rStrm.WriteZeroBytes( 16 );
+ rStrm << maData.mnFlags << maData.mnGroupIdx;
+}
+
+// Axes =======================================================================
+
+XclExpChLabelRange::XclExpChLabelRange( const XclExpChRoot& rRoot ) :
+ XclExpRecord( EXC_ID_CHLABELRANGE, 8 ),
+ XclExpChRoot( rRoot )
+{
+}
+
+void XclExpChLabelRange::Convert( const ScaleData& rScaleData, const ScfPropertySet& rChart1Axis, bool bMirrorOrient )
+{
+ /* Base time unit (using the property 'ExplicitTimeIncrement' from the old
+ chart API allows to detect axis type (date axis, if property exists),
+ and to receive the base time unit currently used in case the base time
+ unit is set to 'automatic'. */
+ cssc::TimeIncrement aTimeIncrement;
+ if( rChart1Axis.GetProperty( aTimeIncrement, EXC_CHPROP_EXPTIMEINCREMENT ) )
+ {
+ // property exists -> this is a date axis currently
+ ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS );
+
+ // automatic base time unit, if the UNO Any 'rScaleData.TimeIncrement.TimeResolution' does not contain a valid value...
+ bool bAutoBase = !rScaleData.TimeIncrement.TimeResolution.has< cssc::TimeIncrement >();
+ ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE, bAutoBase );
+
+ // ...but get the current base time unit from the property of the old chart API
+ sal_Int32 nApiTimeUnit = 0;
+ bool bValidBaseUnit = aTimeIncrement.TimeResolution >>= nApiTimeUnit;
+ DBG_ASSERT( bValidBaseUnit, "XclExpChLabelRange::Convert - cannot ghet base time unit" );
+ maDateData.mnBaseUnit = bValidBaseUnit ? lclGetTimeUnit( nApiTimeUnit ) : EXC_CHDATERANGE_DAYS;
+
+ /* Min/max values depend on base time unit, they specify the number of
+ days, months, or years starting from null date. */
+ bool bAutoMin = lclConvertTimeValue( GetRoot(), maDateData.mnMinDate, rScaleData.Minimum, maDateData.mnBaseUnit );
+ ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN, bAutoMin );
+ bool bAutoMax = lclConvertTimeValue( GetRoot(), maDateData.mnMaxDate, rScaleData.Maximum, maDateData.mnBaseUnit );
+ ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX, bAutoMax );
+ }
+
+ // automatic axis type detection
+ ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE, rScaleData.AutoDateAxis );
+
+ // increment
+ bool bAutoMajor = lclConvertTimeInterval( maDateData.mnMajorStep, maDateData.mnMajorUnit, rScaleData.TimeIncrement.MajorTimeInterval );
+ ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR, bAutoMajor );
+ bool bAutoMinor = lclConvertTimeInterval( maDateData.mnMinorStep, maDateData.mnMinorUnit, rScaleData.TimeIncrement.MinorTimeInterval );
+ ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR, bAutoMinor );
+
+ // origin
+ double fOrigin = 0.0;
+ if( !lclIsAutoAnyOrGetValue( fOrigin, rScaleData.Origin ) )
+ maLabelData.mnCross = limit_cast< sal_uInt16 >( fOrigin, 1, 31999 );
+
+ // reverse order
+ if( (rScaleData.Orientation == cssc2::AxisOrientation_REVERSE) != bMirrorOrient )
+ ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE );
+}
+
+void XclExpChLabelRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
+{
+ cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
+ rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION );
+ double fCrossingPos = 1.0;
+ rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE );
+
+ bool bDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS );
+ switch( eAxisPos )
+ {
+ case cssc::ChartAxisPosition_ZERO:
+ case cssc::ChartAxisPosition_START:
+ maLabelData.mnCross = 1;
+ ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
+ break;
+ case cssc::ChartAxisPosition_END:
+ ::set_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_MAXCROSS );
+ break;
+ case cssc::ChartAxisPosition_VALUE:
+ maLabelData.mnCross = limit_cast< sal_uInt16 >( fCrossingPos, 1, 31999 );
+ ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS, false );
+ if( bDateAxis )
+ maDateData.mnCross = lclGetTimeValue( GetRoot(), fCrossingPos, maDateData.mnBaseUnit );
+ break;
+ default:
+ maLabelData.mnCross = 1;
+ ::set_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
+ }
+}
+
+void XclExpChLabelRange::Save( XclExpStream& rStrm )
+{
+ // the CHLABELRANGE record
+ XclExpRecord::Save( rStrm );
+
+ // the CHDATERANGE record with date axis settings (BIFF8 only)
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ rStrm.StartRecord( EXC_ID_CHDATERANGE, 18 );
+ rStrm << maDateData.mnMinDate
+ << maDateData.mnMaxDate
+ << maDateData.mnMajorStep
+ << maDateData.mnMajorUnit
+ << maDateData.mnMinorStep
+ << maDateData.mnMinorUnit
+ << maDateData.mnBaseUnit
+ << maDateData.mnCross
+ << maDateData.mnFlags;
+ rStrm.EndRecord();
+ }
+}
+
+void XclExpChLabelRange::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maLabelData.mnCross << maLabelData.mnLabelFreq << maLabelData.mnTickFreq << maLabelData.mnFlags;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChValueRange::XclExpChValueRange( const XclExpChRoot& rRoot ) :
+ XclExpRecord( EXC_ID_CHVALUERANGE, 42 ),
+ XclExpChRoot( rRoot )
+{
+}
+
+void XclExpChValueRange::Convert( const ScaleData& rScaleData )
+{
+ // scaling algorithm
+ bool bLogScale = ScfApiHelper::GetServiceName( rScaleData.Scaling ) == SERVICE_CHART2_LOGSCALING;
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, bLogScale );
+
+ // min/max
+ bool bAutoMin = lclIsAutoAnyOrGetScaledValue( maData.mfMin, rScaleData.Minimum, bLogScale );
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN, bAutoMin );
+ bool bAutoMax = lclIsAutoAnyOrGetScaledValue( maData.mfMax, rScaleData.Maximum, bLogScale );
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX, bAutoMax );
+
+ // origin
+ bool bAutoCross = lclIsAutoAnyOrGetScaledValue( maData.mfCross, rScaleData.Origin, bLogScale );
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, bAutoCross );
+
+ // major increment
+ const IncrementData& rIncrementData = rScaleData.IncrementData;
+ bool bAutoMajor = lclIsAutoAnyOrGetValue( maData.mfMajorStep, rIncrementData.Distance ) || (maData.mfMajorStep <= 0.0);
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR, bAutoMajor );
+ // minor increment
+ const Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
+ sal_Int32 nCount = 0;
+ bool bAutoMinor = bLogScale || bAutoMajor || (rSubIncrementSeq.getLength() < 1) ||
+ lclIsAutoAnyOrGetValue( nCount, rSubIncrementSeq[ 0 ].IntervalCount ) || (nCount < 1);
+ if( !bAutoMinor )
+ maData.mfMinorStep = maData.mfMajorStep / nCount;
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR, bAutoMinor );
+
+ // reverse order
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE, rScaleData.Orientation == cssc2::AxisOrientation_REVERSE );
+}
+
+void XclExpChValueRange::ConvertAxisPosition( const ScfPropertySet& rPropSet )
+{
+ cssc::ChartAxisPosition eAxisPos = cssc::ChartAxisPosition_VALUE;
+ double fCrossingPos = 0.0;
+ if( rPropSet.GetProperty( eAxisPos, EXC_CHPROP_CROSSOVERPOSITION ) && rPropSet.GetProperty( fCrossingPos, EXC_CHPROP_CROSSOVERVALUE ) )
+ {
+ switch( eAxisPos )
+ {
+ case cssc::ChartAxisPosition_ZERO:
+ case cssc::ChartAxisPosition_START:
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
+ break;
+ case cssc::ChartAxisPosition_END:
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
+ break;
+ case cssc::ChartAxisPosition_VALUE:
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS, false );
+ maData.mfCross = ::get_flagvalue< double >( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE, log( fCrossingPos ) / log( 10.0 ), fCrossingPos );
+ break;
+ default:
+ ::set_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
+ }
+ }
+}
+
+void XclExpChValueRange::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mfMin
+ << maData.mfMax
+ << maData.mfMajorStep
+ << maData.mfMinorStep
+ << maData.mfCross
+ << maData.mnFlags;
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+sal_uInt8 lclGetXclTickPos( sal_Int32 nApiTickmarks )
+{
+ using namespace cssc2::TickmarkStyle;
+ sal_uInt8 nXclTickPos = 0;
+ ::set_flag( nXclTickPos, EXC_CHTICK_INSIDE, ::get_flag( nApiTickmarks, INNER ) );
+ ::set_flag( nXclTickPos, EXC_CHTICK_OUTSIDE, ::get_flag( nApiTickmarks, OUTER ) );
+ return nXclTickPos;
+}
+
+} // namespace
+
+XclExpChTick::XclExpChTick( const XclExpChRoot& rRoot ) :
+ XclExpRecord( EXC_ID_CHTICK, (rRoot.GetBiff() == EXC_BIFF8) ? 30 : 26 ),
+ XclExpChRoot( rRoot ),
+ mnTextColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_CHWINDOWTEXT ) )
+{
+}
+
+void XclExpChTick::Convert( const ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo, sal_uInt16 nAxisType )
+{
+ // tick mark style
+ sal_Int32 nApiTickmarks = 0;
+ if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MAJORTICKS ) )
+ maData.mnMajor = lclGetXclTickPos( nApiTickmarks );
+ if( rPropSet.GetProperty( nApiTickmarks, EXC_CHPROP_MINORTICKS ) )
+ maData.mnMinor = lclGetXclTickPos( nApiTickmarks );
+
+ // axis labels
+ if( (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) && (nAxisType == EXC_CHAXIS_X) )
+ {
+ /* Radar charts disable their category labels via chart type, not via
+ axis, and axis labels are always 'near axis'. */
+ maData.mnLabelPos = EXC_CHTICK_NEXT;
+ }
+ else if( !rPropSet.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS ) )
+ {
+ // no labels
+ maData.mnLabelPos = EXC_CHTICK_NOLABEL;
+ }
+ else if( rTypeInfo.mb3dChart && (nAxisType == EXC_CHAXIS_Y) )
+ {
+ // Excel expects 'near axis' at Y axes in 3D charts
+ maData.mnLabelPos = EXC_CHTICK_NEXT;
+ }
+ else
+ {
+ cssc::ChartAxisLabelPosition eApiLabelPos = cssc::ChartAxisLabelPosition_NEAR_AXIS;
+ rPropSet.GetProperty( eApiLabelPos, EXC_CHPROP_LABELPOSITION );
+ switch( eApiLabelPos )
+ {
+ case cssc::ChartAxisLabelPosition_NEAR_AXIS:
+ case cssc::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE: maData.mnLabelPos = EXC_CHTICK_NEXT; break;
+ case cssc::ChartAxisLabelPosition_OUTSIDE_START: maData.mnLabelPos = EXC_CHTICK_LOW; break;
+ case cssc::ChartAxisLabelPosition_OUTSIDE_END: maData.mnLabelPos = EXC_CHTICK_HIGH; break;
+ default: maData.mnLabelPos = EXC_CHTICK_NEXT;
+ }
+ }
+}
+
+void XclExpChTick::SetFontColor( const Color& rColor, sal_uInt32 nColorId )
+{
+ maData.maTextColor = rColor;
+ ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR, rColor == COL_AUTO );
+ mnTextColorId = nColorId;
+}
+
+void XclExpChTick::SetRotation( sal_uInt16 nRotation )
+{
+ maData.mnRotation = nRotation;
+ ::set_flag( maData.mnFlags, EXC_CHTICK_AUTOROT, false );
+ ::insert_value( maData.mnFlags, XclTools::GetXclOrientFromRot( nRotation ), 2, 3 );
+}
+
+void XclExpChTick::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnMajor
+ << maData.mnMinor
+ << maData.mnLabelPos
+ << maData.mnBackMode;
+ rStrm.WriteZeroBytes( 16 );
+ rStrm << maData.maTextColor
+ << maData.mnFlags;
+ if( GetBiff() == EXC_BIFF8 )
+ rStrm << GetPalette().GetColorIndex( mnTextColorId ) << maData.mnRotation;
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+/** Returns an API axis object from the passed coordinate system. */
+Reference< XAxis > lclGetApiAxis( Reference< XCoordinateSystem > xCoordSystem,
+ sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
+{
+ Reference< XAxis > xAxis;
+ if( (nApiAxisDim >= 0) && xCoordSystem.is() ) try
+ {
+ xAxis = xCoordSystem->getAxisByDimension( nApiAxisDim, nApiAxesSetIdx );
+ }
+ catch( Exception& )
+ {
+ }
+ return xAxis;
+}
+
+Reference< cssc::XAxis > lclGetApiChart1Axis( Reference< XChartDocument > xChartDoc,
+ sal_Int32 nApiAxisDim, sal_Int32 nApiAxesSetIdx )
+{
+ Reference< cssc::XAxis > xChart1Axis;
+ try
+ {
+ Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY_THROW );
+ Reference< cssc::XAxisSupplier > xChart1AxisSupp( xChart1Doc->getDiagram(), UNO_QUERY_THROW );
+ switch( nApiAxesSetIdx )
+ {
+ case EXC_CHART_AXESSET_PRIMARY:
+ xChart1Axis = xChart1AxisSupp->getAxis( nApiAxisDim );
+ break;
+ case EXC_CHART_AXESSET_SECONDARY:
+ xChart1Axis = xChart1AxisSupp->getSecondaryAxis( nApiAxisDim );
+ break;
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ return xChart1Axis;
+}
+
+} // namespace
+
+XclExpChAxis::XclExpChAxis( const XclExpChRoot& rRoot, sal_uInt16 nAxisType ) :
+ XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXIS, EXC_ID_CHAXIS, 18 ),
+ mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
+{
+ maData.mnType = nAxisType;
+}
+
+void XclExpChAxis::SetFont( XclExpChFontRef xFont, const Color& rColor, sal_uInt32 nColorId )
+{
+ mxFont = xFont;
+ if( mxTick )
+ mxTick->SetFontColor( rColor, nColorId );
+}
+
+void XclExpChAxis::SetRotation( sal_uInt16 nRotation )
+{
+ if( mxTick )
+ mxTick->SetRotation( nRotation );
+}
+
+void XclExpChAxis::Convert( Reference< XAxis > xAxis, Reference< XAxis > xCrossingAxis,
+ Reference< cssc::XAxis > xChart1Axis, const XclChExtTypeInfo& rTypeInfo )
+{
+ ScfPropertySet aAxisProp( xAxis );
+ bool bCategoryAxis = ((GetAxisType() == EXC_CHAXIS_X) && rTypeInfo.mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z);
+
+ // axis line format -------------------------------------------------------
+
+ mxAxisLine.reset( new XclExpChLineFormat( GetChRoot() ) );
+ mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
+ // #i58688# axis enabled
+ mxAxisLine->SetShowAxis( aAxisProp.GetBoolProperty( EXC_CHPROP_SHOW ) );
+
+ // axis scaling and increment ---------------------------------------------
+
+ ScfPropertySet aCrossingProp( xCrossingAxis );
+ if( bCategoryAxis )
+ {
+ mxLabelRange.reset( new XclExpChLabelRange( GetChRoot() ) );
+ mxLabelRange->SetTicksBetweenCateg( rTypeInfo.mbTicksBetweenCateg );
+ if( xAxis.is() )
+ {
+ ScfPropertySet aChart1AxisProp( xChart1Axis );
+ // #i71684# radar charts have reversed rotation direction
+ mxLabelRange->Convert( xAxis->getScaleData(), aChart1AxisProp, (GetAxisType() == EXC_CHAXIS_X) && (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR) );
+ }
+ // get position of crossing axis on this axis from passed axis object
+ if( aCrossingProp.Is() )
+ mxLabelRange->ConvertAxisPosition( aCrossingProp );
+ }
+ else
+ {
+ mxValueRange.reset( new XclExpChValueRange( GetChRoot() ) );
+ if( xAxis.is() )
+ mxValueRange->Convert( xAxis->getScaleData() );
+ // get position of crossing axis on this axis from passed axis object
+ if( aCrossingProp.Is() )
+ mxValueRange->ConvertAxisPosition( aCrossingProp );
+ }
+
+ // axis caption text ------------------------------------------------------
+
+ // axis ticks properties
+ mxTick.reset( new XclExpChTick( GetChRoot() ) );
+ mxTick->Convert( aAxisProp, rTypeInfo, GetAxisType() );
+
+ // axis label formatting and rotation
+ ConvertFontBase( GetChRoot(), aAxisProp );
+ ConvertRotationBase( GetChRoot(), aAxisProp, true );
+
+ // axis number format
+ sal_Int32 nApiNumFmt = 0;
+ if( !bCategoryAxis && aAxisProp.GetProperty( nApiNumFmt, EXC_CHPROP_NUMBERFORMAT ) )
+ mnNumFmtIdx = GetNumFmtBuffer().Insert( static_cast< sal_uInt32 >( nApiNumFmt ) );
+
+ // grid -------------------------------------------------------------------
+
+ if( xAxis.is() )
+ {
+ // main grid
+ ScfPropertySet aGridProp( xAxis->getGridProperties() );
+ if( aGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
+ mxMajorGrid = lclCreateLineFormat( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
+ // sub grid
+ Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
+ if( aSubGridPropSeq.hasElements() )
+ {
+ ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
+ if( aSubGridProp.GetBoolProperty( EXC_CHPROP_SHOW ) )
+ mxMinorGrid = lclCreateLineFormat( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
+ }
+ }
+}
+
+void XclExpChAxis::ConvertWall( XDiagramRef xDiagram )
+{
+ if( xDiagram.is() ) switch( GetAxisType() )
+ {
+ case EXC_CHAXIS_X:
+ {
+ ScfPropertySet aWallProp( xDiagram->getWall() );
+ mxWallFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_WALL3D );
+ }
+ break;
+ case EXC_CHAXIS_Y:
+ {
+ ScfPropertySet aFloorProp( xDiagram->getFloor() );
+ mxWallFrame = lclCreateFrame( GetChRoot(), aFloorProp, EXC_CHOBJTYPE_FLOOR3D );
+ }
+ break;
+ default:
+ mxWallFrame.reset();
+ }
+}
+
+void XclExpChAxis::WriteSubRecords( XclExpStream& rStrm )
+{
+ lclSaveRecord( rStrm, mxLabelRange );
+ lclSaveRecord( rStrm, mxValueRange );
+ if( mnNumFmtIdx != EXC_FORMAT_NOTFOUND )
+ XclExpUInt16Record( EXC_ID_CHFORMAT, mnNumFmtIdx ).Save( rStrm );
+ lclSaveRecord( rStrm, mxTick );
+ lclSaveRecord( rStrm, mxFont );
+ lclSaveRecord( rStrm, mxAxisLine, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_AXISLINE );
+ lclSaveRecord( rStrm, mxMajorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MAJORGRID );
+ lclSaveRecord( rStrm, mxMinorGrid, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_MINORGRID );
+ lclSaveRecord( rStrm, mxWallFrame, EXC_ID_CHAXISLINE, EXC_CHAXISLINE_WALLS );
+}
+
+void XclExpChAxis::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnType;
+ rStrm.WriteZeroBytes( 16 );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChAxesSet::XclExpChAxesSet( const XclExpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
+ XclExpChGroupBase( rRoot, EXC_CHFRBLOCK_TYPE_AXESSET, EXC_ID_CHAXESSET, 18 )
+{
+ maData.mnAxesSetId = nAxesSetId;
+ SetFutureRecordContext( 0, nAxesSetId );
+
+ /* Need to set a reasonable size for the plot area, otherwise Excel will
+ move away embedded shapes while auto-sizing the plot area. This is just
+ a wild guess, but will be fixed with implementing manual positioning of
+ chart elements. */
+ maData.maRect.mnX = 262;
+ maData.maRect.mnY = 626;
+ maData.maRect.mnWidth = 3187;
+ maData.maRect.mnHeight = 2633;
+}
+
+sal_uInt16 XclExpChAxesSet::Convert( Reference< XDiagram > xDiagram, sal_uInt16 nFirstGroupIdx )
+{
+ /* First unused chart type group index is passed to be able to continue
+ counting of chart type groups for secondary axes set. */
+ sal_uInt16 nGroupIdx = nFirstGroupIdx;
+ Reference< XCoordinateSystemContainer > xCoordSysCont( xDiagram, UNO_QUERY );
+ if( xCoordSysCont.is() )
+ {
+ Sequence< Reference< XCoordinateSystem > > aCoordSysSeq = xCoordSysCont->getCoordinateSystems();
+ if( aCoordSysSeq.getLength() > 0 )
+ {
+ /* Process first coordinate system only. Import filter puts all
+ chart types into one coordinate system. */
+ Reference< XCoordinateSystem > xCoordSystem = aCoordSysSeq[ 0 ];
+ sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
+
+ // 3d mode
+ bool b3dChart = xCoordSystem.is() && (xCoordSystem->getDimension() == 3);
+
+ // percent charts
+ namespace ApiAxisType = cssc2::AxisType;
+ Reference< XAxis > xApiYAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_Y, nApiAxesSetIdx );
+ bool bPercent = xApiYAxis.is() && (xApiYAxis->getScaleData().AxisType == ApiAxisType::PERCENT);
+
+ // connector lines in bar charts
+ ScfPropertySet aDiaProp( xDiagram );
+ bool bConnectBars = aDiaProp.GetBoolProperty( EXC_CHPROP_CONNECTBARS );
+
+ // swapped axes sets
+ ScfPropertySet aCoordSysProp( xCoordSystem );
+ bool bSwappedAxesSet = aCoordSysProp.GetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS );
+
+ // X axis for later use
+ Reference< XAxis > xApiXAxis = lclGetApiAxis( xCoordSystem, EXC_CHART_AXIS_X, nApiAxesSetIdx );
+ // X axis labels
+ ScfPropertySet aXAxisProp( xApiXAxis );
+ bool bHasXLabels = aXAxisProp.GetBoolProperty( EXC_CHPROP_DISPLAYLABELS );
+
+ // process chart types
+ Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
+ if( xChartTypeCont.is() )
+ {
+ Sequence< Reference< XChartType > > aChartTypeSeq = xChartTypeCont->getChartTypes();
+ const Reference< XChartType >* pBeg = aChartTypeSeq.getConstArray();
+ const Reference< XChartType >* pEnd = pBeg + aChartTypeSeq.getLength();
+ for( const Reference< XChartType >* pIt = pBeg; pIt != pEnd; ++pIt )
+ {
+ XclExpChTypeGroupRef xTypeGroup( new XclExpChTypeGroup( GetChRoot(), nGroupIdx ) );
+ xTypeGroup->ConvertType( xDiagram, *pIt, nApiAxesSetIdx, b3dChart, bSwappedAxesSet, bHasXLabels );
+ /* If new chart type group cannot be inserted into a combination
+ chart with existing type groups, insert all series into last
+ contained chart type group instead of creating a new group. */
+ XclExpChTypeGroupRef xLastGroup = GetLastTypeGroup();
+ if( xLastGroup && !(xTypeGroup->IsCombinable2d() && xLastGroup->IsCombinable2d()) )
+ {
+ xLastGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
+ }
+ else
+ {
+ xTypeGroup->ConvertSeries( xDiagram, *pIt, nApiAxesSetIdx, bPercent, bConnectBars );
+ if( xTypeGroup->IsValidGroup() )
+ {
+ maTypeGroups.AppendRecord( xTypeGroup );
+ ++nGroupIdx;
+ }
+ }
+ }
+ }
+
+ if( XclExpChTypeGroup* pGroup = GetFirstTypeGroup().get() )
+ {
+ const XclChExtTypeInfo& rTypeInfo = pGroup->GetTypeInfo();
+
+ // create axes according to chart type (no axes for pie and donut charts)
+ if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
+ {
+ ConvertAxis( mxXAxis, EXC_CHAXIS_X, mxXAxisTitle, EXC_CHOBJLINK_XAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_Y );
+ ConvertAxis( mxYAxis, EXC_CHAXIS_Y, mxYAxisTitle, EXC_CHOBJLINK_YAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_X );
+ if( pGroup->Is3dDeepChart() )
+ ConvertAxis( mxZAxis, EXC_CHAXIS_Z, mxZAxisTitle, EXC_CHOBJLINK_ZAXIS, xCoordSystem, rTypeInfo, EXC_CHART_AXIS_NONE );
+ }
+
+ // X axis category ranges
+ if( rTypeInfo.mbCategoryAxis && xApiXAxis.is() )
+ {
+ const ScaleData aScaleData = xApiXAxis->getScaleData();
+ for( size_t nIdx = 0, nSize = maTypeGroups.GetSize(); nIdx < nSize; ++nIdx )
+ maTypeGroups.GetRecord( nIdx )->ConvertCategSequence( aScaleData.Categories );
+ }
+
+ // legend
+ if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
+ {
+ Reference< XLegend > xLegend = xDiagram->getLegend();
+ if( xLegend.is() )
+ {
+ ScfPropertySet aLegendProp( xLegend );
+ pGroup->ConvertLegend( aLegendProp );
+ }
+ }
+ }
+ }
+ }
+
+ // wall/floor/diagram frame formatting
+ if( xDiagram.is() && (GetAxesSetId() == EXC_CHAXESSET_PRIMARY) )
+ {
+ XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
+ if( xTypeGroup && xTypeGroup->Is3dWallChart() )
+ {
+ // wall/floor formatting (3D charts)
+ if( mxXAxis )
+ mxXAxis->ConvertWall( xDiagram );
+ if( mxYAxis )
+ mxYAxis->ConvertWall( xDiagram );
+ }
+ else
+ {
+ // diagram background formatting
+ ScfPropertySet aWallProp( xDiagram->getWall() );
+ mxPlotFrame = lclCreateFrame( GetChRoot(), aWallProp, EXC_CHOBJTYPE_PLOTFRAME );
+ }
+ }
+
+ // inner and outer plot area position and size
+ try
+ {
+ Reference< cssc::XChartDocument > xChart1Doc( GetChartDocument(), UNO_QUERY_THROW );
+ Reference< cssc::XDiagramPositioning > xPositioning( xChart1Doc->getDiagram(), UNO_QUERY_THROW );
+ // set manual flag in chart data
+ if( !xPositioning->isAutomaticDiagramPositioning() )
+ GetChartData().SetManualPlotArea();
+ // the CHAXESSET record contains the inner plot area
+ maData.maRect = CalcChartRectFromHmm( xPositioning->calculateDiagramPositionExcludingAxes() );
+ // the embedded CHFRAMEPOS record contains the outer plot area
+ mxFramePos.reset( new XclExpChFramePos( EXC_CHFRAMEPOS_PARENT, EXC_CHFRAMEPOS_PARENT ) );
+ // for pie charts, always use inner plot area size to exclude the data labels as Excel does
+ const XclExpChTypeGroup* pFirstTypeGroup = GetFirstTypeGroup().get();
+ bool bPieChart = pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE);
+ mxFramePos->GetFramePosData().maRect = bPieChart ? maData.maRect :
+ CalcChartRectFromHmm( xPositioning->calculateDiagramPositionIncludingAxes() );
+ }
+ catch( Exception& )
+ {
+ }
+
+ // return first unused chart type group index for next axes set
+ return nGroupIdx;
+}
+
+bool XclExpChAxesSet::Is3dChart() const
+{
+ XclExpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
+ return xTypeGroup && xTypeGroup->Is3dChart();
+}
+
+void XclExpChAxesSet::WriteSubRecords( XclExpStream& rStrm )
+{
+ lclSaveRecord( rStrm, mxFramePos );
+ lclSaveRecord( rStrm, mxXAxis );
+ lclSaveRecord( rStrm, mxYAxis );
+ lclSaveRecord( rStrm, mxZAxis );
+ lclSaveRecord( rStrm, mxXAxisTitle );
+ lclSaveRecord( rStrm, mxYAxisTitle );
+ lclSaveRecord( rStrm, mxZAxisTitle );
+ if( mxPlotFrame )
+ {
+ XclExpEmptyRecord( EXC_ID_CHPLOTFRAME ).Save( rStrm );
+ mxPlotFrame->Save( rStrm );
+ }
+ maTypeGroups.Save( rStrm );
+}
+
+XclExpChTypeGroupRef XclExpChAxesSet::GetFirstTypeGroup() const
+{
+ return maTypeGroups.GetFirstRecord();
+}
+
+XclExpChTypeGroupRef XclExpChAxesSet::GetLastTypeGroup() const
+{
+ return maTypeGroups.GetLastRecord();
+}
+
+void XclExpChAxesSet::ConvertAxis(
+ XclExpChAxisRef& rxChAxis, sal_uInt16 nAxisType,
+ XclExpChTextRef& rxChAxisTitle, sal_uInt16 nTitleTarget,
+ Reference< XCoordinateSystem > xCoordSystem, const XclChExtTypeInfo& rTypeInfo,
+ sal_Int32 nCrossingAxisDim )
+{
+ // create and convert axis object
+ rxChAxis.reset( new XclExpChAxis( GetChRoot(), nAxisType ) );
+ sal_Int32 nApiAxisDim = rxChAxis->GetApiAxisDimension();
+ sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
+ Reference< XAxis > xAxis = lclGetApiAxis( xCoordSystem, nApiAxisDim, nApiAxesSetIdx );
+ Reference< XAxis > xCrossingAxis = lclGetApiAxis( xCoordSystem, nCrossingAxisDim, nApiAxesSetIdx );
+ Reference< cssc::XAxis > xChart1Axis = lclGetApiChart1Axis( GetChartDocument(), nApiAxisDim, nApiAxesSetIdx );
+ rxChAxis->Convert( xAxis, xCrossingAxis, xChart1Axis, rTypeInfo );
+
+ // create and convert axis title
+ Reference< XTitled > xTitled( xAxis, UNO_QUERY );
+ rxChAxisTitle = lclCreateTitle( GetChRoot(), xTitled, nTitleTarget );
+}
+
+void XclExpChAxesSet::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maData.mnAxesSetId << maData.maRect;
+}
+
+// The chart object ===========================================================
+
+static void lcl_getChartSubTitle(const Reference<XChartDocument>& xChartDoc,
+ String& rSubTitle)
+{
+ Reference< ::com::sun::star::chart::XChartDocument > xChartDoc1(xChartDoc, UNO_QUERY);
+ if (!xChartDoc1.is())
+ return;
+
+ Reference< XPropertySet > xProp(xChartDoc1->getSubTitle(), UNO_QUERY);
+ if (!xProp.is())
+ return;
+
+ OUString aTitle;
+ Any any = xProp->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("String")) );
+ if (any >>= aTitle)
+ rSubTitle = aTitle;
+}
+
+XclExpChChart::XclExpChChart( const XclExpRoot& rRoot,
+ Reference< XChartDocument > xChartDoc, const Rectangle& rChartRect ) :
+ XclExpChGroupBase( XclExpChRoot( rRoot, *this ), EXC_CHFRBLOCK_TYPE_CHART, EXC_ID_CHCHART, 16 )
+{
+ Size aPtSize = OutputDevice::LogicToLogic( rChartRect.GetSize(), MapMode( MAP_100TH_MM ), MapMode( MAP_POINT ) );
+ // rectangle is stored in 16.16 fixed-point format
+ maRect.mnX = maRect.mnY = 0;
+ maRect.mnWidth = static_cast< sal_Int32 >( aPtSize.Width() << 16 );
+ maRect.mnHeight = static_cast< sal_Int32 >( aPtSize.Height() << 16 );
+
+ // global chart properties (default values)
+ ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, false );
+ ::set_flag( maProps.mnFlags, EXC_CHPROPS_MANPLOTAREA );
+ maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP;
+
+ // always create both axes set objects
+ mxPrimAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
+ mxSecnAxesSet.reset( new XclExpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
+
+ if( xChartDoc.is() )
+ {
+ Reference< XDiagram > xDiagram = xChartDoc->getFirstDiagram();
+
+ // global chart properties (only 'include hidden cells' attribute for now)
+ ScfPropertySet aDiagramProp( xDiagram );
+ bool bIncludeHidden = aDiagramProp.GetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS );
+ ::set_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY, !bIncludeHidden );
+
+ // initialize API conversion (remembers xChartDoc and rChartRect internally)
+ InitConversion( xChartDoc, rChartRect );
+
+ // chart frame
+ ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
+ mxFrame = lclCreateFrame( GetChRoot(), aFrameProp, EXC_CHOBJTYPE_BACKGROUND );
+
+ // chart title
+ Reference< XTitled > xTitled( xChartDoc, UNO_QUERY );
+ String aSubTitle;
+ lcl_getChartSubTitle(xChartDoc, aSubTitle);
+ mxTitle = lclCreateTitle( GetChRoot(), xTitled, EXC_CHOBJLINK_TITLE,
+ aSubTitle.Len() ? &aSubTitle : NULL );
+
+ // diagrams (axes sets)
+ sal_uInt16 nFreeGroupIdx = mxPrimAxesSet->Convert( xDiagram, 0 );
+ if( !mxPrimAxesSet->Is3dChart() )
+ mxSecnAxesSet->Convert( xDiagram, nFreeGroupIdx );
+
+ // treatment of missing values
+ ScfPropertySet aDiaProp( xDiagram );
+ sal_Int32 nMissingValues = 0;
+ if( aDiaProp.GetProperty( nMissingValues, EXC_CHPROP_MISSINGVALUETREATMENT ) )
+ {
+ using namespace cssc::MissingValueTreatment;
+ switch( nMissingValues )
+ {
+ case LEAVE_GAP: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_SKIP; break;
+ case USE_ZERO: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_ZERO; break;
+ case CONTINUE: maProps.mnEmptyMode = EXC_CHPROPS_EMPTY_INTERPOLATE; break;
+ }
+ }
+
+ // finish API conversion
+ FinishConversion();
+ }
+}
+
+XclExpChSeriesRef XclExpChChart::CreateSeries()
+{
+ XclExpChSeriesRef xSeries;
+ sal_uInt16 nSeriesIdx = static_cast< sal_uInt16 >( maSeries.GetSize() );
+ if( nSeriesIdx <= EXC_CHSERIES_MAXSERIES )
+ {
+ xSeries.reset( new XclExpChSeries( GetChRoot(), nSeriesIdx ) );
+ maSeries.AppendRecord( xSeries );
+ }
+ return xSeries;
+}
+
+void XclExpChChart::RemoveLastSeries()
+{
+ if( !maSeries.IsEmpty() )
+ maSeries.RemoveRecord( maSeries.GetSize() - 1 );
+}
+
+void XclExpChChart::SetDataLabel( XclExpChTextRef xText )
+{
+ if( xText )
+ maLabels.AppendRecord( xText );
+}
+
+void XclExpChChart::SetManualPlotArea()
+{
+ // this flag does not exist in BIFF5
+ if( GetBiff() == EXC_BIFF8 )
+ ::set_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA );
+}
+
+void XclExpChChart::WriteSubRecords( XclExpStream& rStrm )
+{
+ // background format
+ lclSaveRecord( rStrm, mxFrame );
+
+ // data series
+ maSeries.Save( rStrm );
+
+ // CHPROPERTIES record
+ rStrm.StartRecord( EXC_ID_CHPROPERTIES, 4 );
+ rStrm << maProps.mnFlags << maProps.mnEmptyMode << sal_uInt8( 0 );
+ rStrm.EndRecord();
+
+ // axes sets (always save primary axes set)
+ sal_uInt16 nUsedAxesSets = mxSecnAxesSet->IsValidAxesSet() ? 2 : 1;
+ XclExpUInt16Record( EXC_ID_CHUSEDAXESSETS, nUsedAxesSets ).Save( rStrm );
+ mxPrimAxesSet->Save( rStrm );
+ if( mxSecnAxesSet->IsValidAxesSet() )
+ mxSecnAxesSet->Save( rStrm );
+
+ // chart title and data labels
+ lclSaveRecord( rStrm, mxTitle );
+ maLabels.Save( rStrm );
+}
+
+void XclExpChChart::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maRect;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChartDrawing::XclExpChartDrawing( const XclExpRoot& rRoot,
+ const Reference< XModel >& rxModel, const Size& rChartSize ) :
+ XclExpRoot( rRoot )
+{
+ if( (rChartSize.Width() > 0) && (rChartSize.Height() > 0) )
+ {
+ ScfPropertySet aPropSet( rxModel );
+ Reference< XShapes > xShapes;
+ if( aPropSet.GetProperty( xShapes, EXC_CHPROP_ADDITIONALSHAPES ) && xShapes.is() && (xShapes->getCount() > 0) )
+ {
+ /* Create a new independent object manager with own DFF stream for the
+ DGCONTAINER, pass global manager as parent for shared usage of
+ global DFF data (picture container etc.). */
+ mxObjMgr.reset( new XclExpEmbeddedObjectManager( GetObjectManager(), rChartSize, EXC_CHART_TOTALUNITS, EXC_CHART_TOTALUNITS ) );
+ // initialize the drawing object list
+ mxObjMgr->StartSheet();
+ // process the draw page (convert all shapes)
+ mxObjRecs = mxObjMgr->ProcessDrawing( xShapes );
+ // finalize the DFF stream
+ mxObjMgr->EndDocument();
+ }
+ }
+}
+
+XclExpChartDrawing::~XclExpChartDrawing()
+{
+}
+
+void XclExpChartDrawing::Save( XclExpStream& rStrm )
+{
+ if( mxObjRecs )
+ mxObjRecs->Save( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChart::XclExpChart( const XclExpRoot& rRoot, Reference< XModel > xModel, const Rectangle& rChartRect ) :
+ XclExpSubStream( EXC_BOF_CHART ),
+ XclExpRoot( rRoot )
+{
+ AppendNewRecord( new XclExpChartPageSettings( rRoot ) );
+ AppendNewRecord( new XclExpBoolRecord( EXC_ID_PROTECT, false ) );
+ AppendNewRecord( new XclExpChartDrawing( rRoot, xModel, rChartRect.GetSize() ) );
+ AppendNewRecord( new XclExpUInt16Record( EXC_ID_CHUNITS, EXC_CHUNITS_TWIPS ) );
+
+ Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
+ AppendNewRecord( new XclExpChChart( rRoot, xChartDoc, rChartRect ) );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xecontent.cxx b/sc/source/filter/excel/xecontent.cxx
new file mode 100644
index 000000000000..b25cc7f20b1e
--- /dev/null
+++ b/sc/source/filter/excel/xecontent.cxx
@@ -0,0 +1,1496 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xecontent.hxx"
+
+#include <list>
+#include <algorithm>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/sheet/XAreaLinks.hpp>
+#include <com/sun/star/sheet/XAreaLink.hpp>
+#include <sfx2/objsh.hxx>
+#include <tools/urlobj.hxx>
+#include <svl/itemset.hxx>
+#include <formula/grammar.hxx>
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include "document.hxx"
+#include "validat.hxx"
+#include "unonames.hxx"
+#include "convuno.hxx"
+#include "rangenam.hxx"
+#include "tokenarray.hxx"
+#include "stlpool.hxx"
+#include "patattr.hxx"
+#include "fapihelper.hxx"
+#include "xehelper.hxx"
+#include "xestyle.hxx"
+#include "xename.hxx"
+
+using namespace ::oox;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::frame::XModel;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::sheet::XAreaLinks;
+using ::com::sun::star::sheet::XAreaLink;
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// Shared string table ========================================================
+
+// 1 = SST hash table statistics prompt
+#define EXC_INCL_SST_STATISTICS 0
+
+// ----------------------------------------------------------------------------
+
+/** A single string entry in the hash table. */
+struct XclExpHashEntry
+{
+ const XclExpString* mpString; /// Pointer to the string (no ownership).
+ sal_uInt32 mnSstIndex; /// The SST index of this string.
+ inline explicit XclExpHashEntry( const XclExpString* pString = 0, sal_uInt32 nSstIndex = 0 ) :
+ mpString( pString ), mnSstIndex( nSstIndex ) {}
+};
+
+/** Function object for strict weak ordering. */
+struct XclExpHashEntrySWO
+{
+ inline bool operator()( const XclExpHashEntry& rLeft, const XclExpHashEntry& rRight ) const
+ { return *rLeft.mpString < *rRight.mpString; }
+};
+
+// ----------------------------------------------------------------------------
+
+/** Implementation of the SST export.
+ @descr Stores all passed strings in a hash table and prevents repeated
+ insertion of equal strings. */
+class XclExpSstImpl
+{
+public:
+ explicit XclExpSstImpl();
+
+ /** Inserts the passed string, if not already inserted, and returns the unique SST index. */
+ sal_uInt32 Insert( XclExpStringRef xString );
+
+ /** Writes the complete SST and EXTSST records. */
+ void Save( XclExpStream& rStrm );
+ void SaveXml( XclExpXmlStream& rStrm );
+
+private:
+ typedef ::std::list< XclExpStringRef > XclExpStringList;
+ typedef ::std::vector< XclExpHashEntry > XclExpHashVec;
+ typedef ::std::vector< XclExpHashVec > XclExpHashTab;
+
+ XclExpStringList maStringList; /// List of unique strings (in SST ID order).
+ XclExpHashTab maHashTab; /// Hashed table that manages string pointers.
+ sal_uInt32 mnTotal; /// Total count of strings (including doubles).
+ sal_uInt32 mnSize; /// Size of the SST (count of unique strings).
+};
+
+// ----------------------------------------------------------------------------
+
+const sal_uInt32 EXC_SST_HASHTABLE_SIZE = 2048;
+
+XclExpSstImpl::XclExpSstImpl() :
+ maHashTab( EXC_SST_HASHTABLE_SIZE ),
+ mnTotal( 0 ),
+ mnSize( 0 )
+{
+}
+
+sal_uInt32 XclExpSstImpl::Insert( XclExpStringRef xString )
+{
+ DBG_ASSERT( xString.get(), "XclExpSstImpl::Insert - empty pointer not allowed" );
+ if( !xString.get() )
+ xString.reset( new XclExpString );
+
+ ++mnTotal;
+ sal_uInt32 nSstIndex = 0;
+
+ // calculate hash value in range [0,EXC_SST_HASHTABLE_SIZE)
+ sal_uInt16 nHash = xString->GetHash();
+ (nHash ^= (nHash / EXC_SST_HASHTABLE_SIZE)) %= EXC_SST_HASHTABLE_SIZE;
+
+ XclExpHashVec& rVec = maHashTab[ nHash ];
+ XclExpHashEntry aEntry( xString.get(), mnSize );
+ XclExpHashVec::iterator aIt = ::std::lower_bound( rVec.begin(), rVec.end(), aEntry, XclExpHashEntrySWO() );
+ if( (aIt == rVec.end()) || (*aIt->mpString != *xString) )
+ {
+ nSstIndex = mnSize;
+ maStringList.push_back( xString );
+ rVec.insert( aIt, aEntry );
+ ++mnSize;
+ }
+ else
+ {
+ nSstIndex = aIt->mnSstIndex;
+ }
+
+ return nSstIndex;
+}
+
+void XclExpSstImpl::Save( XclExpStream& rStrm )
+{
+ if( maStringList.empty() )
+ return;
+
+#if (OSL_DEBUG_LEVEL > 1) && EXC_INCL_SST_STATISTICS
+ { // own scope for the statistics
+#define APPENDINT( value ) Append( ByteString::CreateFromInt32( value ) )
+ ScfUInt32Vec aVec;
+ size_t nPerBucket = mnSize / EXC_SST_HASHTABLE_SIZE + 1, nEff = 0;
+ for( XclExpHashTab::const_iterator aTIt = maHashTab.begin(), aTEnd = maHashTab.end(); aTIt != aTEnd; ++aTIt )
+ {
+ size_t nSize = aTIt->size();
+ if( nSize >= aVec.size() ) aVec.resize( nSize + 1, 0 );
+ ++aVec[ nSize ];
+ if( nSize > nPerBucket ) nEff += nSize - nPerBucket;
+ }
+ ByteString aStr( "SST HASHING STATISTICS\n\n" );
+ aStr.Append( "Total count:\t" ).APPENDINT( mnTotal ).Append( " strings\n" );
+ aStr.Append( "Reduced to:\t" ).APPENDINT( mnSize ).Append( " strings (" );
+ aStr.APPENDINT( 100 * mnSize / mnTotal ).Append( "%)\n" );
+ aStr.Append( "Effectivity:\t\t" ).APPENDINT( 100 - 100 * nEff / mnSize );
+ aStr.Append( "% (best: " ).APPENDINT( nPerBucket ).Append( " strings per bucket)\n" );
+ aStr.Append( "\t\tCount of buckets\nBucket size\ttotal\tmax\tTotal strings\n" );
+ for( size_t nIx = 0, nSize = aVec.size(), nInc = 1; nIx < nSize; nIx += nInc )
+ {
+ if( (nIx == 10) || (nIx == 100) || (nIx == 1000) ) nInc = nIx;
+ size_t nMaxIx = ::std::min( nIx + nInc, nSize ), nCount = 0, nMaxCount = 0, nStrings = 0;
+ for( size_t nSubIx = nIx; nSubIx < nMaxIx; ++nSubIx )
+ {
+ nCount += aVec[ nSubIx ];
+ if( aVec[ nSubIx ] > nMaxCount ) nMaxCount = aVec[ nSubIx ];
+ nStrings += nSubIx * aVec[ nSubIx ];
+ }
+ if( nMaxCount )
+ {
+ aStr.APPENDINT( nIx );
+ if( nMaxIx - nIx > 1 ) aStr.Append( '-' ).APPENDINT( nMaxIx - 1 );
+ aStr.Append( "\t\t" ).APPENDINT( nCount ).Append( '\t' ).APPENDINT( nMaxCount );
+ aStr.Append( '\t' ).APPENDINT( nStrings ).Append( '\n' );
+ }
+ }
+ DBG_ERRORFILE( aStr.GetBuffer() );
+#undef APPENDINT
+ }
+#endif
+
+ SvMemoryStream aExtSst( 8192 );
+
+ sal_uInt32 nBucket = mnSize;
+ while( nBucket > 0x0100 )
+ nBucket /= 2;
+
+ sal_uInt16 nPerBucket = llimit_cast< sal_uInt16 >( nBucket, 8 );
+ sal_uInt16 nBucketIndex = 0;
+
+ // *** write the SST record ***
+
+ rStrm.StartRecord( EXC_ID_SST, 8 );
+
+ rStrm << mnTotal << mnSize;
+ for( XclExpStringList::const_iterator aIt = maStringList.begin(), aEnd = maStringList.end(); aIt != aEnd; ++aIt )
+ {
+ if( !nBucketIndex )
+ {
+ // write bucket info before string to get correct record position
+ sal_uInt32 nStrmPos = static_cast< sal_uInt32 >( rStrm.GetSvStreamPos() );
+ sal_uInt16 nRecPos = rStrm.GetRawRecPos() + 4;
+ aExtSst << nStrmPos // stream position
+ << nRecPos // position from start of SST or CONTINUE
+ << sal_uInt16( 0 ); // reserved
+ }
+
+ rStrm << **aIt;
+
+ if( ++nBucketIndex == nPerBucket )
+ nBucketIndex = 0;
+ }
+
+ rStrm.EndRecord();
+
+ // *** write the EXTSST record ***
+
+ rStrm.StartRecord( EXC_ID_EXTSST, 0 );
+
+ rStrm << nPerBucket;
+ rStrm.SetSliceSize( 8 ); // size of one bucket info
+ aExtSst.Seek( STREAM_SEEK_TO_BEGIN );
+ rStrm.CopyFromStream( aExtSst );
+
+ rStrm.EndRecord();
+}
+
+void XclExpSstImpl::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( maStringList.empty() )
+ return;
+
+ sax_fastparser::FSHelperPtr pSst = rStrm.CreateOutputStream(
+ OUString(RTL_CONSTASCII_USTRINGPARAM( "xl/sharedStrings.xml") ),
+ OUString(RTL_CONSTASCII_USTRINGPARAM( "sharedStrings.xml" )),
+ rStrm.GetCurrentStream()->getOutputStream(),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" );
+ rStrm.PushStream( pSst );
+
+ pSst->startElement( XML_sst,
+ XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
+ XML_count, OString::valueOf( (sal_Int32) mnTotal ).getStr(),
+ XML_uniqueCount, OString::valueOf( (sal_Int32) mnSize ).getStr(),
+ FSEND );
+
+ for( XclExpStringList::const_iterator aIt = maStringList.begin(), aEnd = maStringList.end(); aIt != aEnd; ++aIt )
+ {
+ pSst->startElement( XML_si, FSEND );
+ (*aIt)->WriteXml( rStrm );
+ pSst->endElement( XML_si );
+ }
+
+ pSst->endElement( XML_sst );
+
+ rStrm.PopStream();
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpSst::XclExpSst() :
+ mxImpl( new XclExpSstImpl )
+{
+}
+
+XclExpSst::~XclExpSst()
+{
+}
+
+sal_uInt32 XclExpSst::Insert( XclExpStringRef xString )
+{
+ return mxImpl->Insert( xString );
+}
+
+void XclExpSst::Save( XclExpStream& rStrm )
+{
+ mxImpl->Save( rStrm );
+}
+
+void XclExpSst::SaveXml( XclExpXmlStream& rStrm )
+{
+ mxImpl->SaveXml( rStrm );
+}
+
+// Merged cells ===============================================================
+
+XclExpMergedcells::XclExpMergedcells( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+void XclExpMergedcells::AppendRange( const ScRange& rRange, sal_uInt32 nBaseXFId )
+{
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ maMergedRanges.Append( rRange );
+ maBaseXFIds.push_back( nBaseXFId );
+ }
+}
+
+sal_uInt32 XclExpMergedcells::GetBaseXFId( const ScAddress& rPos ) const
+{
+ DBG_ASSERT( maBaseXFIds.size() == maMergedRanges.size(), "XclExpMergedcells::GetBaseXFId - invalid lists" );
+ ScfUInt32Vec::const_iterator aIt = maBaseXFIds.begin();
+ ScRangeList& rNCRanges = const_cast< ScRangeList& >( maMergedRanges );
+ for ( size_t i = 0, nRanges = rNCRanges.size(); i < nRanges; ++i, ++aIt )
+ {
+ const ScRange* pScRange = rNCRanges[ i ];
+ if( pScRange->In( rPos ) )
+ return *aIt;
+ }
+ return EXC_XFID_NOTFOUND;
+}
+
+void XclExpMergedcells::Save( XclExpStream& rStrm )
+{
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ XclRangeList aXclRanges;
+ GetAddressConverter().ConvertRangeList( aXclRanges, maMergedRanges, true );
+ size_t nFirstRange = 0;
+ size_t nRemainingRanges = aXclRanges.size();
+ while( nRemainingRanges > 0 )
+ {
+ size_t nRangeCount = ::std::min< size_t >( nRemainingRanges, EXC_MERGEDCELLS_MAXCOUNT );
+ rStrm.StartRecord( EXC_ID_MERGEDCELLS, 2 + 8 * nRangeCount );
+ aXclRanges.WriteSubList( rStrm, nFirstRange, nRangeCount );
+ rStrm.EndRecord();
+ nFirstRange += nRangeCount;
+ nRemainingRanges -= nRangeCount;
+ }
+ }
+}
+
+void XclExpMergedcells::SaveXml( XclExpXmlStream& rStrm )
+{
+ size_t nCount = maMergedRanges.size();
+ if( !nCount )
+ return;
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_mergeCells,
+ XML_count, OString::valueOf( (sal_Int32) nCount ).getStr(),
+ FSEND );
+ for( size_t i = 0; i < nCount; ++i )
+ {
+ if( const ScRange* pRange = maMergedRanges[ i ] )
+ {
+ rWorksheet->singleElement( XML_mergeCell,
+ XML_ref, XclXmlUtils::ToOString( *pRange ).getStr(),
+ FSEND );
+ }
+ }
+ rWorksheet->endElement( XML_mergeCells );
+}
+
+// Hyperlinks =================================================================
+
+XclExpHyperlink::XclExpHyperlink( const XclExpRoot& rRoot, const SvxURLField& rUrlField, const ScAddress& rScPos ) :
+ XclExpRecord( EXC_ID_HLINK ),
+ maScPos( rScPos ),
+ mxVarData( new SvMemoryStream ),
+ mnFlags( 0 )
+{
+ const String& rUrl = rUrlField.GetURL();
+ const String& rRepr = rUrlField.GetRepresentation();
+ INetURLObject aUrlObj( rUrl );
+ const INetProtocol eProtocol = aUrlObj.GetProtocol();
+ bool bWithRepr = rRepr.Len() > 0;
+ XclExpStream aXclStrm( *mxVarData, rRoot ); // using in raw write mode.
+
+ // description
+ if( bWithRepr )
+ {
+ XclExpString aDescr( rRepr, EXC_STR_FORCEUNICODE, 255 );
+ aXclStrm << sal_uInt32( aDescr.Len() + 1 ); // string length + 1 trailing zero word
+ aDescr.WriteBuffer( aXclStrm ); // NO flags
+ aXclStrm << sal_uInt16( 0 );
+
+ mnFlags |= EXC_HLINK_DESCR;
+ mxRepr.reset( new String( rRepr ) );
+ }
+
+ // file link or URL
+ if( eProtocol == INET_PROT_FILE || eProtocol == INET_PROT_SMB )
+ {
+ sal_uInt16 nLevel;
+ bool bRel;
+ String aFileName( BuildFileName( nLevel, bRel, rUrl, rRoot ) );
+
+ if( eProtocol == INET_PROT_SMB )
+ {
+ // #n382718# (and #n261623#) Convert smb notation to '\\'
+ aFileName = aUrlObj.GetMainURL( INetURLObject::NO_DECODE );
+ aFileName = String( aFileName.GetBuffer() + 4 ); // skip the 'smb:' part
+ aFileName.SearchAndReplaceAll( '/', '\\' );
+ }
+
+ if( !bRel )
+ mnFlags |= EXC_HLINK_ABS;
+ mnFlags |= EXC_HLINK_BODY;
+
+ ByteString aAsciiLink( aFileName, rRoot.GetTextEncoding() );
+ XclExpString aLink( aFileName, EXC_STR_FORCEUNICODE, 255 );
+ aXclStrm << XclTools::maGuidFileMoniker
+ << nLevel
+ << sal_uInt32( aAsciiLink.Len() + 1 ); // string length + 1 trailing zero byte
+ aXclStrm.Write( aAsciiLink.GetBuffer(), aAsciiLink.Len() );
+ aXclStrm << sal_uInt8( 0 )
+ << sal_uInt32( 0xDEADFFFF );
+ aXclStrm.WriteZeroBytes( 20 );
+ aXclStrm << sal_uInt32( aLink.GetBufferSize() + 6 )
+ << sal_uInt32( aLink.GetBufferSize() ) // byte count, not string length
+ << sal_uInt16( 0x0003 );
+ aLink.WriteBuffer( aXclStrm ); // NO flags
+
+ if( !mxRepr.get() )
+ mxRepr.reset( new String( aFileName ) );
+
+ msTarget = XclXmlUtils::ToOUString( aLink );
+ }
+ else if( eProtocol != INET_PROT_NOT_VALID )
+ {
+ XclExpString aUrl( aUrlObj.GetURLNoMark(), EXC_STR_FORCEUNICODE, 255 );
+ aXclStrm << XclTools::maGuidUrlMoniker
+ << sal_uInt32( aUrl.GetBufferSize() + 2 ); // byte count + 1 trailing zero word
+ aUrl.WriteBuffer( aXclStrm ); // NO flags
+ aXclStrm << sal_uInt16( 0 );
+
+ mnFlags |= EXC_HLINK_BODY | EXC_HLINK_ABS;
+ if( !mxRepr.get() )
+ mxRepr.reset( new String( rUrl ) );
+
+ msTarget = XclXmlUtils::ToOUString( aUrl );
+ }
+ else if( rUrl.GetChar( 0 ) == '#' ) // hack for #89066#
+ {
+ String aTextMark( rUrl.Copy( 1 ) );
+
+ xub_StrLen nSepPos = aTextMark.SearchAndReplace( '.', '!' );
+ String aSheetName( aTextMark.Copy(0, nSepPos));
+
+ if ( aSheetName.Search(' ') != STRING_NOTFOUND && aSheetName.GetChar(0) != '\'')
+ {
+ aTextMark.Insert('\'', nSepPos);
+ aTextMark.Insert('\'', 0);
+ }
+
+ mxTextMark.reset( new XclExpString( aTextMark, EXC_STR_FORCEUNICODE, 255 ) );
+ }
+
+ // text mark
+ if( !mxTextMark.get() && aUrlObj.HasMark() )
+ mxTextMark.reset( new XclExpString( aUrlObj.GetMark(), EXC_STR_FORCEUNICODE, 255 ) );
+
+ if( mxTextMark.get() )
+ {
+ aXclStrm << sal_uInt32( mxTextMark->Len() + 1 ); // string length + 1 trailing zero word
+ mxTextMark->WriteBuffer( aXclStrm ); // NO flags
+ aXclStrm << sal_uInt16( 0 );
+
+ mnFlags |= EXC_HLINK_MARK;
+ }
+
+ SetRecSize( 32 + mxVarData->Tell() );
+}
+
+XclExpHyperlink::~XclExpHyperlink()
+{
+}
+
+String XclExpHyperlink::BuildFileName(
+ sal_uInt16& rnLevel, bool& rbRel, const String& rUrl, const XclExpRoot& rRoot ) const
+{
+ String aDosName( INetURLObject( rUrl ).getFSysPath( INetURLObject::FSYS_DOS ) );
+ rnLevel = 0;
+ rbRel = rRoot.IsRelUrl();
+
+ if( rbRel )
+ {
+ // try to convert to relative file name
+ String aTmpName( aDosName );
+ aDosName = INetURLObject::GetRelURL( rRoot.GetBasePath(), rUrl,
+ INetURLObject::WAS_ENCODED, INetURLObject::DECODE_WITH_CHARSET );
+
+ if( aDosName.SearchAscii( INET_FILE_SCHEME ) == 0 )
+ {
+ // not converted to rel -> back to old, return absolute flag
+ aDosName = aTmpName;
+ rbRel = false;
+ }
+ else if( aDosName.SearchAscii( "./" ) == 0 )
+ {
+ aDosName.Erase( 0, 2 );
+ }
+ else
+ {
+ while( aDosName.SearchAndReplaceAscii( "../", EMPTY_STRING ) == 0 )
+ ++rnLevel;
+ }
+ }
+ return aDosName;
+}
+
+void XclExpHyperlink::WriteBody( XclExpStream& rStrm )
+{
+ sal_uInt16 nXclCol = static_cast< sal_uInt16 >( maScPos.Col() );
+ sal_uInt16 nXclRow = static_cast< sal_uInt16 >( maScPos.Row() );
+ rStrm << nXclRow << nXclRow << nXclCol << nXclCol;
+ WriteEmbeddedData( rStrm );
+}
+
+void XclExpHyperlink::WriteEmbeddedData( XclExpStream& rStrm )
+{
+ rStrm << XclTools::maGuidStdLink
+ << sal_uInt32( 2 )
+ << mnFlags;
+
+ mxVarData->Seek( STREAM_SEEK_TO_BEGIN );
+ rStrm.CopyFromStream( *mxVarData );
+}
+
+void XclExpHyperlink::SaveXml( XclExpXmlStream& rStrm )
+{
+ OUString sId = msTarget.getLength() ? rStrm.addRelation( rStrm.GetCurrentStream()->getOutputStream(),
+ XclXmlUtils::ToOUString( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ),
+ msTarget,
+ XclXmlUtils::ToOUString( "External" ) ) : OUString();
+ rStrm.GetCurrentStream()->singleElement( XML_hyperlink,
+ XML_ref, XclXmlUtils::ToOString( maScPos ).getStr(),
+ FSNS( XML_r, XML_id ), sId.getLength()
+ ? XclXmlUtils::ToOString( sId ).getStr()
+ : NULL,
+ XML_location, mxTextMark.get() != NULL
+ ? XclXmlUtils::ToOString( *mxTextMark ).getStr()
+ : NULL,
+ // OOXTODO: XML_tooltip, from record HLinkTooltip 800h wzTooltip
+ XML_display, XclXmlUtils::ToOString( *mxRepr ).getStr(),
+ FSEND );
+}
+
+// Label ranges ===============================================================
+
+XclExpLabelranges::XclExpLabelranges( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+ SCTAB nScTab = GetCurrScTab();
+ // row label ranges
+ FillRangeList( maRowRanges, rRoot.GetDoc().GetRowNameRangesRef(), nScTab );
+ // row labels only over 1 column (restriction of Excel97/2000/XP)
+ for ( size_t i = 0, nRanges = maRowRanges.size(); i < nRanges; ++i )
+ {
+ ScRange* pScRange = maRowRanges[ i ];
+ if( pScRange->aStart.Col() != pScRange->aEnd.Col() )
+ pScRange->aEnd.SetCol( pScRange->aStart.Col() );
+ }
+ // col label ranges
+ FillRangeList( maColRanges, rRoot.GetDoc().GetColNameRangesRef(), nScTab );
+}
+
+void XclExpLabelranges::FillRangeList( ScRangeList& rScRanges,
+ ScRangePairListRef xLabelRangesRef, SCTAB nScTab )
+{
+ for ( size_t i = 0, nPairs = xLabelRangesRef->size(); i < nPairs; ++i )
+ {
+ ScRangePair* pRangePair = (*xLabelRangesRef)[i];
+ const ScRange& rScRange = pRangePair->GetRange( 0 );
+ if( rScRange.aStart.Tab() == nScTab )
+ rScRanges.Append( rScRange );
+ }
+}
+
+void XclExpLabelranges::Save( XclExpStream& rStrm )
+{
+ XclExpAddressConverter& rAddrConv = GetAddressConverter();
+ XclRangeList aRowXclRanges, aColXclRanges;
+ rAddrConv.ConvertRangeList( aRowXclRanges, maRowRanges, false );
+ rAddrConv.ConvertRangeList( aColXclRanges, maColRanges, false );
+ if( !aRowXclRanges.empty() || !aColXclRanges.empty() )
+ {
+ rStrm.StartRecord( EXC_ID_LABELRANGES, 4 + 8 * (aRowXclRanges.size() + aColXclRanges.size()) );
+ rStrm << aRowXclRanges << aColXclRanges;
+ rStrm.EndRecord();
+ }
+}
+
+// Conditional formatting ====================================================
+
+/** Represents a CF record that contains one condition of a conditional format. */
+class XclExpCFImpl : protected XclExpRoot
+{
+public:
+ explicit XclExpCFImpl( const XclExpRoot& rRoot, const ScCondFormatEntry& rFormatEntry );
+
+ /** Writes the body of the CF record. */
+ void WriteBody( XclExpStream& rStrm );
+
+private:
+ const ScCondFormatEntry& mrFormatEntry; /// Calc conditional format entry.
+ XclFontData maFontData; /// Font formatting attributes.
+ XclExpCellBorder maBorder; /// Border formatting attributes.
+ XclExpCellArea maArea; /// Pattern formatting attributes.
+ XclTokenArrayRef mxTokArr1; /// Formula for first condition.
+ XclTokenArrayRef mxTokArr2; /// Formula for second condition.
+ sal_uInt32 mnFontColorId; /// Font color ID.
+ sal_uInt8 mnType; /// Type of the condition (cell/formula).
+ sal_uInt8 mnOperator; /// Comparison operator for cell type.
+ bool mbFontUsed; /// true = Any font attribute used.
+ bool mbHeightUsed; /// true = Font height used.
+ bool mbWeightUsed; /// true = Font weight used.
+ bool mbColorUsed; /// true = Font color used.
+ bool mbUnderlUsed; /// true = Font underline type used.
+ bool mbItalicUsed; /// true = Font posture used.
+ bool mbStrikeUsed; /// true = Font strikeout used.
+ bool mbBorderUsed; /// true = Border attribute used.
+ bool mbPattUsed; /// true = Pattern attribute used.
+};
+
+// ----------------------------------------------------------------------------
+
+XclExpCFImpl::XclExpCFImpl( const XclExpRoot& rRoot, const ScCondFormatEntry& rFormatEntry ) :
+ XclExpRoot( rRoot ),
+ mrFormatEntry( rFormatEntry ),
+ mnFontColorId( 0 ),
+ mnType( EXC_CF_TYPE_CELL ),
+ mnOperator( EXC_CF_CMP_NONE ),
+ mbFontUsed( false ),
+ mbHeightUsed( false ),
+ mbWeightUsed( false ),
+ mbColorUsed( false ),
+ mbUnderlUsed( false ),
+ mbItalicUsed( false ),
+ mbStrikeUsed( false ),
+ mbBorderUsed( false ),
+ mbPattUsed( false )
+{
+ /* Get formatting attributes here, and not in WriteBody(). This is needed to
+ correctly insert all colors into the palette. */
+
+ if( SfxStyleSheetBase* pStyleSheet = GetDoc().GetStyleSheetPool()->Find( mrFormatEntry.GetStyle(), SFX_STYLE_FAMILY_PARA ) )
+ {
+ const SfxItemSet& rItemSet = pStyleSheet->GetItemSet();
+
+ // font
+ mbHeightUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_HEIGHT, true );
+ mbWeightUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_WEIGHT, true );
+ mbColorUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_COLOR, true );
+ mbUnderlUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_UNDERLINE, true );
+ mbItalicUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_POSTURE, true );
+ mbStrikeUsed = ScfTools::CheckItem( rItemSet, ATTR_FONT_CROSSEDOUT, true );
+ mbFontUsed = mbHeightUsed || mbWeightUsed || mbColorUsed || mbUnderlUsed || mbItalicUsed || mbStrikeUsed;
+ if( mbFontUsed )
+ {
+ Font aFont;
+ ScPatternAttr::GetFont( aFont, rItemSet, SC_AUTOCOL_RAW );
+ maFontData.FillFromVclFont( aFont );
+ mnFontColorId = GetPalette().InsertColor( maFontData.maColor, EXC_COLOR_CELLTEXT );
+ }
+
+ // border
+ mbBorderUsed = ScfTools::CheckItem( rItemSet, ATTR_BORDER, true );
+ if( mbBorderUsed )
+ maBorder.FillFromItemSet( rItemSet, GetPalette(), GetBiff() );
+
+ // pattern
+ mbPattUsed = ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, true );
+ if( mbPattUsed )
+ maArea.FillFromItemSet( rItemSet, GetPalette(), GetBiff() );
+ }
+
+ // *** mode and comparison operator ***
+
+ bool bFmla2 = false;
+ switch( rFormatEntry.GetOperation() )
+ {
+ case SC_COND_NONE: mnType = EXC_CF_TYPE_NONE; break;
+ case SC_COND_BETWEEN: mnOperator = EXC_CF_CMP_BETWEEN; bFmla2 = true; break;
+ case SC_COND_NOTBETWEEN: mnOperator = EXC_CF_CMP_NOT_BETWEEN; bFmla2 = true; break;
+ case SC_COND_EQUAL: mnOperator = EXC_CF_CMP_EQUAL; break;
+ case SC_COND_NOTEQUAL: mnOperator = EXC_CF_CMP_NOT_EQUAL; break;
+ case SC_COND_GREATER: mnOperator = EXC_CF_CMP_GREATER; break;
+ case SC_COND_LESS: mnOperator = EXC_CF_CMP_LESS; break;
+ case SC_COND_EQGREATER: mnOperator = EXC_CF_CMP_GREATER_EQUAL; break;
+ case SC_COND_EQLESS: mnOperator = EXC_CF_CMP_LESS_EQUAL; break;
+ case SC_COND_DIRECT: mnType = EXC_CF_TYPE_FMLA; break;
+ default: mnType = EXC_CF_TYPE_NONE;
+ DBG_ERRORFILE( "XclExpCF::WriteBody - unknown condition type" );
+ }
+
+ // *** formulas ***
+
+ XclExpFormulaCompiler& rFmlaComp = GetFormulaCompiler();
+
+ ::std::auto_ptr< ScTokenArray > xScTokArr( mrFormatEntry.CreateTokenArry( 0 ) );
+ mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_CONDFMT, *xScTokArr );
+
+ if( bFmla2 )
+ {
+ xScTokArr.reset( mrFormatEntry.CreateTokenArry( 1 ) );
+ mxTokArr2 = rFmlaComp.CreateFormula( EXC_FMLATYPE_CONDFMT, *xScTokArr );
+ }
+}
+
+void XclExpCFImpl::WriteBody( XclExpStream& rStrm )
+{
+ // *** mode and comparison operator ***
+
+ rStrm << mnType << mnOperator;
+
+ // *** formula sizes ***
+
+ sal_uInt16 nFmlaSize1 = mxTokArr1.get() ? mxTokArr1->GetSize() : 0;
+ sal_uInt16 nFmlaSize2 = mxTokArr2.get() ? mxTokArr2->GetSize() : 0;
+ rStrm << nFmlaSize1 << nFmlaSize2;
+
+ // *** formatting blocks ***
+
+ if( mbFontUsed || mbBorderUsed || mbPattUsed )
+ {
+ sal_uInt32 nFlags = EXC_CF_ALLDEFAULT;
+
+ ::set_flag( nFlags, EXC_CF_BLOCK_FONT, mbFontUsed );
+ ::set_flag( nFlags, EXC_CF_BLOCK_BORDER, mbBorderUsed );
+ ::set_flag( nFlags, EXC_CF_BLOCK_AREA, mbPattUsed );
+
+ // attributes used -> set flags to 0.
+ ::set_flag( nFlags, EXC_CF_BORDER_ALL, !mbBorderUsed );
+ ::set_flag( nFlags, EXC_CF_AREA_ALL, !mbPattUsed );
+
+ rStrm << nFlags << sal_uInt16( 0 );
+
+ if( mbFontUsed )
+ {
+ // font height, 0xFFFFFFFF indicates unused
+ sal_uInt32 nHeight = mbHeightUsed ? maFontData.mnHeight : 0xFFFFFFFF;
+ // font style: italic and strikeout
+ sal_uInt32 nStyle = 0;
+ ::set_flag( nStyle, EXC_CF_FONT_STYLE, maFontData.mbItalic );
+ ::set_flag( nStyle, EXC_CF_FONT_STRIKEOUT, maFontData.mbStrikeout );
+ // font color, 0xFFFFFFFF indicates unused
+ sal_uInt32 nColor = mbColorUsed ? GetPalette().GetColorIndex( mnFontColorId ) : 0xFFFFFFFF;
+ // font used flags for italic, weight, and strikeout -> 0 = used, 1 = default
+ sal_uInt32 nFontFlags1 = EXC_CF_FONT_ALLDEFAULT;
+ ::set_flag( nFontFlags1, EXC_CF_FONT_STYLE, !(mbItalicUsed || mbWeightUsed) );
+ ::set_flag( nFontFlags1, EXC_CF_FONT_STRIKEOUT, !mbStrikeUsed );
+ // font used flag for underline -> 0 = used, 1 = default
+ sal_uInt32 nFontFlags3 = mbUnderlUsed ? 0 : EXC_CF_FONT_UNDERL;
+
+ rStrm.WriteZeroBytesToRecord( 64 );
+ rStrm << nHeight
+ << nStyle
+ << maFontData.mnWeight
+ << EXC_FONTESC_NONE
+ << maFontData.mnUnderline;
+ rStrm.WriteZeroBytesToRecord( 3 );
+ rStrm << nColor
+ << sal_uInt32( 0 )
+ << nFontFlags1
+ << EXC_CF_FONT_ESCAPEM // escapement never used -> set the flag
+ << nFontFlags3;
+ rStrm.WriteZeroBytesToRecord( 16 );
+ rStrm << sal_uInt16( 1 ); // must be 1
+ }
+
+ if( mbBorderUsed )
+ {
+ sal_uInt16 nLineStyle = 0;
+ sal_uInt32 nLineColor = 0;
+ maBorder.SetFinalColors( GetPalette() );
+ maBorder.FillToCF8( nLineStyle, nLineColor );
+ rStrm << nLineStyle << nLineColor << sal_uInt16( 0 );
+ }
+
+ if( mbPattUsed )
+ {
+ sal_uInt16 nPattern = 0, nColor = 0;
+ maArea.SetFinalColors( GetPalette() );
+ maArea.FillToCF8( nPattern, nColor );
+ rStrm << nPattern << nColor;
+ }
+ }
+ else
+ {
+ // no data blocks at all
+ rStrm << sal_uInt32( 0 ) << sal_uInt16( 0 );
+ }
+
+ // *** formulas ***
+
+ if( mxTokArr1.get() )
+ mxTokArr1->WriteArray( rStrm );
+ if( mxTokArr2.get() )
+ mxTokArr2->WriteArray( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpCF::XclExpCF( const XclExpRoot& rRoot, const ScCondFormatEntry& rFormatEntry ) :
+ XclExpRecord( EXC_ID_CF ),
+ XclExpRoot( rRoot ),
+ mxImpl( new XclExpCFImpl( rRoot, rFormatEntry ) )
+{
+}
+
+XclExpCF::~XclExpCF()
+{
+}
+
+void XclExpCF::WriteBody( XclExpStream& rStrm )
+{
+ mxImpl->WriteBody( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpCondfmt::XclExpCondfmt( const XclExpRoot& rRoot, const ScConditionalFormat& rCondFormat ) :
+ XclExpRecord( EXC_ID_CONDFMT ),
+ XclExpRoot( rRoot )
+{
+ ScRangeList aScRanges;
+ GetDoc().FindConditionalFormat( rCondFormat.GetKey(), aScRanges, GetCurrScTab() );
+ GetAddressConverter().ConvertRangeList( maXclRanges, aScRanges, true );
+ if( !maXclRanges.empty() )
+ {
+ for( sal_uInt16 nIndex = 0, nCount = rCondFormat.Count(); nIndex < nCount; ++nIndex )
+ if( const ScCondFormatEntry* pEntry = rCondFormat.GetEntry( nIndex ) )
+ maCFList.AppendNewRecord( new XclExpCF( GetRoot(), *pEntry ) );
+ aScRanges.Format( msSeqRef, SCA_VALID, NULL, formula::FormulaGrammar::CONV_XL_A1 );
+ }
+}
+
+XclExpCondfmt::~XclExpCondfmt()
+{
+}
+
+bool XclExpCondfmt::IsValid() const
+{
+ return !maCFList.IsEmpty() && !maXclRanges.empty();
+}
+
+void XclExpCondfmt::Save( XclExpStream& rStrm )
+{
+ if( IsValid() )
+ {
+ XclExpRecord::Save( rStrm );
+ maCFList.Save( rStrm );
+ }
+}
+
+void XclExpCondfmt::WriteBody( XclExpStream& rStrm )
+{
+ DBG_ASSERT( !maCFList.IsEmpty(), "XclExpCondfmt::WriteBody - no CF records to write" );
+ DBG_ASSERT( !maXclRanges.empty(), "XclExpCondfmt::WriteBody - no cell ranges found" );
+
+ rStrm << static_cast< sal_uInt16 >( maCFList.GetSize() )
+ << sal_uInt16( 1 )
+ << maXclRanges.GetEnclosingRange()
+ << maXclRanges;
+}
+
+void XclExpCondfmt::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( !IsValid() )
+ return;
+
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_conditionalFormatting,
+ XML_sqref, XclXmlUtils::ToOString( msSeqRef ).getStr(),
+ // OOXTODO: XML_pivot,
+ FSEND );
+ maCFList.SaveXml( rStrm );
+ // OOXTODO: XML_extLst
+ rWorksheet->endElement( XML_conditionalFormatting );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpCondFormatBuffer::XclExpCondFormatBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+ if( const ScConditionalFormatList* pCondFmtList = GetDoc().GetCondFormList() )
+ {
+ if( const ScConditionalFormatPtr* ppCondFmt = pCondFmtList->GetData() )
+ {
+ const ScConditionalFormatPtr* ppCondEnd = ppCondFmt + pCondFmtList->Count();
+ for( ; ppCondFmt < ppCondEnd; ++ppCondFmt )
+ {
+ if( *ppCondFmt )
+ {
+ XclExpCondfmtList::RecordRefType xCondfmtRec( new XclExpCondfmt( GetRoot(), **ppCondFmt ) );
+ if( xCondfmtRec->IsValid() )
+ maCondfmtList.AppendRecord( xCondfmtRec );
+ }
+ }
+ }
+ }
+}
+
+void XclExpCondFormatBuffer::Save( XclExpStream& rStrm )
+{
+ maCondfmtList.Save( rStrm );
+}
+
+void XclExpCondFormatBuffer::SaveXml( XclExpXmlStream& rStrm )
+{
+ maCondfmtList.SaveXml( rStrm );
+}
+
+// Validation =================================================================
+
+namespace {
+
+/** Writes a formula for the DV record. */
+void lclWriteDvFormula( XclExpStream& rStrm, const XclTokenArray* pXclTokArr )
+{
+ sal_uInt16 nFmlaSize = pXclTokArr ? pXclTokArr->GetSize() : 0;
+ rStrm << nFmlaSize << sal_uInt16( 0 );
+ if( pXclTokArr )
+ pXclTokArr->WriteArray( rStrm );
+}
+
+/** Writes a formula for the DV record, based on a single string. */
+void lclWriteDvFormula( XclExpStream& rStrm, const XclExpString& rString )
+{
+ // fake a formula with a single tStr token
+ rStrm << static_cast< sal_uInt16 >( rString.GetSize() + 1 )
+ << sal_uInt16( 0 )
+ << EXC_TOKID_STR
+ << rString;
+}
+
+const char* lcl_GetValidationType( sal_uInt32 nFlags )
+{
+ switch( nFlags & EXC_DV_MODE_MASK )
+ {
+ case EXC_DV_MODE_ANY: return "none";
+ case EXC_DV_MODE_WHOLE: return "whole";
+ case EXC_DV_MODE_DECIMAL: return "decimal";
+ case EXC_DV_MODE_LIST: return "list";
+ case EXC_DV_MODE_DATE: return "date";
+ case EXC_DV_MODE_TIME: return "time";
+ case EXC_DV_MODE_TEXTLEN: return "textLength";
+ case EXC_DV_MODE_CUSTOM: return "custom";
+ }
+ return NULL;
+}
+
+const char* lcl_GetOperatorType( sal_uInt32 nFlags )
+{
+ switch( nFlags & EXC_DV_COND_MASK )
+ {
+ case EXC_DV_COND_BETWEEN: return "between";
+ case EXC_DV_COND_NOTBETWEEN: return "notBetween";
+ case EXC_DV_COND_EQUAL: return "equal";
+ case EXC_DV_COND_NOTEQUAL: return "notEqual";
+ case EXC_DV_COND_GREATER: return "greaterThan";
+ case EXC_DV_COND_LESS: return "lessThan";
+ case EXC_DV_COND_EQGREATER: return "greaterThanOrEqual";
+ case EXC_DV_COND_EQLESS: return "lessThanOrEqual";
+ }
+ return NULL;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpDV::XclExpDV( const XclExpRoot& rRoot, sal_uLong nScHandle ) :
+ XclExpRecord( EXC_ID_DV ),
+ XclExpRoot( rRoot ),
+ mnFlags( 0 ),
+ mnScHandle( nScHandle )
+{
+ if( const ScValidationData* pValData = GetDoc().GetValidationEntry( mnScHandle ) )
+ {
+ // prompt box - empty string represented by single NUL character
+ String aTitle, aText;
+ bool bShowPrompt = (pValData->GetInput( aTitle, aText ) == sal_True);
+ if( aTitle.Len() )
+ maPromptTitle.Assign( aTitle );
+ else
+ maPromptTitle.Assign( '\0' );
+ if( aText.Len() )
+ maPromptText.Assign( aText );
+ else
+ maPromptText.Assign( '\0' );
+
+ // error box - empty string represented by single NUL character
+ ScValidErrorStyle eScErrorStyle;
+ bool bShowError = (pValData->GetErrMsg( aTitle, aText, eScErrorStyle ) == sal_True);
+ if( aTitle.Len() )
+ maErrorTitle.Assign( aTitle );
+ else
+ maErrorTitle.Assign( '\0' );
+ if( aText.Len() )
+ maErrorText.Assign( aText );
+ else
+ maErrorText.Assign( '\0' );
+
+ // flags
+ switch( pValData->GetDataMode() )
+ {
+ case SC_VALID_ANY: mnFlags |= EXC_DV_MODE_ANY; break;
+ case SC_VALID_WHOLE: mnFlags |= EXC_DV_MODE_WHOLE; break;
+ case SC_VALID_DECIMAL: mnFlags |= EXC_DV_MODE_DECIMAL; break;
+ case SC_VALID_LIST: mnFlags |= EXC_DV_MODE_LIST; break;
+ case SC_VALID_DATE: mnFlags |= EXC_DV_MODE_DATE; break;
+ case SC_VALID_TIME: mnFlags |= EXC_DV_MODE_TIME; break;
+ case SC_VALID_TEXTLEN: mnFlags |= EXC_DV_MODE_TEXTLEN; break;
+ case SC_VALID_CUSTOM: mnFlags |= EXC_DV_MODE_CUSTOM; break;
+ default: DBG_ERRORFILE( "XclExpDV::XclExpDV - unknown mode" );
+ }
+
+ switch( pValData->GetOperation() )
+ {
+ case SC_COND_NONE:
+ case SC_COND_EQUAL: mnFlags |= EXC_DV_COND_EQUAL; break;
+ case SC_COND_LESS: mnFlags |= EXC_DV_COND_LESS; break;
+ case SC_COND_GREATER: mnFlags |= EXC_DV_COND_GREATER; break;
+ case SC_COND_EQLESS: mnFlags |= EXC_DV_COND_EQLESS; break;
+ case SC_COND_EQGREATER: mnFlags |= EXC_DV_COND_EQGREATER; break;
+ case SC_COND_NOTEQUAL: mnFlags |= EXC_DV_COND_NOTEQUAL; break;
+ case SC_COND_BETWEEN: mnFlags |= EXC_DV_COND_BETWEEN; break;
+ case SC_COND_NOTBETWEEN: mnFlags |= EXC_DV_COND_NOTBETWEEN; break;
+ default: DBG_ERRORFILE( "XclExpDV::XclExpDV - unknown condition" );
+ }
+ switch( eScErrorStyle )
+ {
+ case SC_VALERR_STOP: mnFlags |= EXC_DV_ERROR_STOP; break;
+ case SC_VALERR_WARNING: mnFlags |= EXC_DV_ERROR_WARNING; break;
+ case SC_VALERR_INFO: mnFlags |= EXC_DV_ERROR_INFO; break;
+ case SC_VALERR_MACRO:
+ // set INFO for validity with macro call, delete title
+ mnFlags |= EXC_DV_ERROR_INFO;
+ maErrorTitle.Assign( '\0' ); // contains macro name
+ break;
+ default: DBG_ERRORFILE( "XclExpDV::XclExpDV - unknown error style" );
+ }
+ ::set_flag( mnFlags, EXC_DV_IGNOREBLANK, pValData->IsIgnoreBlank() );
+ ::set_flag( mnFlags, EXC_DV_SUPPRESSDROPDOWN, pValData->GetListType() == ValidListType::INVISIBLE );
+ ::set_flag( mnFlags, EXC_DV_SHOWPROMPT, bShowPrompt );
+ ::set_flag( mnFlags, EXC_DV_SHOWERROR, bShowError );
+
+ // formulas
+ XclExpFormulaCompiler& rFmlaComp = GetFormulaCompiler();
+ ::std::auto_ptr< ScTokenArray > xScTokArr;
+
+ // first formula
+ xScTokArr.reset( pValData->CreateTokenArry( 0 ) );
+ if( xScTokArr.get() )
+ {
+ if( pValData->GetDataMode() == SC_VALID_LIST )
+ {
+ String aString;
+ if( XclTokenArrayHelper::GetStringList( aString, *xScTokArr, '\n' ) )
+ {
+ OUStringBuffer sFormulaBuf;
+ sFormulaBuf.append( (sal_Unicode) '"' );
+ /* Formula is a list of string tokens -> build the Excel string.
+ Data validity is BIFF8 only (important for the XclExpString object).
+ Excel uses the NUL character as string list separator. */
+ mxString1.reset( new XclExpString( EXC_STR_8BITLENGTH ) );
+ xub_StrLen nTokenCnt = aString.GetTokenCount( '\n' );
+ xub_StrLen nStringIx = 0;
+ for( xub_StrLen nToken = 0; nToken < nTokenCnt; ++nToken )
+ {
+ String aToken( aString.GetToken( 0, '\n', nStringIx ) );
+ if( nToken > 0 )
+ {
+ mxString1->Append( '\0' );
+ sFormulaBuf.append( (sal_Unicode) ',' );
+ }
+ mxString1->Append( aToken );
+ sFormulaBuf.append( XclXmlUtils::ToOUString( aToken ) );
+ }
+ ::set_flag( mnFlags, EXC_DV_STRINGLIST );
+
+ sFormulaBuf.append( (sal_Unicode) '"' );
+ msFormula1 = sFormulaBuf.makeStringAndClear();
+ }
+ else
+ {
+ /* All other formulas in validation are stored like conditional
+ formatting formulas (with tRefN/tAreaN tokens as value or
+ array class). But NOT the cell references and defined names
+ in list validation - they are stored as reference class
+ tokens... Example:
+ 1) Cell must be equal to A1 -> formula is =A1 -> writes tRefNV token
+ 2) List is taken from A1 -> formula is =A1 -> writes tRefNR token
+ Formula compiler supports this by offering two different functions
+ CreateDataValFormula() and CreateListValFormula(). */
+ mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_LISTVAL, *xScTokArr );
+ msFormula1 = XclXmlUtils::ToOUString( GetDoc(), pValData->GetSrcPos(), xScTokArr.get() );
+ }
+ }
+ else
+ {
+ // no list validation -> convert the formula
+ mxTokArr1 = rFmlaComp.CreateFormula( EXC_FMLATYPE_DATAVAL, *xScTokArr );
+ msFormula1 = XclXmlUtils::ToOUString( GetDoc(), pValData->GetSrcPos(), xScTokArr.get() );
+ }
+ }
+
+ // second formula
+ xScTokArr.reset( pValData->CreateTokenArry( 1 ) );
+ if( xScTokArr.get() )
+ {
+ mxTokArr2 = rFmlaComp.CreateFormula( EXC_FMLATYPE_DATAVAL, *xScTokArr );
+ msFormula2 = XclXmlUtils::ToOUString( GetDoc(), pValData->GetSrcPos(), xScTokArr.get() );
+ }
+ }
+ else
+ {
+ DBG_ERRORFILE( "XclExpDV::XclExpDV - missing core data" );
+ mnScHandle = ULONG_MAX;
+ }
+}
+
+XclExpDV::~XclExpDV()
+{
+}
+
+void XclExpDV::InsertCellRange( const ScRange& rRange )
+{
+ maScRanges.Join( rRange );
+}
+
+bool XclExpDV::Finalize()
+{
+ GetAddressConverter().ConvertRangeList( maXclRanges, maScRanges, true );
+ return (mnScHandle != ULONG_MAX) && !maXclRanges.empty();
+}
+
+void XclExpDV::WriteBody( XclExpStream& rStrm )
+{
+ // flags and strings
+ rStrm << mnFlags << maPromptTitle << maErrorTitle << maPromptText << maErrorText;
+ // condition formulas
+ if( mxString1.get() )
+ lclWriteDvFormula( rStrm, *mxString1 );
+ else
+ lclWriteDvFormula( rStrm, mxTokArr1.get() );
+ lclWriteDvFormula( rStrm, mxTokArr2.get() );
+ // cell ranges
+ rStrm << maXclRanges;
+}
+
+void XclExpDV::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_dataValidation,
+ XML_allowBlank, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_IGNOREBLANK ) ),
+ XML_error, XESTRING_TO_PSZ( maErrorText ),
+ // OOXTODO: XML_errorStyle,
+ XML_errorTitle, XESTRING_TO_PSZ( maErrorTitle ),
+ // OOXTODO: XML_imeMode,
+ XML_operator, lcl_GetOperatorType( mnFlags ),
+ XML_prompt, XESTRING_TO_PSZ( maPromptText ),
+ XML_promptTitle, XESTRING_TO_PSZ( maPromptTitle ),
+ // showDropDown should have been showNoDropDown - check oox/xlsx import for details
+ XML_showDropDown, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SUPPRESSDROPDOWN ) ),
+ XML_showErrorMessage, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SHOWERROR ) ),
+ XML_showInputMessage, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_DV_SHOWPROMPT ) ),
+ XML_sqref, XclXmlUtils::ToOString( maScRanges ).getStr(),
+ XML_type, lcl_GetValidationType( mnFlags ),
+ FSEND );
+ if( msFormula1.getLength() )
+ {
+ rWorksheet->startElement( XML_formula1, FSEND );
+ rWorksheet->writeEscaped( msFormula1 );
+ rWorksheet->endElement( XML_formula1 );
+ }
+ if( msFormula2.getLength() )
+ {
+ rWorksheet->startElement( XML_formula2, FSEND );
+ rWorksheet->writeEscaped( msFormula2 );
+ rWorksheet->endElement( XML_formula2 );
+ }
+ rWorksheet->endElement( XML_dataValidation );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpDval::XclExpDval( const XclExpRoot& rRoot ) :
+ XclExpRecord( EXC_ID_DVAL, 18 ),
+ XclExpRoot( rRoot )
+{
+}
+
+XclExpDval::~XclExpDval()
+{
+}
+
+void XclExpDval::InsertCellRange( const ScRange& rRange, sal_uLong nScHandle )
+{
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ XclExpDV& rDVRec = SearchOrCreateDv( nScHandle );
+ rDVRec.InsertCellRange( rRange );
+ }
+}
+
+void XclExpDval::Save( XclExpStream& rStrm )
+{
+ // check all records
+ size_t nPos = maDVList.GetSize();
+ while( nPos )
+ {
+ --nPos; // backwards to keep nPos valid
+ XclExpDVRef xDVRec = maDVList.GetRecord( nPos );
+ if( !xDVRec->Finalize() )
+ maDVList.RemoveRecord( nPos );
+ }
+
+ // write the DVAL and the DV's
+ if( !maDVList.IsEmpty() )
+ {
+ XclExpRecord::Save( rStrm );
+ maDVList.Save( rStrm );
+ }
+}
+
+void XclExpDval::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( maDVList.IsEmpty() )
+ return;
+
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_dataValidations,
+ XML_count, OString::valueOf( (sal_Int32) maDVList.GetSize() ).getStr(),
+ // OOXTODO: XML_disablePrompts,
+ // OOXTODO: XML_xWindow,
+ // OOXTODO: XML_yWindow,
+ FSEND );
+ maDVList.SaveXml( rStrm );
+ rWorksheet->endElement( XML_dataValidations );
+}
+
+XclExpDV& XclExpDval::SearchOrCreateDv( sal_uLong nScHandle )
+{
+ // test last found record
+ if( mxLastFoundDV.get() && (mxLastFoundDV->GetScHandle() == nScHandle) )
+ return *mxLastFoundDV;
+
+ // binary search
+ size_t nCurrPos = 0;
+ if( !maDVList.IsEmpty() )
+ {
+ size_t nFirstPos = 0;
+ size_t nLastPos = maDVList.GetSize() - 1;
+ bool bLoop = true;
+ sal_uLong nCurrScHandle = ::std::numeric_limits< sal_uLong >::max();
+ while( (nFirstPos <= nLastPos) && bLoop )
+ {
+ nCurrPos = (nFirstPos + nLastPos) / 2;
+ mxLastFoundDV = maDVList.GetRecord( nCurrPos );
+ nCurrScHandle = mxLastFoundDV->GetScHandle();
+ if( nCurrScHandle == nScHandle )
+ bLoop = false;
+ else if( nCurrScHandle < nScHandle )
+ nFirstPos = nCurrPos + 1;
+ else if( nCurrPos )
+ nLastPos = nCurrPos - 1;
+ else // special case for nLastPos = -1
+ bLoop = false;
+ }
+ if( nCurrScHandle == nScHandle )
+ return *mxLastFoundDV;
+ else if( nCurrScHandle < nScHandle )
+ ++nCurrPos;
+ }
+
+ // create new DV record
+ mxLastFoundDV.reset( new XclExpDV( *this, nScHandle ) );
+ maDVList.InsertRecord( mxLastFoundDV, nCurrPos );
+ return *mxLastFoundDV;
+}
+
+void XclExpDval::WriteBody( XclExpStream& rStrm )
+{
+ rStrm.WriteZeroBytes( 10 );
+ rStrm << EXC_DVAL_NOOBJ << static_cast< sal_uInt32 >( maDVList.GetSize() );
+}
+
+// Web Queries ================================================================
+
+XclExpWebQuery::XclExpWebQuery(
+ const String& rRangeName,
+ const String& rUrl,
+ const String& rSource,
+ sal_Int32 nRefrSecs ) :
+ maDestRange( rRangeName ),
+ maUrl( rUrl ),
+ // refresh delay time: seconds -> minutes
+ mnRefresh( ulimit_cast< sal_Int16 >( (nRefrSecs + 59L) / 60L ) ),
+ mbEntireDoc( false )
+{
+ // comma separated list of HTML table names or indexes
+ xub_StrLen nTokenCnt = rSource.GetTokenCount( ';' );
+ String aNewTables, aAppendTable;
+ xub_StrLen nStringIx = 0;
+ bool bExitLoop = false;
+ for( xub_StrLen nToken = 0; (nToken < nTokenCnt) && !bExitLoop; ++nToken )
+ {
+ String aToken( rSource.GetToken( 0, ';', nStringIx ) );
+ mbEntireDoc = ScfTools::IsHTMLDocName( aToken );
+ bExitLoop = mbEntireDoc || ScfTools::IsHTMLTablesName( aToken );
+ if( !bExitLoop && ScfTools::GetHTMLNameFromName( aToken, aAppendTable ) )
+ ScGlobal::AddToken( aNewTables, aAppendTable, ',' );
+ }
+
+ if( !bExitLoop ) // neither HTML_all nor HTML_tables found
+ {
+ if( aNewTables.Len() )
+ mxQryTables.reset( new XclExpString( aNewTables ) );
+ else
+ mbEntireDoc = true;
+ }
+}
+
+XclExpWebQuery::~XclExpWebQuery()
+{
+}
+
+void XclExpWebQuery::Save( XclExpStream& rStrm )
+{
+ DBG_ASSERT( !mbEntireDoc || !mxQryTables.get(), "XclExpWebQuery::Save - illegal mode" );
+ sal_uInt16 nFlags;
+
+ // QSI record
+ rStrm.StartRecord( EXC_ID_QSI, 10 + maDestRange.GetSize() );
+ rStrm << EXC_QSI_DEFAULTFLAGS
+ << sal_uInt16( 0x0010 )
+ << sal_uInt16( 0x0012 )
+ << sal_uInt32( 0x00000000 )
+ << maDestRange;
+ rStrm.EndRecord();
+
+ // PARAMQRY record
+ nFlags = 0;
+ ::insert_value( nFlags, EXC_PQRYTYPE_WEBQUERY, 0, 3 );
+ ::set_flag( nFlags, EXC_PQRY_WEBQUERY );
+ ::set_flag( nFlags, EXC_PQRY_TABLES, !mbEntireDoc );
+ rStrm.StartRecord( EXC_ID_PQRY, 12 );
+ rStrm << nFlags
+ << sal_uInt16( 0x0000 )
+ << sal_uInt16( 0x0001 );
+ rStrm.WriteZeroBytes( 6 );
+ rStrm.EndRecord();
+
+ // WQSTRING record
+ rStrm.StartRecord( EXC_ID_WQSTRING, maUrl.GetSize() );
+ rStrm << maUrl;
+ rStrm.EndRecord();
+
+ // unknown record 0x0802
+ rStrm.StartRecord( EXC_ID_0802, 16 + maDestRange.GetSize() );
+ rStrm << EXC_ID_0802; // repeated record id ?!?
+ rStrm.WriteZeroBytes( 6 );
+ rStrm << sal_uInt16( 0x0003 )
+ << sal_uInt32( 0x00000000 )
+ << sal_uInt16( 0x0010 )
+ << maDestRange;
+ rStrm.EndRecord();
+
+ // WEBQRYSETTINGS record
+ nFlags = mxQryTables.get() ? EXC_WQSETT_SPECTABLES : EXC_WQSETT_ALL;
+ rStrm.StartRecord( EXC_ID_WQSETT, 28 );
+ rStrm << EXC_ID_WQSETT // repeated record id ?!?
+ << sal_uInt16( 0x0000 )
+ << sal_uInt16( 0x0004 )
+ << sal_uInt16( 0x0000 )
+ << EXC_WQSETT_DEFAULTFLAGS
+ << nFlags;
+ rStrm.WriteZeroBytes( 10 );
+ rStrm << mnRefresh // refresh delay in minutes
+ << EXC_WQSETT_FORMATFULL
+ << sal_uInt16( 0x0000 );
+ rStrm.EndRecord();
+
+ // WEBQRYTABLES record
+ if( mxQryTables.get() )
+ {
+ rStrm.StartRecord( EXC_ID_WQTABLES, 4 + mxQryTables->GetSize() );
+ rStrm << EXC_ID_WQTABLES // repeated record id ?!?
+ << sal_uInt16( 0x0000 )
+ << *mxQryTables; // comma separated list of source tables
+ rStrm.EndRecord();
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpWebQueryBuffer::XclExpWebQueryBuffer( const XclExpRoot& rRoot )
+{
+ SCTAB nScTab = rRoot.GetCurrScTab();
+ SfxObjectShell* pShell = rRoot.GetDocShell();
+ if( !pShell ) return;
+ ScfPropertySet aModelProp( pShell->GetModel() );
+ if( !aModelProp.Is() ) return;
+
+ Reference< XAreaLinks > xAreaLinks;
+ aModelProp.GetProperty( xAreaLinks, CREATE_OUSTRING( SC_UNO_AREALINKS ) );
+ Reference< XIndexAccess > xLinksIA( xAreaLinks, UNO_QUERY );
+ if( !xLinksIA.is() ) return;
+
+ for( sal_Int32 nIndex = 0, nCount = xLinksIA->getCount(); nIndex < nCount; ++nIndex )
+ {
+ Reference< XAreaLink > xAreaLink( xLinksIA->getByIndex( nIndex ), UNO_QUERY );
+ if( xAreaLink.is() )
+ {
+ CellRangeAddress aDestRange( xAreaLink->getDestArea() );
+ if( static_cast< SCTAB >( aDestRange.Sheet ) == nScTab )
+ {
+ ScfPropertySet aLinkProp( xAreaLink );
+ OUString aFilter;
+ if( aLinkProp.GetProperty( aFilter, CREATE_OUSTRING( SC_UNONAME_FILTER ) ) &&
+ (aFilter == CREATE_OUSTRING( EXC_WEBQRY_FILTER )) )
+ {
+ // get properties
+ OUString /*aFilterOpt,*/ aUrl;
+ sal_Int32 nRefresh = 0;
+
+// aLinkProp.GetProperty( aFilterOpt, CREATE_OUSTRING( SC_UNONAME_FILTOPT ) );
+ aLinkProp.GetProperty( aUrl, CREATE_OUSTRING( SC_UNONAME_LINKURL ) );
+ aLinkProp.GetProperty( nRefresh, CREATE_OUSTRING( SC_UNONAME_REFDELAY ) );
+
+ String aAbsDoc( ScGlobal::GetAbsDocName( aUrl, pShell ) );
+ INetURLObject aUrlObj( aAbsDoc );
+ String aWebQueryUrl( aUrlObj.getFSysPath( INetURLObject::FSYS_DOS ) );
+ if( !aWebQueryUrl.Len() )
+ aWebQueryUrl = aAbsDoc;
+
+ // find range or create a new range
+ String aRangeName;
+ ScRange aScDestRange;
+ ScUnoConversion::FillScRange( aScDestRange, aDestRange );
+ if( const ScRangeData* pRangeData = rRoot.GetNamedRanges().findByRange( aScDestRange ) )
+ {
+ aRangeName = pRangeData->GetName();
+ }
+ else
+ {
+ XclExpFormulaCompiler& rFmlaComp = rRoot.GetFormulaCompiler();
+ XclExpNameManager& rNameMgr = rRoot.GetNameManager();
+
+ // create a new unique defined name containing the range
+ XclTokenArrayRef xTokArr = rFmlaComp.CreateFormula( EXC_FMLATYPE_WQUERY, aScDestRange );
+ sal_uInt16 nNameIdx = rNameMgr.InsertUniqueName( aUrlObj.getBase(), xTokArr, nScTab );
+ aRangeName = rNameMgr.GetOrigName( nNameIdx );
+ }
+
+ // create and store the web query record
+ if( aRangeName.Len() )
+ AppendNewRecord( new XclExpWebQuery(
+ aRangeName, aWebQueryUrl, xAreaLink->getSourceArea(), nRefresh ) );
+ }
+ }
+ }
+ }
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xeescher.cxx b/sc/source/filter/excel/xeescher.cxx
new file mode 100644
index 000000000000..30197d25f7d5
--- /dev/null
+++ b/sc/source/filter/excel/xeescher.cxx
@@ -0,0 +1,1641 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "xeescher.hxx"
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/awt/VisualEffect.hpp>
+#include <com/sun/star/awt/ScrollBarOrientation.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XValueBinding.hpp>
+#include <com/sun/star/form/binding/XListEntrySink.hpp>
+#include <com/sun/star/form/binding/XListEntrySource.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+
+#include <set>
+#include <rtl/ustrbuf.h>
+#include <vcl/bmpacc.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdocapt.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+
+#include "editutil.hxx"
+#include "unonames.hxx"
+#include "convuno.hxx"
+#include "postit.hxx"
+
+#include "fapihelper.hxx"
+#include "xechart.hxx"
+#include "xeformula.hxx"
+#include "xelink.hxx"
+#include "xename.hxx"
+#include "xestyle.hxx"
+#include "userdat.hxx"
+#include "drwlayer.hxx"
+#include "svx/unoapi.hxx"
+#include "svx/algitem.hxx"
+#include "scitems.hxx"
+#include <editeng/justifyitem.hxx>
+#include "svx/sdtaitm.hxx"
+#include "attrib.hxx"
+#include "document.hxx"
+#include <svx/svdattr.hxx>
+#include "svx/sdr/properties/properties.hxx"
+#include "detfunc.hxx"
+#include "svx/xflclit.hxx"
+#include "svx/xlnstwit.hxx"
+#include "svx/xlnstit.hxx"
+#include "svx/sxmspitm.hxx"
+
+#include <oox/token/tokens.hxx>
+#include <oox/export/drawingml.hxx>
+#include <oox/export/chartexport.hxx>
+#include <oox/export/utils.hxx>
+#include <boost/shared_ptr.hpp>
+
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::lang::XServiceInfo;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::drawing::XShapes;
+using ::com::sun::star::frame::XModel;
+using ::com::sun::star::embed::XEmbeddedObject;
+using ::com::sun::star::awt::XControlModel;
+using ::com::sun::star::form::binding::XBindableValue;
+using ::com::sun::star::form::binding::XValueBinding;
+using ::com::sun::star::form::binding::XListEntrySink;
+using ::com::sun::star::form::binding::XListEntrySource;
+using ::com::sun::star::script::ScriptEventDescriptor;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+using ::com::sun::star::chart2::XChartDocument;
+using ::com::sun::star::container::XNamed;
+using ::oox::drawingml::DrawingML;
+using ::oox::drawingml::ChartExport;
+using namespace oox;
+
+#define HMM2XL(x) ((x)/26.5)+0.5
+
+#ifdef XLSX_OOXML_FUTURE
+// these function are only used within that context
+// Static Function Helpers
+static const char *ToHorizAlign( SdrTextHorzAdjust eAdjust )
+{
+ switch( eAdjust )
+ {
+ case SDRTEXTHORZADJUST_CENTER:
+ return "center";
+ case SDRTEXTHORZADJUST_RIGHT:
+ return "right";
+ case SDRTEXTHORZADJUST_BLOCK:
+ return "justify";
+ case SDRTEXTHORZADJUST_LEFT:
+ default:
+ return "left";
+ }
+ return "unknown";
+}
+
+static const char *ToVertAlign( SdrTextVertAdjust eAdjust )
+{
+ switch( eAdjust )
+ {
+ case SDRTEXTVERTADJUST_CENTER:
+ return "center";
+ case SDRTEXTVERTADJUST_BOTTOM:
+ return "bottom";
+ case SDRTEXTVERTADJUST_BLOCK:
+ return "justify";
+ case SDRTEXTVERTADJUST_TOP:
+ default:
+ return "top";
+ }
+ return "unknown";
+}
+
+static void lcl_WriteAnchorVertex( sax_fastparser::FSHelperPtr rComments, Rectangle &aRect )
+{
+ rComments->startElement( FSNS( XML_xdr, XML_col ), FSEND );
+ rComments->writeEscaped( OUString::valueOf( aRect.Left() ) );
+ rComments->endElement( FSNS( XML_xdr, XML_col ) );
+ rComments->startElement( FSNS( XML_xdr, XML_colOff ), FSEND );
+ rComments->writeEscaped( OUString::valueOf( aRect.Top() ) );
+ rComments->endElement( FSNS( XML_xdr, XML_colOff ) );
+ rComments->startElement( FSNS( XML_xdr, XML_row ), FSEND );
+ rComments->writeEscaped( OUString::valueOf( aRect.Right() ) );
+ rComments->endElement( FSNS( XML_xdr, XML_row ) );
+ rComments->startElement( FSNS( XML_xdr, XML_rowOff ), FSEND );
+ rComments->writeEscaped( OUString::valueOf( aRect.Bottom() ) );
+ rComments->endElement( FSNS( XML_xdr, XML_rowOff ) );
+}
+#endif
+
+static void lcl_GetFromTo( const XclExpRoot& rRoot, const Rectangle &aRect, sal_Int32 nTab, Rectangle &aFrom, Rectangle &aTo )
+{
+ bool bTo = false;
+ sal_Int32 nCol = 0, nRow = 0;
+ sal_Int32 nColOff = 0, nRowOff= 0;
+
+ while(1)
+ {
+ Rectangle r = rRoot.GetDocPtr()->GetMMRect( nCol,nRow,nCol,nRow,nTab );
+ if( !bTo )
+ {
+ if( r.Left() <= aRect.Left() )
+ {
+ nCol++;
+ nColOff = aRect.Left() - r.Left();
+ }
+ if( r.Top() <= aRect.Top() )
+ {
+ nRow++;
+ nRowOff = aRect.Top() - r.Top();
+ }
+ if( r.Left() > aRect.Left() && r.Top() > aRect.Top() )
+ {
+ aFrom = Rectangle( nCol-1, HMM2XL( nColOff ),
+ nRow-1, HMM2XL( nRowOff ) );
+ bTo=true;
+ }
+ }
+ if( bTo )
+ {
+ if( r.Right() < aRect.Right() )
+ nCol++;
+ if( r.Bottom() < aRect.Bottom() )
+ nRow++;
+ if( r.Right() >= aRect.Right() && r.Bottom() >= aRect.Bottom() )
+ {
+ aTo = Rectangle( nCol, HMM2XL( aRect.Right() - r.Left() ),
+ nRow, HMM2XL( aRect.Bottom() - r.Top() ));
+ break;
+ }
+ }
+ }
+ return;
+}
+
+// Escher client anchor =======================================================
+
+XclExpDffAnchorBase::XclExpDffAnchorBase( const XclExpRoot& rRoot, sal_uInt16 nFlags ) :
+ XclExpRoot( rRoot ),
+ mnFlags( nFlags )
+{
+}
+
+void XclExpDffAnchorBase::SetFlags( const SdrObject& rSdrObj )
+{
+ ImplSetFlags( rSdrObj );
+}
+
+void XclExpDffAnchorBase::SetSdrObject( const SdrObject& rSdrObj )
+{
+ ImplSetFlags( rSdrObj );
+ ImplCalcAnchorRect( rSdrObj.GetCurrentBoundRect(), MAP_100TH_MM );
+}
+
+void XclExpDffAnchorBase::WriteDffData( EscherEx& rEscherEx ) const
+{
+ rEscherEx.AddAtom( 18, ESCHER_ClientAnchor );
+ rEscherEx.GetStream() << mnFlags << maAnchor;
+}
+
+void XclExpDffAnchorBase::WriteData( EscherEx& rEscherEx, const Rectangle& rRect )
+{
+ // the passed rectangle is in twips
+ ImplCalcAnchorRect( rRect, MAP_TWIP );
+ WriteDffData( rEscherEx );
+}
+
+void XclExpDffAnchorBase::ImplSetFlags( const SdrObject& )
+{
+ OSL_FAIL( "XclExpDffAnchorBase::ImplSetFlags - not implemented" );
+}
+
+void XclExpDffAnchorBase::ImplCalcAnchorRect( const Rectangle&, MapUnit )
+{
+ OSL_FAIL( "XclExpDffAnchorBase::ImplCalcAnchorRect - not implemented" );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpDffSheetAnchor::XclExpDffSheetAnchor( const XclExpRoot& rRoot ) :
+ XclExpDffAnchorBase( rRoot ),
+ mnScTab( rRoot.GetCurrScTab() )
+{
+}
+
+void XclExpDffSheetAnchor::ImplSetFlags( const SdrObject& rSdrObj )
+{
+ // Special case "page anchor" (X==0,Y==1) -> lock pos and size.
+ const Point& rPos = rSdrObj.GetAnchorPos();
+ mnFlags = ((rPos.X() == 0) && (rPos.Y() == 1)) ? EXC_ESC_ANCHOR_LOCKED : 0;
+}
+
+void XclExpDffSheetAnchor::ImplCalcAnchorRect( const Rectangle& rRect, MapUnit eMapUnit )
+{
+ maAnchor.SetRect( GetRoot(), mnScTab, rRect, eMapUnit );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpDffEmbeddedAnchor::XclExpDffEmbeddedAnchor( const XclExpRoot& rRoot,
+ const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
+ XclExpDffAnchorBase( rRoot ),
+ maPageSize( rPageSize ),
+ mnScaleX( nScaleX ),
+ mnScaleY( nScaleY )
+{
+}
+
+void XclExpDffEmbeddedAnchor::ImplSetFlags( const SdrObject& /*rSdrObj*/ )
+{
+ // TODO (unsupported feature): fixed size
+}
+
+void XclExpDffEmbeddedAnchor::ImplCalcAnchorRect( const Rectangle& rRect, MapUnit eMapUnit )
+{
+ maAnchor.SetRect( maPageSize, mnScaleX, mnScaleY, rRect, eMapUnit, true );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpDffNoteAnchor::XclExpDffNoteAnchor( const XclExpRoot& rRoot, const Rectangle& rRect ) :
+ XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_SIZELOCKED )
+{
+ maAnchor.SetRect( rRoot, rRoot.GetCurrScTab(), rRect, MAP_100TH_MM );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpDffDropDownAnchor::XclExpDffDropDownAnchor( const XclExpRoot& rRoot, const ScAddress& rScPos ) :
+ XclExpDffAnchorBase( rRoot, EXC_ESC_ANCHOR_POSLOCKED )
+{
+ GetAddressConverter().ConvertAddress( maAnchor.maFirst, rScPos, true );
+ maAnchor.maLast.mnCol = maAnchor.maFirst.mnCol + 1;
+ maAnchor.maLast.mnRow = maAnchor.maFirst.mnRow + 1;
+ maAnchor.mnLX = maAnchor.mnTY = maAnchor.mnRX = maAnchor.mnBY = 0;
+}
+
+// MSODRAWING* records ========================================================
+
+XclExpMsoDrawingBase::XclExpMsoDrawingBase( XclEscherEx& rEscherEx, sal_uInt16 nRecId ) :
+ XclExpRecord( nRecId ),
+ mrEscherEx( rEscherEx ),
+ mnFragmentKey( rEscherEx.InitNextDffFragment() )
+{
+}
+
+void XclExpMsoDrawingBase::WriteBody( XclExpStream& rStrm )
+{
+ OSL_ENSURE( mrEscherEx.GetStreamPos() == mrEscherEx.GetDffFragmentPos( mnFragmentKey ),
+ "XclExpMsoDrawingBase::WriteBody - DFF stream position mismatch" );
+ rStrm.CopyFromStream( mrEscherEx.GetStream(), mrEscherEx.GetDffFragmentSize( mnFragmentKey ) );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpMsoDrawingGroup::XclExpMsoDrawingGroup( XclEscherEx& rEscherEx ) :
+ XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWINGGROUP )
+{
+ SvStream& rDffStrm = mrEscherEx.GetStream();
+
+ // write the DGGCONTAINER with some default settings
+ mrEscherEx.OpenContainer( ESCHER_DggContainer );
+
+ // TODO: stuff the OPT atom with our own document defaults?
+ static const sal_uInt8 spnDffOpt[] = {
+ 0xBF, 0x00, 0x08, 0x00, 0x08, 0x00, 0x81, 0x01,
+ 0x09, 0x00, 0x00, 0x08, 0xC0, 0x01, 0x40, 0x00,
+ 0x00, 0x08
+ };
+ mrEscherEx.AddAtom( sizeof( spnDffOpt ), ESCHER_OPT, 3, 3 );
+ rDffStrm.Write( spnDffOpt, sizeof( spnDffOpt ) );
+
+ // SPLITMENUCOLORS contains colors in toolbar
+ static const sal_uInt8 spnDffSplitMenuColors[] = {
+ 0x0D, 0x00, 0x00, 0x08, 0x0C, 0x00, 0x00, 0x08,
+ 0x17, 0x00, 0x00, 0x08, 0xF7, 0x00, 0x00, 0x10
+ };
+ mrEscherEx.AddAtom( sizeof( spnDffSplitMenuColors ), ESCHER_SplitMenuColors, 0, 4 );
+ rDffStrm.Write( spnDffSplitMenuColors, sizeof( spnDffSplitMenuColors ) );
+
+ // close the DGGCONTAINER
+ mrEscherEx.CloseContainer();
+ mrEscherEx.UpdateDffFragmentEnd();
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpMsoDrawing::XclExpMsoDrawing( XclEscherEx& rEscherEx ) :
+ XclExpMsoDrawingBase( rEscherEx, EXC_ID_MSODRAWING )
+{
+}
+
+// ============================================================================
+
+XclExpImgData::XclExpImgData( const Graphic& rGraphic, sal_uInt16 nRecId ) :
+ maGraphic( rGraphic ),
+ mnRecId( nRecId )
+{
+}
+
+void XclExpImgData::Save( XclExpStream& rStrm )
+{
+ Bitmap aBmp = maGraphic.GetBitmap();
+ if( aBmp.GetBitCount() != 24 )
+ aBmp.Convert( BMP_CONVERSION_24BIT );
+
+ if( BitmapReadAccess* pAccess = aBmp.AcquireReadAccess() )
+ {
+ sal_Int32 nWidth = ::std::min< sal_Int32 >( pAccess->Width(), 0xFFFF );
+ sal_Int32 nHeight = ::std::min< sal_Int32 >( pAccess->Height(), 0xFFFF );
+ if( (nWidth > 0) && (nHeight > 0) )
+ {
+ sal_uInt8 nPadding = static_cast< sal_uInt8 >( nWidth & 0x03 );
+ sal_uInt32 nTmpSize = static_cast< sal_uInt32 >( (nWidth * 3 + nPadding) * nHeight + 12 );
+
+ rStrm.StartRecord( mnRecId, nTmpSize + 4 );
+
+ rStrm << EXC_IMGDATA_BMP // BMP format
+ << EXC_IMGDATA_WIN // Windows
+ << nTmpSize // size after _this_ field
+ << sal_uInt32( 12 ) // BITMAPCOREHEADER size
+ << static_cast< sal_uInt16 >( nWidth ) // width
+ << static_cast< sal_uInt16 >( nHeight ) // height
+ << sal_uInt16( 1 ) // planes
+ << sal_uInt16( 24 ); // bits per pixel
+
+ for( sal_Int32 nY = nHeight - 1; nY >= 0; --nY )
+ {
+ for( sal_Int32 nX = 0; nX < nWidth; ++nX )
+ {
+ const BitmapColor& rBmpColor = pAccess->GetPixel( nY, nX );
+ rStrm << rBmpColor.GetBlue() << rBmpColor.GetGreen() << rBmpColor.GetRed();
+ }
+ rStrm.WriteZeroBytes( nPadding );
+ }
+
+ rStrm.EndRecord();
+ }
+ aBmp.ReleaseAccess( pAccess );
+ }
+}
+
+void XclExpImgData::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr pWorksheet = rStrm.GetCurrentStream();
+
+ DrawingML aDML( pWorksheet, &rStrm, DrawingML::DOCUMENT_XLSX );
+ OUString rId = aDML.WriteImage( maGraphic );
+ pWorksheet->singleElement( XML_picture,
+ FSNS( XML_r, XML_id ), XclXmlUtils::ToOString( rId ).getStr(),
+ FSEND );
+}
+
+// ============================================================================
+
+XclExpControlHelper::XclExpControlHelper( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mnEntryCount( 0 )
+{
+}
+
+XclExpControlHelper::~XclExpControlHelper()
+{
+}
+
+void XclExpControlHelper::ConvertSheetLinks( Reference< XShape > xShape )
+{
+ mxCellLink.reset();
+ mxSrcRange.reset();
+ mnEntryCount = 0;
+
+ // get control model
+ Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
+ if( !xCtrlModel.is() )
+ return;
+
+ // *** cell link *** ------------------------------------------------------
+
+ Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY );
+ if( xBindable.is() )
+ {
+ Reference< XServiceInfo > xServInfo( xBindable->getValueBinding(), UNO_QUERY );
+ if( xServInfo.is() && xServInfo->supportsService( CREATE_OUSTRING( SC_SERVICENAME_VALBIND ) ) )
+ {
+ ScfPropertySet aBindProp( xServInfo );
+ CellAddress aApiAddress;
+ if( aBindProp.GetProperty( aApiAddress, CREATE_OUSTRING( SC_UNONAME_BOUNDCELL ) ) )
+ {
+ ScAddress aCellLink;
+ ScUnoConversion::FillScAddress( aCellLink, aApiAddress );
+ if( GetTabInfo().IsExportTab( aCellLink.Tab() ) )
+ mxCellLink = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, aCellLink );
+ }
+ }
+ }
+
+ // *** source range *** ---------------------------------------------------
+
+ Reference< XListEntrySink > xEntrySink( xCtrlModel, UNO_QUERY );
+ if( xEntrySink.is() )
+ {
+ Reference< XServiceInfo > xServInfo( xEntrySink->getListEntrySource(), UNO_QUERY );
+ if( xServInfo.is() && xServInfo->supportsService( CREATE_OUSTRING( SC_SERVICENAME_LISTSOURCE ) ) )
+ {
+ ScfPropertySet aSinkProp( xServInfo );
+ CellRangeAddress aApiRange;
+ if( aSinkProp.GetProperty( aApiRange, CREATE_OUSTRING( SC_UNONAME_CELLRANGE ) ) )
+ {
+ ScRange aSrcRange;
+ ScUnoConversion::FillScRange( aSrcRange, aApiRange );
+ if( (aSrcRange.aStart.Tab() == aSrcRange.aEnd.Tab()) && GetTabInfo().IsExportTab( aSrcRange.aStart.Tab() ) )
+ mxSrcRange = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, aSrcRange );
+ mnEntryCount = static_cast< sal_uInt16 >( aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1 );
+ }
+ }
+ }
+}
+
+void XclExpControlHelper::WriteFormula( XclExpStream& rStrm, const XclTokenArray& rTokArr ) const
+{
+ sal_uInt16 nFmlaSize = rTokArr.GetSize();
+ rStrm << nFmlaSize << sal_uInt32( 0 );
+ rTokArr.WriteArray( rStrm );
+ if( nFmlaSize & 1 ) // pad to 16-bit
+ rStrm << sal_uInt8( 0 );
+}
+
+void XclExpControlHelper::WriteFormulaSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId, const XclTokenArray& rTokArr ) const
+{
+ rStrm.StartRecord( nSubRecId, (rTokArr.GetSize() + 5) & ~1 );
+ WriteFormula( rStrm, rTokArr );
+ rStrm.EndRecord();
+}
+
+// ----------------------------------------------------------------------------
+
+#if EXC_EXP_OCX_CTRL
+
+XclExpOcxControlObj::XclExpOcxControlObj( XclExpObjectManager& rObjMgr, Reference< XShape > xShape,
+ const Rectangle* pChildAnchor, const String& rClassName, sal_uInt32 nStrmStart, sal_uInt32 nStrmSize ) :
+ XclObj( rObjMgr, EXC_OBJTYPE_PICTURE, true ),
+ XclExpControlHelper( rObjMgr.GetRoot() ),
+ maClassName( rClassName ),
+ mnStrmStart( nStrmStart ),
+ mnStrmSize( nStrmSize )
+{
+ ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
+
+ // OBJ record flags
+ SetLocked( sal_True );
+ SetPrintable( aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "Printable" ) ) );
+ SetAutoFill( false );
+ SetAutoLine( false );
+
+ // fill DFF property set
+ mrEscherEx.OpenContainer( ESCHER_SpContainer );
+ mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, SHAPEFLAG_HAVESPT | SHAPEFLAG_HAVEANCHOR | SHAPEFLAG_OLESHAPE );
+ Rectangle aDummyRect;
+ EscherPropertyContainer aPropOpt( mrEscherEx, mrEscherEx.QueryPicStream(), aDummyRect );
+ aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 ); // bool field
+ aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x08000040 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 ); // bool field
+
+ // #i51348# name of the control, may overwrite shape name
+ OUString aCtrlName;
+ if( aCtrlProp.GetProperty( aCtrlName, CREATE_OUSTRING( "Name" ) ) && (aCtrlName.getLength() > 0) )
+ aPropOpt.AddOpt( ESCHER_Prop_wzName, aCtrlName );
+
+ // meta file
+ //! TODO - needs check
+ Reference< XPropertySet > xShapePS( xShape, UNO_QUERY );
+ if( xShapePS.is() && aPropOpt.CreateGraphicProperties( xShapePS, CREATE_STRING( "MetaFile" ), false ) )
+ {
+ sal_uInt32 nBlipId;
+ if( aPropOpt.GetOpt( ESCHER_Prop_pib, nBlipId ) )
+ aPropOpt.AddOpt( ESCHER_Prop_pictureId, nBlipId );
+ }
+
+ // write DFF property set to stream
+ aPropOpt.Commit( mrEscherEx.GetStream() );
+
+ // anchor
+ ImplWriteAnchor( GetRoot(), SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
+
+ mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record
+ mrEscherEx.CloseContainer(); // ESCHER_SpContainer
+ mrEscherEx.UpdateDffFragmentEnd();
+
+ // spreadsheet links
+ ConvertSheetLinks( xShape );
+}
+
+void XclExpOcxControlObj::WriteSubRecs( XclExpStream& rStrm )
+{
+ // OBJCF - clipboard format
+ rStrm.StartRecord( EXC_ID_OBJCF, 2 );
+ rStrm << sal_uInt16( 2 );
+ rStrm.EndRecord();
+
+ // OBJFLAGS
+ rStrm.StartRecord( EXC_ID_OBJFLAGS, 2 );
+ rStrm << sal_uInt16( 0x0031 );
+ rStrm.EndRecord();
+
+ // OBJPICTFMLA
+ XclExpString aClass( maClassName );
+ sal_uInt16 nClassNameSize = static_cast< sal_uInt16 >( aClass.GetSize() );
+ sal_uInt16 nClassNamePad = nClassNameSize & 1;
+ sal_uInt16 nFirstPartSize = 12 + nClassNameSize + nClassNamePad;
+
+ const XclTokenArray* pCellLink = GetCellLinkTokArr();
+ sal_uInt16 nCellLinkSize = pCellLink ? ((pCellLink->GetSize() + 7) & 0xFFFE) : 0;
+
+ const XclTokenArray* pSrcRange = GetSourceRangeTokArr();
+ sal_uInt16 nSrcRangeSize = pSrcRange ? ((pSrcRange->GetSize() + 7) & 0xFFFE) : 0;
+
+ sal_uInt16 nPictFmlaSize = nFirstPartSize + nCellLinkSize + nSrcRangeSize + 18;
+ rStrm.StartRecord( EXC_ID_OBJPICTFMLA, nPictFmlaSize );
+
+ rStrm << sal_uInt16( nFirstPartSize ) // size of first part
+ << sal_uInt16( 5 ) // formula size
+ << sal_uInt32( 0 ) // unknown ID
+ << sal_uInt8( 0x02 ) << sal_uInt32( 0 ) // tTbl token with unknown ID
+ << sal_uInt8( 3 ) // pad to word
+ << aClass; // "Forms.***.1"
+ rStrm.WriteZeroBytes( nClassNamePad ); // pad to word
+ rStrm << mnStrmStart // start in 'Ctls' stream
+ << mnStrmSize // size in 'Ctls' stream
+ << sal_uInt32( 0 ); // class ID size
+ // cell link
+ rStrm << nCellLinkSize;
+ if( pCellLink )
+ WriteFormula( rStrm, *pCellLink );
+ // list source range
+ rStrm << nSrcRangeSize;
+ if( pSrcRange )
+ WriteFormula( rStrm, *pSrcRange );
+
+ rStrm.EndRecord();
+}
+
+#else
+
+XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference< XShape > xShape , const Rectangle* pChildAnchor ) :
+ XclObj( rRoot, EXC_OBJTYPE_UNKNOWN, true ),
+ XclMacroHelper( rRoot ),
+ mnHeight( 0 ),
+ mnState( 0 ),
+ mnLineCount( 0 ),
+ mnSelEntry( 0 ),
+ mnScrollValue( 0 ),
+ mnScrollMin( 0 ),
+ mnScrollMax( 100 ),
+ mnScrollStep( 1 ),
+ mnScrollPage( 10 ),
+ mbFlatButton( false ),
+ mbFlatBorder( false ),
+ mbMultiSel( false ),
+ mbScrollHor( false )
+{
+ namespace FormCompType = ::com::sun::star::form::FormComponentType;
+ namespace AwtVisualEffect = ::com::sun::star::awt::VisualEffect;
+ namespace AwtScrollOrient = ::com::sun::star::awt::ScrollBarOrientation;
+
+ ScfPropertySet aCtrlProp( XclControlHelper::GetControlModel( xShape ) );
+ if( !xShape.is() || !aCtrlProp.Is() )
+ return;
+
+ mnHeight = xShape->getSize().Height;
+ if( mnHeight <= 0 )
+ return;
+
+ // control type
+ sal_Int16 nClassId = 0;
+ if( aCtrlProp.GetProperty( nClassId, CREATE_OUSTRING( "ClassId" ) ) )
+ {
+ switch( nClassId )
+ {
+ case FormCompType::COMMANDBUTTON: mnObjType = EXC_OBJTYPE_BUTTON; meEventType = EXC_TBX_EVENT_ACTION; break;
+ case FormCompType::RADIOBUTTON: mnObjType = EXC_OBJTYPE_OPTIONBUTTON; meEventType = EXC_TBX_EVENT_ACTION; break;
+ case FormCompType::CHECKBOX: mnObjType = EXC_OBJTYPE_CHECKBOX; meEventType = EXC_TBX_EVENT_ACTION; break;
+ case FormCompType::LISTBOX: mnObjType = EXC_OBJTYPE_LISTBOX; meEventType = EXC_TBX_EVENT_CHANGE; break;
+ case FormCompType::COMBOBOX: mnObjType = EXC_OBJTYPE_DROPDOWN; meEventType = EXC_TBX_EVENT_CHANGE; break;
+ case FormCompType::GROUPBOX: mnObjType = EXC_OBJTYPE_GROUPBOX; meEventType = EXC_TBX_EVENT_MOUSE; break;
+ case FormCompType::FIXEDTEXT: mnObjType = EXC_OBJTYPE_LABEL; meEventType = EXC_TBX_EVENT_MOUSE; break;
+ case FormCompType::SCROLLBAR: mnObjType = EXC_OBJTYPE_SCROLLBAR; meEventType = EXC_TBX_EVENT_VALUE; break;
+ case FormCompType::SPINBUTTON: mnObjType = EXC_OBJTYPE_SPIN; meEventType = EXC_TBX_EVENT_VALUE; break;
+ }
+ }
+ if( mnObjType == EXC_OBJTYPE_UNKNOWN )
+ return;
+
+ // OBJ record flags
+ SetLocked( sal_True );
+ SetPrintable( aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "Printable" ) ) );
+ SetAutoFill( false );
+ SetAutoLine( false );
+
+ // fill DFF property set
+ mrEscherEx.OpenContainer( ESCHER_SpContainer );
+ mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, SHAPEFLAG_HAVEANCHOR | SHAPEFLAG_HAVESPT );
+ EscherPropertyContainer aPropOpt;
+ bool bVisible = aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "EnableVisible" ) );
+ aPropOpt.AddOpt( ESCHER_Prop_fPrint, bVisible ? 0x00080000 : 0x00080002 ); // visible flag
+
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01000100 ); // bool field
+ aPropOpt.AddOpt( ESCHER_Prop_lTxid, 0 ); // Text ID
+ aPropOpt.AddOpt( ESCHER_Prop_WrapText, 0x00000001 );
+ aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x001A0008 ); // bool field
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00100000 ); // bool field
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 ); // bool field
+
+ // #i51348# name of the control, may overwrite shape name
+ OUString aCtrlName;
+ if( aCtrlProp.GetProperty( aCtrlName, CREATE_OUSTRING( "Name" ) ) && (aCtrlName.getLength() > 0) )
+ aPropOpt.AddOpt( ESCHER_Prop_wzName, aCtrlName );
+
+ // write DFF property set to stream
+ aPropOpt.Commit( mrEscherEx.GetStream() );
+
+ // anchor
+ ImplWriteAnchor( GetRoot(), SdrObject::getSdrObjectFromXShape( xShape ), pChildAnchor );
+
+ mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record
+ mrEscherEx.UpdateDffFragmentEnd();
+
+ // control label
+ OUString aString;
+ if( aCtrlProp.GetProperty( aString, CREATE_OUSTRING( "Label" ) ) )
+ {
+ /* Be sure to construct the MSODRAWING record containing the
+ ClientTextbox atom after the base OBJ's MSODRAWING record data is
+ completed. */
+ pClientTextbox = new XclExpMsoDrawing( mrEscherEx );
+ mrEscherEx.AddAtom( 0, ESCHER_ClientTextbox ); // TXO record
+ mrEscherEx.UpdateDffFragmentEnd();
+
+ sal_uInt16 nXclFont = EXC_FONT_APP;
+ if( aString.getLength() > 0 )
+ {
+ XclFontData aFontData;
+ GetFontPropSetHelper().ReadFontProperties( aFontData, aCtrlProp, EXC_FONTPROPSET_CONTROL );
+ if( (aFontData.maName.Len() > 0) && (aFontData.mnHeight > 0) )
+ nXclFont = GetFontBuffer().Insert( aFontData, EXC_COLOR_CTRLTEXT );
+ }
+
+ pTxo = new XclTxo( aString, nXclFont );
+ pTxo->SetHorAlign( (mnObjType == EXC_OBJTYPE_BUTTON) ? EXC_OBJ_HOR_CENTER : EXC_OBJ_HOR_LEFT );
+ pTxo->SetVerAlign( EXC_OBJ_VER_CENTER );
+ }
+
+ mrEscherEx.CloseContainer(); // ESCHER_SpContainer
+
+ // other properties
+ aCtrlProp.GetProperty( mnLineCount, CREATE_OUSTRING( "LineCount" ) );
+
+ // border style
+ sal_Int16 nApiButton = AwtVisualEffect::LOOK3D;
+ sal_Int16 nApiBorder = AwtVisualEffect::LOOK3D;
+ switch( nClassId )
+ {
+ case FormCompType::LISTBOX:
+ case FormCompType::COMBOBOX:
+ aCtrlProp.GetProperty( nApiBorder, CREATE_OUSTRING( "Border" ) );
+ break;
+ case FormCompType::CHECKBOX:
+ case FormCompType::RADIOBUTTON:
+ aCtrlProp.GetProperty( nApiButton, CREATE_OUSTRING( "VisualEffect" ) );
+ nApiBorder = AwtVisualEffect::NONE;
+ break;
+ // Push button cannot be set to flat in Excel
+ case FormCompType::COMMANDBUTTON:
+ nApiBorder = AwtVisualEffect::LOOK3D;
+ break;
+ // Label does not support a border in Excel
+ case FormCompType::FIXEDTEXT:
+ nApiBorder = AwtVisualEffect::NONE;
+ break;
+ /* Scroll bar and spin button have a "Border" property, but it is
+ really used for a border, and not for own 3D/flat look (#i34712#). */
+ case FormCompType::SCROLLBAR:
+ case FormCompType::SPINBUTTON:
+ nApiButton = AwtVisualEffect::LOOK3D;
+ nApiBorder = AwtVisualEffect::NONE;
+ break;
+ // Group box does not support flat style (#i34712#)
+ case FormCompType::GROUPBOX:
+ nApiBorder = AwtVisualEffect::LOOK3D;
+ break;
+ }
+ mbFlatButton = nApiButton != AwtVisualEffect::LOOK3D;
+ mbFlatBorder = nApiBorder != AwtVisualEffect::LOOK3D;
+
+ // control state
+ sal_Int16 nApiState = 0;
+ if( aCtrlProp.GetProperty( nApiState, CREATE_OUSTRING( "State" ) ) )
+ {
+ switch( nApiState )
+ {
+ case 0: mnState = EXC_OBJ_CHECKBOX_UNCHECKED; break;
+ case 1: mnState = EXC_OBJ_CHECKBOX_CHECKED; break;
+ case 2: mnState = EXC_OBJ_CHECKBOX_TRISTATE; break;
+ }
+ }
+
+ // special control contents
+ switch( nClassId )
+ {
+ case FormCompType::LISTBOX:
+ {
+ mbMultiSel = aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "MultiSelection" ) );
+ Sequence< sal_Int16 > aSelection;
+ if( aCtrlProp.GetProperty( aSelection, CREATE_OUSTRING( "SelectedItems" ) ) )
+ {
+ sal_Int32 nLen = aSelection.getLength();
+ if( nLen > 0 )
+ {
+ mnSelEntry = aSelection[ 0 ] + 1;
+ maMultiSel.resize( nLen );
+ const sal_Int16* pnBegin = aSelection.getConstArray();
+ ::std::copy( pnBegin, pnBegin + nLen, maMultiSel.begin() );
+ }
+ }
+
+ // convert listbox with dropdown button to Excel dropdown
+ if( aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "Dropdown" ) ) )
+ mnObjType = EXC_OBJTYPE_DROPDOWN;
+ }
+ break;
+
+ case FormCompType::COMBOBOX:
+ {
+ Sequence< OUString > aStringList;
+ OUString aDefText;
+ if( aCtrlProp.GetProperty( aStringList, CREATE_OUSTRING( "StringItemList" ) ) &&
+ aCtrlProp.GetProperty( aDefText, CREATE_OUSTRING( "Text" ) ) &&
+ aStringList.getLength() && aDefText.getLength() )
+ {
+ const OUString* pBegin = aStringList.getConstArray();
+ const OUString* pEnd = pBegin + aStringList.getLength();
+ const OUString* pString = ::std::find( pBegin, pEnd, aDefText );
+ if( pString != pEnd )
+ mnSelEntry = static_cast< sal_Int16 >( pString - pBegin + 1 ); // 1-based
+ if( mnSelEntry > 0 )
+ maMultiSel.resize( 1, mnSelEntry - 1 );
+ }
+
+ // convert combobox without dropdown button to Excel listbox
+ if( !aCtrlProp.GetBoolProperty( CREATE_OUSTRING( "Dropdown" ) ) )
+ mnObjType = EXC_OBJTYPE_LISTBOX;
+ }
+ break;
+
+ case FormCompType::SCROLLBAR:
+ {
+ sal_Int32 nApiValue = 0;
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "ScrollValueMin" ) ) )
+ mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "ScrollValueMax" ) ) )
+ mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MIN );
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "ScrollValue" ) ) )
+ mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "LineIncrement" ) ) )
+ mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "BlockIncrement" ) ) )
+ mnScrollPage = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "Orientation" ) ) )
+ mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
+ }
+ break;
+
+ case FormCompType::SPINBUTTON:
+ {
+ sal_Int32 nApiValue = 0;
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "SpinValueMin" ) ) )
+ mnScrollMin = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "SpinValueMax" ) ) )
+ mnScrollMax = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, EXC_OBJ_SCROLLBAR_MAX );
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "SpinValue" ) ) )
+ mnScrollValue = limit_cast< sal_uInt16 >( nApiValue, mnScrollMin, mnScrollMax );
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "SpinIncrement" ) ) )
+ mnScrollStep = limit_cast< sal_uInt16 >( nApiValue, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
+ if( aCtrlProp.GetProperty( nApiValue, CREATE_OUSTRING( "Orientation" ) ) )
+ mbScrollHor = nApiValue == AwtScrollOrient::HORIZONTAL;
+ }
+ break;
+ }
+
+ // spreadsheet links
+ ConvertSheetLinks( xShape );
+}
+
+bool XclExpTbxControlObj::SetMacroLink( const ScriptEventDescriptor& rEvent )
+{
+ return XclMacroHelper::SetMacroLink( rEvent, meEventType );
+}
+
+void XclExpTbxControlObj::WriteSubRecs( XclExpStream& rStrm )
+{
+ switch( mnObjType )
+ {
+ // *** Push buttons, labels ***
+
+ case EXC_OBJTYPE_BUTTON:
+ case EXC_OBJTYPE_LABEL:
+ // ftMacro - macro link
+ WriteMacroSubRec( rStrm );
+ break;
+
+ // *** Check boxes, option buttons ***
+
+ case EXC_OBJTYPE_CHECKBOX:
+ case EXC_OBJTYPE_OPTIONBUTTON:
+ {
+ // ftCbls - box properties
+ sal_uInt16 nStyle = 0;
+ ::set_flag( nStyle, EXC_OBJ_CHECKBOX_FLAT, mbFlatButton );
+
+ rStrm.StartRecord( EXC_ID_OBJCBLS, 12 );
+ rStrm << mnState;
+ rStrm.WriteZeroBytes( 8 );
+ rStrm << nStyle;
+ rStrm.EndRecord();
+
+ // ftMacro - macro link
+ WriteMacroSubRec( rStrm );
+ // ftCblsFmla subrecord - cell link
+ WriteCellLinkSubRec( rStrm, EXC_ID_OBJCBLSFMLA );
+
+ // ftCblsData subrecord - box properties, again
+ rStrm.StartRecord( EXC_ID_OBJCBLS, 8 );
+ rStrm << mnState;
+ rStrm.WriteZeroBytes( 4 );
+ rStrm << nStyle;
+ rStrm.EndRecord();
+ }
+ break;
+
+ // *** List boxes, combo boxes ***
+
+ case EXC_OBJTYPE_LISTBOX:
+ case EXC_OBJTYPE_DROPDOWN:
+ {
+ sal_uInt16 nEntryCount = GetSourceEntryCount();
+
+ // ftSbs subrecord - Scroll bars
+ sal_Int32 nLineHeight = XclTools::GetHmmFromTwips( 200 ); // always 10pt
+ if( mnObjType == EXC_OBJTYPE_LISTBOX )
+ mnLineCount = static_cast< sal_uInt16 >( mnHeight / nLineHeight );
+ mnScrollValue = 0;
+ mnScrollMin = 0;
+ sal_uInt16 nInvisLines = (nEntryCount >= mnLineCount) ? (nEntryCount - mnLineCount) : 0;
+ mnScrollMax = limit_cast< sal_uInt16 >( nInvisLines, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
+ mnScrollStep = 1;
+ mnScrollPage = limit_cast< sal_uInt16 >( mnLineCount, EXC_OBJ_SCROLLBAR_MIN, EXC_OBJ_SCROLLBAR_MAX );
+ mbScrollHor = false;
+ WriteSbs( rStrm );
+
+ // ftMacro - macro link
+ WriteMacroSubRec( rStrm );
+ // ftSbsFmla subrecord - cell link
+ WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
+
+ // ftLbsData - source data range and box properties
+ sal_uInt16 nStyle = 0;
+ ::insert_value( nStyle, mbMultiSel ? EXC_OBJ_LISTBOX_MULTI : EXC_OBJ_LISTBOX_SINGLE, 4, 2 );
+ ::set_flag( nStyle, EXC_OBJ_LISTBOX_FLAT, mbFlatBorder );
+
+ rStrm.StartRecord( EXC_ID_OBJLBSDATA, 0 );
+
+ if( const XclTokenArray* pSrcRange = GetSourceRangeTokArr() )
+ {
+ rStrm << static_cast< sal_uInt16 >( (pSrcRange->GetSize() + 7) & 0xFFFE );
+ WriteFormula( rStrm, *pSrcRange );
+ }
+ else
+ rStrm << sal_uInt16( 0 );
+
+ rStrm << nEntryCount << mnSelEntry << nStyle << sal_uInt16( 0 );
+ if( mnObjType == EXC_OBJTYPE_LISTBOX )
+ {
+ if( nEntryCount )
+ {
+ ScfUInt8Vec aSelEx( nEntryCount, 0 );
+ for( ScfInt16Vec::const_iterator aIt = maMultiSel.begin(), aEnd = maMultiSel.end(); aIt != aEnd; ++aIt )
+ if( *aIt < nEntryCount )
+ aSelEx[ *aIt ] = 1;
+ rStrm.Write( &aSelEx[ 0 ], aSelEx.size() );
+ }
+ }
+ else if( mnObjType == EXC_OBJTYPE_DROPDOWN )
+ {
+ rStrm << sal_uInt16( 0 ) << mnLineCount << sal_uInt16( 0 ) << sal_uInt16( 0 );
+ }
+
+ rStrm.EndRecord();
+ }
+ break;
+
+ // *** Spin buttons, scrollbars ***
+
+ case EXC_OBJTYPE_SPIN:
+ case EXC_OBJTYPE_SCROLLBAR:
+ {
+ // ftSbs subrecord - scroll bars
+ WriteSbs( rStrm );
+ // ftMacro - macro link
+ WriteMacroSubRec( rStrm );
+ // ftSbsFmla subrecord - cell link
+ WriteCellLinkSubRec( rStrm, EXC_ID_OBJSBSFMLA );
+ }
+ break;
+
+ // *** Group boxes ***
+
+ case EXC_OBJTYPE_GROUPBOX:
+ {
+ // ftMacro - macro link
+ WriteMacroSubRec( rStrm );
+
+ // ftGboData subrecord - group box properties
+ sal_uInt16 nStyle = 0;
+ ::set_flag( nStyle, EXC_OBJ_GROUPBOX_FLAT, mbFlatBorder );
+
+ rStrm.StartRecord( EXC_ID_OBJGBODATA, 6 );
+ rStrm << sal_uInt32( 0 )
+ << nStyle;
+ rStrm.EndRecord();
+ }
+ break;
+ }
+}
+
+void XclExpTbxControlObj::WriteCellLinkSubRec( XclExpStream& rStrm, sal_uInt16 nSubRecId )
+{
+ if( const XclTokenArray* pCellLink = GetCellLinkTokArr() )
+ WriteFormulaSubRec( rStrm, nSubRecId, *pCellLink );
+}
+
+void XclExpTbxControlObj::WriteSbs( XclExpStream& rStrm )
+{
+ sal_uInt16 nOrient = 0;
+ ::set_flag( nOrient, EXC_OBJ_SCROLLBAR_HOR, mbScrollHor );
+ sal_uInt16 nStyle = EXC_OBJ_SCROLLBAR_DEFFLAGS;
+ ::set_flag( nStyle, EXC_OBJ_SCROLLBAR_FLAT, mbFlatButton );
+
+ rStrm.StartRecord( EXC_ID_OBJSBS, 20 );
+ rStrm << sal_uInt32( 0 ) // reserved
+ << mnScrollValue // thumb position
+ << mnScrollMin // thumb min pos
+ << mnScrollMax // thumb max pos
+ << mnScrollStep // line increment
+ << mnScrollPage // page increment
+ << nOrient // 0 = vertical, 1 = horizontal
+ << sal_uInt16( 15 ) // thumb width
+ << nStyle; // flags/style
+ rStrm.EndRecord();
+}
+
+#endif
+
+// ----------------------------------------------------------------------------
+
+XclExpChartObj::XclExpChartObj( XclExpObjectManager& rObjMgr, Reference< XShape > xShape, const Rectangle* pChildAnchor ) :
+ XclObj( rObjMgr, EXC_OBJTYPE_CHART ),
+ XclExpRoot( rObjMgr.GetRoot() ), mxShape( xShape )
+{
+ // create the MSODRAWING record contents for the chart object
+ mrEscherEx.OpenContainer( ESCHER_SpContainer );
+ mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, SHAPEFLAG_HAVEANCHOR | SHAPEFLAG_HAVESPT );
+ EscherPropertyContainer aPropOpt;
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01040104 );
+ aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 );
+ aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x0800004E );
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x0800004D );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 );
+ aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x0800004D );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080008 );
+ aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x00020000 );
+ aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080000 );
+ aPropOpt.Commit( mrEscherEx.GetStream() );
+
+ // anchor
+ SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape );
+ ImplWriteAnchor( GetRoot(), pSdrObj, pChildAnchor );
+
+ // client data (the following OBJ record)
+ mrEscherEx.AddAtom( 0, ESCHER_ClientData );
+ mrEscherEx.CloseContainer(); // ESCHER_SpContainer
+ mrEscherEx.UpdateDffFragmentEnd();
+
+ // load the chart OLE object
+ if( SdrOle2Obj* pSdrOleObj = dynamic_cast< SdrOle2Obj* >( pSdrObj ) )
+ svt::EmbeddedObjectRef::TryRunningState( pSdrOleObj->GetObjRef() );
+
+ // create the chart substream object
+ ScfPropertySet aShapeProp( xShape );
+ Reference< XModel > xModel;
+ aShapeProp.GetProperty( xModel, CREATE_OUSTRING( "Model" ) );
+ mxChartDoc.set( xModel,UNO_QUERY );
+ ::com::sun::star::awt::Rectangle aBoundRect;
+ aShapeProp.GetProperty( aBoundRect, CREATE_OUSTRING( "BoundRect" ) );
+ Rectangle aChartRect( Point( aBoundRect.X, aBoundRect.Y ), Size( aBoundRect.Width, aBoundRect.Height ) );
+ mxChart.reset( new XclExpChart( GetRoot(), xModel, aChartRect ) );
+}
+
+XclExpChartObj::~XclExpChartObj()
+{
+}
+
+void XclExpChartObj::Save( XclExpStream& rStrm )
+{
+ // content of OBJ record
+ XclObj::Save( rStrm );
+ // chart substream
+ mxChart->Save( rStrm );
+}
+
+void XclExpChartObj::SaveXml( XclExpXmlStream& rStrm )
+{
+ OSL_TRACE("XclExpChartObj::SaveXml -- Entry point to export chart");
+ sax_fastparser::FSHelperPtr pDrawing = rStrm.GetCurrentStream();
+
+ // FIXME: two cell? it seems the two cell anchor is incorrect.
+ pDrawing->startElement( FSNS( XML_xdr, XML_twoCellAnchor ), // OOXTODO: oneCellAnchor, absoluteAnchor
+ XML_editAs, "oneCell",
+ FSEND );
+ Reference< XPropertySet > xPropSet( mxShape, UNO_QUERY );
+ if (xPropSet.is())
+ {
+ XclObjAny::WriteFromTo( rStrm, mxShape, GetTab() );
+ Reference< XModel > xModel( mxChartDoc, UNO_QUERY );
+ ChartExport aChartExport( XML_xdr, pDrawing, xModel, &rStrm, DrawingML::DOCUMENT_XLSX );
+ static sal_Int32 nChartCount = 0;
+ nChartCount++;
+ aChartExport.WriteChartObj( mxShape, nChartCount );
+ // TODO: get the correcto chart number
+ }
+
+ pDrawing->singleElement( FSNS( XML_xdr, XML_clientData),
+ // OOXTODO: XML_fLocksWithSheet
+ // OOXTODO: XML_fPrintsWithSheet
+ FSEND );
+ pDrawing->endElement( FSNS( XML_xdr, XML_twoCellAnchor ) );
+}
+
+void XclExpChartObj::WriteChartObj( sax_fastparser::FSHelperPtr pDrawing, XclExpXmlStream& rStrm )
+{
+ pDrawing->startElement( FSNS( XML_xdr, XML_graphicFrame ), FSEND );
+
+ pDrawing->startElement( FSNS( XML_xdr, XML_nvGraphicFramePr ), FSEND );
+
+ // TODO: get the correct chart name chart id
+ OUString sName = CREATE_OUSTRING("Object 1");
+ Reference< XNamed > xNamed( mxShape, UNO_QUERY );
+ if (xNamed.is())
+ {
+ sName = xNamed->getName();
+ }
+ sal_Int32 nID = rStrm.GetUniqueId();
+
+ pDrawing->singleElement( FSNS( XML_xdr, XML_cNvPr ),
+ XML_id, I32S( nID ),
+ XML_name, USS( sName ),
+ FSEND );
+
+ pDrawing->singleElement( FSNS( XML_xdr, XML_cNvGraphicFramePr ),
+ FSEND );
+
+ pDrawing->endElement( FSNS( XML_xdr, XML_nvGraphicFramePr ) );
+
+ // visual chart properties
+ WriteShapeTransformation( pDrawing, mxShape );
+
+ // writer chart object
+ pDrawing->startElement( FSNS( XML_a, XML_graphic ), FSEND );
+ pDrawing->startElement( FSNS( XML_a, XML_graphicData ),
+ XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/chart",
+ FSEND );
+ OUString sId;
+ // TODO:
+ static sal_Int32 nChartCount = 0;
+ nChartCount++;
+ sax_fastparser::FSHelperPtr pChart = rStrm.CreateOutputStream(
+ XclXmlUtils::GetStreamName( "xl/", "charts/chart", nChartCount ),
+ XclXmlUtils::GetStreamName( "../", "charts/chart", nChartCount ),
+ rStrm.GetCurrentStream()->getOutputStream(),
+ "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",
+ &sId );
+
+ pDrawing->singleElement( FSNS( XML_c, XML_chart ),
+ FSNS( XML_xmlns, XML_c ), "http://schemas.openxmlformats.org/drawingml/2006/chart",
+ FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
+ FSNS( XML_r, XML_id ), XclXmlUtils::ToOString( sId ).getStr(),
+ FSEND );
+
+ rStrm.PushStream( pChart );
+ Reference< XModel > xModel( mxChartDoc, UNO_QUERY );
+ ChartExport aChartExport( XML_xdr, pChart, xModel, &rStrm, DrawingML::DOCUMENT_XLSX );
+ aChartExport.ExportContent();
+
+ rStrm.PopStream();
+
+ pDrawing->endElement( FSNS( XML_a, XML_graphicData ) );
+ pDrawing->endElement( FSNS( XML_a, XML_graphic ) );
+ pDrawing->endElement( FSNS( XML_xdr, XML_graphicFrame ) );
+
+}
+
+void XclExpChartObj::WriteShapeTransformation( sax_fastparser::FSHelperPtr pFS, const XShapeRef& rXShape, sal_Bool bFlipH, sal_Bool bFlipV, sal_Int32 nRotation )
+{
+ ::com::sun::star::awt::Point aPos = rXShape->getPosition();
+ ::com::sun::star::awt::Size aSize = rXShape->getSize();
+
+ pFS->startElementNS( XML_xdr, XML_xfrm,
+ XML_flipH, bFlipH ? "1" : NULL,
+ XML_flipV, bFlipV ? "1" : NULL,
+ XML_rot, nRotation ? I32S( nRotation ) : NULL,
+ FSEND );
+
+ pFS->singleElementNS( XML_a, XML_off, XML_x, IS( MM100toEMU( aPos.X ) ), XML_y, IS( MM100toEMU( aPos.Y ) ), FSEND );
+ pFS->singleElementNS( XML_a, XML_ext, XML_cx, IS( MM100toEMU( aSize.Width ) ), XML_cy, IS( MM100toEMU( aSize.Height ) ), FSEND );
+
+ pFS->endElementNS( XML_xdr, XML_xfrm );
+}
+
+// ============================================================================
+
+XclExpNote::XclExpNote( const XclExpRoot& rRoot, const ScAddress& rScPos,
+ const ScPostIt* pScNote, const String& rAddText ) :
+ XclExpRecord( EXC_ID_NOTE ),
+ maScPos( rScPos ),
+ mnObjId( EXC_OBJ_INVALID_ID ),
+ mbVisible( pScNote && pScNote->IsCaptionShown() )
+{
+ // get the main note text
+ String aNoteText;
+ if( pScNote )
+ {
+ aNoteText = pScNote->GetText();
+ const EditTextObject *pEditObj = pScNote->GetEditTextObject();
+ if( pEditObj )
+ mpNoteContents = XclExpStringHelper::CreateString( rRoot, *pEditObj );
+ }
+ // append additional text
+ ScGlobal::AddToken( aNoteText, rAddText, '\n', 2 );
+ maOrigNoteText = aNoteText;
+
+ // initialize record dependent on BIFF type
+ switch( rRoot.GetBiff() )
+ {
+ case EXC_BIFF5:
+ maNoteText = ByteString( aNoteText, rRoot.GetTextEncoding() );
+ break;
+
+ case EXC_BIFF8:
+ {
+ // TODO: additional text
+ if( pScNote )
+ if( SdrCaptionObj* pCaption = pScNote->GetOrCreateCaption( maScPos ) )
+ {
+ lcl_GetFromTo( rRoot, pCaption->GetLogicRect(), maScPos.Tab(), maCommentFrom, maCommentTo );
+ if( const OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
+ mnObjId = rRoot.GetObjectManager().AddObj( new XclObjComment( rRoot.GetObjectManager(), pCaption->GetLogicRect(), pOPO->GetTextObject(), pCaption, mbVisible, maScPos, maCommentFrom, maCommentTo ) );
+
+ SfxItemSet aItemSet = pCaption->GetMergedItemSet();
+ meTVA = pCaption->GetTextVerticalAdjust();
+ meTHA = pCaption->GetTextHorizontalAdjust();
+ mbAutoScale = pCaption->GetFitToSize()?true:false;
+ mbLocked = pCaption->IsMoveProtect() | pCaption->IsResizeProtect();
+
+ // AutoFill style would change if Postit.cxx object creation values are changed
+ OUString aCol(((XFillColorItem &)GETITEM(aItemSet, XFillColorItem , XATTR_FILLCOLOR)).GetValue());
+ mbAutoFill = !aCol.getLength() && (GETITEMVALUE(aItemSet, XFillStyleItem, XATTR_FILLSTYLE, sal_uLong) == XFILL_SOLID);
+ mbAutoLine = true;
+ mbRowHidden = (rRoot.GetDoc().RowHidden(maScPos.Row(),maScPos.Tab()));
+ mbColHidden = (rRoot.GetDoc().ColHidden(maScPos.Col(),maScPos.Tab()));
+ }
+
+ SetRecSize( 9 + maAuthor.GetSize() );
+ }
+ break;
+
+ default: DBG_ERROR_BIFF();
+ }
+}
+
+void XclExpNote::Save( XclExpStream& rStrm )
+{
+ switch( rStrm.GetRoot().GetBiff() )
+ {
+ case EXC_BIFF5:
+ {
+ // write the NOTE record directly, there may be the need to create more than one
+ const sal_Char* pcBuffer = maNoteText.GetBuffer();
+ sal_uInt16 nCharsLeft = static_cast< sal_uInt16 >( maNoteText.Len() );
+
+ while( nCharsLeft )
+ {
+ sal_uInt16 nWriteChars = ::std::min( nCharsLeft, EXC_NOTE5_MAXLEN );
+
+ rStrm.StartRecord( EXC_ID_NOTE, 6 + nWriteChars );
+ if( pcBuffer == maNoteText.GetBuffer() )
+ {
+ // first record: row, col, length of complete text
+ rStrm << static_cast< sal_uInt16 >( maScPos.Row() )
+ << static_cast< sal_uInt16 >( maScPos.Col() )
+ << nCharsLeft; // still contains full length
+ }
+ else
+ {
+ // next records: -1, 0, length of current text segment
+ rStrm << sal_uInt16( 0xFFFF )
+ << sal_uInt16( 0 )
+ << nWriteChars;
+ }
+ rStrm.Write( pcBuffer, nWriteChars );
+ rStrm.EndRecord();
+
+ pcBuffer += nWriteChars;
+ nCharsLeft = nCharsLeft - nWriteChars;
+ }
+ }
+ break;
+
+ case EXC_BIFF8:
+ if( mnObjId != EXC_OBJ_INVALID_ID )
+ XclExpRecord::Save( rStrm );
+ break;
+
+ default: DBG_ERROR_BIFF();
+ }
+}
+
+void XclExpNote::WriteBody( XclExpStream& rStrm )
+{
+ // BIFF5/BIFF7 is written separately
+ DBG_ASSERT_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
+
+ sal_uInt16 nFlags = 0;
+ ::set_flag( nFlags, EXC_NOTE_VISIBLE, mbVisible );
+
+ rStrm << static_cast< sal_uInt16 >( maScPos.Row() )
+ << static_cast< sal_uInt16 >( maScPos.Col() )
+ << nFlags
+ << mnObjId
+ << maAuthor
+ << sal_uInt8( 0 );
+}
+
+void XclExpNote::WriteXml( sal_Int32 nAuthorId, XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr rComments = rStrm.GetCurrentStream();
+
+ rComments->startElement( XML_comment,
+ XML_ref, XclXmlUtils::ToOString( maScPos ).getStr(),
+ XML_authorId, OString::valueOf( nAuthorId ).getStr(),
+ // OOXTODO: XML_guid,
+ FSEND );
+ rComments->startElement( XML_text, FSEND );
+ // OOXTODO: phoneticPr, rPh, r
+ if( mpNoteContents )
+ mpNoteContents->WriteXml( rStrm );
+ rComments->endElement( XML_text );
+
+/*
+ Export of commentPr is disabled, since the current (Oct 2010)
+ version of MSO 2010 doesn't yet support commentPr
+ */
+#ifdef XLSX_OOXML_FUTURE
+ if( rStrm.getVersion() == oox::core::ISOIEC_29500_2008 )
+ {
+ rComments->startElement( XML_commentPr,
+ XML_autoFill, XclXmlUtils::ToPsz( mbAutoFill ),
+ XML_autoScale, XclXmlUtils::ToPsz( mbAutoScale ),
+ XML_colHidden, XclXmlUtils::ToPsz( mbColHidden ),
+ XML_locked, XclXmlUtils::ToPsz( mbLocked ),
+ XML_rowHidden, XclXmlUtils::ToPsz( mbRowHidden ),
+ XML_textHAlign, ToHorizAlign( meTHA ),
+ XML_textVAlign, ToVertAlign( meTVA ) ,
+ FSEND );
+ rComments->startElement( XML_anchor,
+ XML_moveWithCells, "false",
+ XML_sizeWithCells, "false",
+ FSEND );
+ rComments->startElement( FSNS( XML_xdr, XML_from ), FSEND );
+ lcl_WriteAnchorVertex( rComments, maCommentFrom );
+ rComments->endElement( FSNS( XML_xdr, XML_from ) );
+ rComments->startElement( FSNS( XML_xdr, XML_to ), FSEND );
+ lcl_WriteAnchorVertex( rComments, maCommentTo );
+ rComments->endElement( FSNS( XML_xdr, XML_to ) );
+ rComments->endElement( XML_anchor );
+ rComments->endElement( XML_commentPr );
+ }
+#endif
+ rComments->endElement( XML_comment );
+}
+
+// ============================================================================
+
+XclMacroHelper::XclMacroHelper( const XclExpRoot& rRoot ) :
+ XclExpControlHelper( rRoot )
+{
+}
+
+XclMacroHelper::~XclMacroHelper()
+{
+}
+
+void XclMacroHelper::WriteMacroSubRec( XclExpStream& rStrm )
+{
+ if( mxMacroLink )
+ WriteFormulaSubRec( rStrm, EXC_ID_OBJMACRO, *mxMacroLink );
+}
+
+bool
+XclMacroHelper::SetMacroLink( const ScriptEventDescriptor& rEvent, const XclTbxEventType& nEventType )
+{
+ String aMacroName = XclControlHelper::ExtractFromMacroDescriptor( rEvent, nEventType, GetDocShell() );
+ if( aMacroName.Len() )
+ {
+ return SetMacroLink( aMacroName );
+ }
+ return false;
+}
+
+bool
+XclMacroHelper::SetMacroLink( const String& rMacroName )
+{
+ OSL_TRACE("SetMacroLink( macroname:=%s )", rtl::OUStringToOString( rMacroName, RTL_TEXTENCODING_UTF8 ).getStr() );
+ if( rMacroName.Len() )
+ {
+ sal_uInt16 nExtSheet = GetLocalLinkManager().FindExtSheet( EXC_EXTSH_OWNDOC );
+ sal_uInt16 nNameIdx = GetNameManager().InsertMacroCall( rMacroName, true, false );
+ mxMacroLink = GetFormulaCompiler().CreateNameXFormula( nExtSheet, nNameIdx );
+ return true;
+ }
+ return false;
+}
+
+XclExpShapeObj::XclExpShapeObj( XclExpObjectManager& rRoot, ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > xShape ) :
+ XclObjAny( rRoot, xShape ),
+ XclMacroHelper( rRoot )
+{
+ if( SdrObject* pSdrObj = ::GetSdrObjectFromXShape( xShape ) )
+ {
+ ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( pSdrObj );
+ if ( pInfo && pInfo->GetMacro().getLength() )
+// FIXME ooo330-m2: XclControlHelper::GetXclMacroName was removed in upstream sources; they started to call XclTools::GetXclMacroName instead; is this enough? it has only one parameter
+// SetMacroLink( XclControlHelper::GetXclMacroName( pInfo->GetMacro(), rRoot.GetDocShell() ) );
+ SetMacroLink( XclTools::GetXclMacroName( pInfo->GetMacro() ) );
+ }
+}
+
+XclExpShapeObj::~XclExpShapeObj()
+{
+}
+
+void XclExpShapeObj::WriteSubRecs( XclExpStream& rStrm )
+{
+ XclObjAny::WriteSubRecs( rStrm );
+ WriteMacroSubRec( rStrm );
+}
+
+// ============================================================================
+
+XclExpComments::XclExpComments( SCTAB nTab, XclExpRecordList< XclExpNote >& rNotes )
+ : mnTab( nTab ), mrNotes( rNotes )
+{
+}
+
+struct OUStringLess : public std::binary_function<OUString, OUString, bool>
+{
+ bool operator()(const OUString& x, const OUString& y) const
+ {
+ return x.compareTo( y ) < 0;
+ }
+};
+
+void XclExpComments::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( mrNotes.IsEmpty() )
+ return;
+
+ sax_fastparser::FSHelperPtr rComments = rStrm.CreateOutputStream(
+ XclXmlUtils::GetStreamName( "xl/", "comments", mnTab + 1 ),
+ XclXmlUtils::GetStreamName( "../", "comments", mnTab + 1 ),
+ rStrm.GetCurrentStream()->getOutputStream(),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" );
+ rStrm.PushStream( rComments );
+
+ rComments->startElement( XML_comments,
+ XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
+ FSNS( XML_xmlns, XML_xdr ), "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
+ FSEND );
+ rComments->startElement( XML_authors, FSEND );
+
+ typedef std::set< OUString, OUStringLess > Authors;
+ Authors aAuthors;
+
+ size_t nNotes = mrNotes.GetSize();
+ for( size_t i = 0; i < nNotes; ++i )
+ {
+ aAuthors.insert( XclXmlUtils::ToOUString( mrNotes.GetRecord( i )->GetAuthor() ) );
+ }
+
+ for( Authors::const_iterator b = aAuthors.begin(), e = aAuthors.end(); b != e; ++b )
+ {
+ rComments->startElement( XML_author, FSEND );
+ rComments->writeEscaped( *b );
+ rComments->endElement( XML_author );
+ }
+
+ rComments->endElement( XML_authors );
+ rComments->startElement( XML_commentList, FSEND );
+
+ for( size_t i = 0; i < nNotes; ++i )
+ {
+ XclExpNoteList::RecordRefType xNote = mrNotes.GetRecord( i );
+ Authors::iterator aAuthor = aAuthors.find(
+ XclXmlUtils::ToOUString( xNote->GetAuthor() ) );
+ sal_Int32 nAuthorId = distance( aAuthors.begin(), aAuthor );
+ xNote->WriteXml( nAuthorId, rStrm );
+ }
+
+ rComments->endElement( XML_commentList );
+ rComments->endElement( XML_comments );
+
+ rStrm.PopStream();
+}
+
+// object manager =============================================================
+
+XclExpObjectManager::XclExpObjectManager( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+ InitStream( true );
+ mxEscherEx.reset( new XclEscherEx( GetRoot(), *this, *mxDffStrm ) );
+}
+
+XclExpObjectManager::XclExpObjectManager( const XclExpObjectManager& rParent ) :
+ XclExpRoot( rParent.GetRoot() )
+{
+ InitStream( false );
+ mxEscherEx.reset( new XclEscherEx( GetRoot(), *this, *mxDffStrm, rParent.mxEscherEx.get() ) );
+}
+
+XclExpObjectManager::~XclExpObjectManager()
+{
+}
+
+XclExpDffAnchorBase* XclExpObjectManager::CreateDffAnchor() const
+{
+ return new XclExpDffSheetAnchor( GetRoot() );
+}
+
+boost::shared_ptr< XclExpRecordBase > XclExpObjectManager::CreateDrawingGroup()
+{
+ return boost::shared_ptr< XclExpRecordBase >( new XclExpMsoDrawingGroup( *mxEscherEx ) );
+}
+
+void XclExpObjectManager::StartSheet()
+{
+ mxObjList.reset( new XclExpObjList( GetRoot(), *mxEscherEx ) );
+}
+
+boost::shared_ptr< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( SdrPage* pSdrPage )
+{
+ if( pSdrPage )
+ mxEscherEx->AddSdrPage( *pSdrPage );
+ // the first dummy object may still be open
+ DBG_ASSERT( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
+ while( mxEscherEx->GetGroupLevel() )
+ mxEscherEx->LeaveGroup();
+ mxObjList->EndSheet();
+ return mxObjList;
+}
+
+boost::shared_ptr< XclExpRecordBase > XclExpObjectManager::ProcessDrawing( const Reference< XShapes >& rxShapes )
+{
+ if( rxShapes.is() )
+ mxEscherEx->AddUnoShapes( rxShapes );
+ // the first dummy object may still be open
+ DBG_ASSERT( mxEscherEx->GetGroupLevel() <= 1, "XclExpObjectManager::ProcessDrawing - still groups open?" );
+ while( mxEscherEx->GetGroupLevel() )
+ mxEscherEx->LeaveGroup();
+ mxObjList->EndSheet();
+ return mxObjList;
+}
+
+void XclExpObjectManager::EndDocument()
+{
+ mxEscherEx->EndDocument();
+}
+
+XclExpMsoDrawing* XclExpObjectManager::GetMsodrawingPerSheet()
+{
+ return mxObjList->GetMsodrawingPerSheet();
+}
+
+bool XclExpObjectManager::HasObj() const
+{
+ return mxObjList->Count() > 0;
+}
+
+sal_uInt16 XclExpObjectManager::AddObj( XclObj* pObjRec )
+{
+ return mxObjList->Add( pObjRec );
+}
+
+XclObj* XclExpObjectManager::RemoveLastObj()
+{
+ XclObj* pLastObj = static_cast< XclObj* >( mxObjList->Last() );
+ mxObjList->Remove(); // remove current, which is the Last()
+ return pLastObj;
+}
+
+void XclExpObjectManager::InitStream( bool bTempFile )
+{
+ if( bTempFile )
+ {
+ mxTempFile.reset( new ::utl::TempFile );
+ if( mxTempFile->IsValid() )
+ {
+ mxTempFile->EnableKillingFile();
+ mxDffStrm.reset( ::utl::UcbStreamHelper::CreateStream( mxTempFile->GetURL(), STREAM_STD_READWRITE ) );
+ }
+ }
+
+ if( !mxDffStrm.get() )
+ mxDffStrm.reset( new SvMemoryStream );
+
+ mxDffStrm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpEmbeddedObjectManager::XclExpEmbeddedObjectManager(
+ const XclExpObjectManager& rParent, const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY ) :
+ XclExpObjectManager( rParent ),
+ maPageSize( rPageSize ),
+ mnScaleX( nScaleX ),
+ mnScaleY( nScaleY )
+{
+}
+
+XclExpDffAnchorBase* XclExpEmbeddedObjectManager::CreateDffAnchor() const
+{
+ return new XclExpDffEmbeddedAnchor( GetRoot(), maPageSize, mnScaleX, mnScaleY );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xeformula.cxx b/sc/source/filter/excel/xeformula.cxx
new file mode 100644
index 000000000000..dab35e4ba7b8
--- /dev/null
+++ b/sc/source/filter/excel/xeformula.cxx
@@ -0,0 +1,2629 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// XXX xelink.hxx MUST be included before xeformula.hxx because of the
+// redifinition of the CREATE_OUSTRING() macro, which is in oox/helper.hxx
+// (indirectly included via xelink.hxx) and ../inc/ftools.hxx (indirectly
+// included via xeformula.hxx) that does an undef first. Ugly.
+#include "xelink.hxx"
+#include "xeformula.hxx"
+
+#include <list>
+#include <map>
+#include <memory>
+#include "addincol.hxx"
+#include "compiler.hxx"
+#include "document.hxx"
+#include "externalrefmgr.hxx"
+#include "rangelst.hxx"
+#include "token.hxx"
+#include "tokenarray.hxx"
+#include "xehelper.hxx"
+#include "xename.hxx"
+#include "xestream.hxx"
+
+using namespace ::formula;
+
+// External reference log =====================================================
+
+XclExpRefLogEntry::XclExpRefLogEntry() :
+ mpUrl( 0 ),
+ mpFirstTab( 0 ),
+ mpLastTab( 0 ),
+ mnFirstXclTab( EXC_TAB_DELETED ),
+ mnLastXclTab( EXC_TAB_DELETED )
+{
+}
+
+// Formula compiler ===========================================================
+
+namespace {
+
+/** Wrapper structure for a processed Calc formula token with additional
+ settings (whitespaces). */
+struct XclExpScToken
+{
+ const FormulaToken* mpScToken; /// Currently processed Calc token.
+ sal_uInt8 mnSpaces; /// Number of spaces before the Calc token.
+
+ inline explicit XclExpScToken() : mpScToken( 0 ), mnSpaces( 0 ) {}
+ inline bool Is() const { return mpScToken != 0; }
+ inline StackVar GetType() const { return mpScToken ? mpScToken->GetType() : static_cast< StackVar >( svUnknown ); }
+ inline OpCode GetOpCode() const { return mpScToken ? mpScToken->GetOpCode() : static_cast< OpCode >( ocNone ); }
+};
+
+// ----------------------------------------------------------------------------
+
+/** Effective token class conversion types. */
+enum XclExpClassConv
+{
+ EXC_CLASSCONV_ORG, /// Keep original class of the token.
+ EXC_CLASSCONV_VAL, /// Convert ARR tokens to VAL class (REF remains uncahnged).
+ EXC_CLASSCONV_ARR /// Convert VAL tokens to ARR class (REF remains uncahnged).
+};
+
+// ----------------------------------------------------------------------------
+
+/** Token class conversion and position of a token in the token array. */
+struct XclExpTokenConvInfo
+{
+ sal_uInt16 mnTokPos; /// Position of the token in the token array.
+ XclFuncParamConv meConv; /// Token class conversion type.
+ bool mbValType; /// Data type (false = REFTYPE, true = VALTYPE).
+};
+
+/** Vector of token position and conversion for all operands of an operator,
+ or for all parameters of a function. */
+struct XclExpOperandList : public ::std::vector< XclExpTokenConvInfo >
+{
+ inline explicit XclExpOperandList() { reserve( 2 ); }
+ void AppendOperand( sal_uInt16 nTokPos, XclFuncParamConv eConv, bool bValType );
+};
+
+void XclExpOperandList::AppendOperand( sal_uInt16 nTokPos, XclFuncParamConv eConv, bool bValType )
+{
+ resize( size() + 1 );
+ XclExpTokenConvInfo& rConvInfo = back();
+ rConvInfo.mnTokPos = nTokPos;
+ rConvInfo.meConv = eConv;
+ rConvInfo.mbValType = bValType;
+}
+
+typedef boost::shared_ptr< XclExpOperandList > XclExpOperandListRef;
+typedef ::std::vector< XclExpOperandListRef > XclExpOperandListVector;
+
+// ----------------------------------------------------------------------------
+
+/** Encapsulates all data needed for a call to an external function (macro, add-in). */
+struct XclExpExtFuncData
+{
+ String maFuncName; /// Name of the function.
+ bool mbVBasic; /// True = Visual Basic macro call.
+ bool mbHidden; /// True = Create hidden defined name.
+
+ inline explicit XclExpExtFuncData() : mbVBasic( false ), mbHidden( false ) {}
+ void Set( const String& rFuncName, bool bVBasic, bool bHidden );
+};
+
+void XclExpExtFuncData::Set( const String& rFuncName, bool bVBasic, bool bHidden )
+{
+ maFuncName = rFuncName;
+ mbVBasic = bVBasic;
+ mbHidden = bHidden;
+}
+
+// ----------------------------------------------------------------------------
+
+/** Encapsulates all data needed to process an entire function. */
+class XclExpFuncData
+{
+public:
+ explicit XclExpFuncData(
+ const XclExpScToken& rTokData,
+ const XclFunctionInfo& rFuncInfo,
+ const XclExpExtFuncData& rExtFuncData );
+
+ inline const FormulaToken& GetScToken() const { return *mrTokData.mpScToken; }
+ inline OpCode GetOpCode() const { return mrFuncInfo.meOpCode; }
+ inline sal_uInt16 GetXclFuncIdx() const { return mrFuncInfo.mnXclFunc; }
+ inline bool IsVolatile() const { return mrFuncInfo.IsVolatile(); }
+ inline bool IsFixedParamCount() const { return mrFuncInfo.IsFixedParamCount(); }
+ inline bool IsMacroFunc() const { return mrFuncInfo.IsMacroFunc(); }
+ inline sal_uInt8 GetSpaces() const { return mrTokData.mnSpaces; }
+ inline const XclExpExtFuncData& GetExtFuncData() const { return maExtFuncData; }
+ inline sal_uInt8 GetReturnClass() const { return mrFuncInfo.mnRetClass; }
+
+ const XclFuncParamInfo& GetParamInfo() const;
+ bool IsCalcOnlyParam() const;
+ bool IsExcelOnlyParam() const;
+ void IncParamInfoIdx();
+
+ inline sal_uInt8 GetMinParamCount() const { return mrFuncInfo.mnMinParamCount; }
+ inline sal_uInt8 GetMaxParamCount() const { return mrFuncInfo.mnMaxParamCount; }
+ inline sal_uInt8 GetParamCount() const { return static_cast< sal_uInt8 >( mxOperands->size() ); }
+ void FinishParam( sal_uInt16 nTokPos );
+ inline XclExpOperandListRef GetOperandList() const { return mxOperands; }
+
+ inline ScfUInt16Vec& GetAttrPosVec() { return maAttrPosVec; }
+ inline void AppendAttrPos( sal_uInt16 nPos ) { maAttrPosVec.push_back( nPos ); }
+
+private:
+ ScfUInt16Vec maAttrPosVec; /// Token array positions of tAttr tokens.
+ const XclExpScToken& mrTokData; /// Data about processed function name token.
+ const XclFunctionInfo& mrFuncInfo; /// Constant data about processed function.
+ XclExpExtFuncData maExtFuncData; /// Data for external functions (macro, add-in).
+ XclExpOperandListRef mxOperands; /// Class conversion and position of all parameters.
+ const XclFuncParamInfo* mpParamInfo; /// Information for current parameter.
+};
+
+XclExpFuncData::XclExpFuncData( const XclExpScToken& rTokData,
+ const XclFunctionInfo& rFuncInfo, const XclExpExtFuncData& rExtFuncData ) :
+ mrTokData( rTokData ),
+ mrFuncInfo( rFuncInfo ),
+ maExtFuncData( rExtFuncData ),
+ mxOperands( new XclExpOperandList ),
+ mpParamInfo( rFuncInfo.mpParamInfos )
+{
+ DBG_ASSERT( mrTokData.mpScToken, "XclExpFuncData::XclExpFuncData - missing core token" );
+ // set name of an add-in function
+ if( (maExtFuncData.maFuncName.Len() == 0) && dynamic_cast< const FormulaExternalToken* >( mrTokData.mpScToken ) )
+ maExtFuncData.Set( GetScToken().GetExternal(), true, false );
+}
+
+const XclFuncParamInfo& XclExpFuncData::GetParamInfo() const
+{
+ static const XclFuncParamInfo saInvalidInfo = { EXC_PARAM_NONE, EXC_PARAMCONV_ORG, false };
+ return mpParamInfo ? *mpParamInfo : saInvalidInfo;
+}
+
+bool XclExpFuncData::IsCalcOnlyParam() const
+{
+ return mpParamInfo && (mpParamInfo->meValid == EXC_PARAM_CALCONLY);
+}
+
+bool XclExpFuncData::IsExcelOnlyParam() const
+{
+ return mpParamInfo && (mpParamInfo->meValid == EXC_PARAM_EXCELONLY);
+}
+
+void XclExpFuncData::IncParamInfoIdx()
+{
+ if( mpParamInfo )
+ {
+ // move pointer to next entry, if something explicit follows
+ if( (static_cast<size_t>(mpParamInfo - mrFuncInfo.mpParamInfos + 1) < EXC_FUNCINFO_PARAMINFO_COUNT) && (mpParamInfo[ 1 ].meValid != EXC_PARAM_NONE) )
+ ++mpParamInfo;
+ // if last parameter type is 'Excel-only' or 'Calc-only', do not repeat it
+ else if( IsExcelOnlyParam() || IsCalcOnlyParam() )
+ mpParamInfo = 0;
+ // otherwise: repeat last parameter class
+ }
+}
+
+void XclExpFuncData::FinishParam( sal_uInt16 nTokPos )
+{
+ // write token class conversion info for this parameter
+ const XclFuncParamInfo& rParamInfo = GetParamInfo();
+ mxOperands->AppendOperand( nTokPos, rParamInfo.meConv, rParamInfo.mbValType );
+ // move to next parameter info structure
+ IncParamInfoIdx();
+}
+
+// compiler configuration -----------------------------------------------------
+
+/** Type of token class handling. */
+enum XclExpFmlaClassType
+{
+ EXC_CLASSTYPE_CELL, /// Cell formula, shared formula.
+ EXC_CLASSTYPE_ARRAY, /// Array formula, conditional formatting, data validation.
+ EXC_CLASSTYPE_NAME /// Defined name, range list.
+};
+
+/** Configuration data of the formula compiler. */
+struct XclExpCompConfig
+{
+ XclFormulaType meType; /// Type of the formula to be created.
+ XclExpFmlaClassType meClassType; /// Token class handling type.
+ bool mbLocalLinkMgr; /// True = local (per-sheet) link manager, false = global.
+ bool mbFromCell; /// True = Any kind of cell formula (cell, array, shared).
+ bool mb3DRefOnly; /// True = Only 3D references allowed (e.g. names).
+ bool mbAllowArrays; /// True = Allow inline arrays.
+};
+
+/** The table containing configuration data for all formula types. */
+static const XclExpCompConfig spConfigTable[] =
+{
+ // formula type token class type lclLM inCell 3dOnly allowArray
+ { EXC_FMLATYPE_CELL, EXC_CLASSTYPE_CELL, true, true, false, true },
+ { EXC_FMLATYPE_SHARED, EXC_CLASSTYPE_CELL, true, true, false, true },
+ { EXC_FMLATYPE_MATRIX, EXC_CLASSTYPE_ARRAY, true, true, false, true },
+ { EXC_FMLATYPE_CONDFMT, EXC_CLASSTYPE_ARRAY, true, false, false, false },
+ { EXC_FMLATYPE_DATAVAL, EXC_CLASSTYPE_ARRAY, true, false, false, false },
+ { EXC_FMLATYPE_NAME, EXC_CLASSTYPE_NAME, false, false, true, true },
+ { EXC_FMLATYPE_CHART, EXC_CLASSTYPE_NAME, true, false, true, true },
+ { EXC_FMLATYPE_CONTROL, EXC_CLASSTYPE_NAME, true, false, false, false },
+ { EXC_FMLATYPE_WQUERY, EXC_CLASSTYPE_NAME, true, false, true, false },
+ { EXC_FMLATYPE_LISTVAL, EXC_CLASSTYPE_NAME, true, false, false, false }
+};
+
+// ----------------------------------------------------------------------------
+
+/** Working data of the formula compiler. Used to push onto a stack for recursive calls. */
+struct XclExpCompData
+{
+ typedef boost::shared_ptr< ScTokenArray > ScTokenArrayRef;
+
+ const XclExpCompConfig& mrCfg; /// Configuration for current formula type.
+ ScTokenArrayRef mxOwnScTokArr; /// Own clone of a Calc token array.
+ XclTokenArrayIterator maTokArrIt; /// Iterator in Calc token array.
+ XclExpLinkManager* mpLinkMgr; /// Link manager for current context (local/global).
+ XclExpRefLog* mpRefLog; /// Log for external references.
+ const ScAddress* mpScBasePos; /// Current cell position of the formula.
+
+ ScfUInt8Vec maTokVec; /// Byte vector containing token data.
+ ScfUInt8Vec maExtDataVec; /// Byte vector containing extended data (arrays, stacked NLRs).
+ XclExpOperandListVector maOpListVec; /// Formula structure, maps operators to their operands.
+ ScfUInt16Vec maOpPosStack; /// Stack with positions of operand tokens waiting for an operator.
+ bool mbStopAtSep; /// True = Stop subexpression creation at an ocSep token.
+ bool mbVolatile; /// True = Formula contains volatile function.
+ bool mbOk; /// Current state of the compiler.
+
+ explicit XclExpCompData( const XclExpCompConfig* pCfg );
+};
+
+XclExpCompData::XclExpCompData( const XclExpCompConfig* pCfg ) :
+ mrCfg( pCfg ? *pCfg : spConfigTable[ 0 ] ),
+ mpLinkMgr( 0 ),
+ mpRefLog( 0 ),
+ mpScBasePos( 0 ),
+ mbStopAtSep( false ),
+ mbVolatile( false ),
+ mbOk( pCfg != 0 )
+{
+ DBG_ASSERT( pCfg, "XclExpFmlaCompImpl::Init - unknown formula type" );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+/** Implementation class of the export formula compiler. */
+class XclExpFmlaCompImpl : protected XclExpRoot, protected XclTokenArrayHelper
+{
+public:
+ explicit XclExpFmlaCompImpl( const XclExpRoot& rRoot );
+
+ /** Creates an Excel token array from the passed Calc token array. */
+ XclTokenArrayRef CreateFormula(
+ XclFormulaType eType, const ScTokenArray& rScTokArr,
+ const ScAddress* pScBasePos = 0, XclExpRefLog* pRefLog = 0 );
+ /** Creates a single error token containing the passed error code. */
+ XclTokenArrayRef CreateErrorFormula( sal_uInt8 nErrCode );
+ /** Creates a single token for a special cell reference. */
+ XclTokenArrayRef CreateSpecialRefFormula( sal_uInt8 nTokenId, const XclAddress& rXclPos );
+ /** Creates a single tNameXR token for a reference to an external name. */
+ XclTokenArrayRef CreateNameXFormula( sal_uInt16 nExtSheet, sal_uInt16 nExtName );
+
+ /** Returns true, if the passed formula type allows 3D references only. */
+ bool Is3DRefOnly( XclFormulaType eType ) const;
+
+ // ------------------------------------------------------------------------
+private:
+ const XclExpCompConfig* GetConfigForType( XclFormulaType eType ) const;
+ inline sal_uInt16 GetSize() const { return static_cast< sal_uInt16 >( mxData->maTokVec.size() ); }
+
+ void Init( XclFormulaType eType );
+ void Init( XclFormulaType eType, const ScTokenArray& rScTokArr,
+ const ScAddress* pScBasePos, XclExpRefLog* pRefLog );
+
+ void RecalcTokenClasses();
+ void RecalcTokenClass( const XclExpTokenConvInfo& rConvInfo, XclFuncParamConv ePrevConv, XclExpClassConv ePrevClassConv, bool bWasRefClass );
+
+ void FinalizeFormula();
+ XclTokenArrayRef CreateTokenArray();
+
+ // compiler ---------------------------------------------------------------
+ // XclExpScToken: pass-by-value and return-by-value is intended
+
+ const FormulaToken* GetNextRawToken();
+ const FormulaToken* PeekNextRawToken( bool bSkipSpaces ) const;
+
+ bool GetNextToken( XclExpScToken& rTokData );
+ XclExpScToken GetNextToken();
+
+ XclExpScToken Expression( XclExpScToken aTokData, bool bInParentheses, bool bStopAtSep );
+ XclExpScToken SkipExpression( XclExpScToken aTokData, bool bStopAtSep );
+
+ XclExpScToken OrTerm( XclExpScToken aTokData, bool bInParentheses );
+ XclExpScToken AndTerm( XclExpScToken aTokData, bool bInParentheses );
+ XclExpScToken CompareTerm( XclExpScToken aTokData, bool bInParentheses );
+ XclExpScToken ConcatTerm( XclExpScToken aTokData, bool bInParentheses );
+ XclExpScToken AddSubTerm( XclExpScToken aTokData, bool bInParentheses );
+ XclExpScToken MulDivTerm( XclExpScToken aTokData, bool bInParentheses );
+ XclExpScToken PowTerm( XclExpScToken aTokData, bool bInParentheses );
+ XclExpScToken UnaryPostTerm( XclExpScToken aTokData, bool bInParentheses );
+ XclExpScToken UnaryPreTerm( XclExpScToken aTokData, bool bInParentheses );
+ XclExpScToken ListTerm( XclExpScToken aTokData, bool bInParentheses );
+ XclExpScToken IntersectTerm( XclExpScToken aTokData, bool& rbHasRefOp );
+ XclExpScToken RangeTerm( XclExpScToken aTokData, bool& rbHasRefOp );
+ XclExpScToken Factor( XclExpScToken aTokData );
+
+ // formula structure ------------------------------------------------------
+
+ void ProcessDouble( const XclExpScToken& rTokData );
+ void ProcessString( const XclExpScToken& rTokData );
+ void ProcessMissing( const XclExpScToken& rTokData );
+ void ProcessBad( const XclExpScToken& rTokData );
+ void ProcessParentheses( const XclExpScToken& rTokData );
+ void ProcessBoolean( const XclExpScToken& rTokData );
+ void ProcessDdeLink( const XclExpScToken& rTokData );
+ void ProcessExternal( const XclExpScToken& rTokData );
+ void ProcessMatrix( const XclExpScToken& rTokData );
+
+ void ProcessFunction( const XclExpScToken& rTokData );
+ void PrepareFunction( XclExpFuncData& rFuncData );
+ void FinishFunction( XclExpFuncData& rFuncData, sal_uInt8 nCloseSpaces );
+ void FinishIfFunction( XclExpFuncData& rFuncData );
+ void FinishChooseFunction( XclExpFuncData& rFuncData );
+
+ XclExpScToken ProcessParam( XclExpScToken aTokData, XclExpFuncData& rFuncData );
+ void PrepareParam( XclExpFuncData& rFuncData );
+ void FinishParam( XclExpFuncData& rFuncData );
+ void AppendDefaultParam( XclExpFuncData& rFuncData );
+ void AppendTrailingParam( XclExpFuncData& rFuncData );
+
+ // reference handling -----------------------------------------------------
+
+ SCTAB GetScTab( const ScSingleRefData& rRefData ) const;
+ bool IsRef2D( const ScSingleRefData& rRefData ) const;
+ bool IsRef2D( const ScComplexRefData& rRefData ) const;
+
+ void ConvertRefData( ScSingleRefData& rRefData, XclAddress& rXclPos,
+ bool bNatLangRef, bool bTruncMaxCol, bool bTruncMaxRow ) const;
+ void ConvertRefData( ScComplexRefData& rRefData, XclRange& rXclRange,
+ bool bNatLangRef ) const;
+
+ XclExpRefLogEntry* GetNewRefLogEntry();
+ void ProcessCellRef( const XclExpScToken& rTokData );
+ void ProcessRangeRef( const XclExpScToken& rTokData );
+ void ProcessExternalCellRef( const XclExpScToken& rTokData );
+ void ProcessExternalRangeRef( const XclExpScToken& rTokData );
+ void ProcessDefinedName( const XclExpScToken& rTokData );
+ void ProcessExternalName( const XclExpScToken& rTokData );
+
+ // token vector -----------------------------------------------------------
+
+ void PushOperandPos( sal_uInt16 nTokPos );
+ void PushOperatorPos( sal_uInt16 nTokPos, const XclExpOperandListRef& rxOperands );
+ sal_uInt16 PopOperandPos();
+
+ void Append( sal_uInt8 nData );
+ void Append( sal_uInt8 nData, size_t nCount );
+ void Append( sal_uInt16 nData );
+ void Append( sal_uInt32 nData );
+ void Append( double fData );
+ void Append( const String& rString );
+
+ void AppendAddress( const XclAddress& rXclPos );
+ void AppendRange( const XclRange& rXclRange );
+
+ void AppendSpaceToken( sal_uInt8 nType, sal_uInt8 nCount );
+
+ void AppendOperandTokenId( sal_uInt8 nTokenId, sal_uInt8 nSpaces = 0 );
+ void AppendIntToken( sal_uInt16 nValue, sal_uInt8 nSpaces = 0 );
+ void AppendNumToken( double fValue, sal_uInt8 nSpaces = 0 );
+ void AppendBoolToken( bool bValue, sal_uInt8 nSpaces = 0 );
+ void AppendErrorToken( sal_uInt8 nErrCode, sal_uInt8 nSpaces = 0 );
+ void AppendMissingToken( sal_uInt8 nSpaces = 0 );
+ void AppendNameToken( sal_uInt16 nNameIdx, sal_uInt8 nSpaces = 0 );
+ void AppendMissingNameToken( const String& rName, sal_uInt8 nSpaces = 0 );
+ void AppendNameXToken( sal_uInt16 nExtSheet, sal_uInt16 nExtName, sal_uInt8 nSpaces = 0 );
+ void AppendMacroCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces = 0 );
+ void AppendAddInCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces = 0 );
+ void AppendEuroToolCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces = 0 );
+
+ void AppendOperatorTokenId( sal_uInt8 nTokenId, const XclExpOperandListRef& rxOperands, sal_uInt8 nSpaces = 0 );
+ void AppendUnaryOperatorToken( sal_uInt8 nTokenId, sal_uInt8 nSpaces = 0 );
+ void AppendBinaryOperatorToken( sal_uInt8 nTokenId, bool bValType, sal_uInt8 nSpaces = 0 );
+ void AppendLogicalOperatorToken( sal_uInt16 nXclFuncIdx, sal_uInt8 nOpCount );
+ void AppendFuncToken( const XclExpFuncData& rFuncData );
+
+ void AppendParenToken( sal_uInt8 nOpenSpaces = 0, sal_uInt8 nCloseSpaces = 0 );
+ void AppendJumpToken( XclExpFuncData& rFuncData, sal_uInt8 nAttrType );
+
+ void InsertZeros( sal_uInt16 nInsertPos, sal_uInt16 nInsertSize );
+ void Overwrite( sal_uInt16 nWriteToPos, sal_uInt16 nOffset );
+
+ void UpdateAttrGoto( sal_uInt16 nAttrPos );
+
+ bool IsSpaceToken( sal_uInt16 nPos ) const;
+ void RemoveTrailingParen();
+
+ void AppendExt( sal_uInt8 nData );
+ void AppendExt( sal_uInt8 nData, size_t nCount );
+ void AppendExt( sal_uInt16 nData );
+ void AppendExt( double fData );
+ void AppendExt( const String& rString );
+
+ // ------------------------------------------------------------------------
+private:
+ typedef ::std::map< XclFormulaType, XclExpCompConfig > XclExpCompConfigMap;
+ typedef boost::shared_ptr< XclExpCompData > XclExpCompDataRef;
+ typedef ::std::vector< XclExpCompDataRef > XclExpCompDataVector;
+
+ XclExpCompConfigMap maCfgMap; /// Compiler configuration map for all formula types.
+ XclFunctionProvider maFuncProv; /// Excel function data provider.
+ XclExpCompDataRef mxData; /// Working data for current formula.
+ XclExpCompDataVector maDataStack; /// Stack for working data, when compiler is called recursively.
+ const XclBiff meBiff; /// Cached BIFF version to save GetBiff() calls.
+ const SCsCOL mnMaxAbsCol; /// Maximum column index.
+ const SCsROW mnMaxAbsRow; /// Maximum row index.
+ const SCsCOL mnMaxScCol; /// Maximum column index in Calc itself.
+ const SCsROW mnMaxScRow; /// Maximum row index in Calc itself.
+ const sal_uInt16 mnMaxColMask; /// Mask to delete invalid bits in column fields.
+ const sal_uInt32 mnMaxRowMask; /// Mask to delete invalid bits in row fields.
+};
+
+// ----------------------------------------------------------------------------
+
+XclExpFmlaCompImpl::XclExpFmlaCompImpl( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ maFuncProv( rRoot ),
+ meBiff( rRoot.GetBiff() ),
+ mnMaxAbsCol( static_cast< SCsCOL >( rRoot.GetXclMaxPos().Col() ) ),
+ mnMaxAbsRow( static_cast< SCsROW >( rRoot.GetXclMaxPos().Row() ) ),
+ mnMaxScCol( static_cast< SCsCOL >( rRoot.GetScMaxPos().Col() ) ),
+ mnMaxScRow( static_cast< SCsROW >( rRoot.GetScMaxPos().Row() ) ),
+ mnMaxColMask( static_cast< sal_uInt16 >( rRoot.GetXclMaxPos().Col() ) ),
+ mnMaxRowMask( static_cast< sal_uInt32 >( rRoot.GetXclMaxPos().Row() ) )
+{
+ // build the configuration map
+ for( const XclExpCompConfig* pEntry = spConfigTable; pEntry != STATIC_TABLE_END( spConfigTable ); ++pEntry )
+ maCfgMap[ pEntry->meType ] = *pEntry;
+}
+
+XclTokenArrayRef XclExpFmlaCompImpl::CreateFormula( XclFormulaType eType,
+ const ScTokenArray& rScTokArr, const ScAddress* pScBasePos, XclExpRefLog* pRefLog )
+{
+ // initialize the compiler
+ Init( eType, rScTokArr, pScBasePos, pRefLog );
+
+ // start compilation, if initialization didn't fail
+ if( mxData->mbOk )
+ {
+ XclExpScToken aTokData( GetNextToken() );
+ sal_uInt16 nScError = rScTokArr.GetCodeError();
+ if( (nScError != 0) && (!aTokData.Is() || (aTokData.GetOpCode() == ocStop)) )
+ {
+ // #i50253# convert simple ocStop token to error code formula (e.g. =#VALUE!)
+ AppendErrorToken( XclTools::GetXclErrorCode( nScError ), aTokData.mnSpaces );
+ }
+ else if( aTokData.Is() )
+ {
+ aTokData = Expression( aTokData, false, false );
+ }
+ else
+ {
+ DBG_ERRORFILE( "XclExpFmlaCompImpl::CreateFormula - empty token array" );
+ mxData->mbOk = false;
+ }
+
+ if( mxData->mbOk )
+ {
+ // #i44907# auto-generated SUBTOTAL formula cells have trailing ocStop token
+ mxData->mbOk = !aTokData.Is() || (aTokData.GetOpCode() == ocStop);
+ DBG_ASSERT( mxData->mbOk, "XclExpFmlaCompImpl::CreateFormula - unknown garbage behind formula" );
+ }
+ }
+
+ // finalize (add tAttrVolatile token, calculate all token classes)
+ RecalcTokenClasses();
+ FinalizeFormula();
+
+ // leave recursive call, create and return the final token array
+ return CreateTokenArray();
+}
+
+XclTokenArrayRef XclExpFmlaCompImpl::CreateErrorFormula( sal_uInt8 nErrCode )
+{
+ Init( EXC_FMLATYPE_NAME );
+ AppendErrorToken( nErrCode );
+ return CreateTokenArray();
+}
+
+XclTokenArrayRef XclExpFmlaCompImpl::CreateSpecialRefFormula( sal_uInt8 nTokenId, const XclAddress& rXclPos )
+{
+ Init( EXC_FMLATYPE_NAME );
+ AppendOperandTokenId( nTokenId );
+ Append( static_cast<sal_uInt16>(rXclPos.mnRow) );
+ Append( rXclPos.mnCol ); // do not use AppendAddress(), we always need 16-bit column here
+ return CreateTokenArray();
+}
+
+XclTokenArrayRef XclExpFmlaCompImpl::CreateNameXFormula( sal_uInt16 nExtSheet, sal_uInt16 nExtName )
+{
+ Init( EXC_FMLATYPE_NAME );
+ AppendNameXToken( nExtSheet, nExtName );
+ return CreateTokenArray();
+}
+
+bool XclExpFmlaCompImpl::Is3DRefOnly( XclFormulaType eType ) const
+{
+ const XclExpCompConfig* pCfg = GetConfigForType( eType );
+ return pCfg && pCfg->mb3DRefOnly;
+}
+
+// private --------------------------------------------------------------------
+
+const XclExpCompConfig* XclExpFmlaCompImpl::GetConfigForType( XclFormulaType eType ) const
+{
+ XclExpCompConfigMap::const_iterator aIt = maCfgMap.find( eType );
+ DBG_ASSERT( aIt != maCfgMap.end(), "XclExpFmlaCompImpl::GetConfigForType - unknown formula type" );
+ return (aIt == maCfgMap.end()) ? 0 : &aIt->second;
+}
+
+void XclExpFmlaCompImpl::Init( XclFormulaType eType )
+{
+ // compiler invoked recursively? - store old working data
+ if( mxData.get() )
+ maDataStack.push_back( mxData );
+ // new compiler working data structure
+ mxData.reset( new XclExpCompData( GetConfigForType( eType ) ) );
+}
+
+void XclExpFmlaCompImpl::Init( XclFormulaType eType, const ScTokenArray& rScTokArr,
+ const ScAddress* pScBasePos, XclExpRefLog* pRefLog )
+{
+ // common initialization
+ Init( eType );
+
+ // special initialization
+ if( mxData->mbOk ) switch( mxData->mrCfg.meType )
+ {
+ case EXC_FMLATYPE_CELL:
+ case EXC_FMLATYPE_MATRIX:
+ case EXC_FMLATYPE_CHART:
+ mxData->mbOk = pScBasePos != 0;
+ DBG_ASSERT( mxData->mbOk, "XclExpFmlaCompImpl::Init - missing cell address" );
+ mxData->mpScBasePos = pScBasePos;
+ break;
+ case EXC_FMLATYPE_SHARED:
+ mxData->mbOk = pScBasePos != 0;
+ DBG_ASSERT( mxData->mbOk, "XclExpFmlaCompImpl::Init - missing cell address" );
+ // clone the passed token array, convert references relative to current cell position
+ mxData->mxOwnScTokArr.reset( rScTokArr.Clone() );
+ ScCompiler::MoveRelWrap( *mxData->mxOwnScTokArr, GetDocPtr(), *pScBasePos, MAXCOL, MAXROW );
+ // don't remember pScBasePos in mxData->mpScBasePos, shared formulas use real relative refs
+ break;
+ default:;
+ }
+
+ if( mxData->mbOk )
+ {
+ // link manager to be used
+ mxData->mpLinkMgr = mxData->mrCfg.mbLocalLinkMgr ? &GetLocalLinkManager() : &GetGlobalLinkManager();
+
+ // token array iterator (use cloned token array if present)
+ mxData->maTokArrIt.Init( mxData->mxOwnScTokArr ? *mxData->mxOwnScTokArr : rScTokArr, false );
+ mxData->mpRefLog = pRefLog;
+ }
+}
+
+void XclExpFmlaCompImpl::RecalcTokenClasses()
+{
+ if( mxData->mbOk )
+ {
+ mxData->mbOk = mxData->maOpPosStack.size() == 1;
+ DBG_ASSERT( mxData->mbOk, "XclExpFmlaCompImpl::RecalcTokenClasses - position of root token expected on stack" );
+ if( mxData->mbOk )
+ {
+ /* Cell and array formulas start with VAL conversion and VALTYPE
+ parameter type, defined names start with ARR conversion and
+ REFTYPE parameter type for the root token. */
+ XclExpOperandList aOperands;
+ bool bNameFmla = mxData->mrCfg.meClassType == EXC_CLASSTYPE_NAME;
+ XclFuncParamConv eParamConv = bNameFmla ? EXC_PARAMCONV_ARR : EXC_PARAMCONV_VAL;
+ XclExpClassConv eClassConv = bNameFmla ? EXC_CLASSCONV_ARR : EXC_CLASSCONV_VAL;
+ XclExpTokenConvInfo aConvInfo = { PopOperandPos(), eParamConv, !bNameFmla };
+ RecalcTokenClass( aConvInfo, eParamConv, eClassConv, bNameFmla );
+ }
+
+ // clear operand vectors (calls to the expensive InsertZeros() may follow)
+ mxData->maOpListVec.clear();
+ mxData->maOpPosStack.clear();
+ }
+}
+
+void XclExpFmlaCompImpl::RecalcTokenClass( const XclExpTokenConvInfo& rConvInfo,
+ XclFuncParamConv ePrevConv, XclExpClassConv ePrevClassConv, bool bWasRefClass )
+{
+ DBG_ASSERT( rConvInfo.mnTokPos < GetSize(), "XclExpFmlaCompImpl::RecalcTokenClass - invalid token position" );
+ sal_uInt8& rnTokenId = mxData->maTokVec[ rConvInfo.mnTokPos ];
+ sal_uInt8 nTokClass = GetTokenClass( rnTokenId );
+
+ // REF tokens in VALTYPE parameters behave like VAL tokens
+ if( rConvInfo.mbValType && (nTokClass == EXC_TOKCLASS_REF) )
+ ChangeTokenClass( rnTokenId, nTokClass = EXC_TOKCLASS_VAL );
+
+ // replace RPO conversion of operator with parent conversion
+ XclFuncParamConv eConv = (rConvInfo.meConv == EXC_PARAMCONV_RPO) ? ePrevConv : rConvInfo.meConv;
+
+ // find the effective token class conversion to be performed for this token
+ XclExpClassConv eClassConv = EXC_CLASSCONV_ORG;
+ switch( eConv )
+ {
+ case EXC_PARAMCONV_ORG:
+ // conversion is forced independent of parent conversion
+ eClassConv = EXC_CLASSCONV_ORG;
+ break;
+ case EXC_PARAMCONV_VAL:
+ // conversion is forced independent of parent conversion
+ eClassConv = EXC_CLASSCONV_VAL;
+ break;
+ case EXC_PARAMCONV_ARR:
+ // conversion is forced independent of parent conversion
+ eClassConv = EXC_CLASSCONV_ARR;
+ break;
+ case EXC_PARAMCONV_RPT:
+ switch( ePrevConv )
+ {
+ case EXC_PARAMCONV_ORG:
+ case EXC_PARAMCONV_VAL:
+ case EXC_PARAMCONV_ARR:
+ /* If parent token has REF class (REF token in REFTYPE
+ function parameter), then RPT does not repeat the
+ previous explicit ORG or ARR conversion, but always
+ falls back to VAL conversion. */
+ eClassConv = bWasRefClass ? EXC_CLASSCONV_VAL : ePrevClassConv;
+ break;
+ case EXC_PARAMCONV_RPT:
+ // nested RPT repeats the previous effective conversion
+ eClassConv = ePrevClassConv;
+ break;
+ case EXC_PARAMCONV_RPX:
+ /* If parent token has REF class (REF token in REFTYPE
+ function parameter), then RPX repeats the previous
+ effective conversion (wich will be either ORG or ARR,
+ but never VAL), otherwise falls back to ORG conversion. */
+ eClassConv = bWasRefClass ? ePrevClassConv : EXC_CLASSCONV_ORG;
+ break;
+ case EXC_PARAMCONV_RPO: // does not occur
+ break;
+ }
+ break;
+ case EXC_PARAMCONV_RPX:
+ /* If current token still has REF class, set previous effective
+ conversion as current conversion. This will not have an effect
+ on the REF token but is needed for RPT parameters of this
+ function that want to repeat this conversion type. If current
+ token is VAL or ARR class, the previous ARR conversion will be
+ repeated on the token, but VAL conversion will not. */
+ eClassConv = ((nTokClass == EXC_TOKCLASS_REF) || (ePrevClassConv == EXC_CLASSCONV_ARR)) ?
+ ePrevClassConv : EXC_CLASSCONV_ORG;
+ break;
+ case EXC_PARAMCONV_RPO: // does not occur (see above)
+ break;
+ }
+
+ // do the token class conversion
+ switch( eClassConv )
+ {
+ case EXC_CLASSCONV_ORG:
+ /* Cell formulas: leave the current token class. Cell formulas
+ are the only type of formulas where all tokens can keep
+ their original token class.
+ Array and defined name formulas: convert VAL to ARR. */
+ if( (mxData->mrCfg.meClassType != EXC_CLASSTYPE_CELL) && (nTokClass == EXC_TOKCLASS_VAL) )
+ ChangeTokenClass( rnTokenId, nTokClass = EXC_TOKCLASS_ARR );
+ break;
+ case EXC_CLASSCONV_VAL:
+ // convert ARR to VAL
+ if( nTokClass == EXC_TOKCLASS_ARR )
+ ChangeTokenClass( rnTokenId, nTokClass = EXC_TOKCLASS_VAL );
+ break;
+ case EXC_CLASSCONV_ARR:
+ // convert VAL to ARR
+ if( nTokClass == EXC_TOKCLASS_VAL )
+ ChangeTokenClass( rnTokenId, nTokClass = EXC_TOKCLASS_ARR );
+ break;
+ }
+
+ // do conversion for nested operands, if token is an operator or function
+ if( rConvInfo.mnTokPos < mxData->maOpListVec.size() )
+ if( const XclExpOperandList* pOperands = mxData->maOpListVec[ rConvInfo.mnTokPos ].get() )
+ for( XclExpOperandList::const_iterator aIt = pOperands->begin(), aEnd = pOperands->end(); aIt != aEnd; ++aIt )
+ RecalcTokenClass( *aIt, eConv, eClassConv, nTokClass == EXC_TOKCLASS_REF );
+}
+
+void XclExpFmlaCompImpl::FinalizeFormula()
+{
+ if( mxData->mbOk )
+ {
+ // Volatile? Add a tAttrVolatile token at the beginning of the token array.
+ if( mxData->mbVolatile )
+ {
+ // tAttrSpace token can be extended with volatile flag
+ if( !IsSpaceToken( 0 ) )
+ {
+ InsertZeros( 0, 4 );
+ mxData->maTokVec[ 0 ] = EXC_TOKID_ATTR;
+ }
+ mxData->maTokVec[ 1 ] |= EXC_TOK_ATTR_VOLATILE;
+ }
+
+ // Token array too long? -> error
+ mxData->mbOk = mxData->maTokVec.size() <= EXC_TOKARR_MAXLEN;
+ }
+
+ if( !mxData->mbOk )
+ {
+ // Any unrecoverable error? -> Create a =#NA formula.
+ mxData->maTokVec.clear();
+ mxData->maExtDataVec.clear();
+ mxData->mbVolatile = false;
+ AppendErrorToken( EXC_ERR_NA );
+ }
+}
+
+XclTokenArrayRef XclExpFmlaCompImpl::CreateTokenArray()
+{
+ // create the Excel token array from working data before resetting mxData
+ DBG_ASSERT( mxData->mrCfg.mbAllowArrays || mxData->maExtDataVec.empty(), "XclExpFmlaCompImpl::CreateTokenArray - unexpected extended data" );
+ if( !mxData->mrCfg.mbAllowArrays )
+ mxData->maExtDataVec.clear();
+ XclTokenArrayRef xTokArr( new XclTokenArray( mxData->maTokVec, mxData->maExtDataVec, mxData->mbVolatile ) );
+ mxData.reset();
+
+ // compiler invoked recursively? - restore old working data
+ if( !maDataStack.empty() )
+ {
+ mxData = maDataStack.back();
+ maDataStack.pop_back();
+ }
+
+ return xTokArr;
+}
+
+// compiler -------------------------------------------------------------------
+
+const FormulaToken* XclExpFmlaCompImpl::GetNextRawToken()
+{
+ const FormulaToken* pScToken = mxData->maTokArrIt.Get();
+ ++mxData->maTokArrIt;
+ return pScToken;
+}
+
+const FormulaToken* XclExpFmlaCompImpl::PeekNextRawToken( bool bSkipSpaces ) const
+{
+ /* Returns pointer to next raw token in the token array. The token array
+ iterator already points to the next token (A call to GetNextToken()
+ always increases the iterator), so this function just returns the token
+ the iterator points to. To skip space tokens, a copy of the iterator is
+ created and set to the passed skip-spaces mode. If spaces have to be
+ skipped, and the iterator currently points to a space token, the
+ constructor will move it to the next non-space token. */
+ XclTokenArrayIterator aTempIt( mxData->maTokArrIt, bSkipSpaces );
+ return aTempIt.Get();
+}
+
+bool XclExpFmlaCompImpl::GetNextToken( XclExpScToken& rTokData )
+{
+ rTokData.mpScToken = GetNextRawToken();
+ rTokData.mnSpaces = (rTokData.GetOpCode() == ocSpaces) ? rTokData.mpScToken->GetByte() : 0;
+ while( rTokData.GetOpCode() == ocSpaces )
+ rTokData.mpScToken = GetNextRawToken();
+ return rTokData.Is();
+}
+
+XclExpScToken XclExpFmlaCompImpl::GetNextToken()
+{
+ XclExpScToken aTokData;
+ GetNextToken( aTokData );
+ return aTokData;
+}
+
+namespace {
+
+/** Returns the Excel token ID of a comparison operator or EXC_TOKID_NONE. */
+inline sal_uInt8 lclGetCompareTokenId( OpCode eOpCode )
+{
+ switch( eOpCode )
+ {
+ case ocLess: return EXC_TOKID_LT;
+ case ocLessEqual: return EXC_TOKID_LE;
+ case ocEqual: return EXC_TOKID_EQ;
+ case ocGreaterEqual: return EXC_TOKID_GE;
+ case ocGreater: return EXC_TOKID_GT;
+ case ocNotEqual: return EXC_TOKID_NE;
+ default:;
+ }
+ return EXC_TOKID_NONE;
+}
+
+/** Returns the Excel token ID of a string concatenation operator or EXC_TOKID_NONE. */
+inline sal_uInt8 lclGetConcatTokenId( OpCode eOpCode )
+{
+ return (eOpCode == ocAmpersand) ? EXC_TOKID_CONCAT : EXC_TOKID_NONE;
+}
+
+/** Returns the Excel token ID of an addition/subtraction operator or EXC_TOKID_NONE. */
+inline sal_uInt8 lclGetAddSubTokenId( OpCode eOpCode )
+{
+ switch( eOpCode )
+ {
+ case ocAdd: return EXC_TOKID_ADD;
+ case ocSub: return EXC_TOKID_SUB;
+ default:;
+ }
+ return EXC_TOKID_NONE;
+}
+
+/** Returns the Excel token ID of a multiplication/division operator or EXC_TOKID_NONE. */
+inline sal_uInt8 lclGetMulDivTokenId( OpCode eOpCode )
+{
+ switch( eOpCode )
+ {
+ case ocMul: return EXC_TOKID_MUL;
+ case ocDiv: return EXC_TOKID_DIV;
+ default:;
+ }
+ return EXC_TOKID_NONE;
+}
+
+/** Returns the Excel token ID of a power operator or EXC_TOKID_NONE. */
+inline sal_uInt8 lclGetPowTokenId( OpCode eOpCode )
+{
+ return (eOpCode == ocPow) ? EXC_TOKID_POWER : EXC_TOKID_NONE;
+}
+
+/** Returns the Excel token ID of a trailing unary operator or EXC_TOKID_NONE. */
+inline sal_uInt8 lclGetUnaryPostTokenId( OpCode eOpCode )
+{
+ return (eOpCode == ocPercentSign) ? EXC_TOKID_PERCENT : EXC_TOKID_NONE;
+}
+
+/** Returns the Excel token ID of a leading unary operator or EXC_TOKID_NONE. */
+inline sal_uInt8 lclGetUnaryPreTokenId( OpCode eOpCode )
+{
+ switch( eOpCode )
+ {
+ case ocAdd: return EXC_TOKID_UPLUS; // +(1)
+ case ocNeg: return EXC_TOKID_UMINUS; // NEG(1)
+ case ocNegSub: return EXC_TOKID_UMINUS; // -(1)
+ default:;
+ }
+ return EXC_TOKID_NONE;
+}
+
+/** Returns the Excel token ID of a reference list operator or EXC_TOKID_NONE. */
+inline sal_uInt8 lclGetListTokenId( OpCode eOpCode, bool bStopAtSep )
+{
+ return ((eOpCode == ocUnion) || (!bStopAtSep && (eOpCode == ocSep))) ? EXC_TOKID_LIST : EXC_TOKID_NONE;
+}
+
+/** Returns the Excel token ID of a reference intersection operator or EXC_TOKID_NONE. */
+inline sal_uInt8 lclGetIntersectTokenId( OpCode eOpCode )
+{
+ return (eOpCode == ocIntersect) ? EXC_TOKID_ISECT : EXC_TOKID_NONE;
+}
+
+/** Returns the Excel token ID of a reference range operator or EXC_TOKID_NONE. */
+inline sal_uInt8 lclGetRangeTokenId( OpCode eOpCode )
+{
+ return (eOpCode == ocRange) ? EXC_TOKID_RANGE : EXC_TOKID_NONE;
+}
+
+} // namespace
+
+XclExpScToken XclExpFmlaCompImpl::Expression( XclExpScToken aTokData, bool bInParentheses, bool bStopAtSep )
+{
+ if( mxData->mbOk && aTokData.Is() )
+ {
+ // remember old stop-at-ocSep mode, restored below
+ bool bOldStopAtSep = mxData->mbStopAtSep;
+ mxData->mbStopAtSep = bStopAtSep;
+ // start compilation of the subexpression
+ aTokData = OrTerm( aTokData, bInParentheses );
+ // restore old stop-at-ocSep mode
+ mxData->mbStopAtSep = bOldStopAtSep;
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::SkipExpression( XclExpScToken aTokData, bool bStopAtSep )
+{
+ while( mxData->mbOk && aTokData.Is() && (aTokData.GetOpCode() != ocClose) && (!bStopAtSep || (aTokData.GetOpCode() != ocSep)) )
+ {
+ if( aTokData.GetOpCode() == ocOpen )
+ {
+ aTokData = SkipExpression( GetNextToken(), false );
+ if( mxData->mbOk ) mxData->mbOk = aTokData.GetOpCode() == ocClose;
+ }
+ aTokData = GetNextToken();
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::OrTerm( XclExpScToken aTokData, bool bInParentheses )
+{
+ aTokData = AndTerm( aTokData, bInParentheses );
+ sal_uInt8 nParamCount = 1;
+ while( mxData->mbOk && (aTokData.GetOpCode() == ocOr) )
+ {
+ RemoveTrailingParen();
+ aTokData = AndTerm( GetNextToken(), bInParentheses );
+ RemoveTrailingParen();
+ ++nParamCount;
+ if( mxData->mbOk ) mxData->mbOk = nParamCount <= EXC_FUNC_MAXPARAM;
+ }
+ if( mxData->mbOk && (nParamCount > 1) )
+ AppendLogicalOperatorToken( EXC_FUNCID_OR, nParamCount );
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::AndTerm( XclExpScToken aTokData, bool bInParentheses )
+{
+ aTokData = CompareTerm( aTokData, bInParentheses );
+ sal_uInt8 nParamCount = 1;
+ while( mxData->mbOk && (aTokData.GetOpCode() == ocAnd) )
+ {
+ RemoveTrailingParen();
+ aTokData = CompareTerm( GetNextToken(), bInParentheses );
+ RemoveTrailingParen();
+ ++nParamCount;
+ if( mxData->mbOk ) mxData->mbOk = nParamCount <= EXC_FUNC_MAXPARAM;
+ }
+ if( mxData->mbOk && (nParamCount > 1) )
+ AppendLogicalOperatorToken( EXC_FUNCID_AND, nParamCount );
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::CompareTerm( XclExpScToken aTokData, bool bInParentheses )
+{
+ aTokData = ConcatTerm( aTokData, bInParentheses );
+ sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
+ while( mxData->mbOk && ((nOpTokenId = lclGetCompareTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
+ {
+ sal_uInt8 nSpaces = aTokData.mnSpaces;
+ aTokData = ConcatTerm( GetNextToken(), bInParentheses );
+ AppendBinaryOperatorToken( nOpTokenId, true, nSpaces );
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::ConcatTerm( XclExpScToken aTokData, bool bInParentheses )
+{
+ aTokData = AddSubTerm( aTokData, bInParentheses );
+ sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
+ while( mxData->mbOk && ((nOpTokenId = lclGetConcatTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
+ {
+ sal_uInt8 nSpaces = aTokData.mnSpaces;
+ aTokData = AddSubTerm( GetNextToken(), bInParentheses );
+ AppendBinaryOperatorToken( nOpTokenId, true, nSpaces );
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::AddSubTerm( XclExpScToken aTokData, bool bInParentheses )
+{
+ aTokData = MulDivTerm( aTokData, bInParentheses );
+ sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
+ while( mxData->mbOk && ((nOpTokenId = lclGetAddSubTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
+ {
+ sal_uInt8 nSpaces = aTokData.mnSpaces;
+ aTokData = MulDivTerm( GetNextToken(), bInParentheses );
+ AppendBinaryOperatorToken( nOpTokenId, true, nSpaces );
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::MulDivTerm( XclExpScToken aTokData, bool bInParentheses )
+{
+ aTokData = PowTerm( aTokData, bInParentheses );
+ sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
+ while( mxData->mbOk && ((nOpTokenId = lclGetMulDivTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
+ {
+ sal_uInt8 nSpaces = aTokData.mnSpaces;
+ aTokData = PowTerm( GetNextToken(), bInParentheses );
+ AppendBinaryOperatorToken( nOpTokenId, true, nSpaces );
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::PowTerm( XclExpScToken aTokData, bool bInParentheses )
+{
+ aTokData = UnaryPostTerm( aTokData, bInParentheses );
+ sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
+ while( mxData->mbOk && ((nOpTokenId = lclGetPowTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
+ {
+ sal_uInt8 nSpaces = aTokData.mnSpaces;
+ aTokData = UnaryPostTerm( GetNextToken(), bInParentheses );
+ AppendBinaryOperatorToken( nOpTokenId, true, nSpaces );
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::UnaryPostTerm( XclExpScToken aTokData, bool bInParentheses )
+{
+ aTokData = UnaryPreTerm( aTokData, bInParentheses );
+ sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
+ while( mxData->mbOk && ((nOpTokenId = lclGetUnaryPostTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
+ {
+ AppendUnaryOperatorToken( nOpTokenId, aTokData.mnSpaces );
+ GetNextToken( aTokData );
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::UnaryPreTerm( XclExpScToken aTokData, bool bInParentheses )
+{
+ sal_uInt8 nOpTokenId = mxData->mbOk ? lclGetUnaryPreTokenId( aTokData.GetOpCode() ) : EXC_TOKID_NONE;
+ if( nOpTokenId != EXC_TOKID_NONE )
+ {
+ sal_uInt8 nSpaces = aTokData.mnSpaces;
+ aTokData = UnaryPreTerm( GetNextToken(), bInParentheses );
+ AppendUnaryOperatorToken( nOpTokenId, nSpaces );
+ }
+ else
+ {
+ aTokData = ListTerm( aTokData, bInParentheses );
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::ListTerm( XclExpScToken aTokData, bool bInParentheses )
+{
+ sal_uInt16 nSubExprPos = GetSize();
+ bool bHasAnyRefOp = false;
+ bool bHasListOp = false;
+ aTokData = IntersectTerm( aTokData, bHasAnyRefOp );
+ sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
+ while( mxData->mbOk && ((nOpTokenId = lclGetListTokenId( aTokData.GetOpCode(), mxData->mbStopAtSep )) != EXC_TOKID_NONE) )
+ {
+ sal_uInt8 nSpaces = aTokData.mnSpaces;
+ aTokData = IntersectTerm( GetNextToken(), bHasAnyRefOp );
+ AppendBinaryOperatorToken( nOpTokenId, false, nSpaces );
+ bHasAnyRefOp = bHasListOp = true;
+ }
+ if( bHasAnyRefOp )
+ {
+ // add a tMemFunc token enclosing the entire reference subexpression
+ sal_uInt16 nSubExprSize = GetSize() - nSubExprPos;
+ InsertZeros( nSubExprPos, 3 );
+ mxData->maTokVec[ nSubExprPos ] = GetTokenId( EXC_TOKID_MEMFUNC, EXC_TOKCLASS_REF );
+ Overwrite( nSubExprPos + 1, nSubExprSize );
+ // update the operand/operator stack (set the list expression as operand of the tMemFunc)
+ XclExpOperandListRef xOperands( new XclExpOperandList );
+ xOperands->AppendOperand( PopOperandPos(), EXC_PARAMCONV_VAL, false );
+ PushOperatorPos( nSubExprPos, xOperands );
+ }
+ // #i86439# enclose list operator into parentheses, e.g. Calc's =AREAS(A1~A2) to Excel's =AREAS((A1;A2))
+ if( bHasListOp && !bInParentheses )
+ AppendParenToken();
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::IntersectTerm( XclExpScToken aTokData, bool& rbHasRefOp )
+{
+ aTokData = RangeTerm( aTokData, rbHasRefOp );
+ sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
+ while( mxData->mbOk && ((nOpTokenId = lclGetIntersectTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
+ {
+ sal_uInt8 nSpaces = aTokData.mnSpaces;
+ aTokData = RangeTerm( GetNextToken(), rbHasRefOp );
+ AppendBinaryOperatorToken( nOpTokenId, false, nSpaces );
+ rbHasRefOp = true;
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::RangeTerm( XclExpScToken aTokData, bool& rbHasRefOp )
+{
+ aTokData = Factor( aTokData );
+ sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
+ while( mxData->mbOk && ((nOpTokenId = lclGetRangeTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
+ {
+ sal_uInt8 nSpaces = aTokData.mnSpaces;
+ aTokData = Factor( GetNextToken() );
+ AppendBinaryOperatorToken( nOpTokenId, false, nSpaces );
+ rbHasRefOp = true;
+ }
+ return aTokData;
+}
+
+XclExpScToken XclExpFmlaCompImpl::Factor( XclExpScToken aTokData )
+{
+ if( !mxData->mbOk || !aTokData.Is() ) return XclExpScToken();
+
+ switch( aTokData.GetType() )
+ {
+ case svUnknown: mxData->mbOk = false; break;
+ case svDouble: ProcessDouble( aTokData ); break;
+ case svString: ProcessString( aTokData ); break;
+ case svSingleRef: ProcessCellRef( aTokData ); break;
+ case svDoubleRef: ProcessRangeRef( aTokData ); break;
+ case svExternalSingleRef: ProcessExternalCellRef( aTokData ); break;
+ case svExternalDoubleRef: ProcessExternalRangeRef( aTokData ); break;
+ case svExternalName: ProcessExternalName( aTokData ); break;
+ case svMatrix: ProcessMatrix( aTokData ); break;
+ case svExternal: ProcessExternal( aTokData ); break;
+
+ default: switch( aTokData.GetOpCode() )
+ {
+ case ocNone: /* do nothing */ break;
+ case ocMissing: ProcessMissing( aTokData ); break;
+ case ocBad: ProcessBad( aTokData ); break;
+ case ocOpen: ProcessParentheses( aTokData ); break;
+ case ocName: ProcessDefinedName( aTokData ); break;
+ case ocFalse:
+ case ocTrue: ProcessBoolean( aTokData ); break;
+ case ocDde: ProcessDdeLink( aTokData ); break;
+ default: ProcessFunction( aTokData );
+ }
+ }
+
+ return GetNextToken();
+}
+
+// formula structure ----------------------------------------------------------
+
+void XclExpFmlaCompImpl::ProcessDouble( const XclExpScToken& rTokData )
+{
+ double fValue = rTokData.mpScToken->GetDouble();
+ double fInt;
+ double fFrac = modf( fValue, &fInt );
+ if( (fFrac == 0.0) && (0.0 <= fInt) && (fInt <= 65535.0) )
+ AppendIntToken( static_cast< sal_uInt16 >( fInt ), rTokData.mnSpaces );
+ else
+ AppendNumToken( fValue, rTokData.mnSpaces );
+}
+
+void XclExpFmlaCompImpl::ProcessString( const XclExpScToken& rTokData )
+{
+ AppendOperandTokenId( EXC_TOKID_STR, rTokData.mnSpaces );
+ Append( rTokData.mpScToken->GetString() );
+}
+
+void XclExpFmlaCompImpl::ProcessMissing( const XclExpScToken& rTokData )
+{
+ AppendMissingToken( rTokData.mnSpaces );
+}
+
+void XclExpFmlaCompImpl::ProcessBad( const XclExpScToken& rTokData )
+{
+ AppendErrorToken( EXC_ERR_NA, rTokData.mnSpaces );
+}
+
+void XclExpFmlaCompImpl::ProcessParentheses( const XclExpScToken& rTokData )
+{
+ XclExpScToken aTokData = Expression( GetNextToken(), true, false );
+ mxData->mbOk = aTokData.GetOpCode() == ocClose;
+ AppendParenToken( rTokData.mnSpaces, aTokData.mnSpaces );
+}
+
+void XclExpFmlaCompImpl::ProcessBoolean( const XclExpScToken& rTokData )
+{
+ mxData->mbOk = GetNextToken().GetOpCode() == ocOpen;
+ if( mxData->mbOk ) mxData->mbOk = GetNextToken().GetOpCode() == ocClose;
+ if( mxData->mbOk )
+ AppendBoolToken( rTokData.GetOpCode() == ocTrue, rTokData.mnSpaces );
+}
+
+namespace {
+
+inline bool lclGetTokenString( String& rString, const XclExpScToken& rTokData )
+{
+ bool bIsStr = (rTokData.GetType() == svString) && (rTokData.GetOpCode() == ocPush);
+ if( bIsStr )
+ rString = rTokData.mpScToken->GetString();
+ return bIsStr;
+}
+
+} // namespace
+
+void XclExpFmlaCompImpl::ProcessDdeLink( const XclExpScToken& rTokData )
+{
+ String aApplic, aTopic, aItem;
+
+ mxData->mbOk = GetNextToken().GetOpCode() == ocOpen;
+ if( mxData->mbOk ) mxData->mbOk = lclGetTokenString( aApplic, GetNextToken() );
+ if( mxData->mbOk ) mxData->mbOk = GetNextToken().GetOpCode() == ocSep;
+ if( mxData->mbOk ) mxData->mbOk = lclGetTokenString( aTopic, GetNextToken() );
+ if( mxData->mbOk ) mxData->mbOk = GetNextToken().GetOpCode() == ocSep;
+ if( mxData->mbOk ) mxData->mbOk = lclGetTokenString( aItem, GetNextToken() );
+ if( mxData->mbOk ) mxData->mbOk = GetNextToken().GetOpCode() == ocClose;
+ if( mxData->mbOk ) mxData->mbOk = aApplic.Len() && aTopic.Len() && aItem.Len();
+ if( mxData->mbOk )
+ {
+ sal_uInt16 nExtSheet, nExtName;
+ if( mxData->mpLinkMgr && mxData->mpLinkMgr->InsertDde( nExtSheet, nExtName, aApplic, aTopic, aItem ) )
+ AppendNameXToken( nExtSheet, nExtName, rTokData.mnSpaces );
+ else
+ AppendErrorToken( EXC_ERR_NA, rTokData.mnSpaces );
+ }
+}
+
+void XclExpFmlaCompImpl::ProcessExternal( const XclExpScToken& rTokData )
+{
+ /* #i47228# Excel import generates svExternal/ocMacro tokens for invalid
+ names and for external/invalid function calls. This function looks for
+ the next token in the token array. If it is an opening parenthesis, the
+ token is processed as external function call, otherwise as undefined name. */
+ const FormulaToken* pNextScToken = PeekNextRawToken( true );
+ if( !pNextScToken || (pNextScToken->GetOpCode() != ocOpen) )
+ AppendMissingNameToken( rTokData.mpScToken->GetExternal(), rTokData.mnSpaces );
+ else
+ ProcessFunction( rTokData );
+}
+
+void XclExpFmlaCompImpl::ProcessMatrix( const XclExpScToken& rTokData )
+{
+ const ScMatrix* pMatrix = static_cast< const ScToken* >( rTokData.mpScToken )->GetMatrix();
+ if( pMatrix && mxData->mrCfg.mbAllowArrays )
+ {
+ SCSIZE nScCols, nScRows;
+ pMatrix->GetDimensions( nScCols, nScRows );
+ DBG_ASSERT( (nScCols > 0) && (nScRows > 0), "XclExpFmlaCompImpl::ProcessMatrix - invalid matrix size" );
+ sal_uInt16 nCols = ::limit_cast< sal_uInt16 >( nScCols, 0, 256 );
+ sal_uInt16 nRows = ::limit_cast< sal_uInt16 >( nScRows, 0, 1024 );
+
+ // create the tArray token
+ AppendOperandTokenId( GetTokenId( EXC_TOKID_ARRAY, EXC_TOKCLASS_ARR ), rTokData.mnSpaces );
+ Append( static_cast< sal_uInt8 >( (meBiff == EXC_BIFF8) ? (nCols - 1) : nCols ) );
+ Append( static_cast< sal_uInt16 >( (meBiff == EXC_BIFF8) ? (nRows - 1) : nRows ) );
+ Append( static_cast< sal_uInt32 >( 0 ) );
+
+ // create the extended data containing the array values
+ AppendExt( static_cast< sal_uInt8 >( (meBiff == EXC_BIFF8) ? (nCols - 1) : nCols ) );
+ AppendExt( static_cast< sal_uInt16 >( (meBiff == EXC_BIFF8) ? (nRows - 1) : nRows ) );
+ for( SCSIZE nScRow = 0; nScRow < nScRows; ++nScRow )
+ {
+ for( SCSIZE nScCol = 0; nScCol < nScCols; ++nScCol )
+ {
+ ScMatrixValue nMatVal = pMatrix->Get( nScCol, nScRow );
+ if( ScMatrix::IsValueType( nMatVal.nType ) ) // value, boolean, or error
+ {
+ if( ScMatrix::IsBooleanType( nMatVal.nType ) )
+ {
+ AppendExt( EXC_CACHEDVAL_BOOL );
+ AppendExt( static_cast< sal_uInt8 >( nMatVal.GetBoolean() ? 1 : 0 ) );
+ AppendExt( 0, 7 );
+ }
+ else if( sal_uInt16 nErr = nMatVal.GetError() )
+ {
+ AppendExt( EXC_CACHEDVAL_ERROR );
+ AppendExt( XclTools::GetXclErrorCode( nErr ) );
+ AppendExt( 0, 7 );
+ }
+ else
+ {
+ AppendExt( EXC_CACHEDVAL_DOUBLE );
+ AppendExt( nMatVal.fVal );
+ }
+ }
+ else // string or empty
+ {
+ const String& rStr = nMatVal.GetString();
+ if( rStr.Len() == 0 )
+ {
+ AppendExt( EXC_CACHEDVAL_EMPTY );
+ AppendExt( 0, 8 );
+ }
+ else
+ {
+ AppendExt( EXC_CACHEDVAL_STRING );
+ AppendExt( rStr );
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // array in places that do not allow it (cond fmts, data validation)
+ AppendErrorToken( EXC_ERR_NA, rTokData.mnSpaces );
+ }
+}
+
+void XclExpFmlaCompImpl::ProcessFunction( const XclExpScToken& rTokData )
+{
+ OpCode eOpCode = rTokData.GetOpCode();
+ const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromOpCode( eOpCode );
+
+ XclExpExtFuncData aExtFuncData;
+
+ // no exportable function found - try to create an external macro call
+ if( !pFuncInfo && (eOpCode >= SC_OPCODE_START_NO_PAR) )
+ {
+ const String& rFuncName = ScCompiler::GetNativeSymbol( eOpCode );
+ if( rFuncName.Len() )
+ {
+ aExtFuncData.Set( rFuncName, true, false );
+ pFuncInfo = maFuncProv.GetFuncInfoFromOpCode( ocMacro );
+ }
+ }
+
+ mxData->mbOk = pFuncInfo != 0;
+ if( !mxData->mbOk ) return;
+
+ // functions simulated by a macro call in file format
+ if( pFuncInfo->IsMacroFunc() )
+ aExtFuncData.Set( pFuncInfo->GetMacroFuncName(), false, true );
+
+ XclExpFuncData aFuncData( rTokData, *pFuncInfo, aExtFuncData );
+ XclExpScToken aTokData;
+
+ // preparations for special functions, before function processing starts
+ PrepareFunction( aFuncData );
+
+ enum { STATE_START, STATE_OPEN, STATE_PARAM, STATE_SEP, STATE_CLOSE, STATE_END }
+ eState = STATE_START;
+ while( eState != STATE_END ) switch( eState )
+ {
+ case STATE_START:
+ mxData->mbOk = GetNextToken( aTokData ) && (aTokData.GetOpCode() == ocOpen);
+ eState = mxData->mbOk ? STATE_OPEN : STATE_END;
+ break;
+ case STATE_OPEN:
+ mxData->mbOk = GetNextToken( aTokData );
+ eState = mxData->mbOk ? ((aTokData.GetOpCode() == ocClose) ? STATE_CLOSE : STATE_PARAM) : STATE_END;
+ break;
+ case STATE_PARAM:
+ aTokData = ProcessParam( aTokData, aFuncData );
+ switch( aTokData.GetOpCode() )
+ {
+ case ocSep: eState = STATE_SEP; break;
+ case ocClose: eState = STATE_CLOSE; break;
+ default: mxData->mbOk = false;
+ }
+ if( !mxData->mbOk ) eState = STATE_END;
+ break;
+ case STATE_SEP:
+ mxData->mbOk = (aFuncData.GetParamCount() < EXC_FUNC_MAXPARAM) && GetNextToken( aTokData );
+ eState = mxData->mbOk ? STATE_PARAM : STATE_END;
+ break;
+ case STATE_CLOSE:
+ FinishFunction( aFuncData, aTokData.mnSpaces );
+ eState = STATE_END;
+ break;
+ default:;
+ }
+}
+
+void XclExpFmlaCompImpl::PrepareFunction( XclExpFuncData& rFuncData )
+{
+ switch( rFuncData.GetOpCode() )
+ {
+ case ocCot: // simulate COT(x) by (1/TAN(x))
+ case ocCotHyp: // simulate COTH(x) by (1/TANH(x))
+ AppendIntToken( 1 );
+ break;
+ case ocArcCot: // simulate ACOT(x) by (PI/2-ATAN(x))
+ AppendNumToken( F_PI2 );
+ break;
+ default:;
+ }
+}
+
+void XclExpFmlaCompImpl::FinishFunction( XclExpFuncData& rFuncData, sal_uInt8 nCloseSpaces )
+{
+ // append missing parameters required in Excel, may modify param count
+ AppendTrailingParam( rFuncData );
+
+ // check if parameter count fits into the limits of the function
+ sal_uInt8 nParamCount = rFuncData.GetParamCount();
+ if( (rFuncData.GetMinParamCount() <= nParamCount) && (nParamCount <= rFuncData.GetMaxParamCount()) )
+ {
+ // first put the tAttrSpace tokens, they must not be included in tAttrGoto handling
+ AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP_CLOSE, nCloseSpaces );
+ AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP, rFuncData.GetSpaces() );
+
+ // add tAttrGoto tokens for IF or CHOOSE functions
+ switch( rFuncData.GetOpCode() )
+ {
+ case ocIf:
+ case ocChose:
+ AppendJumpToken( rFuncData, EXC_TOK_ATTR_GOTO );
+ break;
+ default:;
+ }
+
+ // put the tFunc or tFuncVar token (or another special token, e.g. tAttrSum)
+ AppendFuncToken( rFuncData );
+
+ // update volatile flag - is set if at least one used function is volatile
+ mxData->mbVolatile |= rFuncData.IsVolatile();
+
+ // update jump tokens for specific functions, add additional tokens
+ switch( rFuncData.GetOpCode() )
+ {
+ case ocIf:
+ FinishIfFunction( rFuncData );
+ break;
+ case ocChose:
+ FinishChooseFunction( rFuncData );
+ break;
+
+ case ocCot: // simulate COT(x) by (1/TAN(x))
+ case ocCotHyp: // simulate COTH(x) by (1/TANH(x))
+ AppendBinaryOperatorToken( EXC_TOKID_DIV, true );
+ AppendParenToken();
+ break;
+ case ocArcCot: // simulate ACOT(x) by (PI/2-ATAN(x))
+ AppendBinaryOperatorToken( EXC_TOKID_SUB, true );
+ AppendParenToken();
+ break;
+
+ default:;
+ }
+ }
+ else
+ mxData->mbOk = false;
+}
+
+void XclExpFmlaCompImpl::FinishIfFunction( XclExpFuncData& rFuncData )
+{
+ sal_uInt16 nParamCount = rFuncData.GetParamCount();
+ DBG_ASSERT( (nParamCount == 2) || (nParamCount == 3), "XclExpFmlaCompImpl::FinishIfFunction - wrong parameter count" );
+ const ScfUInt16Vec& rAttrPos = rFuncData.GetAttrPosVec();
+ DBG_ASSERT( nParamCount == rAttrPos.size(), "XclExpFmlaCompImpl::FinishIfFunction - wrong number of tAttr tokens" );
+ // update tAttrIf token following the condition parameter
+ Overwrite( rAttrPos[ 0 ] + 2, static_cast< sal_uInt16 >( rAttrPos[ 1 ] - rAttrPos[ 0 ] ) );
+ // update the tAttrGoto tokens following true and false parameters
+ UpdateAttrGoto( rAttrPos[ 1 ] );
+ if( nParamCount == 3 )
+ UpdateAttrGoto( rAttrPos[ 2 ] );
+}
+
+void XclExpFmlaCompImpl::FinishChooseFunction( XclExpFuncData& rFuncData )
+{
+ sal_uInt16 nParamCount = rFuncData.GetParamCount();
+ ScfUInt16Vec& rAttrPos = rFuncData.GetAttrPosVec();
+ DBG_ASSERT( nParamCount == rAttrPos.size(), "XclExpFmlaCompImpl::FinishChooseFunction - wrong number of tAttr tokens" );
+ // number of choices is parameter count minus 1
+ sal_uInt16 nChoices = nParamCount - 1;
+ // tAttrChoose token contains number of choices
+ Overwrite( rAttrPos[ 0 ] + 2, nChoices );
+ // cache position of the jump table (follows number of choices in tAttrChoose token)
+ sal_uInt16 nJumpArrPos = rAttrPos[ 0 ] + 4;
+ // size of jump table: number of choices, plus 1 for error position
+ sal_uInt16 nJumpArrSize = 2 * (nChoices + 1);
+ // insert the jump table into the tAttrChoose token
+ InsertZeros( nJumpArrPos, nJumpArrSize );
+ // update positions of tAttrGoto tokens after jump table insertion
+ sal_uInt16 nIdx;
+ for( nIdx = 1; nIdx < nParamCount; ++nIdx )
+ rAttrPos[ nIdx ] = rAttrPos[ nIdx ] + nJumpArrSize;
+ // update the tAttrGoto tokens (they contain a value one-less to real distance)
+ for( nIdx = 1; nIdx < nParamCount; ++nIdx )
+ UpdateAttrGoto( rAttrPos[ nIdx ] );
+ // update the distances in the jump table
+ Overwrite( nJumpArrPos, nJumpArrSize );
+ for( nIdx = 1; nIdx < nParamCount; ++nIdx )
+ Overwrite( nJumpArrPos + 2 * nIdx, static_cast< sal_uInt16 >( rAttrPos[ nIdx ] + 4 - nJumpArrPos ) );
+}
+
+XclExpScToken XclExpFmlaCompImpl::ProcessParam( XclExpScToken aTokData, XclExpFuncData& rFuncData )
+{
+ if( rFuncData.IsCalcOnlyParam() )
+ {
+ // skip Calc-only parameter, stop at next ocClose or ocSep
+ aTokData = SkipExpression( aTokData, true );
+ rFuncData.IncParamInfoIdx();
+ }
+ else
+ {
+ // insert Excel-only parameters, modifies param count and class in rFuncData
+ while( rFuncData.IsExcelOnlyParam() )
+ AppendDefaultParam( rFuncData );
+
+ // process the parameter, stop at next ocClose or ocSep
+ PrepareParam( rFuncData );
+ /* #i37355# insert tMissArg token for missing parameters --
+ Excel import filter adds ocMissing token (handled in Factor()),
+ but Calc itself does not do this if a new formula is entered. */
+ switch( aTokData.GetOpCode() )
+ {
+ case ocSep:
+ case ocClose: AppendMissingToken(); break; // empty parameter
+ default: aTokData = Expression( aTokData, false, true );
+ }
+ // finalize the parameter and add special tokens, e.g. for IF or CHOOSE parameters
+ if( mxData->mbOk ) FinishParam( rFuncData );
+ }
+ return aTokData;
+}
+
+void XclExpFmlaCompImpl::PrepareParam( XclExpFuncData& rFuncData )
+{
+ // index of this parameter is equal to number of already finished parameters
+ sal_uInt8 nParamIdx = rFuncData.GetParamCount();
+
+ switch( rFuncData.GetOpCode() )
+ {
+ case ocIf:
+ switch( nParamIdx )
+ {
+ // add a tAttrIf token before true-parameter (second parameter)
+ case 1: AppendJumpToken( rFuncData, EXC_TOK_ATTR_IF ); break;
+ // add a tAttrGoto token before false-parameter (third parameter)
+ case 2: AppendJumpToken( rFuncData, EXC_TOK_ATTR_GOTO ); break;
+ }
+ break;
+
+ case ocChose:
+ switch( nParamIdx )
+ {
+ // do nothing for first parameter
+ case 0: break;
+ // add a tAttrChoose token before first value parameter (second parameter)
+ case 1: AppendJumpToken( rFuncData, EXC_TOK_ATTR_CHOOSE ); break;
+ // add a tAttrGoto token before other value parameters
+ default: AppendJumpToken( rFuncData, EXC_TOK_ATTR_GOTO );
+ }
+ break;
+
+ case ocArcCotHyp: // simulate ACOTH(x) by ATANH(1/(x))
+ if( nParamIdx == 0 )
+ AppendIntToken( 1 );
+ break;
+ default:;
+ }
+}
+
+void XclExpFmlaCompImpl::FinishParam( XclExpFuncData& rFuncData )
+{
+ // increase parameter count, update operand stack
+ rFuncData.FinishParam( PopOperandPos() );
+
+ // append more tokens for parameters of some special functions
+ sal_uInt8 nParamIdx = rFuncData.GetParamCount() - 1;
+ switch( rFuncData.GetOpCode() )
+ {
+ case ocArcCotHyp: // simulate ACOTH(x) by ATANH(1/(x))
+ if( nParamIdx == 0 )
+ {
+ AppendParenToken();
+ AppendBinaryOperatorToken( EXC_TOKID_DIV, true );
+ }
+ break;
+ default:;
+ }
+}
+
+void XclExpFmlaCompImpl::AppendDefaultParam( XclExpFuncData& rFuncData )
+{
+ // prepare parameters of some special functions
+ PrepareParam( rFuncData );
+
+ switch( rFuncData.GetOpCode() )
+ {
+ case ocExternal:
+ AppendAddInCallToken( rFuncData.GetExtFuncData() );
+ break;
+ case ocEuroConvert:
+ AppendEuroToolCallToken( rFuncData.GetExtFuncData() );
+ break;
+ case ocMacro:
+ AppendMacroCallToken( rFuncData.GetExtFuncData() );
+ break;
+ default:
+ {
+ DBG_ASSERT( rFuncData.IsMacroFunc(), "XclExpFmlaCompImpl::AppendDefaultParam - unknown opcode" );
+ if( rFuncData.IsMacroFunc() )
+ AppendMacroCallToken( rFuncData.GetExtFuncData() );
+ else
+ AppendMissingToken(); // to keep parameter count valid
+ }
+ }
+
+ // update parameter count, add special parameter tokens
+ FinishParam( rFuncData );
+}
+
+void XclExpFmlaCompImpl::AppendTrailingParam( XclExpFuncData& rFuncData )
+{
+ sal_uInt8 nParamCount = rFuncData.GetParamCount();
+ switch( rFuncData.GetOpCode() )
+ {
+ case ocIf:
+ if( nParamCount == 1 )
+ {
+ // Excel needs at least two parameters in IF function
+ PrepareParam( rFuncData );
+ AppendBoolToken( true );
+ FinishParam( rFuncData );
+ }
+ break;
+
+ case ocRound:
+ case ocRoundUp:
+ case ocRoundDown:
+ if( nParamCount == 1 )
+ {
+ // ROUND, ROUNDUP, ROUNDDOWN functions are fixed to 2 parameters in Excel
+ PrepareParam( rFuncData );
+ AppendIntToken( 0 );
+ FinishParam( rFuncData );
+ }
+ break;
+
+ case ocIndex:
+ if( nParamCount == 1 )
+ {
+ // INDEX function needs at least 2 parameters in Excel
+ PrepareParam( rFuncData );
+ AppendMissingToken();
+ FinishParam( rFuncData );
+ }
+ break;
+
+ case ocExternal:
+ case ocMacro:
+ // external or macro call without parameters needs the external name reference
+ if( nParamCount == 0 )
+ AppendDefaultParam( rFuncData );
+ break;
+
+ case ocGammaDist:
+ if( nParamCount == 3 )
+ {
+ // GAMMADIST function needs 4 parameters in Excel
+ PrepareParam( rFuncData );
+ AppendIntToken( 1 );
+ FinishParam( rFuncData );
+ }
+ break;
+
+ case ocPoissonDist:
+ if( nParamCount == 2 )
+ {
+ // POISSON function needs 3 parameters in Excel
+ PrepareParam( rFuncData );
+ AppendIntToken( 1 );
+ FinishParam( rFuncData );
+ }
+ break;
+
+ case ocNormDist:
+ if( nParamCount == 3 )
+ {
+ // NORMDIST function needs 4 parameters in Excel
+ PrepareParam( rFuncData );
+ AppendBoolToken( true );
+ FinishParam( rFuncData );
+ }
+ break;
+
+ case ocLogNormDist:
+ switch( nParamCount )
+ {
+ // LOGNORMDIST function needs 3 parameters in Excel
+ case 1:
+ PrepareParam( rFuncData );
+ AppendIntToken( 0 );
+ FinishParam( rFuncData );
+ // do not break, add next default parameter
+ case 2:
+ PrepareParam( rFuncData );
+ AppendIntToken( 1 );
+ FinishParam( rFuncData );
+ break;
+ default:;
+ }
+
+ break;
+
+ default:
+ // #i108420# function without parameters stored as macro call needs the external name reference
+ if( (nParamCount == 0) && rFuncData.IsMacroFunc() )
+ AppendDefaultParam( rFuncData );
+
+ }
+}
+
+// reference handling ---------------------------------------------------------
+
+namespace {
+
+inline bool lclIsRefRel2D( const ScSingleRefData& rRefData )
+{
+ return rRefData.IsColRel() || rRefData.IsRowRel();
+}
+
+inline bool lclIsRefDel2D( const ScSingleRefData& rRefData )
+{
+ return rRefData.IsColDeleted() || rRefData.IsRowDeleted();
+}
+
+inline bool lclIsRefRel2D( const ScComplexRefData& rRefData )
+{
+ return lclIsRefRel2D( rRefData.Ref1 ) || lclIsRefRel2D( rRefData.Ref2 );
+}
+
+inline bool lclIsRefDel2D( const ScComplexRefData& rRefData )
+{
+ return lclIsRefDel2D( rRefData.Ref1 ) || lclIsRefDel2D( rRefData.Ref2 );
+}
+
+} // namespace
+
+SCTAB XclExpFmlaCompImpl::GetScTab( const ScSingleRefData& rRefData ) const
+{
+ bool bInvTab = rRefData.IsTabDeleted() || (!mxData->mpScBasePos && IsInGlobals() && rRefData.IsTabRel());
+ return bInvTab ? SCTAB_INVALID : static_cast< SCTAB >( rRefData.nTab );
+}
+
+bool XclExpFmlaCompImpl::IsRef2D( const ScSingleRefData& rRefData ) const
+{
+ /* rRefData.IsFlag3D() determines if sheet name is always visible, even on
+ the own sheet. If 3D references are allowed, the passed reference does
+ not count as 2D reference. */
+ return (!mxData->mpLinkMgr || !rRefData.IsFlag3D()) && !rRefData.IsTabDeleted() &&
+ (rRefData.IsTabRel() ? (rRefData.nRelTab == 0) : (static_cast< SCTAB >( rRefData.nTab ) == GetCurrScTab()));
+}
+
+bool XclExpFmlaCompImpl::IsRef2D( const ScComplexRefData& rRefData ) const
+{
+ return IsRef2D( rRefData.Ref1 ) && IsRef2D( rRefData.Ref2 );
+}
+
+void XclExpFmlaCompImpl::ConvertRefData(
+ ScSingleRefData& rRefData, XclAddress& rXclPos,
+ bool bNatLangRef, bool bTruncMaxCol, bool bTruncMaxRow ) const
+{
+ if( mxData->mpScBasePos )
+ {
+ // *** reference position exists (cell, matrix) - convert to absolute ***
+ rRefData.CalcAbsIfRel( *mxData->mpScBasePos );
+
+ // convert column index
+ SCsCOL& rnScCol = rRefData.nCol;
+ if( bTruncMaxCol && (rnScCol == mnMaxScCol) )
+ rnScCol = mnMaxAbsCol;
+ else if( (rnScCol < 0) || (rnScCol > mnMaxAbsCol) )
+ rRefData.SetColDeleted( sal_True );
+ rXclPos.mnCol = static_cast< sal_uInt16 >( rnScCol ) & mnMaxColMask;
+
+ // convert row index
+ SCsROW& rnScRow = rRefData.nRow;
+ if( bTruncMaxRow && (rnScRow == mnMaxScRow) )
+ rnScRow = mnMaxAbsRow;
+ else if( (rnScRow < 0) || (rnScRow > mnMaxAbsRow) )
+ rRefData.SetRowDeleted( sal_True );
+ rXclPos.mnRow = static_cast< sal_uInt32 >( rnScRow ) & mnMaxRowMask;
+ }
+ else
+ {
+ // *** no reference position (shared, names, condfmt) - use relative values ***
+
+ // convert column index (2-step-cast ScsCOL->sal_Int16->sal_uInt16 to get all bits correctly)
+ sal_Int16 nXclRelCol = static_cast< sal_Int16 >( rRefData.IsColRel() ? rRefData.nRelCol : rRefData.nCol );
+ rXclPos.mnCol = static_cast< sal_uInt16 >( nXclRelCol ) & mnMaxColMask;
+
+ // convert row index (2-step-cast ScsROW->sal_Int16->sal_uInt16 to get all bits correctly)
+ sal_Int16 nXclRelRow = static_cast< sal_Int32 >( rRefData.IsRowRel() ? rRefData.nRelRow : rRefData.nRow );
+ rXclPos.mnRow = static_cast< sal_uInt32 >( nXclRelRow ) & mnMaxRowMask;
+
+ // resolve relative tab index if possible
+ if( rRefData.IsTabRel() && !IsInGlobals() && (GetCurrScTab() < GetDoc().GetTableCount()) )
+ rRefData.nTab = static_cast< SCsTAB >( GetCurrScTab() + rRefData.nRelTab );
+ }
+
+ // flags for relative column and row
+ if( bNatLangRef )
+ {
+ DBG_ASSERT( meBiff == EXC_BIFF8, "XclExpFmlaCompImpl::ConvertRefData - NLRs only for BIFF8" );
+ // Calc does not support absolute reference mode in natural language references
+ ::set_flag( rXclPos.mnCol, EXC_TOK_NLR_REL );
+ }
+ else
+ {
+ sal_uInt16 rnRelRow = rXclPos.mnRow;
+ sal_uInt16& rnRelField = (meBiff <= EXC_BIFF5) ? rnRelRow : rXclPos.mnCol;
+ ::set_flag( rnRelField, EXC_TOK_REF_COLREL, rRefData.IsColRel() );
+ ::set_flag( rnRelField, EXC_TOK_REF_ROWREL, rRefData.IsRowRel() );
+ }
+}
+
+void XclExpFmlaCompImpl::ConvertRefData(
+ ScComplexRefData& rRefData, XclRange& rXclRange, bool bNatLangRef ) const
+{
+ // convert start and end of the range
+ ConvertRefData( rRefData.Ref1, rXclRange.maFirst, bNatLangRef, false, false );
+ bool bTruncMaxCol = !rRefData.Ref1.IsColDeleted() && (rRefData.Ref1.nCol == 0);
+ bool bTruncMaxRow = !rRefData.Ref1.IsRowDeleted() && (rRefData.Ref1.nRow == 0);
+ ConvertRefData( rRefData.Ref2, rXclRange.maLast, bNatLangRef, bTruncMaxCol, bTruncMaxRow );
+}
+
+XclExpRefLogEntry* XclExpFmlaCompImpl::GetNewRefLogEntry()
+{
+ if( mxData->mpRefLog )
+ {
+ mxData->mpRefLog->resize( mxData->mpRefLog->size() + 1 );
+ return &mxData->mpRefLog->back();
+ }
+ return 0;
+}
+
+void XclExpFmlaCompImpl::ProcessCellRef( const XclExpScToken& rTokData )
+{
+ // get the Excel address components, adjust internal data in aRefData
+ bool bNatLangRef = (meBiff == EXC_BIFF8) && mxData->mpScBasePos && (rTokData.GetOpCode() == ocColRowName);
+ ScSingleRefData aRefData = static_cast< const ScToken* >( rTokData.mpScToken )->GetSingleRef();
+ XclAddress aXclPos( ScAddress::UNINITIALIZED );
+ ConvertRefData( aRefData, aXclPos, bNatLangRef, false, false );
+
+ if( bNatLangRef )
+ {
+ DBG_ASSERT( aRefData.IsColRel() != aRefData.IsRowRel(),
+ "XclExpFmlaCompImpl::ProcessCellRef - broken natural language reference" );
+ // create tNlr token for natural language reference
+ sal_uInt8 nSubId = aRefData.IsColRel() ? EXC_TOK_NLR_COLV : EXC_TOK_NLR_ROWV;
+ AppendOperandTokenId( EXC_TOKID_NLR, rTokData.mnSpaces );
+ Append( nSubId );
+ AppendAddress( aXclPos );
+ }
+ else
+ {
+ // store external cell contents in CRN records
+ if( mxData->mrCfg.mbFromCell && mxData->mpLinkMgr && mxData->mpScBasePos )
+ mxData->mpLinkMgr->StoreCell( aRefData );
+
+ // create the tRef, tRefErr, tRefN, tRef3d, or tRefErr3d token
+ if( !mxData->mrCfg.mb3DRefOnly && IsRef2D( aRefData ) )
+ {
+ // 2D reference (not in defined names, but allowed in range lists)
+ sal_uInt8 nBaseId = (!mxData->mpScBasePos && lclIsRefRel2D( aRefData )) ? EXC_TOKID_REFN :
+ (lclIsRefDel2D( aRefData ) ? EXC_TOKID_REFERR : EXC_TOKID_REF);
+ AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
+ AppendAddress( aXclPos );
+ }
+ else if( mxData->mpLinkMgr ) // 3D reference
+ {
+ // 1-based EXTERNSHEET index and 0-based Excel sheet index
+ sal_uInt16 nExtSheet, nXclTab;
+ mxData->mpLinkMgr->FindExtSheet( nExtSheet, nXclTab, GetScTab( aRefData ), GetNewRefLogEntry() );
+ // write the token
+ sal_uInt8 nBaseId = lclIsRefDel2D( aRefData ) ? EXC_TOKID_REFERR3D : EXC_TOKID_REF3D;
+ AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
+ Append( nExtSheet );
+ if( meBiff <= EXC_BIFF5 )
+ {
+ Append( 0, 8 );
+ Append( nXclTab );
+ Append( nXclTab );
+ }
+ AppendAddress( aXclPos );
+ }
+ else
+ {
+ // 3D ref in cond. format, or 2D ref in name
+ AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces );
+ }
+ }
+}
+
+void XclExpFmlaCompImpl::ProcessRangeRef( const XclExpScToken& rTokData )
+{
+ // get the Excel address components, adjust internal data in aRefData
+ ScComplexRefData aRefData = static_cast< const ScToken* >( rTokData.mpScToken )->GetDoubleRef();
+ XclRange aXclRange( ScAddress::UNINITIALIZED );
+ ConvertRefData( aRefData, aXclRange, false );
+
+ // store external cell contents in CRN records
+ if( mxData->mrCfg.mbFromCell && mxData->mpLinkMgr && mxData->mpScBasePos )
+ mxData->mpLinkMgr->StoreCellRange( aRefData );
+
+ // create the tArea, tAreaErr, tAreaN, tArea3d, or tAreaErr3d token
+ if( !mxData->mrCfg.mb3DRefOnly && IsRef2D( aRefData ) )
+ {
+ // 2D reference (not in name formulas, but allowed in range lists)
+ sal_uInt8 nBaseId = (!mxData->mpScBasePos && lclIsRefRel2D( aRefData )) ? EXC_TOKID_AREAN :
+ (lclIsRefDel2D( aRefData ) ? EXC_TOKID_AREAERR : EXC_TOKID_AREA);
+ AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
+ AppendRange( aXclRange );
+ }
+ else if( mxData->mpLinkMgr ) // 3D reference
+ {
+ // 1-based EXTERNSHEET index and 0-based Excel sheet indexes
+ sal_uInt16 nExtSheet, nFirstXclTab, nLastXclTab;
+ mxData->mpLinkMgr->FindExtSheet( nExtSheet, nFirstXclTab, nLastXclTab,
+ GetScTab( aRefData.Ref1 ), GetScTab( aRefData.Ref2 ), GetNewRefLogEntry() );
+ // write the token
+ sal_uInt8 nBaseId = lclIsRefDel2D( aRefData ) ? EXC_TOKID_AREAERR3D : EXC_TOKID_AREA3D;
+ AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
+ Append( nExtSheet );
+ if( meBiff <= EXC_BIFF5 )
+ {
+ Append( 0, 8 );
+ Append( nFirstXclTab );
+ Append( nLastXclTab );
+ }
+ AppendRange( aXclRange );
+ }
+ else
+ {
+ // 3D ref in cond. format, or 2D ref in name
+ AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces );
+ }
+}
+
+void XclExpFmlaCompImpl::ProcessExternalCellRef( const XclExpScToken& rTokData )
+{
+ if( mxData->mpLinkMgr )
+ {
+ // get the Excel address components, adjust internal data in aRefData
+ ScSingleRefData aRefData = static_cast< const ScToken* >( rTokData.mpScToken )->GetSingleRef();
+ XclAddress aXclPos( ScAddress::UNINITIALIZED );
+ ConvertRefData( aRefData, aXclPos, false, false, false );
+
+ // store external cell contents in CRN records
+ sal_uInt16 nFileId = rTokData.mpScToken->GetIndex();
+ const String& rTabName = rTokData.mpScToken->GetString();
+ if( mxData->mrCfg.mbFromCell && mxData->mpScBasePos )
+ mxData->mpLinkMgr->StoreCell( nFileId, rTabName, aRefData );
+
+ // 1-based EXTERNSHEET index and 0-based Excel sheet indexes
+ sal_uInt16 nExtSheet, nFirstSBTab, nLastSBTab;
+ mxData->mpLinkMgr->FindExtSheet( nFileId, rTabName, 1, nExtSheet, nFirstSBTab, nLastSBTab, GetNewRefLogEntry() );
+ // write the token
+ sal_uInt8 nBaseId = lclIsRefDel2D( aRefData ) ? EXC_TOKID_REFERR3D : EXC_TOKID_REF3D;
+ AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
+ Append( nExtSheet );
+ if( meBiff <= EXC_BIFF5 )
+ {
+ Append( 0, 8 );
+ Append( nFirstSBTab );
+ Append( nLastSBTab );
+ }
+ AppendAddress( aXclPos );
+ }
+ else
+ {
+ AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces );
+ }
+}
+
+void XclExpFmlaCompImpl::ProcessExternalRangeRef( const XclExpScToken& rTokData )
+{
+ if( mxData->mpLinkMgr )
+ {
+ // get the Excel address components, adjust internal data in aRefData
+ ScComplexRefData aRefData = static_cast< const ScToken* >( rTokData.mpScToken )->GetDoubleRef();
+ XclRange aXclRange( ScAddress::UNINITIALIZED );
+ ConvertRefData( aRefData, aXclRange, false );
+
+ // store external cell contents in CRN records
+ sal_uInt16 nFileId = rTokData.mpScToken->GetIndex();
+ const String& rTabName = rTokData.mpScToken->GetString();
+ if( mxData->mrCfg.mbFromCell && mxData->mpScBasePos )
+ mxData->mpLinkMgr->StoreCellRange( nFileId, rTabName, aRefData );
+
+ // 1-based EXTERNSHEET index and 0-based Excel sheet indexes
+ sal_uInt16 nExtSheet, nFirstSBTab, nLastSBTab;
+ sal_uInt16 nTabSpan = static_cast< sal_uInt16 >( aRefData.Ref2.nTab - aRefData.Ref1.nTab + 1 );
+ mxData->mpLinkMgr->FindExtSheet( nFileId, rTabName, nTabSpan, nExtSheet, nFirstSBTab, nLastSBTab, GetNewRefLogEntry() );
+ // write the token
+ sal_uInt8 nBaseId = lclIsRefDel2D( aRefData ) ? EXC_TOKID_AREAERR3D : EXC_TOKID_AREA3D;
+ AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
+ Append( nExtSheet );
+ if( meBiff <= EXC_BIFF5 )
+ {
+ Append( 0, 8 );
+ Append( nFirstSBTab );
+ Append( nLastSBTab );
+ }
+ AppendRange( aXclRange );
+ }
+ else
+ {
+ AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces );
+ }
+}
+
+void XclExpFmlaCompImpl::ProcessDefinedName( const XclExpScToken& rTokData )
+{
+ SCTAB nTab = SCTAB_GLOBAL;
+ bool bGlobal = static_cast<bool>(rTokData.mpScToken->GetByte());
+ if (!bGlobal && mxData->mpScBasePos)
+ nTab = mxData->mpScBasePos->Tab();
+
+ XclExpNameManager& rNameMgr = GetNameManager();
+ sal_uInt16 nNameIdx = rNameMgr.InsertName(nTab, rTokData.mpScToken->GetIndex());
+ if( nNameIdx != 0 )
+ {
+ // global names always with tName token, local names dependent on config
+ SCTAB nScTab = rNameMgr.GetScTab( nNameIdx );
+ if( (nScTab == SCTAB_GLOBAL) || (!mxData->mrCfg.mb3DRefOnly && (nScTab == GetCurrScTab())) )
+ {
+ AppendNameToken( nNameIdx, rTokData.mnSpaces );
+ }
+ else if( mxData->mpLinkMgr )
+ {
+ // use the same special EXTERNNAME to refer to any local name
+ sal_uInt16 nExtSheet = mxData->mpLinkMgr->FindExtSheet( EXC_EXTSH_OWNDOC );
+ AppendNameXToken( nExtSheet, nNameIdx, rTokData.mnSpaces );
+ }
+ else
+ AppendErrorToken( EXC_ERR_NAME, rTokData.mnSpaces );
+ // volatile names (containing volatile functions)
+ mxData->mbVolatile |= rNameMgr.IsVolatile( nNameIdx );
+ }
+ else
+ AppendErrorToken( EXC_ERR_NAME, rTokData.mnSpaces );
+}
+
+void XclExpFmlaCompImpl::ProcessExternalName( const XclExpScToken& rTokData )
+{
+ if( mxData->mpLinkMgr )
+ {
+ ScExternalRefManager& rExtRefMgr = *GetDoc().GetExternalRefManager();
+ sal_uInt16 nFileId = rTokData.mpScToken->GetIndex();
+ const String& rName = rTokData.mpScToken->GetString();
+ ScExternalRefCache::TokenArrayRef xArray = rExtRefMgr.getRangeNameTokens( nFileId, rName );
+ if( xArray.get() )
+ {
+ // store external cell contents in CRN records
+ if( mxData->mpScBasePos )
+ {
+ for( FormulaToken* pScToken = xArray->First(); pScToken; pScToken = xArray->Next() )
+ {
+ if( pScToken->IsExternalRef() )
+ {
+ switch( pScToken->GetType() )
+ {
+ case svExternalSingleRef:
+ {
+ ScSingleRefData aRefData = static_cast< ScToken* >( pScToken )->GetSingleRef();
+ aRefData.CalcAbsIfRel( *mxData->mpScBasePos );
+ mxData->mpLinkMgr->StoreCell( nFileId, pScToken->GetString(), aRefData );
+ }
+ break;
+ case svExternalDoubleRef:
+ {
+ ScComplexRefData aRefData = static_cast< ScToken* >( pScToken )->GetDoubleRef();
+ aRefData.CalcAbsIfRel( *mxData->mpScBasePos );
+ mxData->mpLinkMgr->StoreCellRange( nFileId, pScToken->GetString(), aRefData );
+ }
+ default:
+ ; // nothing, avoid compiler warning
+ }
+ }
+ }
+ }
+
+ // insert the new external name and create the tNameX token
+ sal_uInt16 nExtSheet, nExtName;
+ const String* pFile = rExtRefMgr.getExternalFileName( nFileId );
+ if( pFile && mxData->mpLinkMgr->InsertExtName( nExtSheet, nExtName, *pFile, rName, xArray ) )
+ {
+ AppendNameXToken( nExtSheet, nExtName, rTokData.mnSpaces );
+ return;
+ }
+ }
+ }
+
+ // on any error: create a #NAME? error
+ AppendErrorToken( EXC_ERR_NAME, rTokData.mnSpaces );
+}
+
+// token vector ---------------------------------------------------------------
+
+void XclExpFmlaCompImpl::PushOperandPos( sal_uInt16 nTokPos )
+{
+ mxData->maOpPosStack.push_back( nTokPos );
+}
+
+void XclExpFmlaCompImpl::PushOperatorPos( sal_uInt16 nTokPos, const XclExpOperandListRef& rxOperands )
+{
+ PushOperandPos( nTokPos );
+ DBG_ASSERT( rxOperands.get(), "XclExpFmlaCompImpl::AppendOperatorTokenId - missing operand list" );
+ if( mxData->maOpListVec.size() <= nTokPos )
+ mxData->maOpListVec.resize( nTokPos + 1, XclExpOperandListRef() );
+ mxData->maOpListVec[ nTokPos ] = rxOperands;
+}
+
+sal_uInt16 XclExpFmlaCompImpl::PopOperandPos()
+{
+ DBG_ASSERT( !mxData->mbOk || !mxData->maOpPosStack.empty(), "XclExpFmlaCompImpl::PopOperandPos - token stack broken" );
+ mxData->mbOk &= !mxData->maOpPosStack.empty();
+ if( mxData->mbOk )
+ {
+ sal_uInt16 nTokPos = mxData->maOpPosStack.back();
+ mxData->maOpPosStack.pop_back();
+ return nTokPos;
+ }
+ return 0;
+}
+
+namespace {
+
+inline void lclAppend( ScfUInt8Vec& orVector, sal_uInt16 nData )
+{
+ orVector.resize( orVector.size() + 2 );
+ ShortToSVBT16( nData, &*(orVector.end() - 2) );
+}
+
+inline void lclAppend( ScfUInt8Vec& orVector, sal_uInt32 nData )
+{
+ orVector.resize( orVector.size() + 4 );
+ UInt32ToSVBT32( nData, &*(orVector.end() - 4) );
+}
+
+inline void lclAppend( ScfUInt8Vec& orVector, double fData )
+{
+ orVector.resize( orVector.size() + 8 );
+ DoubleToSVBT64( fData, &*(orVector.end() - 8) );
+}
+
+inline void lclAppend( ScfUInt8Vec& orVector, const XclExpRoot& rRoot, const String& rString, XclStrFlags nStrFlags )
+{
+ XclExpStringRef xXclStr = XclExpStringHelper::CreateString( rRoot, rString, nStrFlags, EXC_TOK_STR_MAXLEN );
+ size_t nSize = orVector.size();
+ orVector.resize( nSize + xXclStr->GetSize() );
+ xXclStr->WriteToMem( &orVector[ nSize ] );
+}
+
+} // namespace
+
+void XclExpFmlaCompImpl::Append( sal_uInt8 nData )
+{
+ mxData->maTokVec.push_back( nData );
+}
+
+void XclExpFmlaCompImpl::Append( sal_uInt8 nData, size_t nCount )
+{
+ mxData->maTokVec.resize( mxData->maTokVec.size() + nCount, nData );
+}
+
+void XclExpFmlaCompImpl::Append( sal_uInt16 nData )
+{
+ lclAppend( mxData->maTokVec, nData );
+}
+
+void XclExpFmlaCompImpl::Append( sal_uInt32 nData )
+{
+ lclAppend( mxData->maTokVec, nData );
+}
+
+void XclExpFmlaCompImpl::Append( double fData )
+{
+ lclAppend( mxData->maTokVec, fData );
+}
+
+void XclExpFmlaCompImpl::Append( const String& rString )
+{
+ lclAppend( mxData->maTokVec, GetRoot(), rString, EXC_STR_8BITLENGTH );
+}
+
+void XclExpFmlaCompImpl::AppendAddress( const XclAddress& rXclPos )
+{
+ Append( static_cast<sal_uInt16>(rXclPos.mnRow) );
+ if( meBiff <= EXC_BIFF5 )
+ Append( static_cast< sal_uInt8 >( rXclPos.mnCol ) );
+ else
+ Append( rXclPos.mnCol );
+}
+
+void XclExpFmlaCompImpl::AppendRange( const XclRange& rXclRange )
+{
+ Append( static_cast<sal_uInt16>(rXclRange.maFirst.mnRow) );
+ Append( static_cast<sal_uInt16>(rXclRange.maLast.mnRow) );
+ if( meBiff <= EXC_BIFF5 )
+ {
+ Append( static_cast< sal_uInt8 >( rXclRange.maFirst.mnCol ) );
+ Append( static_cast< sal_uInt8 >( rXclRange.maLast.mnCol ) );
+ }
+ else
+ {
+ Append( rXclRange.maFirst.mnCol );
+ Append( rXclRange.maLast.mnCol );
+ }
+}
+
+void XclExpFmlaCompImpl::AppendSpaceToken( sal_uInt8 nType, sal_uInt8 nCount )
+{
+ if( nCount > 0 )
+ {
+ Append( EXC_TOKID_ATTR );
+ Append( EXC_TOK_ATTR_SPACE );
+ Append( nType );
+ Append( nCount );
+ }
+}
+
+void XclExpFmlaCompImpl::AppendOperandTokenId( sal_uInt8 nTokenId, sal_uInt8 nSpaces )
+{
+ AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP, nSpaces );
+ PushOperandPos( GetSize() );
+ Append( nTokenId );
+}
+
+void XclExpFmlaCompImpl::AppendIntToken( sal_uInt16 nValue, sal_uInt8 nSpaces )
+{
+ AppendOperandTokenId( EXC_TOKID_INT, nSpaces );
+ Append( nValue );
+}
+
+void XclExpFmlaCompImpl::AppendNumToken( double fValue, sal_uInt8 nSpaces )
+{
+ AppendOperandTokenId( EXC_TOKID_NUM, nSpaces );
+ Append( fValue );
+}
+
+void XclExpFmlaCompImpl::AppendBoolToken( bool bValue, sal_uInt8 nSpaces )
+{
+ AppendOperandTokenId( EXC_TOKID_BOOL, nSpaces );
+ Append( bValue ? EXC_TOK_BOOL_TRUE : EXC_TOK_BOOL_FALSE );
+}
+
+void XclExpFmlaCompImpl::AppendErrorToken( sal_uInt8 nErrCode, sal_uInt8 nSpaces )
+{
+ AppendOperandTokenId( EXC_TOKID_ERR, nSpaces );
+ Append( nErrCode );
+}
+
+void XclExpFmlaCompImpl::AppendMissingToken( sal_uInt8 nSpaces )
+{
+ AppendOperandTokenId( EXC_TOKID_MISSARG, nSpaces );
+}
+
+void XclExpFmlaCompImpl::AppendNameToken( sal_uInt16 nNameIdx, sal_uInt8 nSpaces )
+{
+ if( nNameIdx > 0 )
+ {
+ AppendOperandTokenId( GetTokenId( EXC_TOKID_NAME, EXC_TOKCLASS_REF ), nSpaces );
+ Append( nNameIdx );
+ Append( 0, (meBiff <= EXC_BIFF5) ? 12 : 2 );
+ }
+ else
+ AppendErrorToken( EXC_ERR_NAME );
+}
+
+void XclExpFmlaCompImpl::AppendMissingNameToken( const String& rName, sal_uInt8 nSpaces )
+{
+ sal_uInt16 nNameIdx = GetNameManager().InsertRawName( rName );
+ AppendNameToken( nNameIdx, nSpaces );
+}
+
+void XclExpFmlaCompImpl::AppendNameXToken( sal_uInt16 nExtSheet, sal_uInt16 nExtName, sal_uInt8 nSpaces )
+{
+ AppendOperandTokenId( GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ), nSpaces );
+ Append( nExtSheet );
+ if( meBiff <= EXC_BIFF5 )
+ Append( 0, 8 );
+ Append( nExtName );
+ Append( 0, (meBiff <= EXC_BIFF5) ? 12 : 2 );
+}
+
+void XclExpFmlaCompImpl::AppendMacroCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces )
+{
+ sal_uInt16 nNameIdx = GetNameManager().InsertMacroCall( rExtFuncData.maFuncName, rExtFuncData.mbVBasic, true, rExtFuncData.mbHidden );
+ AppendNameToken( nNameIdx, nSpaces );
+}
+
+void XclExpFmlaCompImpl::AppendAddInCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces )
+{
+ String aXclFuncName;
+ if( mxData->mpLinkMgr && ScGlobal::GetAddInCollection()->GetExcelName( rExtFuncData.maFuncName, GetUILanguage(), aXclFuncName ) )
+ {
+ sal_uInt16 nExtSheet, nExtName;
+ if( mxData->mpLinkMgr->InsertAddIn( nExtSheet, nExtName, aXclFuncName ) )
+ {
+ AppendNameXToken( nExtSheet, nExtName, nSpaces );
+ return;
+ }
+ }
+ AppendMacroCallToken( rExtFuncData, nSpaces );
+}
+
+void XclExpFmlaCompImpl::AppendEuroToolCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces )
+{
+ sal_uInt16 nExtSheet, nExtName;
+ if( mxData->mpLinkMgr && mxData->mpLinkMgr->InsertEuroTool( nExtSheet, nExtName, rExtFuncData.maFuncName ) )
+ AppendNameXToken( nExtSheet, nExtName, nSpaces );
+ else
+ AppendMacroCallToken( rExtFuncData, nSpaces );
+}
+
+void XclExpFmlaCompImpl::AppendOperatorTokenId( sal_uInt8 nTokenId, const XclExpOperandListRef& rxOperands, sal_uInt8 nSpaces )
+{
+ AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP, nSpaces );
+ PushOperatorPos( GetSize(), rxOperands );
+ Append( nTokenId );
+}
+
+void XclExpFmlaCompImpl::AppendUnaryOperatorToken( sal_uInt8 nTokenId, sal_uInt8 nSpaces )
+{
+ XclExpOperandListRef xOperands( new XclExpOperandList );
+ xOperands->AppendOperand( PopOperandPos(), EXC_PARAMCONV_RPO, true );
+ AppendOperatorTokenId( nTokenId, xOperands, nSpaces );
+}
+
+void XclExpFmlaCompImpl::AppendBinaryOperatorToken( sal_uInt8 nTokenId, bool bValType, sal_uInt8 nSpaces )
+{
+ XclExpOperandListRef xOperands( new XclExpOperandList );
+ xOperands->AppendOperand( PopOperandPos(), EXC_PARAMCONV_RPO, bValType );
+ xOperands->AppendOperand( PopOperandPos(), EXC_PARAMCONV_RPO, bValType );
+ AppendOperatorTokenId( nTokenId, xOperands, nSpaces );
+}
+
+void XclExpFmlaCompImpl::AppendLogicalOperatorToken( sal_uInt16 nXclFuncIdx, sal_uInt8 nOpCount )
+{
+ XclExpOperandListRef xOperands( new XclExpOperandList );
+ for( sal_uInt8 nOpIdx = 0; nOpIdx < nOpCount; ++nOpIdx )
+ xOperands->AppendOperand( PopOperandPos(), EXC_PARAMCONV_RPX, false );
+ AppendOperatorTokenId( GetTokenId( EXC_TOKID_FUNCVAR, EXC_TOKCLASS_VAL ), xOperands );
+ Append( nOpCount );
+ Append( nXclFuncIdx );
+}
+
+void XclExpFmlaCompImpl::AppendFuncToken( const XclExpFuncData& rFuncData )
+{
+ sal_uInt16 nXclFuncIdx = rFuncData.GetXclFuncIdx();
+ sal_uInt8 nParamCount = rFuncData.GetParamCount();
+ sal_uInt8 nRetClass = rFuncData.GetReturnClass();
+
+ if( (nXclFuncIdx == EXC_FUNCID_SUM) && (nParamCount == 1) )
+ {
+ // SUM with only one parameter
+ AppendOperatorTokenId( EXC_TOKID_ATTR, rFuncData.GetOperandList() );
+ Append( EXC_TOK_ATTR_SUM );
+ Append( sal_uInt16( 0 ) );
+ }
+ else if( rFuncData.IsFixedParamCount() )
+ {
+ // fixed number of parameters
+ AppendOperatorTokenId( GetTokenId( EXC_TOKID_FUNC, nRetClass ), rFuncData.GetOperandList() );
+ Append( nXclFuncIdx );
+ }
+ else
+ {
+ // variable number of parameters
+ AppendOperatorTokenId( GetTokenId( EXC_TOKID_FUNCVAR, nRetClass ), rFuncData.GetOperandList() );
+ Append( nParamCount );
+ Append( nXclFuncIdx );
+ }
+}
+
+void XclExpFmlaCompImpl::AppendParenToken( sal_uInt8 nOpenSpaces, sal_uInt8 nCloseSpaces )
+{
+ AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP_OPEN, nOpenSpaces );
+ AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP_CLOSE, nCloseSpaces );
+ Append( EXC_TOKID_PAREN );
+}
+
+void XclExpFmlaCompImpl::AppendJumpToken( XclExpFuncData& rFuncData, sal_uInt8 nAttrType )
+{
+ // store the start position of the token
+ rFuncData.AppendAttrPos( GetSize() );
+ // create the tAttr token
+ Append( EXC_TOKID_ATTR );
+ Append( nAttrType );
+ Append( sal_uInt16( 0 ) ); // placeholder that will be updated later
+}
+
+void XclExpFmlaCompImpl::InsertZeros( sal_uInt16 nInsertPos, sal_uInt16 nInsertSize )
+{
+ // insert zeros into the token array
+ DBG_ASSERT( nInsertPos < mxData->maTokVec.size(), "XclExpFmlaCompImpl::Insert - invalid position" );
+ mxData->maTokVec.insert( mxData->maTokVec.begin() + nInsertPos, nInsertSize, 0 );
+
+ // update positions of operands waiting for an operator
+ for( ScfUInt16Vec::iterator aIt = mxData->maOpPosStack.begin(), aEnd = mxData->maOpPosStack.end(); aIt != aEnd; ++aIt )
+ if( nInsertPos <= *aIt )
+ *aIt = *aIt + nInsertSize;
+
+ // update operand lists of all operator tokens
+ if( nInsertPos < mxData->maOpListVec.size() )
+ mxData->maOpListVec.insert( mxData->maOpListVec.begin() + nInsertPos, nInsertSize, XclExpOperandListRef() );
+ for( XclExpOperandListVector::iterator aIt = mxData->maOpListVec.begin(), aEnd = mxData->maOpListVec.end(); aIt != aEnd; ++aIt )
+ if( aIt->get() )
+ for( XclExpOperandList::iterator aIt2 = (*aIt)->begin(), aEnd2 = (*aIt)->end(); aIt2 != aEnd2; ++aIt2 )
+ if( nInsertPos <= aIt2->mnTokPos )
+ aIt2->mnTokPos = aIt2->mnTokPos + nInsertSize;
+}
+
+void XclExpFmlaCompImpl::Overwrite( sal_uInt16 nWriteToPos, sal_uInt16 nOffset )
+{
+ DBG_ASSERT( static_cast< size_t >( nWriteToPos + 1 ) < mxData->maTokVec.size(), "XclExpFmlaCompImpl::Overwrite - invalid position" );
+ ShortToSVBT16( nOffset, &mxData->maTokVec[ nWriteToPos ] );
+}
+
+void XclExpFmlaCompImpl::UpdateAttrGoto( sal_uInt16 nAttrPos )
+{
+ /* tAttrGoto contains distance from end of tAttr token to position behind
+ the function token (for IF or CHOOSE function), which is currently at
+ the end of the token array. Additionally this distance is decreased by
+ one, for whatever reason. So we have to subtract 4 and 1 from the
+ distance between the tAttr token start and the end of the token array. */
+ Overwrite( nAttrPos + 2, static_cast< sal_uInt16 >( GetSize() - nAttrPos - 5 ) );
+}
+
+bool XclExpFmlaCompImpl::IsSpaceToken( sal_uInt16 nPos ) const
+{
+ return
+ (static_cast< size_t >( nPos + 4 ) <= mxData->maTokVec.size()) &&
+ (mxData->maTokVec[ nPos ] == EXC_TOKID_ATTR) &&
+ (mxData->maTokVec[ nPos + 1 ] == EXC_TOK_ATTR_SPACE);
+}
+
+void XclExpFmlaCompImpl::RemoveTrailingParen()
+{
+ // remove trailing tParen token
+ if( !mxData->maTokVec.empty() && (mxData->maTokVec.back() == EXC_TOKID_PAREN) )
+ mxData->maTokVec.pop_back();
+ // remove remaining tAttrSpace tokens
+ while( (mxData->maTokVec.size() >= 4) && IsSpaceToken( GetSize() - 4 ) )
+ mxData->maTokVec.erase( mxData->maTokVec.end() - 4, mxData->maTokVec.end() );
+}
+
+void XclExpFmlaCompImpl::AppendExt( sal_uInt8 nData )
+{
+ mxData->maExtDataVec.push_back( nData );
+}
+
+void XclExpFmlaCompImpl::AppendExt( sal_uInt8 nData, size_t nCount )
+{
+ mxData->maExtDataVec.resize( mxData->maExtDataVec.size() + nCount, nData );
+}
+
+void XclExpFmlaCompImpl::AppendExt( sal_uInt16 nData )
+{
+ lclAppend( mxData->maExtDataVec, nData );
+}
+
+void XclExpFmlaCompImpl::AppendExt( double fData )
+{
+ lclAppend( mxData->maExtDataVec, fData );
+}
+
+void XclExpFmlaCompImpl::AppendExt( const String& rString )
+{
+ lclAppend( mxData->maExtDataVec, GetRoot(), rString, (meBiff == EXC_BIFF8) ? EXC_STR_DEFAULT : EXC_STR_8BITLENGTH );
+}
+
+// ============================================================================
+
+namespace {
+
+void lclInitOwnTab( ScSingleRefData& rRef, const ScAddress& rScPos, SCTAB nCurrScTab, bool b3DRefOnly )
+{
+ if( b3DRefOnly )
+ {
+ // no reduction to 2D reference, if global link manager is used
+ rRef.SetFlag3D( sal_True );
+ }
+ else if( rScPos.Tab() == nCurrScTab )
+ {
+ rRef.SetTabRel( sal_True );
+ rRef.nRelTab = 0;
+ }
+}
+
+void lclPutCellToTokenArray( ScTokenArray& rScTokArr, const ScAddress& rScPos, SCTAB nCurrScTab, bool b3DRefOnly )
+{
+ ScSingleRefData aRef;
+ aRef.InitAddress( rScPos );
+ lclInitOwnTab( aRef, rScPos, nCurrScTab, b3DRefOnly );
+ rScTokArr.AddSingleReference( aRef );
+}
+
+void lclPutRangeToTokenArray( ScTokenArray& rScTokArr, const ScRange& rScRange, SCTAB nCurrScTab, bool b3DRefOnly )
+{
+ if( rScRange.aStart == rScRange.aEnd )
+ {
+ lclPutCellToTokenArray( rScTokArr, rScRange.aStart, nCurrScTab, b3DRefOnly );
+ }
+ else
+ {
+ ScComplexRefData aRef;
+ aRef.InitRange( rScRange );
+ lclInitOwnTab( aRef.Ref1, rScRange.aStart, nCurrScTab, b3DRefOnly );
+ lclInitOwnTab( aRef.Ref2, rScRange.aEnd, nCurrScTab, b3DRefOnly );
+ rScTokArr.AddDoubleReference( aRef );
+ }
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpFormulaCompiler::XclExpFormulaCompiler( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mxImpl( new XclExpFmlaCompImpl( rRoot ) )
+{
+}
+
+XclExpFormulaCompiler::~XclExpFormulaCompiler()
+{
+}
+
+XclTokenArrayRef XclExpFormulaCompiler::CreateFormula(
+ XclFormulaType eType, const ScTokenArray& rScTokArr,
+ const ScAddress* pScBasePos, XclExpRefLog* pRefLog )
+{
+ return mxImpl->CreateFormula( eType, rScTokArr, pScBasePos, pRefLog );
+}
+
+XclTokenArrayRef XclExpFormulaCompiler::CreateFormula( XclFormulaType eType, const ScAddress& rScPos )
+{
+ ScTokenArray aScTokArr;
+ lclPutCellToTokenArray( aScTokArr, rScPos, GetCurrScTab(), mxImpl->Is3DRefOnly( eType ) );
+ return mxImpl->CreateFormula( eType, aScTokArr );
+}
+
+XclTokenArrayRef XclExpFormulaCompiler::CreateFormula( XclFormulaType eType, const ScRange& rScRange )
+{
+ ScTokenArray aScTokArr;
+ lclPutRangeToTokenArray( aScTokArr, rScRange, GetCurrScTab(), mxImpl->Is3DRefOnly( eType ) );
+ return mxImpl->CreateFormula( eType, aScTokArr );
+}
+
+XclTokenArrayRef XclExpFormulaCompiler::CreateFormula( XclFormulaType eType, const ScRangeList& rScRanges )
+{
+ size_t nCount = rScRanges.size();
+ if( nCount == 0 )
+ return XclTokenArrayRef();
+
+ ScTokenArray aScTokArr;
+ SCTAB nCurrScTab = GetCurrScTab();
+ bool b3DRefOnly = mxImpl->Is3DRefOnly( eType );
+ for( size_t nIdx = 0; nIdx < nCount; ++nIdx )
+ {
+ if( nIdx > 0 )
+ aScTokArr.AddOpCode( ocUnion );
+ lclPutRangeToTokenArray( aScTokArr, *rScRanges[ nIdx ], nCurrScTab, b3DRefOnly );
+ }
+ return mxImpl->CreateFormula( eType, aScTokArr );
+}
+
+XclTokenArrayRef XclExpFormulaCompiler::CreateErrorFormula( sal_uInt8 nErrCode )
+{
+ return mxImpl->CreateErrorFormula( nErrCode );
+}
+
+XclTokenArrayRef XclExpFormulaCompiler::CreateSpecialRefFormula(
+ sal_uInt8 nTokenId, const XclAddress& rXclPos )
+{
+ return mxImpl->CreateSpecialRefFormula( nTokenId, rXclPos );
+}
+
+XclTokenArrayRef XclExpFormulaCompiler::CreateNameXFormula(
+ sal_uInt16 nExtSheet, sal_uInt16 nExtName )
+{
+ return mxImpl->CreateNameXFormula( nExtSheet, nExtName );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xehelper.cxx b/sc/source/filter/excel/xehelper.cxx
new file mode 100644
index 000000000000..77b81686432f
--- /dev/null
+++ b/sc/source/filter/excel/xehelper.cxx
@@ -0,0 +1,1127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <sfx2/objsh.hxx>
+#include <vcl/font.hxx>
+#include <tools/urlobj.hxx>
+#include <svl/itemset.hxx>
+#include <svtools/ctrltool.hxx>
+#include <svx/svdotext.hxx>
+#include <editeng/outlobj.hxx>
+#include "scitems.hxx"
+#include <editeng/fhgtitem.hxx>
+#include <editeng/flstitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/svxfont.hxx>
+
+#define _SVSTDARR_USHORTS
+#include <svl/svstdarr.hxx>
+#include "document.hxx"
+#include "docpool.hxx"
+#include "cell.hxx"
+#include "editutil.hxx"
+#include "patattr.hxx"
+#include "xestyle.hxx"
+#include "fprogressbar.hxx"
+#include "xltracer.hxx"
+#include "xecontent.hxx"
+#include "xelink.hxx"
+#include "xehelper.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::i18n::XBreakIterator;
+
+// Export progress bar ========================================================
+
+XclExpProgressBar::XclExpProgressBar( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mxProgress( new ScfProgressBar( rRoot.GetDocShell(), STR_SAVE_DOC ) ),
+ mpSubProgress( 0 ),
+ mpSubRowCreate( 0 ),
+ mpSubRowFinal( 0 ),
+ mnSegRowFinal( SCF_INV_SEGMENT ),
+ mnRowCount( 0 )
+{
+}
+
+XclExpProgressBar::~XclExpProgressBar()
+{
+}
+
+void XclExpProgressBar::Initialize()
+{
+ const ScDocument& rDoc = GetDoc();
+ const XclExpTabInfo& rTabInfo = GetTabInfo();
+ SCTAB nScTabCount = rTabInfo.GetScTabCount();
+
+ // *** segment: creation of ROW records *** -------------------------------
+
+ sal_Int32 nSegRowCreate = mxProgress->AddSegment( 2000 );
+ mpSubRowCreate = &mxProgress->GetSegmentProgressBar( nSegRowCreate );
+ maSubSegRowCreate.resize( nScTabCount, SCF_INV_SEGMENT );
+
+ for( SCTAB nScTab = 0; nScTab < nScTabCount; ++nScTab )
+ {
+ if( rTabInfo.IsExportTab( nScTab ) )
+ {
+ SCCOL nLastUsedScCol;
+ SCROW nLastUsedScRow;
+ rDoc.GetTableArea( nScTab, nLastUsedScCol, nLastUsedScRow );
+ sal_Size nSegSize = static_cast< sal_Size >( nLastUsedScRow + 1 );
+ maSubSegRowCreate[ nScTab ] = mpSubRowCreate->AddSegment( nSegSize );
+ }
+ }
+
+ // *** segment: writing all ROW records *** -------------------------------
+
+ mnSegRowFinal = mxProgress->AddSegment( 1000 );
+ // sub progress bar and segment are created later in ActivateFinalRowsSegment()
+}
+
+void XclExpProgressBar::IncRowRecordCount()
+{
+ ++mnRowCount;
+}
+
+void XclExpProgressBar::ActivateCreateRowsSegment()
+{
+ DBG_ASSERT( (0 <= GetCurrScTab()) && (GetCurrScTab() < GetTabInfo().GetScTabCount()),
+ "XclExpProgressBar::ActivateCreateRowsSegment - invalid sheet" );
+ sal_Int32 nSeg = maSubSegRowCreate[ GetCurrScTab() ];
+ DBG_ASSERT( nSeg != SCF_INV_SEGMENT, "XclExpProgressBar::ActivateCreateRowsSegment - invalid segment" );
+ if( nSeg != SCF_INV_SEGMENT )
+ {
+ mpSubProgress = mpSubRowCreate;
+ mpSubProgress->ActivateSegment( nSeg );
+ }
+ else
+ mpSubProgress = 0;
+}
+
+void XclExpProgressBar::ActivateFinalRowsSegment()
+{
+ if( !mpSubRowFinal && (mnRowCount > 0) )
+ {
+ mpSubRowFinal = &mxProgress->GetSegmentProgressBar( mnSegRowFinal );
+ mpSubRowFinal->AddSegment( mnRowCount );
+ }
+ mpSubProgress = mpSubRowFinal;
+ if( mpSubProgress )
+ mpSubProgress->Activate();
+}
+
+void XclExpProgressBar::Progress()
+{
+ if( mpSubProgress && !mpSubProgress->IsFull() )
+ mpSubProgress->Progress();
+}
+
+// Calc->Excel cell address/range conversion ==================================
+
+namespace {
+
+/** Fills the passed Excel address with the passed Calc cell coordinates without checking any limits. */
+inline void lclFillAddress( XclAddress& rXclPos, SCCOL nScCol, SCROW nScRow )
+{
+ rXclPos.mnCol = static_cast< sal_uInt16 >( nScCol );
+ rXclPos.mnRow = static_cast< sal_uInt32 >( nScRow );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpAddressConverter::XclExpAddressConverter( const XclExpRoot& rRoot ) :
+ XclAddressConverterBase( rRoot.GetTracer(), rRoot.GetXclMaxPos() )
+{
+}
+
+// cell address ---------------------------------------------------------------
+
+bool XclExpAddressConverter::CheckAddress( const ScAddress& rScPos, bool bWarn )
+{
+ // ScAddress::operator<=() doesn't do what we want here
+ bool bValidCol = (0 <= rScPos.Col()) && (rScPos.Col() <= maMaxPos.Col());
+ bool bValidRow = (0 <= rScPos.Row()) && (rScPos.Row() <= maMaxPos.Row());
+ bool bValidTab = (0 <= rScPos.Tab()) && (rScPos.Tab() <= maMaxPos.Tab());
+
+ bool bValid = bValidCol && bValidRow && bValidTab;
+ if( !bValid && bWarn )
+ {
+ mbColTrunc |= !bValidCol;
+ mbRowTrunc |= !bValidRow;
+ mbTabTrunc |= (rScPos.Tab() > maMaxPos.Tab()); // do not warn for deleted refs
+ mrTracer.TraceInvalidAddress( rScPos, maMaxPos );
+ }
+ return bValid;
+}
+
+bool XclExpAddressConverter::ConvertAddress( XclAddress& rXclPos,
+ const ScAddress& rScPos, bool bWarn )
+{
+ bool bValid = CheckAddress( rScPos, bWarn );
+ if( bValid )
+ lclFillAddress( rXclPos, rScPos.Col(), rScPos.Row() );
+ return bValid;
+}
+
+XclAddress XclExpAddressConverter::CreateValidAddress( const ScAddress& rScPos, bool bWarn )
+{
+ XclAddress aXclPos( ScAddress::UNINITIALIZED );
+ if( !ConvertAddress( aXclPos, rScPos, bWarn ) )
+ lclFillAddress( aXclPos, ::std::min( rScPos.Col(), maMaxPos.Col() ), ::std::min( rScPos.Row(), maMaxPos.Row() ) );
+ return aXclPos;
+}
+
+// cell range -----------------------------------------------------------------
+
+bool XclExpAddressConverter::CheckRange( const ScRange& rScRange, bool bWarn )
+{
+ return CheckAddress( rScRange.aStart, bWarn ) && CheckAddress( rScRange.aEnd, bWarn );
+}
+
+bool XclExpAddressConverter::ValidateRange( ScRange& rScRange, bool bWarn )
+{
+ rScRange.Justify();
+
+ // check start position
+ bool bValidStart = CheckAddress( rScRange.aStart, bWarn );
+ if( bValidStart )
+ {
+ // check & correct end position
+ ScAddress& rScEnd = rScRange.aEnd;
+ if( !CheckAddress( rScEnd, bWarn ) )
+ {
+ rScEnd.SetCol( ::std::min( rScEnd.Col(), maMaxPos.Col() ) );
+ rScEnd.SetRow( ::std::min( rScEnd.Row(), maMaxPos.Row() ) );
+ rScEnd.SetTab( ::std::min( rScEnd.Tab(), maMaxPos.Tab() ) );
+ }
+ }
+
+ return bValidStart;
+}
+
+bool XclExpAddressConverter::ConvertRange( XclRange& rXclRange,
+ const ScRange& rScRange, bool bWarn )
+{
+ // check start position
+ bool bValidStart = CheckAddress( rScRange.aStart, bWarn );
+ if( bValidStart )
+ {
+ lclFillAddress( rXclRange.maFirst, rScRange.aStart.Col(), rScRange.aStart.Row() );
+
+ // check & correct end position
+ SCCOL nScCol2 = rScRange.aEnd.Col();
+ SCROW nScRow2 = rScRange.aEnd.Row();
+ if( !CheckAddress( rScRange.aEnd, bWarn ) )
+ {
+ nScCol2 = ::std::min( nScCol2, maMaxPos.Col() );
+ nScRow2 = ::std::min( nScRow2, maMaxPos.Row() );
+ }
+ lclFillAddress( rXclRange.maLast, nScCol2, nScRow2 );
+ }
+ return bValidStart;
+}
+
+// cell range list ------------------------------------------------------------
+
+void XclExpAddressConverter::ValidateRangeList( ScRangeList& rScRanges, bool bWarn )
+{
+ for ( size_t nRange = rScRanges.size(); nRange > 0; )
+ {
+ ScRange* pScRange = rScRanges[ --nRange ];
+ if( !CheckRange( *pScRange, bWarn ) )
+ delete rScRanges.Remove(nRange);
+ }
+}
+
+void XclExpAddressConverter::ConvertRangeList( XclRangeList& rXclRanges,
+ const ScRangeList& rScRanges, bool bWarn )
+{
+ rXclRanges.clear();
+ for( size_t nPos = 0, nCount = rScRanges.size(); nPos < nCount; ++nPos )
+ {
+ if( const ScRange* pScRange = rScRanges[ nPos ] )
+ {
+ XclRange aXclRange( ScAddress::UNINITIALIZED );
+ if( ConvertRange( aXclRange, *pScRange, bWarn ) )
+ rXclRanges.push_back( aXclRange );
+ }
+ }
+}
+
+// EditEngine->String conversion ==============================================
+
+namespace {
+
+String lclGetUrlRepresentation( const SvxURLField& rUrlField )
+{
+ String aRepr( rUrlField.GetRepresentation() );
+ // no representation -> use URL
+ return aRepr.Len() ? aRepr : rUrlField.GetURL();
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpHyperlinkHelper::XclExpHyperlinkHelper( const XclExpRoot& rRoot, const ScAddress& rScPos ) :
+ XclExpRoot( rRoot ),
+ maScPos( rScPos ),
+ mbMultipleUrls( false )
+{
+}
+
+XclExpHyperlinkHelper::~XclExpHyperlinkHelper()
+{
+}
+
+String XclExpHyperlinkHelper::ProcessUrlField( const SvxURLField& rUrlField )
+{
+ String aUrlRepr;
+
+ if( GetBiff() == EXC_BIFF8 ) // no HLINK records in BIFF2-BIFF7
+ {
+ // there was/is already a HLINK record
+ mbMultipleUrls = mxLinkRec;
+
+ mxLinkRec.reset( new XclExpHyperlink( GetRoot(), rUrlField, maScPos ) );
+
+ if( const String* pRepr = mxLinkRec->GetRepr() )
+ aUrlRepr = *pRepr;
+
+ // add URL to note text
+ ScGlobal::AddToken( maUrlList, rUrlField.GetURL(), '\n' );
+ }
+
+ // no hyperlink representation from Excel HLINK record -> use it from text field
+ return aUrlRepr.Len() ? aUrlRepr : lclGetUrlRepresentation( rUrlField );
+}
+
+bool XclExpHyperlinkHelper::HasLinkRecord() const
+{
+ return !mbMultipleUrls && mxLinkRec;
+}
+
+XclExpHyperlinkHelper::XclExpHyperlinkRef XclExpHyperlinkHelper::GetLinkRecord()
+{
+ if( HasLinkRecord() )
+ return mxLinkRec;
+ return XclExpHyperlinkRef();
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+/** Creates a new formatted string from the passed unformatted string.
+
+ Creates a Unicode string or a byte string, depending on the current BIFF
+ version contained in the passed XclExpRoot object. May create a formatted
+ string object, if the text contains different script types.
+
+ @param pCellAttr
+ Cell attributes used for font formatting.
+ @param nFlags
+ Modifiers for string export.
+ @param nMaxLen
+ The maximum number of characters to store in this string.
+ @return
+ The new string object.
+ */
+XclExpStringRef lclCreateFormattedString(
+ const XclExpRoot& rRoot, const String& rText, const ScPatternAttr* pCellAttr,
+ XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ /* Create an empty Excel string object with correctly initialized BIFF mode,
+ because this function only uses Append() functions that require this. */
+ XclExpStringRef xString = XclExpStringHelper::CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
+
+ // script type handling
+ Reference< XBreakIterator > xBreakIt = rRoot.GetDoc().GetBreakIterator();
+ namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
+ // #i63255# get script type for leading weak characters
+ sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( rRoot, rText );
+
+ // font buffer and cell item set
+ XclExpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
+ const SfxItemSet& rItemSet = pCellAttr ? pCellAttr->GetItemSet() : rRoot.GetDoc().GetDefPattern()->GetItemSet();
+
+ // process all script portions
+ OUString aOUText( rText );
+ sal_Int32 nPortionPos = 0;
+ sal_Int32 nTextLen = aOUText.getLength();
+ while( nPortionPos < nTextLen )
+ {
+ // get script type and end position of next script portion
+ sal_Int16 nScript = xBreakIt->getScriptType( aOUText, nPortionPos );
+ sal_Int32 nPortionEnd = xBreakIt->endOfScript( aOUText, nPortionPos, nScript );
+
+ // reuse previous script for following weak portions
+ if( nScript == ApiScriptType::WEAK )
+ nScript = nLastScript;
+
+ // construct font from current text portion
+ SvxFont aFont( XclExpFontHelper::GetFontFromItemSet( rRoot, rItemSet, nScript ) );
+
+ // Excel start position of this portion
+ sal_uInt16 nXclPortionStart = xString->Len();
+ // add portion text to Excel string
+ XclExpStringHelper::AppendString( *xString, rRoot, aOUText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
+ if( nXclPortionStart < xString->Len() )
+ {
+ // insert font into buffer
+ sal_uInt16 nFontIdx = rFontBuffer.Insert( aFont, EXC_COLOR_CELLTEXT );
+ // insert font index into format run vector
+ xString->AppendFormat( nXclPortionStart, nFontIdx );
+ }
+
+ // go to next script portion
+ nLastScript = nScript;
+ nPortionPos = nPortionEnd;
+ }
+
+ return xString;
+}
+
+/** Creates a new formatted string from an edit engine text object.
+
+ Creates a Unicode string or a byte string, depending on the current BIFF
+ version contained in the passed XclExpRoot object.
+
+ @param rEE
+ The edit engine in use. The text object must already be set.
+ @param nFlags
+ Modifiers for string export.
+ @param nMaxLen
+ The maximum number of characters to store in this string.
+ @return
+ The new string object.
+ */
+XclExpStringRef lclCreateFormattedString(
+ const XclExpRoot& rRoot, EditEngine& rEE, XclExpHyperlinkHelper* pLinkHelper,
+ XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ /* Create an empty Excel string object with correctly initialized BIFF mode,
+ because this function only uses Append() functions that require this. */
+ XclExpStringRef xString = XclExpStringHelper::CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
+
+ // font buffer and helper item set for edit engine -> Calc item conversion
+ XclExpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
+ SfxItemSet aItemSet( *rRoot.GetDoc().GetPool(), ATTR_PATTERN_START, ATTR_PATTERN_END );
+
+ // script type handling
+ Reference< XBreakIterator > xBreakIt = rRoot.GetDoc().GetBreakIterator();
+ namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
+ // #i63255# get script type for leading weak characters
+ sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( rRoot, rEE.GetText() );
+
+ // process all paragraphs
+ sal_uInt16 nParaCount = rEE.GetParagraphCount();
+ for( sal_uInt16 nPara = 0; nPara < nParaCount; ++nPara )
+ {
+ ESelection aSel( nPara, 0 );
+ String aParaText( rEE.GetText( nPara ) );
+
+ SvUShorts aPosList;
+ rEE.GetPortions( nPara, aPosList );
+
+ // process all portions in the paragraph
+ sal_uInt16 nPosCount = aPosList.Count();
+ for( sal_uInt16 nPos = 0; nPos < nPosCount; ++nPos )
+ {
+ aSel.nEndPos = static_cast< xub_StrLen >( aPosList.GetObject( nPos ) );
+ String aXclPortionText( aParaText, aSel.nStartPos, aSel.nEndPos - aSel.nStartPos );
+
+ aItemSet.ClearItem();
+ SfxItemSet aEditSet( rEE.GetAttribs( aSel ) );
+ ScPatternAttr::GetFromEditItemSet( aItemSet, aEditSet );
+
+ // get escapement value
+ short nEsc = GETITEM( aEditSet, SvxEscapementItem, EE_CHAR_ESCAPEMENT ).GetEsc();
+
+ // process text fields
+ bool bIsHyperlink = false;
+ if( aSel.nStartPos + 1 == aSel.nEndPos )
+ {
+ // test if the character is a text field
+ const SfxPoolItem* pItem;
+ if( aEditSet.GetItemState( EE_FEATURE_FIELD, false, &pItem ) == SFX_ITEM_SET )
+ {
+ const SvxFieldData* pField = static_cast< const SvxFieldItem* >( pItem )->GetField();
+ if( const SvxURLField* pUrlField = PTR_CAST( SvxURLField, pField ) )
+ {
+ // convert URL field to string representation
+ aXclPortionText = pLinkHelper ?
+ pLinkHelper->ProcessUrlField( *pUrlField ) :
+ lclGetUrlRepresentation( *pUrlField );
+ bIsHyperlink = true;
+ }
+ else
+ {
+ DBG_ERRORFILE( "lclCreateFormattedString - unknown text field" );
+ aXclPortionText.Erase();
+ }
+ }
+ }
+
+ // Excel start position of this portion
+ sal_uInt16 nXclPortionStart = xString->Len();
+ // add portion text to Excel string
+ XclExpStringHelper::AppendString( *xString, rRoot, aXclPortionText );
+ if( (nXclPortionStart < xString->Len()) || (aParaText.Len() == 0) )
+ {
+ /* Construct font from current edit engine text portion. Edit engine
+ creates different portions for different script types, no need to loop. */
+ sal_Int16 nScript = xBreakIt->getScriptType( aXclPortionText, 0 );
+ if( nScript == ApiScriptType::WEAK )
+ nScript = nLastScript;
+ SvxFont aFont( XclExpFontHelper::GetFontFromItemSet( rRoot, aItemSet, nScript ) );
+ nLastScript = nScript;
+
+ // add escapement
+ aFont.SetEscapement( nEsc );
+ // modify automatic font color for hyperlinks
+ if( bIsHyperlink && (GETITEM( aItemSet, SvxColorItem, ATTR_FONT_COLOR ).GetValue().GetColor() == COL_AUTO) )
+ aFont.SetColor( Color( COL_LIGHTBLUE ) );
+
+ // insert font into buffer
+ sal_uInt16 nFontIdx = rFontBuffer.Insert( aFont, EXC_COLOR_CELLTEXT );
+ // insert font index into format run vector
+ xString->AppendFormat( nXclPortionStart, nFontIdx );
+ }
+
+ aSel.nStartPos = aSel.nEndPos;
+ }
+
+ // add trailing newline (important for correct character index calculation)
+ if( nPara + 1 < nParaCount )
+ XclExpStringHelper::AppendChar( *xString, rRoot, '\n' );
+ }
+
+ return xString;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpStringRef XclExpStringHelper::CreateString(
+ const XclExpRoot& rRoot, const String& rString, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ XclExpStringRef xString( new XclExpString );
+ if( rRoot.GetBiff() == EXC_BIFF8 )
+ xString->Assign( rString, nFlags, nMaxLen );
+ else
+ xString->AssignByte( rString, rRoot.GetTextEncoding(), nFlags, nMaxLen );
+ return xString;
+}
+
+XclExpStringRef XclExpStringHelper::CreateString(
+ const XclExpRoot& rRoot, sal_Unicode cChar, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ XclExpStringRef xString = CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
+ AppendChar( *xString, rRoot, cChar );
+ return xString;
+}
+
+void XclExpStringHelper::AppendString( XclExpString& rXclString, const XclExpRoot& rRoot, const String& rString )
+{
+ if( rRoot.GetBiff() == EXC_BIFF8 )
+ rXclString.Append( rString );
+ else
+ rXclString.AppendByte( rString, rRoot.GetTextEncoding() );
+}
+
+void XclExpStringHelper::AppendChar( XclExpString& rXclString, const XclExpRoot& rRoot, sal_Unicode cChar )
+{
+ if( rRoot.GetBiff() == EXC_BIFF8 )
+ rXclString.Append( cChar );
+ else
+ rXclString.AppendByte( cChar, rRoot.GetTextEncoding() );
+}
+
+XclExpStringRef XclExpStringHelper::CreateCellString(
+ const XclExpRoot& rRoot, const ScStringCell& rStringCell, const ScPatternAttr* pCellAttr,
+ XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ String aCellText;
+ rStringCell.GetString( aCellText );
+ return lclCreateFormattedString( rRoot, aCellText, pCellAttr, nFlags, nMaxLen );
+}
+
+XclExpStringRef XclExpStringHelper::CreateCellString(
+ const XclExpRoot& rRoot, const ScEditCell& rEditCell, const ScPatternAttr* pCellAttr,
+ XclExpHyperlinkHelper& rLinkHelper, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ XclExpStringRef xString;
+ if( const EditTextObject* pEditObj = rEditCell.GetData() )
+ {
+ // formatted cell
+ ScEditEngineDefaulter& rEE = rRoot.GetEditEngine();
+ sal_Bool bOldUpdateMode = rEE.GetUpdateMode();
+ rEE.SetUpdateMode( sal_True );
+ // default items
+ const SfxItemSet& rItemSet = pCellAttr ? pCellAttr->GetItemSet() : rRoot.GetDoc().GetDefPattern()->GetItemSet();
+ SfxItemSet* pEEItemSet = new SfxItemSet( rEE.GetEmptyItemSet() );
+ ScPatternAttr::FillToEditItemSet( *pEEItemSet, rItemSet );
+ rEE.SetDefaults( pEEItemSet ); // edit engine takes ownership
+ // create the string
+ rEE.SetText( *pEditObj );
+ xString = lclCreateFormattedString( rRoot, rEE, &rLinkHelper, nFlags, nMaxLen );
+ rEE.SetUpdateMode( bOldUpdateMode );
+ }
+ else
+ {
+ // unformatted cell
+ String aCellText;
+ rEditCell.GetString( aCellText );
+ xString = lclCreateFormattedString( rRoot, aCellText, pCellAttr, nFlags, nMaxLen );
+ }
+ return xString;
+}
+
+XclExpStringRef XclExpStringHelper::CreateString(
+ const XclExpRoot& rRoot, const SdrTextObj& rTextObj,
+ XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ XclExpStringRef xString;
+ if( const OutlinerParaObject* pParaObj = rTextObj.GetOutlinerParaObject() )
+ {
+ EditEngine& rEE = rRoot.GetDrawEditEngine();
+ sal_Bool bOldUpdateMode = rEE.GetUpdateMode();
+ rEE.SetUpdateMode( sal_True );
+ // create the string
+ rEE.SetText( pParaObj->GetTextObject() );
+ xString = lclCreateFormattedString( rRoot, rEE, 0, nFlags, nMaxLen );
+ rEE.SetUpdateMode( bOldUpdateMode );
+ // limit formats - TODO: BIFF dependent
+ if( !xString->IsEmpty() )
+ {
+ xString->LimitFormatCount( EXC_MAXRECSIZE_BIFF8 / 8 - 1 );
+ xString->AppendTrailingFormat( EXC_FONT_APP );
+ }
+ }
+ else
+ {
+ DBG_ERRORFILE( "XclExpStringHelper::CreateString - textbox without para object" );
+ // create BIFF dependent empty Excel string
+ xString = CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
+ }
+ return xString;
+}
+
+XclExpStringRef XclExpStringHelper::CreateString(
+ const XclExpRoot& rRoot, const EditTextObject& rEditObj,
+ XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ XclExpStringRef xString;
+ EditEngine& rEE = rRoot.GetDrawEditEngine();
+ sal_Bool bOldUpdateMode = rEE.GetUpdateMode();
+ rEE.SetUpdateMode( sal_True );
+ rEE.SetText( rEditObj );
+ xString = lclCreateFormattedString( rRoot, rEE, 0, nFlags, nMaxLen );
+ rEE.SetUpdateMode( bOldUpdateMode );
+ // limit formats - TODO: BIFF dependent
+ if( !xString->IsEmpty() )
+ {
+ xString->LimitFormatCount( EXC_MAXRECSIZE_BIFF8 / 8 - 1 );
+ xString->AppendTrailingFormat( EXC_FONT_APP );
+ }
+ return xString;
+}
+
+sal_Int16 XclExpStringHelper::GetLeadingScriptType( const XclExpRoot& rRoot, const String& rString )
+{
+ namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
+ Reference< XBreakIterator > xBreakIt = rRoot.GetDoc().GetBreakIterator();
+ OUString aOUString( rString );
+ sal_Int32 nStrPos = 0;
+ sal_Int32 nStrLen = aOUString.getLength();
+ sal_Int16 nScript = ApiScriptType::WEAK;
+ while( (nStrPos < nStrLen) && (nScript == ApiScriptType::WEAK) )
+ {
+ nScript = xBreakIt->getScriptType( aOUString, nStrPos );
+ nStrPos = xBreakIt->endOfScript( aOUString, nStrPos, nScript );
+ }
+ return (nScript == ApiScriptType::WEAK) ? rRoot.GetDefApiScript() : nScript;
+}
+
+// Header/footer conversion ===================================================
+
+XclExpHFConverter::XclExpHFConverter( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mrEE( rRoot.GetHFEditEngine() ),
+ mnTotalHeight( 0 )
+{
+}
+
+void XclExpHFConverter::GenerateString(
+ const EditTextObject* pLeftObj,
+ const EditTextObject* pCenterObj,
+ const EditTextObject* pRightObj )
+{
+ maHFString.Erase();
+ mnTotalHeight = 0;
+ AppendPortion( pLeftObj, 'L' );
+ AppendPortion( pCenterObj, 'C' );
+ AppendPortion( pRightObj, 'R' );
+}
+
+void XclExpHFConverter::AppendPortion( const EditTextObject* pTextObj, sal_Unicode cPortionCode )
+{
+ if( !pTextObj ) return;
+
+ String aText;
+ sal_Int32 nHeight = 0;
+ SfxItemSet aItemSet( *GetDoc().GetPool(), ATTR_PATTERN_START, ATTR_PATTERN_END );
+
+ // edit engine
+ sal_Bool bOldUpdateMode = mrEE.GetUpdateMode();
+ mrEE.SetUpdateMode( sal_True );
+ mrEE.SetText( *pTextObj );
+
+ // font information
+ XclFontData aFontData, aNewData;
+ if( const XclExpFont* pFirstFont = GetFontBuffer().GetFont( EXC_FONT_APP ) )
+ {
+ aFontData = pFirstFont->GetFontData();
+ (aFontData.mnHeight += 10) /= 20; // using pt here, not twips
+ }
+ else
+ aFontData.mnHeight = 10;
+
+ const FontList* pFontList = 0;
+ if( SfxObjectShell* pDocShell = GetDocShell() )
+ {
+ if( const SvxFontListItem* pInfoItem = static_cast< const SvxFontListItem* >(
+ pDocShell->GetItem( SID_ATTR_CHAR_FONTLIST ) ) )
+ pFontList = pInfoItem->GetFontList();
+ }
+
+ sal_uInt16 nParaCount = mrEE.GetParagraphCount();
+ for( sal_uInt16 nPara = 0; nPara < nParaCount; ++nPara )
+ {
+ ESelection aSel( nPara, 0 );
+ String aParaText;
+ sal_Int32 nParaHeight = 0;
+ SvUShorts aPosList;
+ mrEE.GetPortions( nPara, aPosList );
+
+ sal_uInt16 nPosCount = aPosList.Count();
+ for( sal_uInt16 nPos = 0; nPos < nPosCount; ++nPos )
+ {
+ aSel.nEndPos = static_cast< xub_StrLen >( aPosList.GetObject( nPos ) );
+ if( aSel.nStartPos < aSel.nEndPos )
+ {
+
+// --- font attributes ---
+
+ Font aFont;
+ aItemSet.ClearItem();
+ SfxItemSet aEditSet( mrEE.GetAttribs( aSel ) );
+ ScPatternAttr::GetFromEditItemSet( aItemSet, aEditSet );
+ ScPatternAttr::GetFont( aFont, aItemSet, SC_AUTOCOL_RAW );
+
+ // font name and style
+ aNewData.maName = XclTools::GetXclFontName( aFont.GetName() );
+ aNewData.mnWeight = (aFont.GetWeight() > WEIGHT_NORMAL) ? EXC_FONTWGHT_BOLD : EXC_FONTWGHT_NORMAL;
+ aNewData.mbItalic = (aFont.GetItalic() != ITALIC_NONE);
+ bool bNewFont = !(aFontData.maName == aNewData.maName);
+ bool bNewStyle = (aFontData.mnWeight != aNewData.mnWeight) ||
+ (aFontData.mbItalic != aNewData.mbItalic);
+ if( bNewFont || (bNewStyle && pFontList) )
+ {
+ aParaText.AppendAscii( "&\"" ).Append( aNewData.maName );
+ if( pFontList )
+ {
+ FontInfo aFontInfo( pFontList->Get(
+ aNewData.maName,
+ (aNewData.mnWeight > EXC_FONTWGHT_NORMAL) ? WEIGHT_BOLD : WEIGHT_NORMAL,
+ aNewData.mbItalic ? ITALIC_NORMAL : ITALIC_NONE ) );
+ aNewData.maStyle = pFontList->GetStyleName( aFontInfo );
+ if( aNewData.maStyle.Len() )
+ aParaText.Append( ',' ).Append( aNewData.maStyle );
+ }
+ aParaText.Append( '"' );
+ }
+
+ // height
+ // is calculated wrong in ScPatternAttr::GetFromEditItemSet, because already in twips and not 100thmm
+ // -> get it directly from edit engine item set
+ aNewData.mnHeight = ulimit_cast< sal_uInt16 >( GETITEM( aEditSet, SvxFontHeightItem, EE_CHAR_FONTHEIGHT ).GetHeight() );
+ (aNewData.mnHeight += 10) /= 20;
+ bool bFontHtChanged = (aFontData.mnHeight != aNewData.mnHeight);
+ if( bFontHtChanged )
+ aParaText.Append( '&' ).Append( String::CreateFromInt32( aNewData.mnHeight ) );
+ // update maximum paragraph height, convert to twips
+ nParaHeight = ::std::max< sal_Int32 >( nParaHeight, aNewData.mnHeight * 20 );
+
+ // underline
+ aNewData.mnUnderline = EXC_FONTUNDERL_NONE;
+ switch( aFont.GetUnderline() )
+ {
+ case UNDERLINE_NONE: aNewData.mnUnderline = EXC_FONTUNDERL_NONE; break;
+ case UNDERLINE_SINGLE: aNewData.mnUnderline = EXC_FONTUNDERL_SINGLE; break;
+ case UNDERLINE_DOUBLE: aNewData.mnUnderline = EXC_FONTUNDERL_DOUBLE; break;
+ default: aNewData.mnUnderline = EXC_FONTUNDERL_SINGLE;
+ }
+ if( aFontData.mnUnderline != aNewData.mnUnderline )
+ {
+ sal_uInt8 nTmpUnderl = (aNewData.mnUnderline == EXC_FONTUNDERL_NONE) ?
+ aFontData.mnUnderline : aNewData.mnUnderline;
+ aParaText.AppendAscii( (nTmpUnderl == EXC_FONTUNDERL_SINGLE) ? "&U" : "&E" );
+ }
+
+ // strikeout
+ aNewData.mbStrikeout = (aFont.GetStrikeout() != STRIKEOUT_NONE);
+ if( aFontData.mbStrikeout != aNewData.mbStrikeout )
+ aParaText.AppendAscii( "&S" );
+
+ // super/sub script
+ const SvxEscapementItem& rEscapeItem = GETITEM( aEditSet, SvxEscapementItem, EE_CHAR_ESCAPEMENT );
+ aNewData.SetScEscapement( rEscapeItem.GetEsc() );
+ if( aFontData.mnEscapem != aNewData.mnEscapem )
+ {
+ switch(aNewData.mnEscapem)
+ {
+ // close the previous super/sub script.
+ case EXC_FONTESC_NONE: aParaText.AppendAscii( (aFontData.mnEscapem == EXC_FONTESC_SUPER) ? "&X" : "&Y" ); break;
+ case EXC_FONTESC_SUPER: aParaText.AppendAscii( "&X" ); break;
+ case EXC_FONTESC_SUB: aParaText.AppendAscii( "&Y" ); break;
+ default: break;
+ }
+ }
+
+ aFontData = aNewData;
+
+// --- text content or text fields ---
+
+ const SfxPoolItem* pItem;
+ if( (aSel.nStartPos + 1 == aSel.nEndPos) && // fields are single characters
+ (aEditSet.GetItemState( EE_FEATURE_FIELD, false, &pItem ) == SFX_ITEM_SET) )
+ {
+ if( const SvxFieldData* pFieldData = static_cast< const SvxFieldItem* >( pItem )->GetField() )
+ {
+ if( pFieldData->ISA( SvxPageField ) )
+ aParaText.AppendAscii( "&P" );
+ else if( pFieldData->ISA( SvxPagesField ) )
+ aParaText.AppendAscii( "&N" );
+ else if( pFieldData->ISA( SvxDateField ) )
+ aParaText.AppendAscii( "&D" );
+ else if( pFieldData->ISA( SvxTimeField ) || pFieldData->ISA( SvxExtTimeField ) )
+ aParaText.AppendAscii( "&T" );
+ else if( pFieldData->ISA( SvxTableField ) )
+ aParaText.AppendAscii( "&A" );
+ else if( pFieldData->ISA( SvxFileField ) ) // title -> file name
+ aParaText.AppendAscii( "&F" );
+ else if( const SvxExtFileField* pFileField = PTR_CAST( SvxExtFileField, pFieldData ) )
+ {
+ switch( pFileField->GetFormat() )
+ {
+ case SVXFILEFORMAT_NAME_EXT:
+ case SVXFILEFORMAT_NAME:
+ aParaText.AppendAscii( "&F" );
+ break;
+ case SVXFILEFORMAT_PATH:
+ aParaText.AppendAscii( "&Z" );
+ break;
+ case SVXFILEFORMAT_FULLPATH:
+ aParaText.AppendAscii( "&Z&F" );
+ break;
+ default:
+ DBG_ERRORFILE( "XclExpHFConverter::AppendPortion - unknown file field" );
+ }
+ }
+ }
+ }
+ else
+ {
+ String aPortionText( mrEE.GetText( aSel ) );
+ aPortionText.SearchAndReplaceAll( String( '&' ), String( RTL_CONSTASCII_USTRINGPARAM( "&&" ) ) );
+ // #i17440# space between font height and numbers in text
+ if( bFontHtChanged && aParaText.Len() && aPortionText.Len() )
+ {
+ sal_Unicode cLast = aParaText.GetChar( aParaText.Len() - 1 );
+ sal_Unicode cFirst = aPortionText.GetChar( 0 );
+ if( ('0' <= cLast) && (cLast <= '9') && ('0' <= cFirst) && (cFirst <= '9') )
+ aParaText.Append( ' ' );
+ }
+ aParaText.Append( aPortionText );
+ }
+ }
+
+ aSel.nStartPos = aSel.nEndPos;
+ }
+
+ ScGlobal::AddToken( aText, aParaText, '\n' );
+ if( nParaHeight == 0 )
+ nParaHeight = aFontData.mnHeight * 20; // points -> twips
+ nHeight += nParaHeight;
+ }
+
+ mrEE.SetUpdateMode( bOldUpdateMode );
+
+ if( aText.Len() )
+ {
+ maHFString.Append( '&' ).Append( cPortionCode ).Append( aText );
+ mnTotalHeight = ::std::max( mnTotalHeight, nHeight );
+ }
+}
+
+// URL conversion =============================================================
+
+namespace {
+
+/** Converts the file URL passed in rUrl to a URL in DOS notation (local or UNC).
+ @param rUrl (in/out-param) In: URL to convert; Out: Converted URL in DOS notation.
+ @param rBasePath Base path for relative URLs.
+ @param bSaveRelUrl Converts to a relative URL, using rBasePath.
+ @return True = Conversion successful, rUrl contains converted file URL. */
+bool lclConvertToDos( String& rUrl, const String& rBasePath, bool bSaveRelUrl )
+{
+ String aDosUrl( INetURLObject( rUrl ).getFSysPath( INetURLObject::FSYS_DOS ) );
+ bool bRet = (aDosUrl.Len() > 0);
+ if( bRet && bSaveRelUrl )
+ {
+ // try to convert to relative path
+ String aDosBase( INetURLObject( rBasePath ).getFSysPath( INetURLObject::FSYS_DOS ) );
+ if( aDosBase.Len() )
+ {
+ xub_StrLen nPos;
+
+ // --- 1st step: delete equal subdirectories ---
+
+ // special handling for UNC
+ xub_StrLen nStartSearch = aDosBase.EqualsAscii( "\\\\", 0, 2 ) ? 2 : 0;
+ bool bEqualBase = false;
+ bool bLoop = true;
+ while( bLoop && ((nPos = aDosBase.Search( '\\', nStartSearch )) != STRING_NOTFOUND) )
+ {
+ bLoop = (sal_True == aDosBase.Equals( aDosUrl, 0, nPos + 1 ));
+ if( bLoop )
+ {
+ aDosBase.Erase( 0, nPos + 1 );
+ aDosUrl.Erase( 0, nPos + 1 );
+ nStartSearch = 0;
+ bEqualBase = true;
+ }
+ }
+
+ // --- 2nd step: add parent directory levels ---
+
+ if( bEqualBase )
+ {
+ while( (nPos = aDosBase.Search( '\\' )) != STRING_NOTFOUND )
+ {
+ aDosBase.Erase( 0, nPos + 1 );
+ aDosUrl.InsertAscii( "..\\", 0 );
+ }
+ }
+ }
+ rUrl = aDosUrl;
+ }
+ return bRet;
+}
+
+/** Encodes special parts of the URL, i.e. directory separators and volume names.
+ @param pTableName Pointer to a table name to be encoded in this URL, or 0. */
+void lclEncodeDosUrl( XclBiff eBiff, String& rUrl, const String* pTableName = 0 )
+{
+ if( rUrl.Len() )
+ {
+ String aOldUrl( rUrl );
+ rUrl = EXC_URLSTART_ENCODED;
+
+ if( (aOldUrl.Len() > 2) && aOldUrl.EqualsAscii( "\\\\", 0, 2 ) )
+ {
+ // UNC
+ rUrl.Append( EXC_URL_DOSDRIVE ).Append( '@' );
+ aOldUrl.Erase( 0, 2 );
+ }
+ else if( (aOldUrl.Len() > 2) && aOldUrl.EqualsAscii( ":\\", 1, 2 ) )
+ {
+ // drive letter
+ rUrl.Append( EXC_URL_DOSDRIVE ).Append( aOldUrl.GetChar( 0 ) );
+ aOldUrl.Erase( 0, 3 );
+ }
+
+ // directories
+ xub_StrLen nPos;
+ while( (nPos = aOldUrl.Search( '\\' )) != STRING_NOTFOUND )
+ {
+ if( aOldUrl.EqualsAscii( "..", 0, 2 ) )
+ rUrl.Append( EXC_URL_PARENTDIR ); // parent dir
+ else
+ rUrl.Append( aOldUrl.GetBuffer(), nPos ).Append( EXC_URL_SUBDIR );
+ aOldUrl.Erase( 0, nPos + 1 );
+ }
+
+ // file name
+ if( pTableName ) // enclose file name in brackets if table name follows
+ rUrl.Append( '[' ).Append( aOldUrl ).Append( ']' );
+ else
+ rUrl.Append( aOldUrl );
+ }
+ else // empty URL -> self reference
+ {
+ switch( eBiff )
+ {
+ case EXC_BIFF5:
+ rUrl = pTableName ? EXC_URLSTART_SELFENCODED : EXC_URLSTART_SELF;
+ break;
+ case EXC_BIFF8:
+ DBG_ASSERT( pTableName, "lclEncodeDosUrl - sheet name required for BIFF8" );
+ rUrl = EXC_URLSTART_SELF;
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+ }
+
+ // table name
+ if( pTableName )
+ rUrl.Append( *pTableName );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+String XclExpUrlHelper::EncodeUrl( const XclExpRoot& rRoot, const String& rAbsUrl, const String* pTableName )
+{
+ String aDosUrl( rAbsUrl );
+ if( !aDosUrl.Len() || lclConvertToDos( aDosUrl, rRoot.GetBasePath(), rRoot.IsRelUrl() ) )
+ lclEncodeDosUrl( rRoot.GetBiff(), aDosUrl, pTableName );
+ return aDosUrl;
+}
+
+String XclExpUrlHelper::EncodeDde( const String& rApplic, const String rTopic )
+{
+ String aDde( rApplic );
+ aDde.Append( EXC_DDE_DELIM ).Append( rTopic );
+ return aDde;
+}
+
+// Cached Value Lists =========================================================
+
+XclExpCachedMatrix::XclExpCachedMatrix( const ScMatrix& rMatrix )
+ : mrMatrix( rMatrix )
+{
+ mrMatrix.IncRef();
+}
+XclExpCachedMatrix::~XclExpCachedMatrix()
+{
+ mrMatrix.DecRef();
+}
+
+void XclExpCachedMatrix::GetDimensions( SCSIZE & nCols, SCSIZE & nRows ) const
+{
+ mrMatrix.GetDimensions( nCols, nRows );
+
+ DBG_ASSERT( nCols && nRows, "XclExpCachedMatrix::GetDimensions - empty matrix" );
+ DBG_ASSERT( nCols <= 256, "XclExpCachedMatrix::GetDimensions - too many columns" );
+}
+
+sal_Size XclExpCachedMatrix::GetSize() const
+{
+ SCSIZE nCols, nRows;
+
+ GetDimensions( nCols, nRows );
+
+ /* The returned size may be wrong if the matrix contains strings. The only
+ effect is that the export stream has to update a wrong record size which is
+ faster than to iterate through all cached values and calculate their sizes. */
+ return 3 + 9 * (nCols * nRows);
+}
+
+void XclExpCachedMatrix::Save( XclExpStream& rStrm ) const
+{
+ SCSIZE nCols, nRows;
+
+ GetDimensions( nCols, nRows );
+
+ if( rStrm.GetRoot().GetBiff() <= EXC_BIFF5 )
+ // in BIFF2-BIFF7: 256 columns represented by 0 columns
+ rStrm << static_cast< sal_uInt8 >( nCols ) << static_cast< sal_uInt16 >( nRows );
+ else
+ // in BIFF8: columns and rows decreaed by 1
+ rStrm << static_cast< sal_uInt8 >( nCols - 1 ) << static_cast< sal_uInt16 >( nRows - 1 );
+
+ for( SCSIZE nRow = 0; nRow < nRows; ++nRow )
+ {
+ for( SCSIZE nCol = 0; nCol < nCols; ++nCol )
+ {
+ ScMatrixValue nMatVal = mrMatrix.Get( nCol, nRow );
+
+ if( SC_MATVAL_EMPTY == nMatVal.nType )
+ {
+ rStrm.SetSliceSize( 9 );
+ rStrm << EXC_CACHEDVAL_EMPTY;
+ rStrm.WriteZeroBytes( 8 );
+ }
+ else if( ScMatrix::IsNonValueType( nMatVal.nType ) )
+ {
+ XclExpString aStr( nMatVal.GetString(), EXC_STR_DEFAULT );
+ rStrm.SetSliceSize( 6 );
+ rStrm << EXC_CACHEDVAL_STRING << aStr;
+ }
+ else if( SC_MATVAL_BOOLEAN == nMatVal.nType )
+ {
+ sal_Int8 nBool = nMatVal.GetBoolean();
+ rStrm.SetSliceSize( 9 );
+ rStrm << EXC_CACHEDVAL_BOOL << nBool;
+ rStrm.WriteZeroBytes( 7 );
+ }
+ else if( sal_uInt16 nScError = nMatVal.GetError() )
+ {
+ sal_Int8 nError ( XclTools::GetXclErrorCode( nScError ) );
+ rStrm.SetSliceSize( 9 );
+ rStrm << EXC_CACHEDVAL_ERROR << nError;
+ rStrm.WriteZeroBytes( 7 );
+ }
+ else
+ {
+ rStrm.SetSliceSize( 9 );
+ rStrm << EXC_CACHEDVAL_DOUBLE << nMatVal.fVal;
+ }
+ }
+ }
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xelink.cxx b/sc/source/filter/excel/xelink.cxx
new file mode 100644
index 000000000000..43f8342bf815
--- /dev/null
+++ b/sc/source/filter/excel/xelink.cxx
@@ -0,0 +1,2367 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xelink.hxx"
+
+#include <algorithm>
+#include <unotools/collatorwrapper.hxx>
+#include <svl/zforlist.hxx>
+#include "document.hxx"
+#include "cell.hxx"
+#include "scextopt.hxx"
+#include "externalrefmgr.hxx"
+
+#include <vector>
+#include <memory>
+
+using ::std::auto_ptr;
+using ::std::find_if;
+using ::std::vector;
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+
+// ============================================================================
+// *** Helper classes ***
+// ============================================================================
+
+// External names =============================================================
+
+/** This is a base class for any external name (i.e. add-in names or DDE links).
+ @descr Derived classes implement creation and export of the external names. */
+class XclExpExtNameBase : public XclExpRecord, protected XclExpRoot
+{
+public:
+ /** @param nFlags The flags to export. */
+ explicit XclExpExtNameBase( const XclExpRoot& rRoot,
+ const String& rName, sal_uInt16 nFlags = 0 );
+ virtual ~XclExpExtNameBase();
+
+ /** Returns the name string of the external name. */
+ inline const String& GetName() const { return maName; }
+
+private:
+ /** Writes the start of the record that is equal in all EXTERNNAME records and calls WriteAddData(). */
+ virtual void WriteBody( XclExpStream& rStrm );
+ /** Called to write additional data following the common record contents.
+ @descr Derived classes should overwrite this function to write their data. */
+ virtual void WriteAddData( XclExpStream& rStrm );
+
+private:
+ String maName; /// Calc name (title) of the external name.
+ XclExpStringRef mxName; /// Excel name (title) of the external name.
+ sal_uInt16 mnFlags; /// Flags for record export.
+};
+
+// ----------------------------------------------------------------------------
+
+/** Represents an EXTERNNAME record for an add-in function name. */
+class XclExpExtNameAddIn : public XclExpExtNameBase
+{
+public:
+ explicit XclExpExtNameAddIn( const XclExpRoot& rRoot, const String& rName );
+
+private:
+ /** Writes additional record contents. */
+ virtual void WriteAddData( XclExpStream& rStrm );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Represents an EXTERNNAME record for a DDE link. */
+class XclExpExtNameDde : public XclExpExtNameBase
+{
+public:
+ explicit XclExpExtNameDde( const XclExpRoot& rRoot, const String& rName,
+ sal_uInt16 nFlags, const ScMatrix* pResults = 0 );
+
+private:
+ /** Writes additional record contents. */
+ virtual void WriteAddData( XclExpStream& rStrm );
+
+private:
+ typedef boost::shared_ptr< XclExpCachedMatrix > XclExpCachedMatRef;
+ XclExpCachedMatRef mxMatrix; /// Cached results of the DDE link.
+};
+
+// ----------------------------------------------------------------------------
+
+class XclExpSupbook;
+
+class XclExpExtName : public XclExpExtNameBase
+{
+public:
+ explicit XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook, const String& rName,
+ const ScExternalRefCache::TokenArrayRef pArray );
+
+private:
+ /** Writes additional record contents. */
+ virtual void WriteAddData( XclExpStream& rStrm );
+
+private:
+ const XclExpSupbook& mrSupbook;
+ auto_ptr<ScTokenArray> mpArray;
+};
+
+// List of external names =====================================================
+
+/** List of all external names of a sheet. */
+class XclExpExtNameBuffer : public XclExpRecordBase, protected XclExpRoot
+{
+public:
+ explicit XclExpExtNameBuffer( const XclExpRoot& rRoot );
+
+ /** Inserts an add-in function name
+ @return The 1-based (Excel-like) list index of the name. */
+ sal_uInt16 InsertAddIn( const String& rName );
+ /** InsertEuroTool */
+ sal_uInt16 InsertEuroTool( const String& rName );
+ /** Inserts a DDE link.
+ @return The 1-based (Excel-like) list index of the DDE link. */
+ sal_uInt16 InsertDde( const String& rApplic, const String& rTopic, const String& rItem );
+
+ sal_uInt16 InsertExtName( const XclExpSupbook& rSupbook, const String& rName, const ScExternalRefCache::TokenArrayRef pArray );
+
+ /** Writes the EXTERNNAME record list. */
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ typedef XclExpRecordList< XclExpExtNameBase > XclExpExtNameList;
+ typedef XclExpExtNameList::RecordRefType XclExpExtNameRef;
+
+private:
+ /** Returns the 1-based (Excel-like) list index of the external name or 0, if not found. */
+ sal_uInt16 GetIndex( const String& rName ) const;
+ /** Appends the passed newly crested external name.
+ @return The 1-based (Excel-like) list index of the appended name. */
+ sal_uInt16 AppendNew( XclExpExtNameBase* pExtName );
+
+private:
+ XclExpExtNameList maNameList; /// The list with all EXTERNNAME records.
+};
+
+// Cached external cells ======================================================
+
+/** Stores the contents of a consecutive row of external cells (record CRN). */
+class XclExpCrn : public XclExpRecord
+{
+public:
+ explicit XclExpCrn( SCCOL nScCol, SCROW nScRow, const Any& rValue );
+
+ /** Returns true, if the passed value could be appended to this record. */
+ bool InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue );
+
+private:
+ virtual void WriteBody( XclExpStream& rStrm );
+
+ void WriteBool( XclExpStream& rStrm, bool bValue );
+ void WriteDouble( XclExpStream& rStrm, double fValue );
+ void WriteString( XclExpStream& rStrm, const OUString& rValue );
+ void WriteError( XclExpStream& rStrm, sal_uInt8 nErrCode );
+ void WriteEmpty( XclExpStream& rStrm );
+
+private:
+ typedef ::std::vector< Any > CachedValues;
+
+ CachedValues maValues; /// All cached values.
+ SCCOL mnScCol; /// Column index of the first external cell.
+ SCROW mnScRow; /// Row index of the external cells.
+};
+
+// ----------------------------------------------------------------------------
+
+/** Represents the record XCT which is the header record of a CRN record list.
+ */
+class XclExpXct : public XclExpRecordBase, protected XclExpRoot
+{
+public:
+ explicit XclExpXct( const XclExpRoot& rRoot,
+ const String& rTabName, sal_uInt16 nSBTab,
+ ScExternalRefCache::TableTypeRef xCacheTable );
+
+ /** Returns the external sheet name. */
+ inline const XclExpString& GetTabName() const { return maTabName; }
+
+ /** Stores all cells in the given range in the CRN list. */
+ void StoreCellRange( const ScRange& rRange );
+
+ void StoreCell( const ScAddress& rCell, const ::formula::FormulaToken& rToken );
+ void StoreCellRange( const ScRange& rRange, const ::formula::FormulaToken& rToken );
+
+ /** Writes the XCT and all CRN records. */
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ ScExternalRefCache::TableTypeRef mxCacheTable;
+ ScMarkData maUsedCells; /// Contains addresses of all stored cells.
+ ScRange maBoundRange; /// Bounding box of maUsedCells.
+ XclExpString maTabName; /// Sheet name of the external sheet.
+ sal_uInt16 mnSBTab; /// Referred sheet index in SUPBOOK record.
+};
+
+// External documents (EXTERNSHEET/SUPBOOK), base class =======================
+
+/** Base class for records representing external sheets/documents.
+
+ In BIFF5/BIFF7, this record is the EXTERNSHEET record containing one sheet
+ of the own or an external document. In BIFF8, this record is the SUPBOOK
+ record representing the entire own or external document with all referenced
+ sheets.
+ */
+class XclExpExternSheetBase : public XclExpRecord, protected XclExpRoot
+{
+public:
+ explicit XclExpExternSheetBase( const XclExpRoot& rRoot,
+ sal_uInt16 nRecId, sal_uInt32 nRecSize = 0 );
+
+protected:
+ /** Creates and returns the list of EXTERNNAME records. */
+ XclExpExtNameBuffer& GetExtNameBuffer();
+ /** Creates and returns the list of EXTERNNAME records. */
+ void WriteExtNameBuffer( XclExpStream& rStrm );
+
+private:
+ typedef boost::shared_ptr< XclExpExtNameBuffer > XclExpExtNameBfrRef;
+ XclExpExtNameBfrRef mxExtNameBfr; /// List of EXTERNNAME records.
+};
+
+// External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
+
+/** Represents an EXTERNSHEET record containing the URL and sheet name of a sheet.
+ @descr This class is used up to BIFF7 only, writing a BIFF8 EXTERNSHEET
+ record is implemented directly in the link manager. */
+class XclExpExternSheet : public XclExpExternSheetBase
+{
+public:
+ /** Creates an EXTERNSHEET record containing a special code (i.e. own document or sheet). */
+ explicit XclExpExternSheet( const XclExpRoot& rRoot, sal_Unicode cCode );
+ /** Creates an EXTERNSHEET record referring to an internal sheet. */
+ explicit XclExpExternSheet( const XclExpRoot& rRoot, const String& rTabName );
+
+ /** Finds or inserts an EXTERNNAME record for add-ins.
+ @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
+ sal_uInt16 InsertAddIn( const String& rName );
+
+ /** Writes the EXTERNSHEET and all EXTERNNAME, XCT and CRN records. */
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ /** Initializes the record data with the passed encoded URL. */
+ void Init( const String& rEncUrl );
+ /** Writes the contents of the EXTERNSHEET record. */
+ virtual void WriteBody( XclExpStream& rStrm );
+
+private:
+ XclExpString maTabName; /// The name of the sheet.
+};
+
+// External documents (SUPBOOK, BIFF8) ========================================
+
+/** The SUPBOOK record contains data for an external document (URL, sheet names, external values). */
+class XclExpSupbook : public XclExpExternSheetBase
+{
+public:
+ /** Creates a SUPBOOK record for internal references. */
+ explicit XclExpSupbook( const XclExpRoot& rRoot, sal_uInt16 nXclTabCount );
+ /** Creates a SUPBOOK record for add-in functions. */
+ explicit XclExpSupbook( const XclExpRoot& rRoot );
+ /** EUROTOOL SUPBOOK */
+ explicit XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl, XclSupbookType );
+ /** Creates a SUPBOOK record for an external document. */
+ explicit XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl );
+ /** Creates a SUPBOOK record for a DDE link. */
+ explicit XclExpSupbook( const XclExpRoot& rRoot, const String& rApplic, const String& rTopic );
+
+ /** Returns true, if this SUPBOOK contains the passed URL of an external document. */
+ bool IsUrlLink( const String& rUrl ) const;
+ /** Returns true, if this SUPBOOK contains the passed DDE link. */
+ bool IsDdeLink( const String& rApplic, const String& rTopic ) const;
+ /** Fills the passed reference log entry with the URL and sheet names. */
+ void FillRefLogEntry( XclExpRefLogEntry& rRefLogEntry,
+ sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) const;
+
+ /** Stores all cells in the given range in the CRN list of the specified SUPBOOK sheet. */
+ void StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab );
+
+ void StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const ::formula::FormulaToken& rToken );
+ void StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const ::formula::FormulaToken& rToken );
+
+ sal_uInt16 GetTabIndex( const String& rTabName ) const;
+ sal_uInt16 GetTabCount() const;
+
+ /** Inserts a new sheet name into the SUPBOOK and returns the SUPBOOK internal sheet index. */
+ sal_uInt16 InsertTabName( const String& rTabName, ScExternalRefCache::TableTypeRef xCacheTable );
+ /** Finds or inserts an EXTERNNAME record for add-ins.
+ @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
+ sal_uInt16 InsertAddIn( const String& rName );
+ /** InsertEuroTool */
+ sal_uInt16 InsertEuroTool( const String& rName );
+ /** Finds or inserts an EXTERNNAME record for DDE links.
+ @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
+ sal_uInt16 InsertDde( const String& rItem );
+
+ sal_uInt16 InsertExtName( const String& rName, const ScExternalRefCache::TokenArrayRef pArray );
+
+ /** Writes the SUPBOOK and all EXTERNNAME, XCT and CRN records. */
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ /** Returns the sheet name inside of this SUPBOOK. */
+ const XclExpString* GetTabName( sal_uInt16 nSBTab ) const;
+
+ /** Writes the SUPBOOK record contents. */
+ virtual void WriteBody( XclExpStream& rStrm );
+
+private:
+ typedef XclExpRecordList< XclExpXct > XclExpXctList;
+ typedef XclExpXctList::RecordRefType XclExpXctRef;
+
+ XclExpXctList maXctList; /// List of XCT records (which contain CRN records).
+ String maUrl; /// URL of the external document or application name for DDE.
+ String maDdeTopic; /// Topic of an DDE link.
+ XclExpString maUrlEncoded; /// Document name encoded for Excel.
+ XclSupbookType meType; /// Type of this SUPBOOK record.
+ sal_uInt16 mnXclTabCount; /// Number of internal sheets.
+};
+
+// All SUPBOOKS in a document =================================================
+
+/** This struct contains a sheet index range for 3D references.
+ @descr This reference consists of an index to a SUPBOOK record and indexes
+ to SUPBOOK sheet names. */
+struct XclExpXti
+{
+ sal_uInt16 mnSupbook; /// Index to SUPBOOK record.
+ sal_uInt16 mnFirstSBTab; /// Index to the first sheet of the range in the SUPBOOK.
+ sal_uInt16 mnLastSBTab; /// Index to the last sheet of the range in the SUPBOOK.
+
+ inline explicit XclExpXti() : mnSupbook( 0 ), mnFirstSBTab( 0 ), mnLastSBTab( 0 ) {}
+ inline explicit XclExpXti( sal_uInt16 nSupbook, sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) :
+ mnSupbook( nSupbook ), mnFirstSBTab( nFirstSBTab ), mnLastSBTab( nLastSBTab ) {}
+
+ /** Writes this XTI structure (inside of the EXTERNSHEET record). */
+ inline void Save( XclExpStream& rStrm ) const
+ { rStrm << mnSupbook << mnFirstSBTab << mnLastSBTab; }
+};
+
+inline bool operator==( const XclExpXti& rLeft, const XclExpXti& rRight )
+{
+ return
+ (rLeft.mnSupbook == rRight.mnSupbook) &&
+ (rLeft.mnFirstSBTab == rRight.mnFirstSBTab) &&
+ (rLeft.mnLastSBTab == rRight.mnLastSBTab);
+}
+
+// ----------------------------------------------------------------------------
+
+/** Contains a list of all SUPBOOK records and index arrays of external sheets. */
+class XclExpSupbookBuffer : public XclExpRecordBase, protected XclExpRoot
+{
+public:
+ explicit XclExpSupbookBuffer( const XclExpRoot& rRoot );
+
+ /** Finds SUPBOOK index and SUPBOOK sheet range from given Excel sheet range.
+ @return An XTI structure containing SUPBOOK and sheet indexes. */
+ XclExpXti GetXti( sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab,
+ XclExpRefLogEntry* pRefLogEntry = 0 ) const;
+
+ /** Stores all cells in the given range in a CRN record list. */
+ void StoreCellRange( const ScRange& rRange );
+
+ void StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell );
+ void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange );
+
+ /** Finds or inserts an EXTERNNAME record for an add-in function name.
+ @param rnSupbook Returns the index of the SUPBOOK record which contains the add-in function name.
+ @param rnExtName Returns the 1-based EXTERNNAME record index. */
+ bool InsertAddIn(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
+ const String& rName );
+ /** InsertEuroTool */
+ bool InsertEuroTool(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
+ const String& rName );
+ /** Finds or inserts an EXTERNNAME record for DDE links.
+ @param rnSupbook Returns the index of the SUPBOOK record which contains the DDE link.
+ @param rnExtName Returns the 1-based EXTERNNAME record index. */
+ bool InsertDde(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
+ const String& rApplic, const String& rTopic, const String& rItem );
+
+ bool InsertExtName(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rUrl,
+ const String& rName, const ScExternalRefCache::TokenArrayRef pArray );
+
+ XclExpXti GetXti( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
+ XclExpRefLogEntry* pRefLogEntry = NULL );
+
+ /** Writes all SUPBOOK records with their sub records. */
+ virtual void Save( XclExpStream& rStrm );
+
+ struct XclExpSBIndex
+ {
+ sal_uInt16 mnSupbook; /// SUPBOOK index for an Excel sheet.
+ sal_uInt16 mnSBTab; /// Sheet name index in SUPBOOK for an Excel sheet.
+ inline void Set( sal_uInt16 nSupbook, sal_uInt16 nSBTab )
+ { mnSupbook = nSupbook; mnSBTab = nSBTab; }
+ };
+ typedef ::std::vector< XclExpSBIndex > XclExpSBIndexVec;
+
+private:
+ typedef XclExpRecordList< XclExpSupbook > XclExpSupbookList;
+ typedef XclExpSupbookList::RecordRefType XclExpSupbookRef;
+
+private:
+ /** Searches for the SUPBOOK record containing the passed document URL.
+ @param rxSupbook (out-param) Returns a reference to the SUPBOOK record, or 0.
+ @param rnIndex (out-param) Returns the list index, if the SUPBOOK exists.
+ @return True, if the SUPBOOK record exists (out-parameters are valid). */
+ bool GetSupbookUrl( XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex,
+ const String& rUrl ) const;
+ /** Searches for the SUPBOOK record containing the passed DDE link.
+ @param rxSupbook (out-param) Returns a reference to the SUPBOOK record, or 0.
+ @param rnIndex (out-param) Returns the list index, if the SUPBOOK exists.
+ @return True, if the SUPBOOK record exists (out-parameters are valid). */
+ bool GetSupbookDde( XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex,
+ const String& rApplic, const String& rTopic ) const;
+
+ /** Appends a new SUPBOOK to the list.
+ @return The list index of the SUPBOOK record. */
+ sal_uInt16 Append( XclExpSupbookRef xSupbook );
+
+private:
+ XclExpSupbookList maSupbookList; /// List of all SUPBOOK records.
+ XclExpSBIndexVec maSBIndexVec; /// SUPBOOK and sheet name index for each Excel sheet.
+ sal_uInt16 mnOwnDocSB; /// Index to SUPBOOK for own document.
+ sal_uInt16 mnAddInSB; /// Index to add-in SUPBOOK.
+};
+
+// Export link manager ========================================================
+
+/** Abstract base class for implementation classes of the link manager. */
+class XclExpLinkManagerImpl : protected XclExpRoot
+{
+public:
+ /** Derived classes search for an EXTSHEET structure for the given Calc sheet range. */
+ virtual void FindExtSheet( sal_uInt16& rnExtSheet,
+ sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab,
+ XclExpRefLogEntry* pRefLogEntry ) = 0;
+ /** Derived classes search for a special EXTERNSHEET index for the own document. */
+ virtual sal_uInt16 FindExtSheet( sal_Unicode cCode ) = 0;
+
+ virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
+ XclExpRefLogEntry* pRefLogEntry ) = 0;
+
+ /** Derived classes store all cells in the given range in a CRN record list. */
+ virtual void StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 ) = 0;
+
+ virtual void StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef ) = 0;
+ virtual void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 ) = 0;
+
+ /** Derived classes find or insert an EXTERNNAME record for an add-in function name. */
+ virtual bool InsertAddIn(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName ) = 0;
+ /** InsertEuroTool */
+ virtual bool InsertEuroTool(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName ) = 0;
+
+ /** Derived classes find or insert an EXTERNNAME record for DDE links. */
+ virtual bool InsertDde(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rApplic, const String& rTopic, const String& rItem ) = 0;
+
+ virtual bool InsertExtName(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl,
+ const String& rName, const ScExternalRefCache::TokenArrayRef pArray ) = 0;
+
+ /** Derived classes write the entire link table to the passed stream. */
+ virtual void Save( XclExpStream& rStrm ) = 0;
+
+protected:
+ explicit XclExpLinkManagerImpl( const XclExpRoot& rRoot );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Implementation of the link manager for BIFF5/BIFF7. */
+class XclExpLinkManagerImpl5 : public XclExpLinkManagerImpl
+{
+public:
+ explicit XclExpLinkManagerImpl5( const XclExpRoot& rRoot );
+
+ virtual void FindExtSheet( sal_uInt16& rnExtSheet,
+ sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab,
+ XclExpRefLogEntry* pRefLogEntry );
+ virtual sal_uInt16 FindExtSheet( sal_Unicode cCode );
+
+ virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
+ XclExpRefLogEntry* pRefLogEntry );
+
+ virtual void StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
+
+ virtual void StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef );
+ virtual void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
+
+ virtual bool InsertAddIn(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName );
+
+ /** InsertEuroTool */
+ virtual bool InsertEuroTool(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName );
+
+ virtual bool InsertDde(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rApplic, const String& rTopic, const String& rItem );
+
+ virtual bool InsertExtName(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl,
+ const String& rName, const ScExternalRefCache::TokenArrayRef pArray );
+
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ typedef XclExpRecordList< XclExpExternSheet > XclExpExtSheetList;
+ typedef XclExpExtSheetList::RecordRefType XclExpExtSheetRef;
+ typedef ::std::map< SCTAB, sal_uInt16 > XclExpIntTabMap;
+ typedef ::std::map< sal_Unicode, sal_uInt16 > XclExpCodeMap;
+
+private:
+ /** Returns the number of EXTERNSHEET records. */
+ sal_uInt16 GetExtSheetCount() const;
+
+ /** Appends an internal EXTERNSHEET record and returns the one-based index. */
+ sal_uInt16 AppendInternal( XclExpExtSheetRef xExtSheet );
+ /** Creates all EXTERNSHEET records for internal sheets on first call. */
+ void CreateInternal();
+
+ /** Returns the specified internal EXTERNSHEET record. */
+ XclExpExtSheetRef GetInternal( sal_uInt16 nExtSheet );
+ /** Returns the EXTERNSHEET index of an internal Calc sheet, or a deleted reference. */
+ XclExpExtSheetRef FindInternal( sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab, SCTAB nScTab );
+ /** Finds or creates the EXTERNSHEET index of an internal special EXTERNSHEET. */
+ XclExpExtSheetRef FindInternal( sal_uInt16& rnExtSheet, sal_Unicode cCode );
+
+private:
+ XclExpExtSheetList maExtSheetList; /// List with EXTERNSHEET records.
+ XclExpIntTabMap maIntTabMap; /// Maps internal Calc sheets to EXTERNSHEET records.
+ XclExpCodeMap maCodeMap; /// Maps special external codes to EXTERNSHEET records.
+};
+
+// ----------------------------------------------------------------------------
+
+/** Implementation of the link manager for BIFF8. */
+class XclExpLinkManagerImpl8 : public XclExpLinkManagerImpl
+{
+public:
+ explicit XclExpLinkManagerImpl8( const XclExpRoot& rRoot );
+
+ virtual void FindExtSheet( sal_uInt16& rnExtSheet,
+ sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab,
+ XclExpRefLogEntry* pRefLogEntry );
+ virtual sal_uInt16 FindExtSheet( sal_Unicode cCode );
+
+ virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
+ XclExpRefLogEntry* pRefLogEntry );
+
+ virtual void StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
+
+ virtual void StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef );
+ virtual void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
+
+ virtual bool InsertAddIn(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName );
+ /** InsertEuroTool */
+ virtual bool InsertEuroTool(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName );
+
+ virtual bool InsertDde(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rApplic, const String& rTopic, const String& rItem );
+
+ virtual bool InsertExtName(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl,
+ const String& rName, const ScExternalRefCache::TokenArrayRef pArray );
+
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ /** Searches for or inserts a new XTI structure.
+ @return The 0-based list index of the XTI structure. */
+ sal_uInt16 InsertXti( const XclExpXti& rXti );
+
+private:
+ typedef ::std::vector< XclExpXti > XclExpXtiVec;
+
+ XclExpSupbookBuffer maSBBuffer; /// List of all SUPBOOK records.
+ XclExpXtiVec maXtiVec; /// List of XTI structures for the EXTERNSHEET record.
+};
+
+// ============================================================================
+// *** Implementation ***
+// ============================================================================
+
+// Excel sheet indexes ========================================================
+
+const sal_uInt8 EXC_TABBUF_IGNORE = 0x01; /// Sheet will be ignored completely.
+const sal_uInt8 EXC_TABBUF_EXTERN = 0x02; /// Sheet is linked externally.
+const sal_uInt8 EXC_TABBUF_SKIPMASK = 0x0F; /// Sheet will be skipped, if any flag is set.
+const sal_uInt8 EXC_TABBUF_VISIBLE = 0x10; /// Sheet is visible.
+const sal_uInt8 EXC_TABBUF_SELECTED = 0x20; /// Sheet is selected.
+const sal_uInt8 EXC_TABBUF_MIRRORED = 0x40; /// Sheet is mirrored (right-to-left).
+
+// ----------------------------------------------------------------------------
+
+XclExpTabInfo::XclExpTabInfo( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mnScCnt( 0 ),
+ mnXclCnt( 0 ),
+ mnXclExtCnt( 0 ),
+ mnXclSelCnt( 0 ),
+ mnDisplXclTab( 0 ),
+ mnFirstVisXclTab( 0 )
+{
+ ScDocument& rDoc = GetDoc();
+ ScExtDocOptions& rDocOpt = GetExtDocOptions();
+
+ mnScCnt = rDoc.GetTableCount();
+
+ SCTAB nScTab;
+ SCTAB nFirstVisScTab = SCTAB_INVALID; // first visible sheet
+ SCTAB nFirstExpScTab = SCTAB_INVALID; // first exported sheet
+
+ // --- initialize the flags in the index buffer ---
+
+ maTabInfoVec.resize( mnScCnt );
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ {
+ // ignored sheets (skipped by export, with invalid Excel sheet index)
+ if( rDoc.IsScenario( nScTab ) )
+ {
+ SetFlag( nScTab, EXC_TABBUF_IGNORE );
+ }
+
+ // external sheets (skipped, but with valid Excel sheet index for ref's)
+ else if( rDoc.GetLinkMode( nScTab ) == SC_LINK_VALUE )
+ {
+ SetFlag( nScTab, EXC_TABBUF_EXTERN );
+ }
+
+ // exported sheets
+ else
+ {
+ // sheet name
+ rDoc.GetName( nScTab, maTabInfoVec[ nScTab ].maScName );
+
+ // remember first exported sheet
+ if( nFirstExpScTab == SCTAB_INVALID )
+ nFirstExpScTab = nScTab;
+ // remember first visible exported sheet
+ if( (nFirstVisScTab == SCTAB_INVALID) && rDoc.IsVisible( nScTab ) )
+ nFirstVisScTab = nScTab;
+
+ // sheet visible (only exported sheets)
+ SetFlag( nScTab, EXC_TABBUF_VISIBLE, rDoc.IsVisible( nScTab ) );
+
+ // sheet selected (only exported sheets)
+ if( const ScExtTabSettings* pTabSett = rDocOpt.GetTabSettings( nScTab ) )
+ SetFlag( nScTab, EXC_TABBUF_SELECTED, pTabSett->mbSelected );
+
+ // sheet mirrored (only exported sheets)
+ SetFlag( nScTab, EXC_TABBUF_MIRRORED, rDoc.IsLayoutRTL( nScTab ) );
+ }
+ }
+
+ // --- visible/selected sheets ---
+
+ SCTAB nDisplScTab = rDocOpt.GetDocSettings().mnDisplTab;
+
+ // find first visible exported sheet
+ if( (nFirstVisScTab == SCTAB_INVALID) || !IsExportTab( nFirstVisScTab ) )
+ {
+ // no exportable visible sheet -> use first exportable sheet
+ nFirstVisScTab = nFirstExpScTab;
+ if( (nFirstVisScTab == SCTAB_INVALID) || !IsExportTab( nFirstVisScTab ) )
+ {
+ // no exportable sheet at all -> use active sheet and export it
+ nFirstVisScTab = nDisplScTab;
+ SetFlag( nFirstVisScTab, EXC_TABBUF_SKIPMASK, false ); // clear skip flags
+ }
+ SetFlag( nFirstVisScTab, EXC_TABBUF_VISIBLE ); // must be visible, even if originally hidden
+ }
+
+ // find currently displayed sheet
+ if( !IsExportTab( nDisplScTab ) ) // selected sheet not exported (i.e. scenario) -> use first visible
+ nDisplScTab = nFirstVisScTab;
+ SetFlag( nDisplScTab, EXC_TABBUF_VISIBLE | EXC_TABBUF_SELECTED );
+
+ // number of selected sheets
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ if( IsSelectedTab( nScTab ) )
+ ++mnXclSelCnt;
+
+ // --- calculate resulting Excel sheet indexes ---
+
+ CalcXclIndexes();
+ mnFirstVisXclTab = GetXclTab( nFirstVisScTab );
+ mnDisplXclTab = GetXclTab( nDisplScTab );
+
+ // --- sorted vectors for index lookup ---
+
+ CalcSortedIndexes();
+}
+
+bool XclExpTabInfo::IsExportTab( SCTAB nScTab ) const
+{
+ /* Check sheet index before to avoid assertion in GetFlag(). */
+ return (nScTab < mnScCnt) && !GetFlag( nScTab, EXC_TABBUF_SKIPMASK );
+}
+
+bool XclExpTabInfo::IsExternalTab( SCTAB nScTab ) const
+{
+ /* Check sheet index before to avoid assertion (called from formula
+ compiler also for deleted references). */
+ return (nScTab < mnScCnt) && GetFlag( nScTab, EXC_TABBUF_EXTERN );
+}
+
+bool XclExpTabInfo::IsVisibleTab( SCTAB nScTab ) const
+{
+ return GetFlag( nScTab, EXC_TABBUF_VISIBLE );
+}
+
+bool XclExpTabInfo::IsSelectedTab( SCTAB nScTab ) const
+{
+ return GetFlag( nScTab, EXC_TABBUF_SELECTED );
+}
+
+bool XclExpTabInfo::IsDisplayedTab( SCTAB nScTab ) const
+{
+ DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::IsActiveTab - sheet out of range" );
+ return GetXclTab( nScTab ) == mnDisplXclTab;
+}
+
+bool XclExpTabInfo::IsMirroredTab( SCTAB nScTab ) const
+{
+ return GetFlag( nScTab, EXC_TABBUF_MIRRORED );
+}
+
+const String& XclExpTabInfo::GetScTabName( SCTAB nScTab ) const
+{
+ DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::IsActiveTab - sheet out of range" );
+ return (nScTab < mnScCnt) ? maTabInfoVec[ nScTab ].maScName : EMPTY_STRING;
+}
+
+sal_uInt16 XclExpTabInfo::GetXclTab( SCTAB nScTab ) const
+{
+ return (nScTab < mnScCnt) ? maTabInfoVec[ nScTab ].mnXclTab : EXC_TAB_DELETED;
+}
+
+SCTAB XclExpTabInfo::GetRealScTab( SCTAB nSortedScTab ) const
+{
+ DBG_ASSERT( nSortedScTab < mnScCnt, "XclExpTabInfo::GetRealScTab - sheet out of range" );
+ return (nSortedScTab < mnScCnt) ? maFromSortedVec[ nSortedScTab ] : SCTAB_INVALID;
+}
+
+bool XclExpTabInfo::GetFlag( SCTAB nScTab, sal_uInt8 nFlags ) const
+{
+ DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::GetFlag - sheet out of range" );
+ return (nScTab < mnScCnt) && ::get_flag( maTabInfoVec[ nScTab ].mnFlags, nFlags );
+}
+
+void XclExpTabInfo::SetFlag( SCTAB nScTab, sal_uInt8 nFlags, bool bSet )
+{
+ DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::SetFlag - sheet out of range" );
+ if( nScTab < mnScCnt )
+ ::set_flag( maTabInfoVec[ nScTab ].mnFlags, nFlags, bSet );
+}
+
+void XclExpTabInfo::CalcXclIndexes()
+{
+ sal_uInt16 nXclTab = 0;
+ SCTAB nScTab = 0;
+
+ // --- pass 1: process regular sheets ---
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ {
+ if( IsExportTab( nScTab ) )
+ {
+ maTabInfoVec[ nScTab ].mnXclTab = nXclTab;
+ ++nXclTab;
+ }
+ else
+ maTabInfoVec[ nScTab ].mnXclTab = EXC_TAB_DELETED;
+ }
+ mnXclCnt = nXclTab;
+
+ // --- pass 2: process external sheets (nXclTab continues) ---
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ {
+ if( IsExternalTab( nScTab ) )
+ {
+ maTabInfoVec[ nScTab ].mnXclTab = nXclTab;
+ ++nXclTab;
+ ++mnXclExtCnt;
+ }
+ }
+
+ // result: first occur all exported sheets, followed by all external sheets
+}
+
+typedef ::std::pair< String, SCTAB > XclExpTabName;
+typedef ::std::vector< XclExpTabName > XclExpTabNameVec;
+
+inline bool operator<( const XclExpTabName& rArg1, const XclExpTabName& rArg2 )
+{
+ // compare the sheet names only
+ return ScGlobal::GetCollator()->compareString( rArg1.first, rArg2.first ) == COMPARE_LESS;
+}
+
+void XclExpTabInfo::CalcSortedIndexes()
+{
+ ScDocument& rDoc = GetDoc();
+ XclExpTabNameVec aVec( mnScCnt );
+ SCTAB nScTab;
+
+ // fill with sheet names
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ {
+ rDoc.GetName( nScTab, aVec[ nScTab ].first );
+ aVec[ nScTab ].second = nScTab;
+ }
+ ::std::sort( aVec.begin(), aVec.end() );
+
+ // fill index vectors from sorted sheet name vector
+ maFromSortedVec.resize( mnScCnt );
+ maToSortedVec.resize( mnScCnt );
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ {
+ maFromSortedVec[ nScTab ] = aVec[ nScTab ].second;
+ maToSortedVec[ aVec[ nScTab ].second ] = nScTab;
+ }
+}
+
+// External names =============================================================
+
+XclExpExtNameBase::XclExpExtNameBase(
+ const XclExpRoot& rRoot, const String& rName, sal_uInt16 nFlags ) :
+ XclExpRecord( EXC_ID_EXTERNNAME ),
+ XclExpRoot( rRoot ),
+ maName( rName ),
+ mxName( XclExpStringHelper::CreateString( rRoot, rName, EXC_STR_8BITLENGTH ) ),
+ mnFlags( nFlags )
+{
+ DBG_ASSERT( maName.Len() <= 255, "XclExpExtNameBase::XclExpExtNameBase - string too long" );
+ SetRecSize( 6 + mxName->GetSize() );
+}
+
+XclExpExtNameBase::~XclExpExtNameBase()
+{
+}
+
+void XclExpExtNameBase::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << mnFlags
+ << sal_uInt32( 0 )
+ << *mxName;
+ WriteAddData( rStrm );
+}
+
+void XclExpExtNameBase::WriteAddData( XclExpStream& /*rStrm*/ )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpExtNameAddIn::XclExpExtNameAddIn( const XclExpRoot& rRoot, const String& rName ) :
+ XclExpExtNameBase( rRoot, rName )
+{
+ AddRecSize( 4 );
+}
+
+void XclExpExtNameAddIn::WriteAddData( XclExpStream& rStrm )
+{
+ // write a #REF! error formula
+ rStrm << sal_uInt16( 2 ) << EXC_TOKID_ERR << EXC_ERR_REF;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpExtNameDde::XclExpExtNameDde( const XclExpRoot& rRoot,
+ const String& rName, sal_uInt16 nFlags, const ScMatrix* pResults ) :
+ XclExpExtNameBase( rRoot, rName, nFlags )
+{
+ if( pResults )
+ {
+ mxMatrix.reset( new XclExpCachedMatrix( *pResults ) );
+ AddRecSize( mxMatrix->GetSize() );
+ }
+}
+
+void XclExpExtNameDde::WriteAddData( XclExpStream& rStrm )
+{
+ if( mxMatrix )
+ mxMatrix->Save( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpExtName::XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook,
+ const String& rName, const ScExternalRefCache::TokenArrayRef pArray ) :
+ XclExpExtNameBase( rRoot, rName ),
+ mrSupbook(rSupbook),
+ mpArray(pArray->Clone())
+{
+}
+
+void XclExpExtName::WriteAddData( XclExpStream& rStrm )
+{
+ // Write only if it only has a single token that is either a cell or cell
+ // range address. Excel just writes '02 00 1C 17' for all the other types
+ // of external names.
+
+ using namespace ::formula;
+ do
+ {
+ if (mpArray->GetLen() != 1)
+ break;
+
+ const ScToken* p = static_cast<const ScToken*>(mpArray->First());
+ if (!p->IsExternalRef())
+ break;
+
+ switch (p->GetType())
+ {
+ case svExternalSingleRef:
+ {
+ const ScSingleRefData& rRef = p->GetSingleRef();
+ if (rRef.IsTabRel())
+ break;
+
+ bool bColRel = rRef.IsColRel();
+ bool bRowRel = rRef.IsRowRel();
+ sal_uInt16 nCol = static_cast< sal_uInt16 >( bColRel ? rRef.nRelCol : rRef.nCol );
+ sal_uInt16 nRow = static_cast< sal_uInt16 >( bRowRel ? rRef.nRelRow : rRef.nRow );
+ if (bColRel) nCol |= 0x4000;
+ if (bRowRel) nCol |= 0x8000;
+
+ const String& rTabName = p->GetString();
+ sal_uInt16 nSBTab = mrSupbook.GetTabIndex(rTabName);
+
+ // size is always 9
+ rStrm << static_cast<sal_uInt16>(9);
+ // operator token (3A for cell reference)
+ rStrm << static_cast<sal_uInt8>(0x3A);
+ // cell address (Excel's address has 2 sheet IDs.)
+ rStrm << nSBTab << nSBTab << nRow << nCol;
+ return;
+ }
+ case svExternalDoubleRef:
+ {
+ const ScComplexRefData& rRef = p->GetDoubleRef();
+ const ScSingleRefData& r1 = rRef.Ref1;
+ const ScSingleRefData& r2 = rRef.Ref2;
+ if (r1.IsTabRel() || r2.IsTabRel())
+ break;
+
+ sal_uInt16 nTab1 = r1.nTab;
+ sal_uInt16 nTab2 = r2.nTab;
+ bool bCol1Rel = r1.IsColRel();
+ bool bRow1Rel = r1.IsRowRel();
+ bool bCol2Rel = r2.IsColRel();
+ bool bRow2Rel = r2.IsRowRel();
+
+ sal_uInt16 nCol1 = static_cast< sal_uInt16 >( bCol1Rel ? r1.nRelCol : r1.nCol );
+ sal_uInt16 nCol2 = static_cast< sal_uInt16 >( bCol2Rel ? r2.nRelCol : r2.nCol );
+ sal_uInt16 nRow1 = static_cast< sal_uInt16 >( bRow1Rel ? r1.nRelRow : r1.nRow );
+ sal_uInt16 nRow2 = static_cast< sal_uInt16 >( bRow2Rel ? r2.nRelRow : r2.nRow );
+ if (bCol1Rel) nCol1 |= 0x4000;
+ if (bRow1Rel) nCol1 |= 0x8000;
+ if (bCol2Rel) nCol2 |= 0x4000;
+ if (bRow2Rel) nCol2 |= 0x8000;
+
+ const String& rTabName = p->GetString();
+ sal_uInt16 nSBTab = mrSupbook.GetTabIndex(rTabName);
+
+ // size is always 13 (0x0D)
+ rStrm << static_cast<sal_uInt16>(13);
+ // operator token (3B for area reference)
+ rStrm << static_cast<sal_uInt8>(0x3B);
+ // range (area) address
+ sal_uInt16 nSBTab2 = nSBTab + nTab2 - nTab1;
+ rStrm << nSBTab << nSBTab2 << nRow1 << nRow2 << nCol1 << nCol2;
+ return;
+ }
+ default:
+ ; // nothing
+ }
+ }
+ while (false);
+
+ // special value for #REF! (02 00 1C 17)
+ rStrm << static_cast<sal_uInt16>(2) << EXC_TOKID_ERR << EXC_ERR_REF;
+}
+
+// List of external names =====================================================
+
+XclExpExtNameBuffer::XclExpExtNameBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+sal_uInt16 XclExpExtNameBuffer::InsertAddIn( const String& rName )
+{
+ sal_uInt16 nIndex = GetIndex( rName );
+ return nIndex ? nIndex : AppendNew( new XclExpExtNameAddIn( GetRoot(), rName ) );
+}
+
+sal_uInt16 XclExpExtNameBuffer::InsertEuroTool( const String& rName )
+{
+ sal_uInt16 nIndex = GetIndex( rName );
+ return nIndex ? nIndex : AppendNew( new XclExpExtNameBase( GetRoot(), rName ) );
+}
+
+sal_uInt16 XclExpExtNameBuffer::InsertDde(
+ const String& rApplic, const String& rTopic, const String& rItem )
+{
+ sal_uInt16 nIndex = GetIndex( rItem );
+ if( nIndex == 0 )
+ {
+ sal_uInt16 nPos;
+ if( GetDoc().FindDdeLink( rApplic, rTopic, rItem, SC_DDE_IGNOREMODE, nPos ) )
+ {
+ // create the leading 'StdDocumentName' EXTERNNAME record
+ if( maNameList.IsEmpty() )
+ AppendNew( new XclExpExtNameDde(
+ GetRoot(), CREATE_STRING( "StdDocumentName" ), EXC_EXTN_EXPDDE_STDDOC ) );
+
+ // try to find DDE result array, but create EXTERNNAME record without them too
+ const ScMatrix* pScMatrix = GetDoc().GetDdeLinkResultMatrix( nPos );
+ nIndex = AppendNew( new XclExpExtNameDde( GetRoot(), rItem, EXC_EXTN_EXPDDE, pScMatrix ) );
+ }
+ }
+ return nIndex;
+}
+
+sal_uInt16 XclExpExtNameBuffer::InsertExtName( const XclExpSupbook& rSupbook,
+ const String& rName, const ScExternalRefCache::TokenArrayRef pArray )
+{
+ sal_uInt16 nIndex = GetIndex( rName );
+ return nIndex ? nIndex : AppendNew( new XclExpExtName( GetRoot(), rSupbook, rName, pArray ) );
+}
+
+void XclExpExtNameBuffer::Save( XclExpStream& rStrm )
+{
+ maNameList.Save( rStrm );
+}
+
+sal_uInt16 XclExpExtNameBuffer::GetIndex( const String& rName ) const
+{
+ for( size_t nPos = 0, nSize = maNameList.GetSize(); nPos < nSize; ++nPos )
+ if( maNameList.GetRecord( nPos )->GetName() == rName )
+ return static_cast< sal_uInt16 >( nPos + 1 );
+ return 0;
+}
+
+sal_uInt16 XclExpExtNameBuffer::AppendNew( XclExpExtNameBase* pExtName )
+{
+ XclExpExtNameRef xExtName( pExtName );
+ size_t nSize = maNameList.GetSize();
+ if( nSize < 0x7FFF )
+ {
+ maNameList.AppendRecord( xExtName );
+ return static_cast< sal_uInt16 >( nSize + 1 );
+ }
+ return 0;
+}
+
+// Cached external cells ======================================================
+
+XclExpCrn::XclExpCrn( SCCOL nScCol, SCROW nScRow, const Any& rValue ) :
+ XclExpRecord( EXC_ID_CRN, 4 ),
+ mnScCol( nScCol ),
+ mnScRow( nScRow )
+{
+ maValues.push_back( rValue );
+}
+
+bool XclExpCrn::InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue )
+{
+ if( (nScRow != mnScRow) || (nScCol != static_cast< SCCOL >( mnScCol + maValues.size() )) )
+ return false;
+ maValues.push_back( rValue );
+ return true;
+}
+
+void XclExpCrn::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << static_cast< sal_uInt8 >( mnScCol + maValues.size() - 1 )
+ << static_cast< sal_uInt8 >( mnScCol )
+ << static_cast< sal_uInt16 >( mnScRow );
+ for( CachedValues::iterator aIt = maValues.begin(), aEnd = maValues.end(); aIt != aEnd; ++aIt )
+ {
+ if( aIt->has< bool >() )
+ WriteBool( rStrm, aIt->get< bool >() );
+ else if( aIt->has< double >() )
+ WriteDouble( rStrm, aIt->get< double >() );
+ else if( aIt->has< OUString >() )
+ WriteString( rStrm, aIt->get< OUString >() );
+ else
+ WriteEmpty( rStrm );
+ }
+}
+
+void XclExpCrn::WriteBool( XclExpStream& rStrm, bool bValue )
+{
+ rStrm << EXC_CACHEDVAL_BOOL << sal_uInt8( bValue ? 1 : 0);
+ rStrm.WriteZeroBytes( 7 );
+}
+
+void XclExpCrn::WriteDouble( XclExpStream& rStrm, double fValue )
+{
+ if( ::rtl::math::isNan( fValue ) )
+ {
+ sal_uInt16 nScError = static_cast< sal_uInt16 >( reinterpret_cast< const sal_math_Double* >( &fValue )->nan_parts.fraction_lo );
+ WriteError( rStrm, XclTools::GetXclErrorCode( nScError ) );
+ }
+ else
+ {
+ rStrm << EXC_CACHEDVAL_DOUBLE << fValue;
+ }
+}
+
+void XclExpCrn::WriteString( XclExpStream& rStrm, const OUString& rValue )
+{
+ rStrm << EXC_CACHEDVAL_STRING << XclExpString( rValue );
+}
+
+void XclExpCrn::WriteError( XclExpStream& rStrm, sal_uInt8 nErrCode )
+{
+ rStrm << EXC_CACHEDVAL_ERROR << nErrCode;
+ rStrm.WriteZeroBytes( 7 );
+}
+
+void XclExpCrn::WriteEmpty( XclExpStream& rStrm )
+{
+ rStrm << EXC_CACHEDVAL_EMPTY;
+ rStrm.WriteZeroBytes( 8 );
+}
+
+// Cached cells of a sheet ====================================================
+
+XclExpXct::XclExpXct( const XclExpRoot& rRoot, const String& rTabName,
+ sal_uInt16 nSBTab, ScExternalRefCache::TableTypeRef xCacheTable ) :
+ XclExpRoot( rRoot ),
+ mxCacheTable( xCacheTable ),
+ maBoundRange( ScAddress::INITIALIZE_INVALID ),
+ maTabName( rTabName ),
+ mnSBTab( nSBTab )
+{
+}
+
+void XclExpXct::StoreCellRange( const ScRange& rRange )
+{
+ // #i70418# restrict size of external range to prevent memory overflow
+ if( (rRange.aEnd.Col() - rRange.aStart.Col()) * (rRange.aEnd.Row() - rRange.aStart.Row()) > 1024 )
+ return;
+
+ maUsedCells.SetMultiMarkArea( rRange );
+ maBoundRange.ExtendTo( rRange );
+}
+
+void XclExpXct::StoreCell( const ScAddress& rCell, const ::formula::FormulaToken& rToken )
+{
+ maUsedCells.SetMultiMarkArea( ScRange( rCell ) );
+ maBoundRange.ExtendTo( ScRange( rCell ) );
+ (void)rToken;
+}
+
+void XclExpXct::StoreCellRange( const ScRange& rRange, const ::formula::FormulaToken& rToken )
+{
+ maUsedCells.SetMultiMarkArea( rRange );
+ maBoundRange.ExtendTo( rRange );
+ (void)rToken;
+}
+
+namespace {
+
+class XclExpCrnList : public XclExpRecordList< XclExpCrn >
+{
+public:
+ /** Inserts the passed value into an existing or new CRN record.
+ @return True = value inserted successfully, false = CRN list is full. */
+ bool InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue );
+};
+
+bool XclExpCrnList::InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue )
+{
+ RecordRefType xLastRec = GetLastRecord();
+ if( xLastRec && xLastRec->InsertValue( nScCol, nScRow, rValue ) )
+ return true;
+ if( GetSize() == SAL_MAX_UINT16 )
+ return false;
+ AppendNewRecord( new XclExpCrn( nScCol, nScRow, rValue ) );
+ return true;
+}
+
+} // namespace
+
+void XclExpXct::Save( XclExpStream& rStrm )
+{
+ if( !mxCacheTable )
+ return;
+
+ /* Get the range of used rows in the cache table. This may help to
+ optimize building the CRN record list if the cache table does not
+ contain all referred cells, e.g. if big empty ranges are used in the
+ formulas. */
+ ::std::pair< SCROW, SCROW > aRowRange = mxCacheTable->getRowRange();
+ if( aRowRange.first >= aRowRange.second )
+ return;
+
+ /* Crop the bounding range of used cells in this table to Excel limits.
+ Return if there is no external cell inside these limits. */
+ if( !GetAddressConverter().ValidateRange( maBoundRange, false ) )
+ return;
+
+ /* Find the resulting row range that needs to be processed. */
+ SCROW nScRow1 = ::std::max( aRowRange.first, maBoundRange.aStart.Row() );
+ SCROW nScRow2 = ::std::min( aRowRange.second - 1, maBoundRange.aEnd.Row() );
+ if( nScRow1 > nScRow2 )
+ return;
+
+ /* Build and collect all CRN records before writing the XCT record. This
+ is needed to determine the total number of CRN records which must be
+ known when writing the XCT record (possibly encrypted, so seeking the
+ output strem back after writing the CRN records is not an option). */
+ XclExpCrnList aCrnRecs;
+ SvNumberFormatter& rFormatter = GetFormatter();
+ bool bValid = true;
+ for( SCROW nScRow = nScRow1; bValid && (nScRow <= nScRow2); ++nScRow )
+ {
+ ::std::pair< SCCOL, SCCOL > aColRange = mxCacheTable->getColRange( nScRow );
+ for( SCCOL nScCol = aColRange.first; bValid && (nScCol < aColRange.second); ++nScCol )
+ {
+ if( maUsedCells.IsCellMarked( nScCol, nScRow, sal_True ) )
+ {
+ sal_uInt32 nScNumFmt = 0;
+ ScExternalRefCache::TokenRef xToken = mxCacheTable->getCell( nScCol, nScRow, &nScNumFmt );
+ using namespace ::formula;
+ if( xToken.get() ) switch( xToken->GetType() )
+ {
+ case svDouble:
+ bValid = (rFormatter.GetType( nScNumFmt ) == NUMBERFORMAT_LOGICAL) ?
+ aCrnRecs.InsertValue( nScCol, nScRow, Any( xToken->GetDouble() != 0 ) ) :
+ aCrnRecs.InsertValue( nScCol, nScRow, Any( xToken->GetDouble() ) );
+ break;
+ case svString:
+ // do not save empty strings (empty cells) to cache
+ if( xToken->GetString().Len() > 0 )
+ bValid = aCrnRecs.InsertValue( nScCol, nScRow, Any( OUString( xToken->GetString() ) ) );
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // write the XCT record and the list of CRN records
+ rStrm.StartRecord( EXC_ID_XCT, 4 );
+ rStrm << static_cast< sal_uInt16 >( aCrnRecs.GetSize() ) << mnSBTab;
+ rStrm.EndRecord();
+ aCrnRecs.Save( rStrm );
+}
+
+// External documents (EXTERNSHEET/SUPBOOK), base class =======================
+
+XclExpExternSheetBase::XclExpExternSheetBase( const XclExpRoot& rRoot, sal_uInt16 nRecId, sal_uInt32 nRecSize ) :
+ XclExpRecord( nRecId, nRecSize ),
+ XclExpRoot( rRoot )
+{
+}
+
+XclExpExtNameBuffer& XclExpExternSheetBase::GetExtNameBuffer()
+{
+ if( !mxExtNameBfr )
+ mxExtNameBfr.reset( new XclExpExtNameBuffer( GetRoot() ) );
+ return *mxExtNameBfr;
+}
+
+void XclExpExternSheetBase::WriteExtNameBuffer( XclExpStream& rStrm )
+{
+ if( mxExtNameBfr )
+ mxExtNameBfr->Save( rStrm );
+}
+
+// External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
+
+XclExpExternSheet::XclExpExternSheet( const XclExpRoot& rRoot, sal_Unicode cCode ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_EXTERNSHEET )
+{
+ Init( String( cCode ) );
+}
+
+XclExpExternSheet::XclExpExternSheet( const XclExpRoot& rRoot, const String& rTabName ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_EXTERNSHEET )
+{
+ // reference to own sheet: \03<sheetname>
+ Init( String( EXC_EXTSH_TABNAME ).Append( rTabName ) );
+}
+
+void XclExpExternSheet::Save( XclExpStream& rStrm )
+{
+ // EXTERNSHEET record
+ XclExpRecord::Save( rStrm );
+ // EXTERNNAME records
+ WriteExtNameBuffer( rStrm );
+}
+
+void XclExpExternSheet::Init( const String& rEncUrl )
+{
+ DBG_ASSERT_BIFF( GetBiff() <= EXC_BIFF5 );
+ maTabName.AssignByte( rEncUrl, GetTextEncoding(), EXC_STR_8BITLENGTH );
+ SetRecSize( maTabName.GetSize() );
+}
+
+sal_uInt16 XclExpExternSheet::InsertAddIn( const String& rName )
+{
+ return GetExtNameBuffer().InsertAddIn( rName );
+}
+
+void XclExpExternSheet::WriteBody( XclExpStream& rStrm )
+{
+ sal_uInt8 nNameSize = static_cast< sal_uInt8 >( maTabName.Len() );
+ // special case: reference to own sheet (starting with '\03') needs wrong string length
+ if( maTabName.GetChar( 0 ) == EXC_EXTSH_TABNAME )
+ --nNameSize;
+ rStrm << nNameSize;
+ maTabName.WriteBuffer( rStrm );
+}
+
+// External document (SUPBOOK, BIFF8) =========================================
+
+XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, sal_uInt16 nXclTabCount ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
+ meType( EXC_SBTYPE_SELF ),
+ mnXclTabCount( nXclTabCount )
+{
+}
+
+XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
+ meType( EXC_SBTYPE_ADDIN ),
+ mnXclTabCount( 1 )
+{
+}
+
+XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl, XclSupbookType ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK ),
+ maUrl( rUrl ),
+ maUrlEncoded( rUrl ),
+ meType( EXC_SBTYPE_EUROTOOL ),
+ mnXclTabCount( 0 )
+{
+ SetRecSize( 2 + maUrlEncoded.GetSize() );
+}
+
+
+XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK ),
+ maUrl( rUrl ),
+ maUrlEncoded( XclExpUrlHelper::EncodeUrl( rRoot, rUrl ) ),
+ meType( EXC_SBTYPE_EXTERN ),
+ mnXclTabCount( 0 )
+{
+ SetRecSize( 2 + maUrlEncoded.GetSize() );
+
+ // We need to create all tables up front to ensure the correct table order.
+ ScExternalRefManager* pRefMgr = rRoot.GetDoc().GetExternalRefManager();
+ sal_uInt16 nFileId = pRefMgr->getExternalFileId( rUrl );
+ ScfStringVec aTabNames;
+ pRefMgr->getAllCachedTableNames( nFileId, aTabNames );
+ for( ScfStringVec::const_iterator aBeg = aTabNames.begin(), aIt = aBeg, aEnd = aTabNames.end(); aIt != aEnd; ++aIt )
+ InsertTabName( *aIt, pRefMgr->getCacheTable( nFileId, aIt - aBeg ) );
+}
+
+XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rApplic, const String& rTopic ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
+ maUrl( rApplic ),
+ maDdeTopic( rTopic ),
+ maUrlEncoded( XclExpUrlHelper::EncodeDde( rApplic, rTopic ) ),
+ meType( EXC_SBTYPE_SPECIAL ),
+ mnXclTabCount( 0 )
+{
+ SetRecSize( 2 + maUrlEncoded.GetSize() );
+}
+
+bool XclExpSupbook::IsUrlLink( const String& rUrl ) const
+{
+ return (meType == EXC_SBTYPE_EXTERN || meType == EXC_SBTYPE_EUROTOOL) && (maUrl == rUrl);
+}
+
+bool XclExpSupbook::IsDdeLink( const String& rApplic, const String& rTopic ) const
+{
+ return (meType == EXC_SBTYPE_SPECIAL) && (maUrl == rApplic) && (maDdeTopic == rTopic);
+}
+
+void XclExpSupbook::FillRefLogEntry( XclExpRefLogEntry& rRefLogEntry,
+ sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) const
+{
+ rRefLogEntry.mpUrl = maUrlEncoded.IsEmpty() ? 0 : &maUrlEncoded;
+ rRefLogEntry.mpFirstTab = GetTabName( nFirstSBTab );
+ rRefLogEntry.mpLastTab = GetTabName( nLastSBTab );
+}
+
+void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab )
+{
+ if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
+ pXct->StoreCellRange( rRange );
+}
+
+void XclExpSupbook::StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const formula::FormulaToken& rToken )
+{
+ if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
+ pXct->StoreCell( rCell, rToken );
+}
+
+void XclExpSupbook::StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const formula::FormulaToken& rToken )
+{
+ // multi-table range is not allowed!
+ if( rRange.aStart.Tab() == rRange.aEnd.Tab() )
+ if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
+ pXct->StoreCellRange( rRange, rToken );
+}
+
+sal_uInt16 XclExpSupbook::GetTabIndex( const String& rTabName ) const
+{
+ XclExpString aXclName(rTabName);
+ size_t nSize = maXctList.GetSize();
+ for (size_t i = 0; i < nSize; ++i)
+ {
+ XclExpXctRef aRec = maXctList.GetRecord(i);
+ if (aXclName == aRec->GetTabName())
+ return ulimit_cast<sal_uInt16>(i);
+ }
+ return EXC_NOTAB;
+}
+
+sal_uInt16 XclExpSupbook::GetTabCount() const
+{
+ return ulimit_cast<sal_uInt16>(maXctList.GetSize());
+}
+
+sal_uInt16 XclExpSupbook::InsertTabName( const String& rTabName, ScExternalRefCache::TableTypeRef xCacheTable )
+{
+ DBG_ASSERT( meType == EXC_SBTYPE_EXTERN, "XclExpSupbook::InsertTabName - don't insert sheet names here" );
+ sal_uInt16 nSBTab = ulimit_cast< sal_uInt16 >( maXctList.GetSize() );
+ XclExpXctRef xXct( new XclExpXct( GetRoot(), rTabName, nSBTab, xCacheTable ) );
+ AddRecSize( xXct->GetTabName().GetSize() );
+ maXctList.AppendRecord( xXct );
+ return nSBTab;
+}
+
+sal_uInt16 XclExpSupbook::InsertAddIn( const String& rName )
+{
+ return GetExtNameBuffer().InsertAddIn( rName );
+}
+
+sal_uInt16 XclExpSupbook::InsertEuroTool( const String& rName )
+{
+ return GetExtNameBuffer().InsertEuroTool( rName );
+}
+
+sal_uInt16 XclExpSupbook::InsertDde( const String& rItem )
+{
+ return GetExtNameBuffer().InsertDde( maUrl, maDdeTopic, rItem );
+}
+
+sal_uInt16 XclExpSupbook::InsertExtName( const String& rName, const ScExternalRefCache::TokenArrayRef pArray )
+{
+ return GetExtNameBuffer().InsertExtName(*this, rName, pArray);
+}
+
+void XclExpSupbook::Save( XclExpStream& rStrm )
+{
+ // SUPBOOK record
+ XclExpRecord::Save( rStrm );
+ // XCT record, CRN records
+ maXctList.Save( rStrm );
+ // EXTERNNAME records
+ WriteExtNameBuffer( rStrm );
+}
+
+const XclExpString* XclExpSupbook::GetTabName( sal_uInt16 nSBTab ) const
+{
+ XclExpXctRef xXct = maXctList.GetRecord( nSBTab );
+ return xXct ? &xXct->GetTabName() : 0;
+}
+
+void XclExpSupbook::WriteBody( XclExpStream& rStrm )
+{
+ switch( meType )
+ {
+ case EXC_SBTYPE_SELF:
+ rStrm << mnXclTabCount << EXC_SUPB_SELF;
+ break;
+ case EXC_SBTYPE_EXTERN:
+ case EXC_SBTYPE_SPECIAL:
+ case EXC_SBTYPE_EUROTOOL:
+ {
+ sal_uInt16 nCount = ulimit_cast< sal_uInt16 >( maXctList.GetSize() );
+ rStrm << nCount << maUrlEncoded;
+
+ for( size_t nPos = 0, nSize = maXctList.GetSize(); nPos < nSize; ++nPos )
+ rStrm << maXctList.GetRecord( nPos )->GetTabName();
+ }
+ break;
+ case EXC_SBTYPE_ADDIN:
+ rStrm << mnXclTabCount << EXC_SUPB_ADDIN;
+ break;
+ default:
+ DBG_ERRORFILE( "XclExpSupbook::WriteBody - unknown SUPBOOK type" );
+ }
+}
+
+// All SUPBOOKS in a document =================================================
+
+XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mnOwnDocSB( SAL_MAX_UINT16 ),
+ mnAddInSB( SAL_MAX_UINT16 )
+{
+ XclExpTabInfo& rTabInfo = GetTabInfo();
+ sal_uInt16 nXclCnt = rTabInfo.GetXclTabCount();
+ sal_uInt16 nCodeCnt = static_cast< sal_uInt16 >( GetExtDocOptions().GetCodeNameCount() );
+ size_t nCount = nXclCnt + rTabInfo.GetXclExtTabCount();
+
+ DBG_ASSERT( nCount > 0, "XclExpSupbookBuffer::XclExpSupbookBuffer - no sheets to export" );
+ if( nCount )
+ {
+ maSBIndexVec.resize( nCount );
+
+ // self-ref SUPBOOK first of list
+ XclExpSupbookRef xSupbook( new XclExpSupbook( GetRoot(), ::std::max( nXclCnt, nCodeCnt ) ) );
+ mnOwnDocSB = Append( xSupbook );
+ for( sal_uInt16 nXclTab = 0; nXclTab < nXclCnt; ++nXclTab )
+ maSBIndexVec[ nXclTab ].Set( mnOwnDocSB, nXclTab );
+ }
+}
+
+XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab,
+ XclExpRefLogEntry* pRefLogEntry ) const
+{
+ XclExpXti aXti;
+ size_t nSize = maSBIndexVec.size();
+ if( (nFirstXclTab < nSize) && (nLastXclTab < nSize) )
+ {
+ // index of the SUPBOOK record
+ aXti.mnSupbook = maSBIndexVec[ nFirstXclTab ].mnSupbook;
+
+ // all sheets in the same supbook?
+ bool bSameSB = true;
+ for( sal_uInt16 nXclTab = nFirstXclTab + 1; bSameSB && (nXclTab <= nLastXclTab); ++nXclTab )
+ {
+ bSameSB = maSBIndexVec[ nXclTab ].mnSupbook == aXti.mnSupbook;
+ if( !bSameSB )
+ nLastXclTab = nXclTab - 1;
+ }
+ aXti.mnFirstSBTab = maSBIndexVec[ nFirstXclTab ].mnSBTab;
+ aXti.mnLastSBTab = maSBIndexVec[ nLastXclTab ].mnSBTab;
+
+ // fill external reference log entry (for change tracking)
+ if( pRefLogEntry )
+ {
+ pRefLogEntry->mnFirstXclTab = nFirstXclTab;
+ pRefLogEntry->mnLastXclTab = nLastXclTab;
+ XclExpSupbookRef xSupbook = maSupbookList.GetRecord( aXti.mnSupbook );
+ if( xSupbook )
+ xSupbook->FillRefLogEntry( *pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab );
+ }
+ }
+ else
+ {
+ // special range, i.e. for deleted sheets or add-ins
+ aXti.mnSupbook = mnOwnDocSB;
+ aXti.mnFirstSBTab = nFirstXclTab;
+ aXti.mnLastSBTab = nLastXclTab;
+ }
+
+ return aXti;
+}
+
+void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange )
+{
+ sal_uInt16 nXclTab = GetTabInfo().GetXclTab( rRange.aStart.Tab() );
+ if( nXclTab < maSBIndexVec.size() )
+ {
+ const XclExpSBIndex& rSBIndex = maSBIndexVec[ nXclTab ];
+ XclExpSupbookRef xSupbook = maSupbookList.GetRecord( rSBIndex.mnSupbook );
+ DBG_ASSERT( xSupbook , "XclExpSupbookBuffer::StoreCellRange - missing SUPBOOK record" );
+ if( xSupbook )
+ xSupbook->StoreCellRange( rRange, rSBIndex.mnSBTab );
+ }
+}
+
+namespace {
+
+class FindSBIndexEntry
+{
+public:
+ explicit FindSBIndexEntry(sal_uInt16 nSupbookId, sal_uInt16 nTabId) :
+ mnSupbookId(nSupbookId), mnTabId(nTabId) {}
+
+ bool operator()(const XclExpSupbookBuffer::XclExpSBIndex& r) const
+ {
+ return mnSupbookId == r.mnSupbook && mnTabId == r.mnSBTab;
+ }
+
+private:
+ sal_uInt16 mnSupbookId;
+ sal_uInt16 mnTabId;
+};
+
+}
+
+void XclExpSupbookBuffer::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell )
+{
+ ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
+ const String* pUrl = pRefMgr->getExternalFileName(nFileId);
+ if (!pUrl)
+ return;
+
+ XclExpSupbookRef xSupbook;
+ sal_uInt16 nSupbookId;
+ if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
+ {
+ xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
+ nSupbookId = Append(xSupbook);
+ }
+
+ ScExternalRefCache::TokenRef pToken = pRefMgr->getSingleRefToken(nFileId, rTabName, rCell, NULL, NULL);
+ if (!pToken.get())
+ return;
+
+ sal_uInt16 nSheetId = xSupbook->GetTabIndex(rTabName);
+ if (nSheetId == EXC_NOTAB)
+ // specified table name not found in this SUPBOOK.
+ return;
+
+ FindSBIndexEntry f(nSupbookId, nSheetId);
+ XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
+ XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
+ if (itr == itrEnd)
+ {
+ maSBIndexVec.push_back(XclExpSBIndex());
+ XclExpSBIndex& r = maSBIndexVec.back();
+ r.mnSupbook = nSupbookId;
+ r.mnSBTab = nSheetId;
+ }
+
+ xSupbook->StoreCell(nSheetId, rCell, *pToken);
+}
+
+void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange )
+{
+ ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
+ const String* pUrl = pRefMgr->getExternalFileName(nFileId);
+ if (!pUrl)
+ return;
+
+ XclExpSupbookRef xSupbook;
+ sal_uInt16 nSupbookId;
+ if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
+ {
+ xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
+ nSupbookId = Append(xSupbook);
+ }
+
+ SCTAB nTabCount = rRange.aEnd.Tab() - rRange.aStart.Tab() + 1;
+
+ // If this is a multi-table range, get token for each table.
+ using namespace ::formula;
+ vector<FormulaToken*> aMatrixList;
+ aMatrixList.reserve(nTabCount);
+
+ // This is a new'ed instance, so we must manage its life cycle here.
+ ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, rRange, NULL);
+ if (!pArray.get())
+ return;
+
+ for (FormulaToken* p = pArray->First(); p; p = pArray->Next())
+ {
+ if (p->GetType() == svMatrix)
+ aMatrixList.push_back(p);
+ else if (p->GetOpCode() != ocSep)
+ {
+ // This is supposed to be ocSep!!!
+ return;
+ }
+ }
+
+ if (aMatrixList.size() != static_cast<size_t>(nTabCount))
+ {
+ // matrix size mis-match !
+ return;
+ }
+
+ sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName);
+
+ ScRange aRange(rRange);
+ aRange.aStart.SetTab(0);
+ aRange.aEnd.SetTab(0);
+ for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+ {
+ sal_uInt16 nSheetId = nFirstSheetId + static_cast<sal_uInt16>(nTab);
+ FindSBIndexEntry f(nSupbookId, nSheetId);
+ XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
+ XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
+ if (itr == itrEnd)
+ {
+ maSBIndexVec.push_back(XclExpSBIndex());
+ XclExpSBIndex& r = maSBIndexVec.back();
+ r.mnSupbook = nSupbookId;
+ r.mnSBTab = nSheetId;
+ }
+
+ xSupbook->StoreCellRange(nSheetId, aRange, *aMatrixList[nTab]);
+ }
+}
+
+bool XclExpSupbookBuffer::InsertAddIn(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rName )
+{
+ XclExpSupbookRef xSupbook;
+ if( mnAddInSB == SAL_MAX_UINT16 )
+ {
+ xSupbook.reset( new XclExpSupbook( GetRoot() ) );
+ mnAddInSB = Append( xSupbook );
+ }
+ else
+ xSupbook = maSupbookList.GetRecord( mnAddInSB );
+ DBG_ASSERT( xSupbook, "XclExpSupbookBuffer::InsertAddin - missing add-in supbook" );
+ rnSupbook = mnAddInSB;
+ rnExtName = xSupbook->InsertAddIn( rName );
+ return rnExtName > 0;
+}
+
+bool XclExpSupbookBuffer::InsertEuroTool(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rName )
+{
+ XclExpSupbookRef xSupbook;
+ String aUrl( RTL_CONSTASCII_USTRINGPARAM("\001\010EUROTOOL.XLA"));
+ if( !GetSupbookUrl( xSupbook, rnSupbook, aUrl ) )
+ {
+ xSupbook.reset( new XclExpSupbook( GetRoot(), aUrl, EXC_SBTYPE_EUROTOOL ) );
+ rnSupbook = Append( xSupbook );
+ }
+ rnExtName = xSupbook->InsertEuroTool( rName );
+ return rnExtName > 0;
+}
+
+bool XclExpSupbookBuffer::InsertDde(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
+ const String& rApplic, const String& rTopic, const String& rItem )
+{
+ XclExpSupbookRef xSupbook;
+ if( !GetSupbookDde( xSupbook, rnSupbook, rApplic, rTopic ) )
+ {
+ xSupbook.reset( new XclExpSupbook( GetRoot(), rApplic, rTopic ) );
+ rnSupbook = Append( xSupbook );
+ }
+ rnExtName = xSupbook->InsertDde( rItem );
+ return rnExtName > 0;
+}
+
+bool XclExpSupbookBuffer::InsertExtName(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rUrl,
+ const String& rName, const ScExternalRefCache::TokenArrayRef pArray )
+{
+ XclExpSupbookRef xSupbook;
+ if (!GetSupbookUrl(xSupbook, rnSupbook, rUrl))
+ {
+ xSupbook.reset( new XclExpSupbook(GetRoot(), rUrl) );
+ rnSupbook = Append(xSupbook);
+ }
+ rnExtName = xSupbook->InsertExtName(rName, pArray);
+ return rnExtName > 0;
+}
+
+XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
+ XclExpRefLogEntry* pRefLogEntry )
+{
+ XclExpXti aXti(0, EXC_NOTAB, EXC_NOTAB);
+ ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
+ const String* pUrl = pRefMgr->getExternalFileName(nFileId);
+ if (!pUrl)
+ return aXti;
+
+ XclExpSupbookRef xSupbook;
+ sal_uInt16 nSupbookId;
+ if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
+ {
+ xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
+ nSupbookId = Append(xSupbook);
+ }
+ aXti.mnSupbook = nSupbookId;
+
+ sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName);
+ if (nFirstSheetId == EXC_NOTAB)
+ {
+ // first sheet not found in SUPBOOK.
+ return aXti;
+ }
+ sal_uInt16 nSheetCount = xSupbook->GetTabCount();
+ for (sal_uInt16 i = 0; i < nXclTabSpan; ++i)
+ {
+ sal_uInt16 nSheetId = nFirstSheetId + i;
+ if (nSheetId >= nSheetCount)
+ return aXti;
+
+ FindSBIndexEntry f(nSupbookId, nSheetId);
+ XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
+ XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
+ if (itr == itrEnd)
+ {
+ maSBIndexVec.push_back(XclExpSBIndex());
+ XclExpSBIndex& r = maSBIndexVec.back();
+ r.mnSupbook = nSupbookId;
+ r.mnSBTab = nSheetId;
+ }
+ if (i == 0)
+ aXti.mnFirstSBTab = nSheetId;
+ if (i == nXclTabSpan - 1)
+ aXti.mnLastSBTab = nSheetId;
+ }
+
+ if (pRefLogEntry)
+ {
+ pRefLogEntry->mnFirstXclTab = 0;
+ pRefLogEntry->mnLastXclTab = 0;
+ if (xSupbook)
+ xSupbook->FillRefLogEntry(*pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab);
+ }
+
+ return aXti;
+}
+
+void XclExpSupbookBuffer::Save( XclExpStream& rStrm )
+{
+ maSupbookList.Save( rStrm );
+}
+
+bool XclExpSupbookBuffer::GetSupbookUrl(
+ XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex, const String& rUrl ) const
+{
+ for( size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; ++nPos )
+ {
+ rxSupbook = maSupbookList.GetRecord( nPos );
+ if( rxSupbook->IsUrlLink( rUrl ) )
+ {
+ rnIndex = ulimit_cast< sal_uInt16 >( nPos );
+ return true;
+ }
+ }
+ return false;
+}
+
+bool XclExpSupbookBuffer::GetSupbookDde( XclExpSupbookRef& rxSupbook,
+ sal_uInt16& rnIndex, const String& rApplic, const String& rTopic ) const
+{
+ for( size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; ++nPos )
+ {
+ rxSupbook = maSupbookList.GetRecord( nPos );
+ if( rxSupbook->IsDdeLink( rApplic, rTopic ) )
+ {
+ rnIndex = ulimit_cast< sal_uInt16 >( nPos );
+ return true;
+ }
+ }
+ return false;
+}
+
+sal_uInt16 XclExpSupbookBuffer::Append( XclExpSupbookRef xSupbook )
+{
+ maSupbookList.AppendRecord( xSupbook );
+ return ulimit_cast< sal_uInt16 >( maSupbookList.GetSize() - 1 );
+}
+
+// Export link manager ========================================================
+
+XclExpLinkManagerImpl::XclExpLinkManagerImpl( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpLinkManagerImpl5::XclExpLinkManagerImpl5( const XclExpRoot& rRoot ) :
+ XclExpLinkManagerImpl( rRoot )
+{
+}
+
+void XclExpLinkManagerImpl5::FindExtSheet(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
+{
+ FindInternal( rnExtSheet, rnFirstXclTab, nFirstScTab );
+ if( (rnFirstXclTab == EXC_TAB_DELETED) || (nFirstScTab == nLastScTab) )
+ {
+ rnLastXclTab = rnFirstXclTab;
+ }
+ else
+ {
+ sal_uInt16 nDummyExtSheet;
+ FindInternal( nDummyExtSheet, rnLastXclTab, nLastScTab );
+ }
+
+ (void)pRefLogEntry; // avoid compiler warning
+ DBG_ASSERT( !pRefLogEntry, "XclExpLinkManagerImpl5::FindExtSheet - fill reflog entry not implemented" );
+}
+
+sal_uInt16 XclExpLinkManagerImpl5::FindExtSheet( sal_Unicode cCode )
+{
+ sal_uInt16 nExtSheet;
+ FindInternal( nExtSheet, cCode );
+ return nExtSheet;
+}
+
+void XclExpLinkManagerImpl5::FindExtSheet(
+ sal_uInt16 /*nFileId*/, const String& /*rTabName*/, sal_uInt16 /*nXclTabSpan*/,
+ sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnFirstSBTab*/, sal_uInt16& /*rnLastSBTab*/,
+ XclExpRefLogEntry* /*pRefLogEntry*/ )
+{
+ // not implemented
+}
+
+void XclExpLinkManagerImpl5::StoreCellRange( const ScSingleRefData& /*rRef1*/, const ScSingleRefData& /*rRef2*/ )
+{
+ // not implemented
+}
+
+void XclExpLinkManagerImpl5::StoreCell( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const ScSingleRefData& /*rRef*/ )
+{
+ // not implemented
+}
+
+void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const ScSingleRefData& /*rRef1*/, const ScSingleRefData& /*rRef2*/ )
+{
+ // not implemented
+}
+
+bool XclExpLinkManagerImpl5::InsertAddIn(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+{
+ XclExpExtSheetRef xExtSheet = FindInternal( rnExtSheet, EXC_EXTSH_ADDIN );
+ if( xExtSheet )
+ {
+ rnExtName = xExtSheet->InsertAddIn( rName );
+ return rnExtName > 0;
+ }
+ return false;
+}
+
+bool XclExpLinkManagerImpl5::InsertEuroTool(
+ sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/, const String& /*rName*/ )
+{
+ return false;
+}
+
+
+bool XclExpLinkManagerImpl5::InsertDde(
+ sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/,
+ const String& /*rApplic*/, const String& /*rTopic*/, const String& /*rItem*/ )
+{
+ // not implemented
+ return false;
+}
+
+bool XclExpLinkManagerImpl5::InsertExtName(
+ sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/, const String& /*rUrl*/,
+ const String& /*rName*/, const ScExternalRefCache::TokenArrayRef /*pArray*/ )
+{
+ // not implemented
+ return false;
+}
+
+void XclExpLinkManagerImpl5::Save( XclExpStream& rStrm )
+{
+ if( sal_uInt16 nExtSheetCount = GetExtSheetCount() )
+ {
+ // EXTERNCOUNT record
+ XclExpUInt16Record( EXC_ID_EXTERNCOUNT, nExtSheetCount ).Save( rStrm );
+ // list of EXTERNSHEET records with EXTERNNAME, XCT, CRN records
+ maExtSheetList.Save( rStrm );
+ }
+}
+
+sal_uInt16 XclExpLinkManagerImpl5::GetExtSheetCount() const
+{
+ return static_cast< sal_uInt16 >( maExtSheetList.GetSize() );
+}
+
+sal_uInt16 XclExpLinkManagerImpl5::AppendInternal( XclExpExtSheetRef xExtSheet )
+{
+ if( GetExtSheetCount() < 0x7FFF )
+ {
+ maExtSheetList.AppendRecord( xExtSheet );
+ // return negated one-based EXTERNSHEET index (i.e. 0xFFFD for 3rd record)
+ return static_cast< sal_uInt16 >( -GetExtSheetCount() );
+ }
+ return 0;
+}
+
+void XclExpLinkManagerImpl5::CreateInternal()
+{
+ if( maIntTabMap.empty() )
+ {
+ // create EXTERNSHEET records for all internal exported sheets
+ XclExpTabInfo& rTabInfo = GetTabInfo();
+ for( SCTAB nScTab = 0, nScCnt = rTabInfo.GetScTabCount(); nScTab < nScCnt; ++nScTab )
+ {
+ if( rTabInfo.IsExportTab( nScTab ) )
+ {
+ XclExpExtSheetRef xRec;
+ if( nScTab == GetCurrScTab() )
+ xRec.reset( new XclExpExternSheet( GetRoot(), EXC_EXTSH_OWNTAB ) );
+ else
+ xRec.reset( new XclExpExternSheet( GetRoot(), rTabInfo.GetScTabName( nScTab ) ) );
+ maIntTabMap[ nScTab ] = AppendInternal( xRec );
+ }
+ }
+ }
+}
+
+XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::GetInternal( sal_uInt16 nExtSheet )
+{
+ return maExtSheetList.GetRecord( static_cast< sal_uInt16 >( -nExtSheet - 1 ) );
+}
+
+XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::FindInternal(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab, SCTAB nScTab )
+{
+ // create internal EXTERNSHEET records on demand
+ CreateInternal();
+
+ // try to find an EXTERNSHEET record - if not, return a "deleted sheet" reference
+ XclExpExtSheetRef xExtSheet;
+ XclExpIntTabMap::const_iterator aIt = maIntTabMap.find( nScTab );
+ if( aIt == maIntTabMap.end() )
+ {
+ xExtSheet = FindInternal( rnExtSheet, EXC_EXTSH_OWNDOC );
+ rnXclTab = EXC_TAB_DELETED;
+ }
+ else
+ {
+ rnExtSheet = aIt->second;
+ xExtSheet = GetInternal( rnExtSheet );
+ rnXclTab = GetTabInfo().GetXclTab( nScTab );
+ }
+ return xExtSheet;
+}
+
+XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::FindInternal(
+ sal_uInt16& rnExtSheet, sal_Unicode cCode )
+{
+ XclExpExtSheetRef xExtSheet;
+ XclExpCodeMap::const_iterator aIt = maCodeMap.find( cCode );
+ if( aIt == maCodeMap.end() )
+ {
+ xExtSheet.reset( new XclExpExternSheet( GetRoot(), cCode ) );
+ rnExtSheet = maCodeMap[ cCode ] = AppendInternal( xExtSheet );
+ }
+ else
+ {
+ rnExtSheet = aIt->second;
+ xExtSheet = GetInternal( rnExtSheet );
+ }
+ return xExtSheet;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpLinkManagerImpl8::XclExpLinkManagerImpl8( const XclExpRoot& rRoot ) :
+ XclExpLinkManagerImpl( rRoot ),
+ maSBBuffer( rRoot )
+{
+}
+
+void XclExpLinkManagerImpl8::FindExtSheet(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
+{
+ XclExpTabInfo& rTabInfo = GetTabInfo();
+ rnFirstXclTab = rTabInfo.GetXclTab( nFirstScTab );
+ rnLastXclTab = rTabInfo.GetXclTab( nLastScTab );
+ rnExtSheet = InsertXti( maSBBuffer.GetXti( rnFirstXclTab, rnLastXclTab, pRefLogEntry ) );
+}
+
+sal_uInt16 XclExpLinkManagerImpl8::FindExtSheet( sal_Unicode cCode )
+{
+ (void)cCode; // avoid compiler warning
+ DBG_ASSERT( (cCode == EXC_EXTSH_OWNDOC) || (cCode == EXC_EXTSH_ADDIN),
+ "XclExpLinkManagerImpl8::FindExtSheet - unknown externsheet code" );
+ return InsertXti( maSBBuffer.GetXti( EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
+}
+
+void XclExpLinkManagerImpl8::FindExtSheet(
+ sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
+ XclExpRefLogEntry* pRefLogEntry )
+{
+ XclExpXti aXti = maSBBuffer.GetXti(nFileId, rTabName, nXclTabSpan, pRefLogEntry);
+ rnExtSheet = InsertXti(aXti);
+ rnFirstSBTab = aXti.mnFirstSBTab;
+ rnLastSBTab = aXti.mnLastSBTab;
+}
+
+void XclExpLinkManagerImpl8::StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 )
+{
+ if( !rRef1.IsDeleted() && !rRef2.IsDeleted() && (rRef1.nTab >= 0) && (rRef2.nTab >= 0) )
+ {
+ const XclExpTabInfo& rTabInfo = GetTabInfo();
+ SCTAB nFirstScTab = static_cast< SCTAB >( rRef1.nTab );
+ SCTAB nLastScTab = static_cast< SCTAB >( rRef2.nTab );
+ ScRange aRange(
+ static_cast< SCCOL >( rRef1.nCol ), static_cast< SCROW >( rRef1.nRow ), 0,
+ static_cast< SCCOL >( rRef2.nCol ), static_cast< SCROW >( rRef2.nRow ), 0 );
+ for( SCTAB nScTab = nFirstScTab; nScTab <= nLastScTab; ++nScTab )
+ {
+ if( rTabInfo.IsExternalTab( nScTab ) )
+ {
+ aRange.aStart.SetTab( nScTab );
+ aRange.aEnd.SetTab( nScTab );
+ maSBBuffer.StoreCellRange( aRange );
+ }
+ }
+ }
+}
+
+void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
+{
+ ScAddress aAddr(rRef.nCol, rRef.nRow, rRef.nTab);
+ maSBBuffer.StoreCell(nFileId, rTabName, aAddr);
+}
+
+void XclExpLinkManagerImpl8::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 )
+{
+ ScRange aRange(static_cast<SCCOL>(rRef1.nCol), static_cast<SCROW>(rRef1.nRow), static_cast<SCTAB>(rRef1.nTab),
+ static_cast<SCCOL>(rRef2.nCol), static_cast<SCROW>(rRef2.nRow), static_cast<SCTAB>(rRef2.nTab));
+ maSBBuffer.StoreCellRange(nFileId, rTabName, aRange);
+}
+
+bool XclExpLinkManagerImpl8::InsertAddIn(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+{
+ sal_uInt16 nSupbook;
+ if( maSBBuffer.InsertAddIn( nSupbook, rnExtName, rName ) )
+ {
+ rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
+ return true;
+ }
+ return false;
+}
+
+bool XclExpLinkManagerImpl8::InsertEuroTool(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+{
+ sal_uInt16 nSupbook;
+ if( maSBBuffer.InsertEuroTool( nSupbook, rnExtName, rName ) )
+ {
+ rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
+ return true;
+ }
+ return false;
+}
+
+
+bool XclExpLinkManagerImpl8::InsertDde(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rApplic, const String& rTopic, const String& rItem )
+{
+ sal_uInt16 nSupbook;
+ if( maSBBuffer.InsertDde( nSupbook, rnExtName, rApplic, rTopic, rItem ) )
+ {
+ rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
+ return true;
+ }
+ return false;
+}
+
+bool XclExpLinkManagerImpl8::InsertExtName( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName, const String& rUrl, const ScExternalRefCache::TokenArrayRef pArray )
+{
+ sal_uInt16 nSupbook;
+ if( maSBBuffer.InsertExtName( nSupbook, rnExtName, rUrl, rName, pArray ) )
+ {
+ rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
+ return true;
+ }
+ return false;
+}
+
+void XclExpLinkManagerImpl8::Save( XclExpStream& rStrm )
+{
+ if( !maXtiVec.empty() )
+ {
+ // SUPBOOKs, XCTs, CRNs, EXTERNNAMEs
+ maSBBuffer.Save( rStrm );
+
+ // EXTERNSHEET
+ sal_uInt16 nCount = ulimit_cast< sal_uInt16 >( maXtiVec.size() );
+ rStrm.StartRecord( EXC_ID_EXTERNSHEET, 2 + 6 * nCount );
+ rStrm << nCount;
+ rStrm.SetSliceSize( 6 );
+ for( XclExpXtiVec::const_iterator aIt = maXtiVec.begin(), aEnd = maXtiVec.end(); aIt != aEnd; ++aIt )
+ aIt->Save( rStrm );
+ rStrm.EndRecord();
+ }
+}
+
+sal_uInt16 XclExpLinkManagerImpl8::InsertXti( const XclExpXti& rXti )
+{
+ for( XclExpXtiVec::const_iterator aIt = maXtiVec.begin(), aEnd = maXtiVec.end(); aIt != aEnd; ++aIt )
+ if( *aIt == rXti )
+ return ulimit_cast< sal_uInt16 >( aIt - maXtiVec.begin() );
+ maXtiVec.push_back( rXti );
+ return ulimit_cast< sal_uInt16 >( maXtiVec.size() - 1 );
+}
+
+// ============================================================================
+
+XclExpLinkManager::XclExpLinkManager( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+ switch( GetBiff() )
+ {
+ case EXC_BIFF5:
+ mxImpl.reset( new XclExpLinkManagerImpl5( rRoot ) );
+ break;
+ case EXC_BIFF8:
+ mxImpl.reset( new XclExpLinkManagerImpl8( rRoot ) );
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+}
+
+XclExpLinkManager::~XclExpLinkManager()
+{
+}
+
+void XclExpLinkManager::FindExtSheet(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab,
+ SCTAB nScTab, XclExpRefLogEntry* pRefLogEntry )
+{
+ mxImpl->FindExtSheet( rnExtSheet, rnXclTab, rnXclTab, nScTab, nScTab, pRefLogEntry );
+}
+
+void XclExpLinkManager::FindExtSheet(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
+{
+ mxImpl->FindExtSheet( rnExtSheet, rnFirstXclTab, rnLastXclTab, nFirstScTab, nLastScTab, pRefLogEntry );
+}
+
+sal_uInt16 XclExpLinkManager::FindExtSheet( sal_Unicode cCode )
+{
+ return mxImpl->FindExtSheet( cCode );
+}
+
+void XclExpLinkManager::FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
+ XclExpRefLogEntry* pRefLogEntry )
+{
+ mxImpl->FindExtSheet( nFileId, rTabName, nXclTabSpan, rnExtSheet, rnFirstSBTab, rnLastSBTab, pRefLogEntry );
+}
+
+void XclExpLinkManager::StoreCell( const ScSingleRefData& rRef )
+{
+ mxImpl->StoreCellRange( rRef, rRef );
+}
+
+void XclExpLinkManager::StoreCellRange( const ScComplexRefData& rRef )
+{
+ mxImpl->StoreCellRange( rRef.Ref1, rRef.Ref2 );
+}
+
+void XclExpLinkManager::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
+{
+ mxImpl->StoreCell( nFileId, rTabName, rRef );
+}
+
+void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef )
+{
+ mxImpl->StoreCellRange( nFileId, rTabName, rRef.Ref1, rRef.Ref2 );
+}
+
+bool XclExpLinkManager::InsertAddIn(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+{
+ return mxImpl->InsertAddIn( rnExtSheet, rnExtName, rName );
+}
+
+bool XclExpLinkManager::InsertEuroTool(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+{
+ return mxImpl->InsertEuroTool( rnExtSheet, rnExtName, rName );
+}
+
+bool XclExpLinkManager::InsertDde(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rApplic, const String& rTopic, const String& rItem )
+{
+ return mxImpl->InsertDde( rnExtSheet, rnExtName, rApplic, rTopic, rItem );
+}
+
+bool XclExpLinkManager::InsertExtName(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName, const String& rUrl,
+ const ScExternalRefCache::TokenArrayRef pArray )
+{
+ return mxImpl->InsertExtName( rnExtSheet, rnExtName, rUrl, rName, pArray );
+}
+
+void XclExpLinkManager::Save( XclExpStream& rStrm )
+{
+ mxImpl->Save( rStrm );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xename.cxx b/sc/source/filter/excel/xename.cxx
new file mode 100644
index 000000000000..69377c5d06f4
--- /dev/null
+++ b/sc/source/filter/excel/xename.cxx
@@ -0,0 +1,767 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xename.hxx"
+
+#include <map>
+
+#include "globstr.hrc"
+#include "document.hxx"
+#include "rangenam.hxx"
+#include "dbcolect.hxx"
+#include "xehelper.hxx"
+#include "xelink.hxx"
+#include "globalnames.hxx"
+
+// for filter manager
+#include "excrecds.hxx"
+
+#include <formula/grammar.hxx>
+
+using namespace ::oox;
+
+using ::rtl::OString;
+
+// ============================================================================
+// *** Helper classes ***
+// ============================================================================
+
+/** Represents an internal defined name, supports writing it to a NAME record. */
+class XclExpName : public XclExpRecord, protected XclExpRoot
+{
+public:
+ /** Creates a standard defined name. */
+ explicit XclExpName( const XclExpRoot& rRoot, const String& rName );
+ /** Creates a built-in defined name. */
+ explicit XclExpName( const XclExpRoot& rRoot, sal_Unicode cBuiltIn );
+
+ /** Sets a token array containing the definition of this name. */
+ void SetTokenArray( XclTokenArrayRef xTokArr );
+ /** Changes this defined name to be local on the specified Calc sheet. */
+ void SetLocalTab( SCTAB nScTab );
+ /** Hides or unhides the defined name. */
+ void SetHidden( bool bHidden = true );
+ /** Changes this name to be the call to a VB macro function or procedure.
+ @param bVBasic true = Visual Basic macro, false = Sheet macro.
+ @param bFunc true = Macro function; false = Macro procedure. */
+ void SetMacroCall( bool bVBasic, bool bFunc );
+
+
+ /** Sets the name's symbol value
+ @param sValue the name's symbolic value */
+ void SetSymbol( String sValue );
+ /** Returns the name's symbol value */
+ inline const String& GetSymbol() const { return msSymbol; }
+
+ /** Returns the original name (title) of this defined name. */
+ inline const String& GetOrigName() const { return maOrigName; }
+ /** Returns the Excel built-in name index of this defined name.
+ @return The built-in name index or EXC_BUILTIN_UNKNOWN for user-defined names. */
+ inline sal_Unicode GetBuiltInName() const { return mcBuiltIn; }
+
+ /** Returns the token array for this defined name. */
+ inline XclTokenArrayRef GetTokenArray() const { return mxTokArr; }
+
+ /** Returns true, if this is a document-global defined name. */
+ inline bool IsGlobal() const { return mnXclTab == EXC_NAME_GLOBAL; }
+ /** Returns the Calc sheet of a local defined name. */
+ inline SCTAB GetScTab() const { return mnScTab; }
+
+ /** Returns true, if this defined name is volatile. */
+ bool IsVolatile() const;
+ /** Returns true, if this defined name is hidden. */
+ bool IsHidden() const;
+ /** Returns true, if this defined name describes a macro call.
+ @param bFunc true = Macro function; false = Macro procedure. */
+ bool IsMacroCall( bool bVBasic, bool bFunc ) const;
+
+ /** Writes the entire NAME record to the passed stream. */
+ virtual void Save( XclExpStream& rStrm );
+
+ virtual void SaveXml( XclExpXmlStream& rStrm );
+
+private:
+ /** Writes the body of the NAME record to the passed stream. */
+ virtual void WriteBody( XclExpStream& rStrm );
+
+private:
+ String maOrigName; /// The original user-defined name.
+ String msSymbol; /// The value of the symbol
+ XclExpStringRef mxName; /// The name as Excel string object.
+ XclTokenArrayRef mxTokArr; /// The definition of the defined name.
+ sal_Unicode mcBuiltIn; /// The built-in index for built-in names.
+ SCTAB mnScTab; /// The Calc sheet index for local names.
+ sal_uInt16 mnFlags; /// Additional flags for this defined name.
+ sal_uInt16 mnExtSheet; /// The 1-based index to a global EXTERNSHEET record.
+ sal_uInt16 mnXclTab; /// The 1-based Excel sheet index for local names.
+};
+
+// ----------------------------------------------------------------------------
+
+class ScRangeData;
+class ScDBData;
+
+/** Implementation class of the name manager. */
+class XclExpNameManagerImpl : protected XclExpRoot
+{
+public:
+ explicit XclExpNameManagerImpl( const XclExpRoot& rRoot );
+
+ /** Creates NAME records for built-in and user defined names. */
+ void Initialize();
+
+ /** Inserts the Calc name with the passed index and returns the Excel NAME index. */
+ sal_uInt16 InsertName( SCTAB nTab, sal_uInt16 nScNameIdx );
+
+ /** Inserts a new built-in defined name. */
+ sal_uInt16 InsertBuiltInName( sal_Unicode cBuiltIn, XclTokenArrayRef xTokArr, SCTAB nScTab );
+ sal_uInt16 InsertBuiltInName( sal_Unicode cBuiltIn, XclTokenArrayRef xTokArr, const ScRange& aRange );
+ /** Inserts a new defined name. Sets another unused name, if rName already exists. */
+ sal_uInt16 InsertUniqueName( const String& rName, XclTokenArrayRef xTokArr, SCTAB nScTab );
+ /** Returns index of an existing name, or creates a name without definition. */
+ sal_uInt16 InsertRawName( const String& rName );
+ /** Searches or inserts a defined name describing a macro name.
+ @param bVBasic true = Visual Basic macro; false = Sheet macro.
+ @param bFunc true = Macro function; false = Macro procedure. */
+ sal_uInt16 InsertMacroCall( const String& rMacroName, bool bVBasic, bool bFunc, bool bHidden );
+
+ /** Returns the NAME record at the specified position or 0 on error. */
+ const XclExpName* GetName( sal_uInt16 nNameIdx ) const;
+
+ /** Writes the entire list of NAME records.
+ @descr In BIFF7 and lower, writes the entire global link table, which
+ consists of an EXTERNCOUNT record, several EXTERNSHEET records, and
+ the list of NAME records. */
+ void Save( XclExpStream& rStrm );
+
+ void SaveXml( XclExpXmlStream& rStrm );
+
+private:
+ typedef XclExpRecordList< XclExpName > XclExpNameList;
+ typedef XclExpNameList::RecordRefType XclExpNameRef;
+ typedef ::std::map< sal_uInt16, sal_uInt16 > XclExpIndexMap;
+
+ typedef ::std::map< ::std::pair<SCTAB, sal_uInt16>, sal_uInt16> NamedExpIndexMap;
+
+private:
+ /**
+ * @param nTab 0-based table index, or SCTAB_GLOBAL for global names.
+ * @param nScIdx calc's name index.
+ *
+ * @return excel's name index.
+ */
+ sal_uInt16 FindNamedExpIndex( SCTAB nTab, sal_uInt16 nScIdx );
+
+ /** Returns the index of an existing built-in NAME record with the passed definition, otherwise 0. */
+ sal_uInt16 FindBuiltInNameIdx( const String& rName,
+ const XclTokenArray& rTokArr, bool bDBRange ) const;
+ /** Returns an unused name for the passed name. */
+ String GetUnusedName( const String& rName ) const;
+
+ /** Appends a new NAME record to the record list.
+ @return The 1-based NAME record index used elsewhere in the Excel file. */
+ sal_uInt16 Append( XclExpNameRef xName );
+ /** Creates a new NAME record for the passed user-defined name.
+ @return The 1-based NAME record index used elsewhere in the Excel file. */
+ sal_uInt16 CreateName( SCTAB nTab, const ScRangeData& rRangeData );
+ /** Creates a new NAME record for the passed database range.
+ @return The 1-based NAME record index used elsewhere in the Excel file. */
+ sal_uInt16 CreateName( const ScDBData& rDBData );
+
+ /** Creates NAME records for all built-in names in the document. */
+ void CreateBuiltInNames();
+ /** Creates NAME records for all user-defined names in the document. */
+ void CreateUserNames();
+
+private:
+ /**
+ * Maps Calc's named range to Excel's NAME records. Global names use
+ * -1 as their table index, whereas sheet-local names have 0-based table
+ * index.
+ */
+ NamedExpIndexMap maNamedExpMap;
+ XclExpNameList maNameList; /// List of NAME records.
+ size_t mnFirstUserIdx; /// List index of first user-defined NAME record.
+};
+
+// ============================================================================
+// *** Implementation ***
+// ============================================================================
+
+XclExpName::XclExpName( const XclExpRoot& rRoot, const String& rName ) :
+ XclExpRecord( EXC_ID_NAME ),
+ XclExpRoot( rRoot ),
+ maOrigName( rName ),
+ mxName( XclExpStringHelper::CreateString( rRoot, rName, EXC_STR_8BITLENGTH ) ),
+ mcBuiltIn( EXC_BUILTIN_UNKNOWN ),
+ mnScTab( SCTAB_GLOBAL ),
+ mnFlags( EXC_NAME_DEFAULT ),
+ mnExtSheet( EXC_NAME_GLOBAL ),
+ mnXclTab( EXC_NAME_GLOBAL )
+{
+}
+
+XclExpName::XclExpName( const XclExpRoot& rRoot, sal_Unicode cBuiltIn ) :
+ XclExpRecord( EXC_ID_NAME ),
+ XclExpRoot( rRoot ),
+ mcBuiltIn( cBuiltIn ),
+ mnScTab( SCTAB_GLOBAL ),
+ mnFlags( EXC_NAME_DEFAULT ),
+ mnExtSheet( EXC_NAME_GLOBAL ),
+ mnXclTab( EXC_NAME_GLOBAL )
+{
+ // filter source range is hidden in Excel
+ if( cBuiltIn == EXC_BUILTIN_FILTERDATABASE )
+ SetHidden();
+
+ // special case for BIFF5/7 filter source range - name appears as plain text without built-in flag
+ if( (GetBiff() <= EXC_BIFF5) && (cBuiltIn == EXC_BUILTIN_FILTERDATABASE) )
+ {
+ String aName( XclTools::GetXclBuiltInDefName( EXC_BUILTIN_FILTERDATABASE ) );
+ mxName = XclExpStringHelper::CreateString( rRoot, aName, EXC_STR_8BITLENGTH );
+ maOrigName = XclTools::GetXclBuiltInDefName( cBuiltIn );
+ }
+ else
+ {
+ maOrigName = XclTools::GetBuiltInDefNameXml( cBuiltIn ) ;
+ mxName = XclExpStringHelper::CreateString( rRoot, cBuiltIn, EXC_STR_8BITLENGTH );
+ ::set_flag( mnFlags, EXC_NAME_BUILTIN );
+ }
+}
+
+void XclExpName::SetTokenArray( XclTokenArrayRef xTokArr )
+{
+ mxTokArr = xTokArr;
+}
+
+void XclExpName::SetLocalTab( SCTAB nScTab )
+{
+ DBG_ASSERT( GetTabInfo().IsExportTab( nScTab ), "XclExpName::SetLocalTab - invalid sheet index" );
+ if( GetTabInfo().IsExportTab( nScTab ) )
+ {
+ mnScTab = nScTab;
+ GetGlobalLinkManager().FindExtSheet( mnExtSheet, mnXclTab, nScTab );
+
+ // special handling for NAME record
+ switch( GetBiff() )
+ {
+ case EXC_BIFF5: // EXTERNSHEET index is positive in NAME record
+ mnExtSheet = ~mnExtSheet + 1;
+ break;
+ case EXC_BIFF8: // EXTERNSHEET index not used, but must be created in link table
+ mnExtSheet = 0;
+ break;
+ default: DBG_ERROR_BIFF();
+ }
+
+ // Excel sheet index is 1-based
+ ++mnXclTab;
+ }
+}
+
+void XclExpName::SetHidden( bool bHidden )
+{
+ ::set_flag( mnFlags, EXC_NAME_HIDDEN, bHidden );
+}
+
+void XclExpName::SetMacroCall( bool bVBasic, bool bFunc )
+{
+ ::set_flag( mnFlags, EXC_NAME_PROC );
+ ::set_flag( mnFlags, EXC_NAME_VB, bVBasic );
+ ::set_flag( mnFlags, EXC_NAME_FUNC, bFunc );
+}
+
+void XclExpName::SetSymbol( String sSymbol )
+{
+ msSymbol = sSymbol;
+}
+
+bool XclExpName::IsVolatile() const
+{
+ return mxTokArr && mxTokArr->IsVolatile();
+}
+
+bool XclExpName::IsHidden() const
+{
+ return ::get_flag( mnFlags, EXC_NAME_HIDDEN );
+}
+
+bool XclExpName::IsMacroCall( bool bVBasic, bool bFunc ) const
+{
+ return
+ (::get_flag( mnFlags, EXC_NAME_VB ) == bVBasic) &&
+ (::get_flag( mnFlags, EXC_NAME_FUNC ) == bFunc);
+}
+
+void XclExpName::Save( XclExpStream& rStrm )
+{
+ DBG_ASSERT( mxName && (mxName->Len() > 0), "XclExpName::Save - missing name" );
+ DBG_ASSERT( !(IsGlobal() && ::get_flag( mnFlags, EXC_NAME_BUILTIN )), "XclExpName::Save - global built-in name" );
+ SetRecSize( 11 + mxName->GetSize() + (mxTokArr ? mxTokArr->GetSize() : 2) );
+ XclExpRecord::Save( rStrm );
+}
+
+void XclExpName::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
+ rWorkbook->startElement( XML_definedName,
+ // OOXTODO: XML_comment, "",
+ // OOXTODO: XML_customMenu, "",
+ // OOXTODO: XML_description, "",
+ XML_function, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_NAME_VB ) ),
+ // OOXTODO: XML_functionGroupId, "",
+ // OOXTODO: XML_help, "",
+ XML_hidden, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_NAME_HIDDEN ) ),
+ XML_localSheetId, mnScTab == SCTAB_GLOBAL ? NULL : OString::valueOf( (sal_Int32)mnScTab ).getStr(),
+ XML_name, XclXmlUtils::ToOString( maOrigName ).getStr(),
+ // OOXTODO: XML_publishToServer, "",
+ // OOXTODO: XML_shortcutKey, "",
+ // OOXTODO: XML_statusBar, "",
+ XML_vbProcedure, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_NAME_VB ) ),
+ // OOXTODO: XML_workbookParameter, "",
+ // OOXTODO: XML_xlm, "",
+ FSEND );
+ rWorkbook->writeEscaped( XclXmlUtils::ToOUString( msSymbol ) );
+ rWorkbook->endElement( XML_definedName );
+}
+
+void XclExpName::WriteBody( XclExpStream& rStrm )
+{
+ sal_uInt16 nFmlaSize = mxTokArr ? mxTokArr->GetSize() : 0;
+
+ rStrm << mnFlags // flags
+ << sal_uInt8( 0 ); // keyboard shortcut
+ mxName->WriteLenField( rStrm ); // length of name
+ rStrm << nFmlaSize // size of token array
+ << mnExtSheet // BIFF5/7: EXTSHEET index, BIFF8: not used
+ << mnXclTab // 1-based sheet index for local names
+ << sal_uInt32( 0 ); // length of menu/descr/help/status text
+ mxName->WriteFlagField( rStrm ); // BIFF8 flag field (no-op in <=BIFF7)
+ mxName->WriteBuffer( rStrm ); // character array of the name
+ if( mxTokArr )
+ mxTokArr->WriteArray( rStrm ); // token array without size
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpNameManagerImpl::XclExpNameManagerImpl( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mnFirstUserIdx( 0 )
+{
+}
+
+void XclExpNameManagerImpl::Initialize()
+{
+ CreateBuiltInNames();
+ mnFirstUserIdx = maNameList.GetSize();
+ CreateUserNames();
+}
+
+sal_uInt16 XclExpNameManagerImpl::InsertName( SCTAB nTab, sal_uInt16 nScNameIdx )
+{
+ sal_uInt16 nNameIdx = FindNamedExpIndex( nTab, nScNameIdx );
+ if (nNameIdx)
+ return nNameIdx;
+
+ const ScRangeData* pData = NULL;
+ ScRangeName* pRN = (nTab == SCTAB_GLOBAL) ? GetDoc().GetRangeName() : GetDoc().GetRangeName(nTab);
+ if (pRN)
+ pData = pRN->findByIndex(nScNameIdx);
+
+ if (pData)
+ nNameIdx = CreateName(nTab, *pData);
+
+ return nNameIdx;
+}
+
+sal_uInt16 XclExpNameManagerImpl::InsertBuiltInName( sal_Unicode cBuiltIn, XclTokenArrayRef xTokArr, const ScRange& aRange )
+{
+ XclExpNameRef xName( new XclExpName( GetRoot(), cBuiltIn ) );
+ xName->SetTokenArray( xTokArr );
+ xName->SetLocalTab( aRange.aStart.Tab() );
+ String sSymbol;
+ aRange.Format( sSymbol, SCR_ABS_3D, GetDocPtr(), ScAddress::Details( ::formula::FormulaGrammar::CONV_XL_A1 ) );
+ xName->SetSymbol( sSymbol );
+ return Append( xName );
+}
+
+sal_uInt16 XclExpNameManagerImpl::InsertBuiltInName( sal_Unicode cBuiltIn, XclTokenArrayRef xTokArr, SCTAB nScTab )
+{
+ XclExpNameRef xName( new XclExpName( GetRoot(), cBuiltIn ) );
+ xName->SetTokenArray( xTokArr );
+ xName->SetLocalTab( nScTab );
+ return Append( xName );
+}
+
+sal_uInt16 XclExpNameManagerImpl::InsertUniqueName(
+ const String& rName, XclTokenArrayRef xTokArr, SCTAB nScTab )
+{
+ DBG_ASSERT( rName.Len(), "XclExpNameManagerImpl::InsertUniqueName - empty name" );
+ XclExpNameRef xName( new XclExpName( GetRoot(), GetUnusedName( rName ) ) );
+ xName->SetTokenArray( xTokArr );
+ xName->SetLocalTab( nScTab );
+ return Append( xName );
+}
+
+sal_uInt16 XclExpNameManagerImpl::InsertRawName( const String& rName )
+{
+ // empty name? may occur in broken external Calc tokens
+ if( !rName.Len() )
+ return 0;
+
+ // try to find an existing NAME record, regardless of its type
+ for( size_t nListIdx = mnFirstUserIdx, nListSize = maNameList.GetSize(); nListIdx < nListSize; ++nListIdx )
+ {
+ XclExpNameRef xName = maNameList.GetRecord( nListIdx );
+ if( xName->IsGlobal() && (xName->GetOrigName() == rName) )
+ return static_cast< sal_uInt16 >( nListIdx + 1 );
+ }
+
+ // create a new NAME record
+ XclExpNameRef xName( new XclExpName( GetRoot(), rName ) );
+ return Append( xName );
+}
+
+sal_uInt16 XclExpNameManagerImpl::InsertMacroCall( const String& rMacroName, bool bVBasic, bool bFunc, bool bHidden )
+{
+ // empty name? may occur in broken external Calc tokens
+ if( !rMacroName.Len() )
+ return 0;
+
+ // try to find an existing NAME record
+ for( size_t nListIdx = mnFirstUserIdx, nListSize = maNameList.GetSize(); nListIdx < nListSize; ++nListIdx )
+ {
+ XclExpNameRef xName = maNameList.GetRecord( nListIdx );
+ if( xName->IsMacroCall( bVBasic, bFunc ) && (xName->GetOrigName() == rMacroName) )
+ return static_cast< sal_uInt16 >( nListIdx + 1 );
+ }
+
+ // create a new NAME record
+ XclExpNameRef xName( new XclExpName( GetRoot(), rMacroName ) );
+ xName->SetMacroCall( bVBasic, bFunc );
+ xName->SetHidden( bHidden );
+
+ // for sheet macros, add a #NAME! error
+ if( !bVBasic )
+ xName->SetTokenArray( GetFormulaCompiler().CreateErrorFormula( EXC_ERR_NAME ) );
+
+ return Append( xName );
+}
+
+const XclExpName* XclExpNameManagerImpl::GetName( sal_uInt16 nNameIdx ) const
+{
+ DBG_ASSERT( maNameList.HasRecord( nNameIdx - 1 ), "XclExpNameManagerImpl::GetName - wrong record index" );
+ return maNameList.GetRecord( nNameIdx - 1 ).get();
+}
+
+void XclExpNameManagerImpl::Save( XclExpStream& rStrm )
+{
+ maNameList.Save( rStrm );
+}
+
+void XclExpNameManagerImpl::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( maNameList.IsEmpty() )
+ return;
+ sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
+ rWorkbook->startElement( XML_definedNames, FSEND );
+ maNameList.SaveXml( rStrm );
+ rWorkbook->endElement( XML_definedNames );
+}
+
+// private --------------------------------------------------------------------
+
+sal_uInt16 XclExpNameManagerImpl::FindNamedExpIndex( SCTAB nTab, sal_uInt16 nScIdx )
+{
+ NamedExpIndexMap::key_type key = NamedExpIndexMap::key_type(nTab, nScIdx);
+ NamedExpIndexMap::const_iterator itr = maNamedExpMap.find(key);
+ return (itr == maNamedExpMap.end()) ? 0 : itr->second;
+}
+
+sal_uInt16 XclExpNameManagerImpl::FindBuiltInNameIdx(
+ const String& rName, const XclTokenArray& rTokArr, bool bDBRange ) const
+{
+ /* Get built-in index from the name. Special case: the database range
+ 'unnamed' will be mapped to Excel's built-in '_FilterDatabase' name. */
+ sal_Unicode cBuiltIn = (bDBRange && (rName == String(RTL_CONSTASCII_USTRINGPARAM(STR_DB_LOCAL_NONAME)))) ?
+ EXC_BUILTIN_FILTERDATABASE : XclTools::GetBuiltInDefNameIndex( rName );
+
+ if( cBuiltIn < EXC_BUILTIN_UNKNOWN )
+ {
+ // try to find the record in existing built-in NAME record list
+ for( size_t nPos = 0; nPos < mnFirstUserIdx; ++nPos )
+ {
+ XclExpNameRef xName = maNameList.GetRecord( nPos );
+ if( xName->GetBuiltInName() == cBuiltIn )
+ {
+ XclTokenArrayRef xTokArr = xName->GetTokenArray();
+ if( xTokArr && (*xTokArr == rTokArr) )
+ return static_cast< sal_uInt16 >( nPos + 1 );
+ }
+ }
+ }
+ return 0;
+}
+
+String XclExpNameManagerImpl::GetUnusedName( const String& rName ) const
+{
+ String aNewName( rName );
+ sal_Int32 nAppIdx = 0;
+ bool bExist = true;
+ while( bExist )
+ {
+ // search the list of user-defined names
+ bExist = false;
+ for( size_t nPos = mnFirstUserIdx, nSize = maNameList.GetSize(); !bExist && (nPos < nSize); ++nPos )
+ {
+ XclExpNameRef xName = maNameList.GetRecord( nPos );
+ bExist = xName->GetOrigName() == aNewName;
+ // name exists -> create a new name "<originalname>_<counter>"
+ if( bExist )
+ aNewName.Assign( rName ).Append( '_' ).Append( String::CreateFromInt32( ++nAppIdx ) );
+ }
+ }
+ return aNewName;
+}
+
+sal_uInt16 XclExpNameManagerImpl::Append( XclExpNameRef xName )
+{
+ if( maNameList.GetSize() == 0xFFFF )
+ return 0;
+ maNameList.AppendRecord( xName );
+ return static_cast< sal_uInt16 >( maNameList.GetSize() ); // 1-based
+}
+
+sal_uInt16 XclExpNameManagerImpl::CreateName( SCTAB nTab, const ScRangeData& rRangeData )
+{
+ const String& rName = rRangeData.GetName();
+
+ /* #i38821# recursive names: first insert the (empty) name object,
+ otherwise a recursive call of this function from the formula compiler
+ with the same defined name will not find it and will create it again. */
+ size_t nOldListSize = maNameList.GetSize();
+ XclExpNameRef xName( new XclExpName( GetRoot(), rName ) );
+ if (nTab != SCTAB_GLOBAL)
+ xName->SetLocalTab(nTab);
+ sal_uInt16 nNameIdx = Append( xName );
+ // store the index of the NAME record in the lookup map
+ NamedExpIndexMap::key_type key = NamedExpIndexMap::key_type(nTab, rRangeData.GetIndex());
+ maNamedExpMap[key] = nNameIdx;
+
+ /* Create the definition formula.
+ This may cause recursive creation of other defined names. */
+ if( const ScTokenArray* pScTokArr = const_cast< ScRangeData& >( rRangeData ).GetCode() )
+ {
+ XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, *pScTokArr );
+ xName->SetTokenArray( xTokArr );
+
+ String sSymbol;
+ rRangeData.GetSymbol( sSymbol, formula::FormulaGrammar::GRAM_ENGLISH_XL_A1 );
+ xName->SetSymbol( sSymbol );
+
+ /* Try to replace by existing built-in name - complete token array is
+ needed for comparison, and due to the recursion problem above this
+ cannot be done earlier. If a built-in name is found, the created NAME
+ record for this name and all following records in the list must be
+ deleted, otherwise they may contain wrong name list indexes. */
+ sal_uInt16 nBuiltInIdx = FindBuiltInNameIdx( rName, *xTokArr, false );
+ if( nBuiltInIdx != 0 )
+ {
+ // delete the new NAME records
+ while( maNameList.GetSize() > nOldListSize )
+ maNameList.RemoveRecord( maNameList.GetSize() - 1 );
+ // use index of the found built-in NAME record
+ key = NamedExpIndexMap::key_type(nTab, rRangeData.GetIndex());
+ maNamedExpMap[key] = nNameIdx = nBuiltInIdx;
+ }
+ }
+
+ return nNameIdx;
+}
+
+void XclExpNameManagerImpl::CreateBuiltInNames()
+{
+ ScDocument& rDoc = GetDoc();
+ XclExpTabInfo& rTabInfo = GetTabInfo();
+
+ /* #i2394# built-in defined names must be sorted by the name of the
+ containing sheet. Example: SheetA!Print_Range must be stored *before*
+ SheetB!Print_Range, regardless of the position of SheetA in the document! */
+ for( SCTAB nScTabIdx = 0, nScTabCount = rTabInfo.GetScTabCount(); nScTabIdx < nScTabCount; ++nScTabIdx )
+ {
+ // find real sheet index from the nScTabIdx counter
+ SCTAB nScTab = rTabInfo.GetRealScTab( nScTabIdx );
+ // create NAME records for all built-in names of this sheet
+ if( rTabInfo.IsExportTab( nScTab ) )
+ {
+ // *** 1) print ranges *** ----------------------------------------
+
+ if( rDoc.HasPrintRange() )
+ {
+ ScRangeList aRangeList;
+ for( sal_uInt16 nIdx = 0, nCount = rDoc.GetPrintRangeCount( nScTab ); nIdx < nCount; ++nIdx )
+ {
+ ScRange aRange( *rDoc.GetPrintRange( nScTab, nIdx ) );
+ // Calc document does not care about sheet index in print ranges
+ aRange.aStart.SetTab( nScTab );
+ aRange.aEnd.SetTab( nScTab );
+ aRange.Justify();
+ aRangeList.Append( aRange );
+ }
+ // create the NAME record (do not warn if ranges are shrunken)
+ GetAddressConverter().ValidateRangeList( aRangeList, false );
+ if( !aRangeList.empty() )
+ GetNameManager().InsertBuiltInName( EXC_BUILTIN_PRINTAREA, aRangeList );
+ }
+
+ // *** 2) print titles *** ----------------------------------------
+
+ ScRangeList aTitleList;
+ // repeated columns
+ if( const ScRange* pColRange = rDoc.GetRepeatColRange( nScTab ) )
+ aTitleList.Append( ScRange(
+ pColRange->aStart.Col(), 0, nScTab,
+ pColRange->aEnd.Col(), GetXclMaxPos().Row(), nScTab ) );
+ // repeated rows
+ if( const ScRange* pRowRange = rDoc.GetRepeatRowRange( nScTab ) )
+ aTitleList.Append( ScRange(
+ 0, pRowRange->aStart.Row(), nScTab,
+ GetXclMaxPos().Col(), pRowRange->aEnd.Row(), nScTab ) );
+ // create the NAME record
+ GetAddressConverter().ValidateRangeList( aTitleList, false );
+ if( !aTitleList.empty() )
+ GetNameManager().InsertBuiltInName( EXC_BUILTIN_PRINTTITLES, aTitleList );
+
+ // *** 3) filter ranges *** ---------------------------------------
+
+ if( GetBiff() == EXC_BIFF8 )
+ GetFilterManager().InitTabFilter( nScTab );
+ }
+ }
+}
+
+void XclExpNameManagerImpl::CreateUserNames()
+{
+ const ScRangeName& rNamedRanges = GetNamedRanges();
+ ScRangeName::const_iterator itr = rNamedRanges.begin(), itrEnd = rNamedRanges.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ // skip definitions of shared formulas
+ if (!itr->HasType(RT_SHARED) && !FindNamedExpIndex(SCTAB_GLOBAL, itr->GetIndex()))
+ CreateName(SCTAB_GLOBAL, *itr);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpNameManager::XclExpNameManager( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mxImpl( new XclExpNameManagerImpl( rRoot ) )
+{
+}
+
+XclExpNameManager::~XclExpNameManager()
+{
+}
+
+void XclExpNameManager::Initialize()
+{
+ mxImpl->Initialize();
+}
+
+sal_uInt16 XclExpNameManager::InsertName( SCTAB nTab, sal_uInt16 nScNameIdx )
+{
+ return mxImpl->InsertName( nTab, nScNameIdx );
+}
+
+sal_uInt16 XclExpNameManager::InsertBuiltInName( sal_Unicode cBuiltIn, const ScRange& rRange )
+{
+ XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, rRange );
+ return mxImpl->InsertBuiltInName( cBuiltIn, xTokArr, rRange );
+}
+
+sal_uInt16 XclExpNameManager::InsertBuiltInName( sal_Unicode cBuiltIn, const ScRangeList& rRangeList )
+{
+ sal_uInt16 nNameIdx = 0;
+ if( !rRangeList.empty() )
+ {
+ XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, rRangeList );
+ nNameIdx = mxImpl->InsertBuiltInName( cBuiltIn, xTokArr, rRangeList.front()->aStart.Tab() );
+ }
+ return nNameIdx;
+}
+
+sal_uInt16 XclExpNameManager::InsertUniqueName(
+ const String& rName, XclTokenArrayRef xTokArr, SCTAB nScTab )
+{
+ return mxImpl->InsertUniqueName( rName, xTokArr, nScTab );
+}
+
+sal_uInt16 XclExpNameManager::InsertRawName( const String& rName )
+{
+ return mxImpl->InsertRawName( rName );
+}
+
+sal_uInt16 XclExpNameManager::InsertMacroCall( const String& rMacroName, bool bVBasic, bool bFunc, bool bHidden )
+{
+ return mxImpl->InsertMacroCall( rMacroName, bVBasic, bFunc, bHidden );
+}
+
+const String& XclExpNameManager::GetOrigName( sal_uInt16 nNameIdx ) const
+{
+ const XclExpName* pName = mxImpl->GetName( nNameIdx );
+ return pName ? pName->GetOrigName() : EMPTY_STRING;
+}
+
+SCTAB XclExpNameManager::GetScTab( sal_uInt16 nNameIdx ) const
+{
+ const XclExpName* pName = mxImpl->GetName( nNameIdx );
+ return pName ? pName->GetScTab() : SCTAB_GLOBAL;
+}
+
+bool XclExpNameManager::IsVolatile( sal_uInt16 nNameIdx ) const
+{
+ const XclExpName* pName = mxImpl->GetName( nNameIdx );
+ return pName && pName->IsVolatile();
+}
+
+void XclExpNameManager::Save( XclExpStream& rStrm )
+{
+ mxImpl->Save( rStrm );
+}
+
+void XclExpNameManager::SaveXml( XclExpXmlStream& rStrm )
+{
+ mxImpl->SaveXml( rStrm );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xepage.cxx b/sc/source/filter/excel/xepage.cxx
new file mode 100644
index 000000000000..3831bc7822ac
--- /dev/null
+++ b/sc/source/filter/excel/xepage.cxx
@@ -0,0 +1,436 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "xepage.hxx"
+#include <svl/itemset.hxx>
+#include "scitems.hxx"
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/brshitem.hxx>
+#include "document.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "attrib.hxx"
+#include "xehelper.hxx"
+#include "xeescher.hxx"
+
+#include <set>
+#include <limits>
+
+using namespace ::oox;
+
+using ::rtl::OString;
+using ::std::set;
+using ::std::numeric_limits;
+
+// Page settings records ======================================================
+
+// Header/footer --------------------------------------------------------------
+
+XclExpHeaderFooter::XclExpHeaderFooter( sal_uInt16 nRecId, const String& rHdrString ) :
+ XclExpRecord( nRecId ),
+ maHdrString( rHdrString )
+{
+}
+
+void XclExpHeaderFooter::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ sal_Int32 nElement = GetRecId() == EXC_ID_HEADER ? XML_oddHeader : XML_oddFooter;
+ rWorksheet->startElement( nElement, FSEND );
+ rWorksheet->writeEscaped( XclXmlUtils::ToOUString( maHdrString ) );
+ rWorksheet->endElement( nElement );
+}
+
+void XclExpHeaderFooter::WriteBody( XclExpStream& rStrm )
+{
+ if( maHdrString.Len() )
+ {
+ XclExpString aExString;
+ if( rStrm.GetRoot().GetBiff() <= EXC_BIFF5 )
+ aExString.AssignByte( maHdrString, rStrm.GetRoot().GetTextEncoding(), EXC_STR_8BITLENGTH );
+ else
+ aExString.Assign( maHdrString, EXC_STR_DEFAULT, 255 ); // 16-bit length, but max 255 chars
+ rStrm << aExString;
+ }
+}
+
+// General page settings ------------------------------------------------------
+
+XclExpSetup::XclExpSetup( const XclPageData& rPageData ) :
+ XclExpRecord( EXC_ID_SETUP, 34 ),
+ mrData( rPageData )
+{
+}
+
+void XclExpSetup::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FastAttributeList* pAttrList=rStrm.GetCurrentStream()->createAttrList();
+ if( rStrm.getVersion() != oox::core::ISOIEC_29500_2008 ||
+ mrData.mnStrictPaperSize != EXC_PAPERSIZE_USER )
+ {
+ pAttrList->add( XML_paperSize, OString::valueOf( (sal_Int32) mrData.mnPaperSize ).getStr() );
+ }
+ else
+ {
+ pAttrList->add( XML_paperWidth, OString::valueOf( (sal_Int32) mrData.mnPaperWidth ).concat(OString("mm")).getStr() );
+ pAttrList->add( XML_paperHeight, OString::valueOf( (sal_Int32) mrData.mnPaperHeight ).concat(OString("mm")).getStr() );
+ // pAttrList->add( XML_paperUnits, "mm" );
+ }
+ pAttrList->add( XML_scale, OString::valueOf( (sal_Int32) mrData.mnScaling ).getStr() );
+ pAttrList->add( XML_firstPageNumber, OString::valueOf( (sal_Int32) mrData.mnStartPage ).getStr() );
+ pAttrList->add( XML_fitToWidth, OString::valueOf( (sal_Int32) mrData.mnFitToWidth ).getStr() );
+ pAttrList->add( XML_fitToHeight, OString::valueOf( (sal_Int32) mrData.mnFitToHeight ).getStr() );
+ pAttrList->add( XML_pageOrder, mrData.mbPrintInRows ? "overThenDown" : "downThenOver" );
+ pAttrList->add( XML_orientation, mrData.mbPortrait ? "portrait" : "landscape" ); // OOXTODO: "default"?
+ pAttrList->add( XML_usePrinterDefaults, XclXmlUtils::ToPsz( !mrData.mbValid ) );
+ pAttrList->add( XML_blackAndWhite, XclXmlUtils::ToPsz( mrData.mbBlackWhite ) );
+ pAttrList->add( XML_draft, XclXmlUtils::ToPsz( mrData.mbDraftQuality ) );
+ pAttrList->add( XML_cellComments, mrData.mbPrintNotes ? "atEnd" : "none" ); // OOXTODO: "asDisplayed"?
+ pAttrList->add( XML_useFirstPageNumber, XclXmlUtils::ToPsz( mrData.mbManualStart ) );
+ // OOXTODO: XML_errors, // == displayed|blank|dash|NA
+ pAttrList->add( XML_horizontalDpi, OString::valueOf( (sal_Int32) mrData.mnHorPrintRes ).getStr() );
+ pAttrList->add( XML_verticalDpi, OString::valueOf( (sal_Int32) mrData.mnVerPrintRes ).getStr() );
+ pAttrList->add( XML_copies, OString::valueOf( (sal_Int32) mrData.mnCopies ).getStr() );
+ // OOXTODO: devMode settings part RelationshipId: FSNS( XML_r, XML_id ),
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList > aAttrs(pAttrList);
+ rStrm.GetCurrentStream()->singleElement( XML_pageSetup, aAttrs );
+}
+
+void XclExpSetup::WriteBody( XclExpStream& rStrm )
+{
+ XclBiff eBiff = rStrm.GetRoot().GetBiff();
+
+ sal_uInt16 nFlags = 0;
+ ::set_flag( nFlags, EXC_SETUP_INROWS, mrData.mbPrintInRows );
+ ::set_flag( nFlags, EXC_SETUP_PORTRAIT, mrData.mbPortrait );
+ ::set_flag( nFlags, EXC_SETUP_INVALID, !mrData.mbValid );
+ ::set_flag( nFlags, EXC_SETUP_BLACKWHITE, mrData.mbBlackWhite );
+ if( eBiff >= EXC_BIFF5 )
+ {
+ ::set_flag( nFlags, EXC_SETUP_DRAFT, mrData.mbDraftQuality );
+ /* Set the Comments/Notes to "At end of sheet" if Print Notes is true.
+ We don't currently support "as displayed on sheet". Thus this value
+ will be re-interpreted to "At end of sheet". */
+ const sal_uInt16 nNotes = EXC_SETUP_PRINTNOTES | EXC_SETUP_NOTES_END;
+ ::set_flag( nFlags, nNotes, mrData.mbPrintNotes );
+ ::set_flag( nFlags, EXC_SETUP_STARTPAGE, mrData.mbManualStart );
+ }
+
+ rStrm << mrData.mnPaperSize << mrData.mnScaling << mrData.mnStartPage
+ << mrData.mnFitToWidth << mrData.mnFitToHeight << nFlags;
+ if( eBiff >= EXC_BIFF5 )
+ {
+ rStrm << mrData.mnHorPrintRes << mrData.mnVerPrintRes
+ << mrData.mfHeaderMargin << mrData.mfFooterMargin << mrData.mnCopies;
+ }
+}
+
+// Manual page breaks ---------------------------------------------------------
+
+XclExpPageBreaks::XclExpPageBreaks( sal_uInt16 nRecId, const ScfUInt16Vec& rPageBreaks, sal_uInt16 nMaxPos ) :
+ XclExpRecord( nRecId ),
+ mrPageBreaks( rPageBreaks ),
+ mnMaxPos( nMaxPos )
+{
+}
+
+void XclExpPageBreaks::Save( XclExpStream& rStrm )
+{
+ if( !mrPageBreaks.empty() )
+ {
+ SetRecSize( 2 + ((rStrm.GetRoot().GetBiff() <= EXC_BIFF5) ? 2 : 6) * mrPageBreaks.size() );
+ XclExpRecord::Save( rStrm );
+ }
+}
+
+void XclExpPageBreaks::WriteBody( XclExpStream& rStrm )
+{
+ bool bWriteRange = (rStrm.GetRoot().GetBiff() == EXC_BIFF8);
+
+ rStrm << static_cast< sal_uInt16 >( mrPageBreaks.size() );
+ for( ScfUInt16Vec::const_iterator aIt = mrPageBreaks.begin(), aEnd = mrPageBreaks.end(); aIt != aEnd; ++aIt )
+ {
+ rStrm << *aIt;
+ if( bWriteRange )
+ rStrm << sal_uInt16( 0 ) << mnMaxPos;
+ }
+}
+
+void XclExpPageBreaks::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( mrPageBreaks.empty() )
+ return;
+
+ sal_Int32 nElement = GetRecId() == EXC_ID_HORPAGEBREAKS ? XML_rowBreaks : XML_colBreaks;
+ sax_fastparser::FSHelperPtr& pWorksheet = rStrm.GetCurrentStream();
+ OString sNumPageBreaks = OString::valueOf( (sal_Int32) mrPageBreaks.size() );
+ pWorksheet->startElement( nElement,
+ XML_count, sNumPageBreaks.getStr(),
+ XML_manualBreakCount, sNumPageBreaks.getStr(),
+ FSEND );
+ for( ScfUInt16Vec::const_iterator aIt = mrPageBreaks.begin(), aEnd = mrPageBreaks.end(); aIt != aEnd; ++aIt )
+ {
+ pWorksheet->singleElement( XML_brk,
+ XML_id, OString::valueOf( (sal_Int32) *aIt ).getStr(),
+ XML_man, "true",
+ XML_max, OString::valueOf( (sal_Int32) mnMaxPos ).getStr(),
+ XML_min, "0",
+ // OOXTODO: XML_pt, "",
+ FSEND );
+ }
+ pWorksheet->endElement( nElement );
+}
+
+// Page settings ==============================================================
+
+XclExpPageSettings::XclExpPageSettings( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+ ScDocument& rDoc = GetDoc();
+ SCTAB nScTab = GetCurrScTab();
+
+ if( SfxStyleSheetBase* pStyleSheet = GetStyleSheetPool().Find( rDoc.GetPageStyle( nScTab ), SFX_STYLE_FAMILY_PAGE ) )
+ {
+ const SfxItemSet& rItemSet = pStyleSheet->GetItemSet();
+ maData.mbValid = true;
+
+ // *** page settings ***
+
+ maData.mbPrintInRows = !GETITEMBOOL( rItemSet, ATTR_PAGE_TOPDOWN );
+ maData.mbHorCenter = GETITEMBOOL( rItemSet, ATTR_PAGE_HORCENTER );
+ maData.mbVerCenter = GETITEMBOOL( rItemSet, ATTR_PAGE_VERCENTER );
+ maData.mbPrintHeadings = GETITEMBOOL( rItemSet, ATTR_PAGE_HEADERS );
+ maData.mbPrintGrid = GETITEMBOOL( rItemSet, ATTR_PAGE_GRID );
+ maData.mbPrintNotes = GETITEMBOOL( rItemSet, ATTR_PAGE_NOTES );
+
+ maData.mnStartPage = GETITEMVALUE( rItemSet, SfxUInt16Item, ATTR_PAGE_FIRSTPAGENO, sal_uInt16 );
+ maData.mbManualStart = maData.mnStartPage && (!nScTab || rDoc.NeedPageResetAfterTab( nScTab - 1 ));
+
+ const SvxLRSpaceItem& rLRItem = GETITEM( rItemSet, SvxLRSpaceItem, ATTR_LRSPACE );
+ maData.mfLeftMargin = XclTools::GetInchFromTwips( rLRItem.GetLeft() );
+ maData.mfRightMargin = XclTools::GetInchFromTwips( rLRItem.GetRight() );
+ const SvxULSpaceItem& rULItem = GETITEM( rItemSet, SvxULSpaceItem, ATTR_ULSPACE );
+ maData.mfTopMargin = XclTools::GetInchFromTwips( rULItem.GetUpper() );
+ maData.mfBottomMargin = XclTools::GetInchFromTwips( rULItem.GetLower() );
+
+ const SvxPageItem& rPageItem = GETITEM( rItemSet, SvxPageItem, ATTR_PAGE );
+ const SvxSizeItem& rSizeItem = GETITEM( rItemSet, SvxSizeItem, ATTR_PAGE_SIZE );
+ maData.SetScPaperSize( rSizeItem.GetSize(), !rPageItem.IsLandscape() );
+
+ const ScPageScaleToItem& rScaleToItem = GETITEM( rItemSet, ScPageScaleToItem, ATTR_PAGE_SCALETO );
+ sal_uInt16 nPages = GETITEMVALUE( rItemSet, SfxUInt16Item, ATTR_PAGE_SCALETOPAGES, sal_uInt16 );
+ sal_uInt16 nScale = GETITEMVALUE( rItemSet, SfxUInt16Item, ATTR_PAGE_SCALE, sal_uInt16 );
+
+ if( ScfTools::CheckItem( rItemSet, ATTR_PAGE_SCALETO, false ) && rScaleToItem.IsValid() )
+ {
+ maData.mnFitToWidth = rScaleToItem.GetWidth();
+ maData.mnFitToHeight = rScaleToItem.GetHeight();
+ maData.mbFitToPages = true;
+
+ }
+ else if( ScfTools::CheckItem( rItemSet, ATTR_PAGE_SCALETOPAGES, false ) && nPages )
+ {
+ maData.mnFitToWidth = 1;
+ maData.mnFitToHeight = nPages;
+ maData.mbFitToPages = true;
+ }
+ else if( nScale )
+ {
+ maData.mnScaling = nScale;
+ maData.mbFitToPages = false;
+ }
+
+ maData.mxBrushItem.reset( new SvxBrushItem( GETITEM( rItemSet, SvxBrushItem, ATTR_BACKGROUND ) ) );
+
+ // *** header and footer ***
+
+ XclExpHFConverter aHFConv( GetRoot() );
+
+ // header
+ const SfxItemSet& rHdrItemSet = GETITEM( rItemSet, SvxSetItem, ATTR_PAGE_HEADERSET ).GetItemSet();
+ if( GETITEMBOOL( rHdrItemSet, ATTR_PAGE_ON ) )
+ {
+ const ScPageHFItem& rHFItem = GETITEM( rItemSet, ScPageHFItem, ATTR_PAGE_HEADERRIGHT );
+ aHFConv.GenerateString( rHFItem.GetLeftArea(), rHFItem.GetCenterArea(), rHFItem.GetRightArea() );
+ maData.maHeader = aHFConv.GetHFString();
+ // header height (Excel excludes header from top margin)
+ sal_Int32 nHdrHeight = GETITEMBOOL( rHdrItemSet, ATTR_PAGE_DYNAMIC ) ?
+ // dynamic height: calculate header height, add header <-> sheet area distance
+ (aHFConv.GetTotalHeight() + GETITEM( rHdrItemSet, SvxULSpaceItem, ATTR_ULSPACE ).GetLower()) :
+ // static height: ATTR_PAGE_SIZE already includes header <-> sheet area distance
+ static_cast< sal_Int32 >( GETITEM( rHdrItemSet, SvxSizeItem, ATTR_PAGE_SIZE ).GetSize().Height() );
+ maData.mfHeaderMargin = maData.mfTopMargin;
+ maData.mfTopMargin += XclTools::GetInchFromTwips( nHdrHeight );
+ }
+
+ // footer
+ const SfxItemSet& rFtrItemSet = GETITEM( rItemSet, SvxSetItem, ATTR_PAGE_FOOTERSET ).GetItemSet();
+ if( GETITEMBOOL( rFtrItemSet, ATTR_PAGE_ON ) )
+ {
+ const ScPageHFItem& rHFItem = GETITEM( rItemSet, ScPageHFItem, ATTR_PAGE_FOOTERRIGHT );
+ aHFConv.GenerateString( rHFItem.GetLeftArea(), rHFItem.GetCenterArea(), rHFItem.GetRightArea() );
+ maData.maFooter = aHFConv.GetHFString();
+ // footer height (Excel excludes footer from bottom margin)
+ sal_Int32 nFtrHeight = GETITEMBOOL( rFtrItemSet, ATTR_PAGE_DYNAMIC ) ?
+ // dynamic height: calculate footer height, add sheet area <-> footer distance
+ (aHFConv.GetTotalHeight() + GETITEM( rFtrItemSet, SvxULSpaceItem, ATTR_ULSPACE ).GetUpper()) :
+ // static height: ATTR_PAGE_SIZE already includes sheet area <-> footer distance
+ static_cast< sal_Int32 >( GETITEM( rFtrItemSet, SvxSizeItem, ATTR_PAGE_SIZE ).GetSize().Height() );
+ maData.mfFooterMargin = maData.mfBottomMargin;
+ maData.mfBottomMargin += XclTools::GetInchFromTwips( nFtrHeight );
+ }
+ }
+
+ // *** page breaks ***
+
+ set<SCROW> aRowBreaks;
+ rDoc.GetAllRowBreaks(aRowBreaks, nScTab, false, true);
+
+ SCROW nMaxRow = numeric_limits<sal_uInt16>::max();
+ for (set<SCROW>::const_iterator itr = aRowBreaks.begin(), itrEnd = aRowBreaks.end(); itr != itrEnd; ++itr)
+ {
+ SCROW nRow = *itr;
+ if (nRow > nMaxRow)
+ break;
+
+ maData.maHorPageBreaks.push_back(nRow);
+ }
+
+ if (maData.maHorPageBreaks.size() > 1026)
+ {
+ // Excel allows only up to 1026 page breaks. Trim any excess page breaks.
+ ScfUInt16Vec::iterator itr = maData.maHorPageBreaks.begin();
+ ::std::advance(itr, 1026);
+ maData.maHorPageBreaks.erase(itr, maData.maHorPageBreaks.end());
+ }
+
+ set<SCCOL> aColBreaks;
+ rDoc.GetAllColBreaks(aColBreaks, nScTab, false, true);
+ for (set<SCCOL>::const_iterator itr = aColBreaks.begin(), itrEnd = aColBreaks.end(); itr != itrEnd; ++itr)
+ maData.maVerPageBreaks.push_back(*itr);
+}
+
+static void lcl_WriteHeaderFooter( XclExpXmlStream& rStrm )
+{
+ // OOXTODO: we currently only emit oddHeader/oddFooter elements, and
+ // do not support the first/even/odd page distinction.
+ rStrm.WriteAttributes(
+ // OOXTODO: XML_alignWithMargins,
+ XML_differentFirst, "false", // OOXTODO
+ XML_differentOddEven, "false", // OOXTODO
+ // OOXTODO: XML_scaleWithDoc
+ FSEND );
+ rStrm.GetCurrentStream()->write( ">" );
+}
+
+void XclExpPageSettings::Save( XclExpStream& rStrm )
+{
+ XclExpBoolRecord( EXC_ID_PRINTHEADERS, maData.mbPrintHeadings ).Save( rStrm );
+ XclExpBoolRecord( EXC_ID_PRINTGRIDLINES, maData.mbPrintGrid ).Save( rStrm );
+ XclExpBoolRecord( EXC_ID_GRIDSET, true ).Save( rStrm );
+ XclExpPageBreaks( EXC_ID_HORPAGEBREAKS, maData.maHorPageBreaks, static_cast< sal_uInt16 >( GetXclMaxPos().Col() ) ).Save( rStrm );
+ XclExpPageBreaks( EXC_ID_VERPAGEBREAKS, maData.maVerPageBreaks, static_cast< sal_uInt16 >( GetXclMaxPos().Row() ) ).Save( rStrm );
+ XclExpHeaderFooter( EXC_ID_HEADER, maData.maHeader ).Save( rStrm );
+ XclExpHeaderFooter( EXC_ID_FOOTER, maData.maFooter ).Save( rStrm );
+ XclExpBoolRecord( EXC_ID_HCENTER, maData.mbHorCenter ).Save( rStrm );
+ XclExpBoolRecord( EXC_ID_VCENTER, maData.mbVerCenter ).Save( rStrm );
+ XclExpDoubleRecord( EXC_ID_LEFTMARGIN, maData.mfLeftMargin ).Save( rStrm );
+ XclExpDoubleRecord( EXC_ID_RIGHTMARGIN, maData.mfRightMargin ).Save( rStrm );
+ XclExpDoubleRecord( EXC_ID_TOPMARGIN, maData.mfTopMargin ).Save( rStrm );
+ XclExpDoubleRecord( EXC_ID_BOTTOMMARGIN, maData.mfBottomMargin ).Save( rStrm );
+ XclExpSetup( maData ).Save( rStrm );
+
+ if( (GetBiff() == EXC_BIFF8) && maData.mxBrushItem.get() )
+ if( const Graphic* pGraphic = maData.mxBrushItem->GetGraphic() )
+ XclExpImgData( *pGraphic, EXC_ID8_IMGDATA ).Save( rStrm );
+}
+
+void XclExpPageSettings::SaveXml( XclExpXmlStream& rStrm )
+{
+ XclExpXmlStartSingleElementRecord( XML_printOptions ).SaveXml( rStrm );
+ XclExpBoolRecord( EXC_ID_PRINTHEADERS, maData.mbPrintHeadings, XML_headings ).SaveXml( rStrm );
+ XclExpBoolRecord( EXC_ID_PRINTGRIDLINES, maData.mbPrintGrid, XML_gridLines ).SaveXml( rStrm );
+ XclExpBoolRecord( EXC_ID_GRIDSET, true, XML_gridLinesSet ).SaveXml( rStrm );
+ XclExpBoolRecord( EXC_ID_HCENTER, maData.mbHorCenter, XML_horizontalCentered ).SaveXml( rStrm );
+ XclExpBoolRecord( EXC_ID_VCENTER, maData.mbVerCenter, XML_verticalCentered ).SaveXml( rStrm );
+ XclExpXmlEndSingleElementRecord().SaveXml( rStrm ); // XML_printOptions
+
+ XclExpXmlStartSingleElementRecord( XML_pageMargins ).SaveXml( rStrm );
+ XclExpDoubleRecord( EXC_ID_LEFTMARGIN, maData.mfLeftMargin ).SetAttribute( XML_left )->SaveXml( rStrm );
+ XclExpDoubleRecord( EXC_ID_RIGHTMARGIN, maData.mfRightMargin ).SetAttribute( XML_right )->SaveXml( rStrm );
+ XclExpDoubleRecord( EXC_ID_TOPMARGIN, maData.mfTopMargin ).SetAttribute( XML_top )->SaveXml( rStrm );
+ XclExpDoubleRecord( EXC_ID_BOTTOMMARGIN, maData.mfBottomMargin ).SetAttribute( XML_bottom )->SaveXml( rStrm );
+ XclExpDoubleRecord( 0, maData.mfHeaderMargin).SetAttribute( XML_header )->SaveXml( rStrm );
+ XclExpDoubleRecord( 0, maData.mfFooterMargin).SetAttribute( XML_footer )->SaveXml( rStrm );
+ XclExpXmlEndSingleElementRecord().SaveXml( rStrm ); // XML_pageMargins
+
+ XclExpSetup( maData ).SaveXml( rStrm );
+
+ XclExpXmlStartElementRecord( XML_headerFooter, lcl_WriteHeaderFooter ).SaveXml( rStrm );
+ XclExpHeaderFooter( EXC_ID_HEADER, maData.maHeader ).SaveXml( rStrm );
+ XclExpHeaderFooter( EXC_ID_FOOTER, maData.maFooter ).SaveXml( rStrm );
+ XclExpXmlEndElementRecord( XML_headerFooter ).SaveXml( rStrm );
+
+ XclExpPageBreaks( EXC_ID_HORPAGEBREAKS, maData.maHorPageBreaks,
+ static_cast< sal_uInt16 >( GetXclMaxPos().Col() ) ).SaveXml( rStrm );
+ XclExpPageBreaks( EXC_ID_VERPAGEBREAKS, maData.maVerPageBreaks,
+ static_cast< sal_uInt16 >( GetXclMaxPos().Row() ) ).SaveXml( rStrm );
+
+ if( const Graphic* pGraphic = maData.mxBrushItem->GetGraphic() )
+ XclExpImgData( *pGraphic, EXC_ID8_IMGDATA ).SaveXml( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpChartPageSettings::XclExpChartPageSettings( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+void XclExpChartPageSettings::Save( XclExpStream& rStrm )
+{
+ XclExpHeaderFooter( EXC_ID_HEADER, maData.maHeader ).Save( rStrm );
+ XclExpHeaderFooter( EXC_ID_FOOTER, maData.maFooter ).Save( rStrm );
+ XclExpBoolRecord( EXC_ID_HCENTER, maData.mbHorCenter ).Save( rStrm );
+ XclExpBoolRecord( EXC_ID_VCENTER, maData.mbVerCenter ).Save( rStrm );
+ XclExpSetup( maData ).Save( rStrm );
+ XclExpUInt16Record( EXC_ID_PRINTSIZE, EXC_PRINTSIZE_FULL ).Save( rStrm );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xepivot.cxx b/sc/source/filter/excel/xepivot.cxx
new file mode 100644
index 000000000000..be8557eac430
--- /dev/null
+++ b/sc/source/filter/excel/xepivot.cxx
@@ -0,0 +1,1971 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xepivot.hxx"
+#include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReference.hpp>
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+
+#include <algorithm>
+#include <math.h>
+
+#include <rtl/math.hxx>
+#include <tools/date.hxx>
+#include <svl/zformat.hxx>
+#include <sot/storage.hxx>
+#include "document.hxx"
+#include "dpobject.hxx"
+#include "dpsave.hxx"
+#include "dpdimsave.hxx"
+#include "dpshttab.hxx"
+#include "globstr.hrc"
+#include "fapihelper.hxx"
+#include "xestring.hxx"
+#include "xelink.hxx"
+
+using namespace ::oox;
+
+using ::com::sun::star::sheet::DataPilotFieldOrientation;
+using ::com::sun::star::sheet::DataPilotFieldOrientation_HIDDEN;
+using ::com::sun::star::sheet::DataPilotFieldOrientation_ROW;
+using ::com::sun::star::sheet::DataPilotFieldOrientation_COLUMN;
+using ::com::sun::star::sheet::DataPilotFieldOrientation_PAGE;
+using ::com::sun::star::sheet::DataPilotFieldOrientation_DATA;
+using ::com::sun::star::sheet::GeneralFunction;
+using ::com::sun::star::sheet::DataPilotFieldSortInfo;
+using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
+using ::com::sun::star::sheet::DataPilotFieldLayoutInfo;
+using ::com::sun::star::sheet::DataPilotFieldReference;
+using ::rtl::OUString;
+
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+// Pivot cache
+// ============================================================================
+
+namespace {
+
+// constants to track occurrence of specific data types
+const sal_uInt16 EXC_PCITEM_DATA_STRING = 0x0001; /// String, empty, boolean, error.
+const sal_uInt16 EXC_PCITEM_DATA_DOUBLE = 0x0002; /// Double with fraction.
+const sal_uInt16 EXC_PCITEM_DATA_INTEGER = 0x0004; /// Integer, double without fraction.
+const sal_uInt16 EXC_PCITEM_DATA_DATE = 0x0008; /// Date, time, date/time.
+
+/** Maps a bitfield consisting of EXC_PCITEM_DATA_* flags above to SXFIELD data type bitfield. */
+static const sal_uInt16 spnPCItemFlags[] =
+{ // STR DBL INT DAT
+ EXC_SXFIELD_DATA_NONE, //
+ EXC_SXFIELD_DATA_STR, // x
+ EXC_SXFIELD_DATA_INT, // x
+ EXC_SXFIELD_DATA_STR_INT, // x x
+ EXC_SXFIELD_DATA_DBL, // x
+ EXC_SXFIELD_DATA_STR_DBL, // x x
+ EXC_SXFIELD_DATA_INT, // x x
+ EXC_SXFIELD_DATA_STR_INT, // x x x
+ EXC_SXFIELD_DATA_DATE, // x
+ EXC_SXFIELD_DATA_DATE_STR, // x x
+ EXC_SXFIELD_DATA_DATE_NUM, // x x
+ EXC_SXFIELD_DATA_DATE_STR, // x x x
+ EXC_SXFIELD_DATA_DATE_NUM, // x x
+ EXC_SXFIELD_DATA_DATE_STR, // x x x
+ EXC_SXFIELD_DATA_DATE_NUM, // x x x
+ EXC_SXFIELD_DATA_DATE_STR // x x x x
+};
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpPCItem::XclExpPCItem( const String& rText ) :
+ XclExpRecord( (rText.Len() > 0) ? EXC_ID_SXSTRING : EXC_ID_SXEMPTY, 0 ),
+ mnTypeFlag( EXC_PCITEM_DATA_STRING )
+{
+ if( rText.Len() )
+ SetText( rText );
+ else
+ SetEmpty();
+}
+
+XclExpPCItem::XclExpPCItem( double fValue ) :
+ XclExpRecord( EXC_ID_SXDOUBLE, 8 )
+{
+ SetDouble( fValue );
+ mnTypeFlag = (fValue - floor( fValue ) == 0.0) ?
+ EXC_PCITEM_DATA_INTEGER : EXC_PCITEM_DATA_DOUBLE;
+}
+
+XclExpPCItem::XclExpPCItem( const DateTime& rDateTime ) :
+ XclExpRecord( EXC_ID_SXDATETIME, 8 )
+{
+ SetDateTime( rDateTime );
+ mnTypeFlag = EXC_PCITEM_DATA_DATE;
+}
+
+XclExpPCItem::XclExpPCItem( sal_Int16 nValue ) :
+ XclExpRecord( EXC_ID_SXINTEGER, 2 ),
+ mnTypeFlag( EXC_PCITEM_DATA_INTEGER )
+{
+ SetInteger( nValue );
+}
+
+XclExpPCItem::XclExpPCItem( bool bValue ) :
+ XclExpRecord( EXC_ID_SXBOOLEAN, 2 ),
+ mnTypeFlag( EXC_PCITEM_DATA_STRING )
+{
+ SetBool( bValue );
+}
+
+// ----------------------------------------------------------------------------
+
+bool XclExpPCItem::EqualsText( const String& rText ) const
+{
+ return (rText.Len() == 0) ? IsEmpty() : (GetText() && (*GetText() == rText));
+}
+
+bool XclExpPCItem::EqualsDouble( double fValue ) const
+{
+ return GetDouble() && (*GetDouble() == fValue);
+}
+
+bool XclExpPCItem::EqualsDateTime( const DateTime& rDateTime ) const
+{
+ return GetDateTime() && (*GetDateTime() == rDateTime);
+}
+
+bool XclExpPCItem::EqualsBool( bool bValue ) const
+{
+ return GetBool() && (*GetBool() == bValue);
+}
+
+// ----------------------------------------------------------------------------
+
+void XclExpPCItem::WriteBody( XclExpStream& rStrm )
+{
+ if( const String* pText = GetText() )
+ {
+ rStrm << XclExpString( *pText );
+ }
+ else if( const double* pfValue = GetDouble() )
+ {
+ rStrm << *pfValue;
+ }
+ else if( const sal_Int16* pnValue = GetInteger() )
+ {
+ rStrm << *pnValue;
+ }
+ else if( const DateTime* pDateTime = GetDateTime() )
+ {
+ sal_uInt16 nYear = static_cast< sal_uInt16 >( pDateTime->GetYear() );
+ sal_uInt16 nMonth = static_cast< sal_uInt16 >( pDateTime->GetMonth() );
+ sal_uInt8 nDay = static_cast< sal_uInt8 >( pDateTime->GetDay() );
+ sal_uInt8 nHour = static_cast< sal_uInt8 >( pDateTime->GetHour() );
+ sal_uInt8 nMin = static_cast< sal_uInt8 >( pDateTime->GetMin() );
+ sal_uInt8 nSec = static_cast< sal_uInt8 >( pDateTime->GetSec() );
+ if( nYear < 1900 ) { nYear = 1900; nMonth = 1; nDay = 0; }
+ rStrm << nYear << nMonth << nDay << nHour << nMin << nSec;
+ }
+ else if( const bool* pbValue = GetBool() )
+ {
+ rStrm << static_cast< sal_uInt16 >( *pbValue ? 1 : 0 );
+ }
+ else
+ {
+ // nothing to do for SXEMPTY
+ DBG_ASSERT( IsEmpty(), "XclExpPCItem::WriteBody - no data found" );
+ }
+}
+
+// ============================================================================
+
+XclExpPCField::XclExpPCField(
+ const XclExpRoot& rRoot, const XclExpPivotCache& rPCache, sal_uInt16 nFieldIdx,
+ const ScDPObject& rDPObj, const ScRange& rRange ) :
+ XclExpRecord( EXC_ID_SXFIELD ),
+ XclPCField( EXC_PCFIELD_STANDARD, nFieldIdx ),
+ XclExpRoot( rRoot ),
+ mrPCache( rPCache ),
+ mnTypeFlags( 0 )
+{
+ // general settings for the standard field, insert all items from source range
+ InitStandardField( rRange );
+
+ // add special settings for inplace numeric grouping
+ if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
+ {
+ if( const ScDPDimensionSaveData* pSaveDimData = pSaveData->GetExistingDimensionData() )
+ {
+ if( const ScDPSaveNumGroupDimension* pNumGroupDim = pSaveDimData->GetNumGroupDim( GetFieldName() ) )
+ {
+ const ScDPNumGroupInfo& rNumInfo = pNumGroupDim->GetInfo();
+ const ScDPNumGroupInfo& rDateInfo = pNumGroupDim->GetDateInfo();
+ DBG_ASSERT( !rNumInfo.Enable || !rDateInfo.Enable,
+ "XclExpPCField::XclExpPCField - numeric and date grouping enabled" );
+
+ if( rNumInfo.Enable )
+ InitNumGroupField( rDPObj, rNumInfo );
+ else if( rDateInfo.Enable )
+ InitDateGroupField( rDPObj, rDateInfo, pNumGroupDim->GetDatePart() );
+ }
+ }
+ }
+
+ // final settings (flags, item numbers)
+ Finalize();
+}
+
+XclExpPCField::XclExpPCField(
+ const XclExpRoot& rRoot, const XclExpPivotCache& rPCache, sal_uInt16 nFieldIdx,
+ const ScDPObject& rDPObj, const ScDPSaveGroupDimension& rGroupDim, const XclExpPCField& rBaseField ) :
+ XclExpRecord( EXC_ID_SXFIELD ),
+ XclPCField( EXC_PCFIELD_STDGROUP, nFieldIdx ),
+ XclExpRoot( rRoot ),
+ mrPCache( rPCache ),
+ mnTypeFlags( 0 )
+{
+ // add base field info (always using first base field, not predecessor of this field) ***
+ DBG_ASSERT( rBaseField.GetFieldName() == rGroupDim.GetSourceDimName(),
+ "XclExpPCField::FillFromGroup - wrong base cache field" );
+ maFieldInfo.maName = rGroupDim.GetGroupDimName();
+ maFieldInfo.mnGroupBase = rBaseField.GetFieldIndex();
+
+ // add standard group info or date group info
+ const ScDPNumGroupInfo& rDateInfo = rGroupDim.GetDateInfo();
+ if( rDateInfo.Enable && (rGroupDim.GetDatePart() != 0) )
+ InitDateGroupField( rDPObj, rDateInfo, rGroupDim.GetDatePart() );
+ else
+ InitStdGroupField( rBaseField, rGroupDim );
+
+ // final settings (flags, item numbers)
+ Finalize();
+}
+
+XclExpPCField::~XclExpPCField()
+{
+}
+
+void XclExpPCField::SetGroupChildField( const XclExpPCField& rChildField )
+{
+ DBG_ASSERT( !::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD ),
+ "XclExpPCField::SetGroupChildIndex - field already has a grouping child field" );
+ ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD );
+ maFieldInfo.mnGroupChild = rChildField.GetFieldIndex();
+}
+
+sal_uInt16 XclExpPCField::GetItemCount() const
+{
+ return static_cast< sal_uInt16 >( GetVisItemList().GetSize() );
+}
+
+const XclExpPCItem* XclExpPCField::GetItem( sal_uInt16 nItemIdx ) const
+{
+ return GetVisItemList().GetRecord( nItemIdx ).get();
+}
+
+sal_uInt16 XclExpPCField::GetItemIndex( const String& rItemName ) const
+{
+ const XclExpPCItemList& rItemList = GetVisItemList();
+ for( size_t nPos = 0, nSize = rItemList.GetSize(); nPos < nSize; ++nPos )
+ if( rItemList.GetRecord( nPos )->ConvertToText() == rItemName )
+ return static_cast< sal_uInt16 >( nPos );
+ return EXC_PC_NOITEM;
+}
+
+sal_Size XclExpPCField::GetIndexSize() const
+{
+ return Has16BitIndexes() ? 2 : 1;
+}
+
+void XclExpPCField::WriteIndex( XclExpStream& rStrm, sal_uInt32 nSrcRow ) const
+{
+ // only standard fields write item indexes
+ if( nSrcRow < maIndexVec.size() )
+ {
+ sal_uInt16 nIndex = maIndexVec[ nSrcRow ];
+ if( Has16BitIndexes() )
+ rStrm << nIndex;
+ else
+ rStrm << static_cast< sal_uInt8 >( nIndex );
+ }
+}
+
+void XclExpPCField::Save( XclExpStream& rStrm )
+{
+ DBG_ASSERT( IsSupportedField(), "XclExpPCField::Save - unknown field type" );
+ // SXFIELD
+ XclExpRecord::Save( rStrm );
+ // SXFDBTYPE
+ XclExpUInt16Record( EXC_ID_SXFDBTYPE, EXC_SXFDBTYPE_DEFAULT ).Save( rStrm );
+ // list of grouping items
+ maGroupItemList.Save( rStrm );
+ // SXGROUPINFO
+ WriteSxgroupinfo( rStrm );
+ // SXNUMGROUP and additional grouping items (grouping limit settings)
+ WriteSxnumgroup( rStrm );
+ // list of original items
+ maOrigItemList.Save( rStrm );
+}
+
+// private --------------------------------------------------------------------
+
+const XclExpPCField::XclExpPCItemList& XclExpPCField::GetVisItemList() const
+{
+ DBG_ASSERT( IsStandardField() == maGroupItemList.IsEmpty(),
+ "XclExpPCField::GetVisItemList - unexpected additional items in standard field" );
+ return IsStandardField() ? maOrigItemList : maGroupItemList;
+}
+
+void XclExpPCField::InitStandardField( const ScRange& rRange )
+{
+ DBG_ASSERT( IsStandardField(), "XclExpPCField::InitStandardField - only for standard fields" );
+ DBG_ASSERT( rRange.aStart.Col() == rRange.aEnd.Col(), "XclExpPCField::InitStandardField - cell range with multiple columns" );
+
+ ScDocument& rDoc = GetDoc();
+ SvNumberFormatter& rFormatter = GetFormatter();
+
+ // field name is in top cell of the range
+ ScAddress aPos( rRange.aStart );
+ rDoc.GetString( aPos.Col(), aPos.Row(), aPos.Tab(), maFieldInfo.maName );
+ // #i76047# maximum field name length in pivot cache is 255
+ maFieldInfo.maName.Erase( ::std::min( maFieldInfo.maName.Len(), EXC_PC_MAXSTRLEN ) );
+
+ // loop over all cells, create pivot cache items
+ for( aPos.IncRow(); (aPos.Row() <= rRange.aEnd.Row()) && (maOrigItemList.GetSize() < EXC_PC_MAXITEMCOUNT); aPos.IncRow() )
+ {
+ if( rDoc.HasValueData( aPos.Col(), aPos.Row(), aPos.Tab() ) )
+ {
+ double fValue = rDoc.GetValue( aPos );
+ short nFmtType = rFormatter.GetType( rDoc.GetNumberFormat( aPos ) );
+ if( nFmtType == NUMBERFORMAT_LOGICAL )
+ InsertOrigBoolItem( fValue != 0 );
+ else if( nFmtType & NUMBERFORMAT_DATETIME )
+ InsertOrigDateTimeItem( GetDateTimeFromDouble( ::std::max( fValue, 0.0 ) ) );
+ else
+ InsertOrigDoubleItem( fValue );
+ }
+ else
+ {
+ String aText;
+ rDoc.GetString( aPos.Col(), aPos.Row(), aPos.Tab(), aText );
+ InsertOrigTextItem( aText );
+ }
+ }
+}
+
+void XclExpPCField::InitStdGroupField( const XclExpPCField& rBaseField, const ScDPSaveGroupDimension& rGroupDim )
+{
+ DBG_ASSERT( IsGroupField(), "XclExpPCField::InitStdGroupField - only for standard grouping fields" );
+
+ maFieldInfo.mnBaseItems = rBaseField.GetItemCount();
+ maGroupOrder.resize( maFieldInfo.mnBaseItems, EXC_PC_NOITEM );
+
+ // loop over all groups of this field
+ for( long nGroupIdx = 0, nGroupCount = rGroupDim.GetGroupCount(); nGroupIdx < nGroupCount; ++nGroupIdx )
+ {
+ if( const ScDPSaveGroupItem* pGroupItem = rGroupDim.GetGroupByIndex( nGroupIdx ) )
+ {
+ // the index of the new item containing the grouping name
+ sal_uInt16 nGroupItemIdx = EXC_PC_NOITEM;
+ // loop over all elements of one group
+ for( size_t nElemIdx = 0, nElemCount = pGroupItem->GetElementCount(); nElemIdx < nElemCount; ++nElemIdx )
+ {
+ if( const String* pElemName = pGroupItem->GetElementByIndex( nElemIdx ) )
+ {
+ // try to find the item that is part of the group in the base field
+ sal_uInt16 nBaseItemIdx = rBaseField.GetItemIndex( *pElemName );
+ if( nBaseItemIdx < maFieldInfo.mnBaseItems )
+ {
+ // add group name item only if there are any valid base items
+ if( nGroupItemIdx == EXC_PC_NOITEM )
+ nGroupItemIdx = InsertGroupItem( new XclExpPCItem( pGroupItem->GetGroupName() ) );
+ maGroupOrder[ nBaseItemIdx ] = nGroupItemIdx;
+ }
+ }
+ }
+ }
+ }
+
+ // add items and base item indexes of all ungrouped elements
+ for( sal_uInt16 nBaseItemIdx = 0; nBaseItemIdx < maFieldInfo.mnBaseItems; ++nBaseItemIdx )
+ // items that are not part of a group still have the EXC_PC_NOITEM entry
+ if( maGroupOrder[ nBaseItemIdx ] == EXC_PC_NOITEM )
+ // try to find the base item
+ if( const XclExpPCItem* pBaseItem = rBaseField.GetItem( nBaseItemIdx ) )
+ // create a clone of the base item, insert its index into item order list
+ maGroupOrder[ nBaseItemIdx ] = InsertGroupItem( new XclExpPCItem( *pBaseItem ) );
+}
+
+void XclExpPCField::InitNumGroupField( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rNumInfo )
+{
+ DBG_ASSERT( IsStandardField(), "XclExpPCField::InitNumGroupField - only for standard fields" );
+ DBG_ASSERT( rNumInfo.Enable, "XclExpPCField::InitNumGroupField - numeric grouping not enabled" );
+
+ // new field type, date type, limit settings (min/max/step/auto)
+ if( rNumInfo.DateValues )
+ {
+ // special case: group by days with step count
+ meFieldType = EXC_PCFIELD_DATEGROUP;
+ maNumGroupInfo.SetScDateType( com::sun::star::sheet::DataPilotFieldGroupBy::DAYS );
+ SetDateGroupLimit( rNumInfo, true );
+ }
+ else
+ {
+ meFieldType = EXC_PCFIELD_NUMGROUP;
+ maNumGroupInfo.SetNumType();
+ SetNumGroupLimit( rNumInfo );
+ }
+
+ // generate visible items
+ InsertNumDateGroupItems( rDPObj, rNumInfo );
+}
+
+void XclExpPCField::InitDateGroupField( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nDatePart )
+{
+ DBG_ASSERT( IsStandardField() || IsStdGroupField(), "XclExpPCField::InitDateGroupField - only for standard fields" );
+ DBG_ASSERT( rDateInfo.Enable, "XclExpPCField::InitDateGroupField - date grouping not enabled" );
+
+ // new field type
+ meFieldType = IsStandardField() ? EXC_PCFIELD_DATEGROUP : EXC_PCFIELD_DATECHILD;
+
+ // date type, limit settings (min/max/step/auto)
+ maNumGroupInfo.SetScDateType( nDatePart );
+ SetDateGroupLimit( rDateInfo, false );
+
+ // generate visible items
+ InsertNumDateGroupItems( rDPObj, rDateInfo, nDatePart );
+}
+
+void XclExpPCField::InsertItemArrayIndex( size_t nListPos )
+{
+ DBG_ASSERT( IsStandardField(), "XclExpPCField::InsertItemArrayIndex - only for standard fields" );
+ maIndexVec.push_back( static_cast< sal_uInt16 >( nListPos ) );
+}
+
+void XclExpPCField::InsertOrigItem( XclExpPCItem* pNewItem )
+{
+ size_t nItemIdx = maOrigItemList.GetSize();
+ maOrigItemList.AppendNewRecord( pNewItem );
+ InsertItemArrayIndex( nItemIdx );
+ mnTypeFlags |= pNewItem->GetTypeFlag();
+}
+
+void XclExpPCField::InsertOrigTextItem( const String& rText )
+{
+ size_t nPos = 0;
+ bool bFound = false;
+ // #i76047# maximum item text length in pivot cache is 255
+ String aShortText( rText, 0, ::std::min( rText.Len(), EXC_PC_MAXSTRLEN ) );
+ for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
+ if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsText( aShortText )) == true )
+ InsertItemArrayIndex( nPos );
+ if( !bFound )
+ InsertOrigItem( new XclExpPCItem( aShortText ) );
+}
+
+void XclExpPCField::InsertOrigDoubleItem( double fValue )
+{
+ size_t nPos = 0;
+ bool bFound = false;
+ for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
+ if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsDouble( fValue )) == true )
+ InsertItemArrayIndex( nPos );
+ if( !bFound )
+ InsertOrigItem( new XclExpPCItem( fValue ) );
+}
+
+void XclExpPCField::InsertOrigDateTimeItem( const DateTime& rDateTime )
+{
+ size_t nPos = 0;
+ bool bFound = false;
+ for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
+ if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsDateTime( rDateTime )) == true )
+ InsertItemArrayIndex( nPos );
+ if( !bFound )
+ InsertOrigItem( new XclExpPCItem( rDateTime ) );
+}
+
+void XclExpPCField::InsertOrigBoolItem( bool bValue )
+{
+ size_t nPos = 0;
+ bool bFound = false;
+ for( size_t nSize = maOrigItemList.GetSize(); !bFound && (nPos < nSize); ++nPos )
+ if( (bFound = maOrigItemList.GetRecord( nPos )->EqualsBool( bValue )) == true )
+ InsertItemArrayIndex( nPos );
+ if( !bFound )
+ InsertOrigItem( new XclExpPCItem( bValue ) );
+}
+
+sal_uInt16 XclExpPCField::InsertGroupItem( XclExpPCItem* pNewItem )
+{
+ maGroupItemList.AppendNewRecord( pNewItem );
+ return static_cast< sal_uInt16 >( maGroupItemList.GetSize() - 1 );
+}
+
+void XclExpPCField::InsertNumDateGroupItems( const ScDPObject& rDPObj, const ScDPNumGroupInfo& rNumInfo, sal_Int32 nDatePart )
+{
+ DBG_ASSERT( rDPObj.GetSheetDesc(), "XclExpPCField::InsertNumDateGroupItems - cannot generate element list" );
+ if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
+ {
+ // get the string collection with original source elements
+ const ScDPCache* pCache = pSrcDesc->CreateCache();
+ if (!pCache)
+ return;
+
+ ScSheetDPData aDPData(GetDocPtr(), *pSrcDesc, pCache);
+ const std::vector< SCROW > aOrignial = aDPData.GetColumnEntries( static_cast< long >( GetBaseFieldIndex() ) );
+ // get the string collection with generated grouping elements
+ ScDPNumGroupDimension aTmpDim( rNumInfo );
+ if( nDatePart != 0 )
+ aTmpDim.MakeDateHelper( rNumInfo, nDatePart );
+ const std::vector<SCROW>& aMemberIds = aTmpDim.GetNumEntries(
+ static_cast<SCCOL>( GetBaseFieldIndex() ), aDPData.GetCacheTable().getCache(), aOrignial);
+ for ( size_t nIdx = 0 ; nIdx < aMemberIds.size(); nIdx++ )
+ {
+ const ScDPItemData* pData = aDPData.GetMemberById( static_cast< long >( GetBaseFieldIndex() ) , aMemberIds[ nIdx] );
+ if ( pData )
+ InsertGroupItem( new XclExpPCItem( pData->GetString() ) );
+ }
+ }
+}
+
+void XclExpPCField::SetNumGroupLimit( const ScDPNumGroupInfo& rNumInfo )
+{
+ ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN, rNumInfo.AutoStart );
+ ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX, rNumInfo.AutoEnd );
+ maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.Start ) );
+ maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.End ) );
+ maNumGroupLimits.AppendNewRecord( new XclExpPCItem( rNumInfo.Step ) );
+}
+
+void XclExpPCField::SetDateGroupLimit( const ScDPNumGroupInfo& rDateInfo, bool bUseStep )
+{
+ ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN, rDateInfo.AutoStart );
+ ::set_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX, rDateInfo.AutoEnd );
+ maNumGroupLimits.AppendNewRecord( new XclExpPCItem( GetDateTimeFromDouble( rDateInfo.Start ) ) );
+ maNumGroupLimits.AppendNewRecord( new XclExpPCItem( GetDateTimeFromDouble( rDateInfo.End ) ) );
+ sal_Int16 nStep = bUseStep ? limit_cast< sal_Int16 >( rDateInfo.Step, 1, SAL_MAX_INT16 ) : 1;
+ maNumGroupLimits.AppendNewRecord( new XclExpPCItem( nStep ) );
+}
+
+void XclExpPCField::Finalize()
+{
+ // flags
+ ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASITEMS, !GetVisItemList().IsEmpty() );
+ // Excel writes long indexes even for 0x0100 items (indexes from 0x00 to 0xFF)
+ ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_16BIT, maOrigItemList.GetSize() >= 0x0100 );
+ ::set_flag( maFieldInfo.mnFlags, EXC_SXFIELD_NUMGROUP, IsNumGroupField() || IsDateGroupField() );
+ /* mnTypeFlags is updated in all Insert***Item() functions. Now the flags
+ for the current combination of item types is added to the flags. */
+ ::set_flag( maFieldInfo.mnFlags, spnPCItemFlags[ mnTypeFlags ] );
+
+ // item count fields
+ maFieldInfo.mnVisItems = static_cast< sal_uInt16 >( GetVisItemList().GetSize() );
+ maFieldInfo.mnGroupItems = static_cast< sal_uInt16 >( maGroupItemList.GetSize() );
+ // maFieldInfo.mnBaseItems set in InitStdGroupField()
+ maFieldInfo.mnOrigItems = static_cast< sal_uInt16 >( maOrigItemList.GetSize() );
+}
+
+void XclExpPCField::WriteSxnumgroup( XclExpStream& rStrm )
+{
+ if( IsNumGroupField() || IsDateGroupField() )
+ {
+ // SXNUMGROUP record
+ rStrm.StartRecord( EXC_ID_SXNUMGROUP, 2 );
+ rStrm << maNumGroupInfo;
+ rStrm.EndRecord();
+
+ // limits (min/max/step) for numeric grouping
+ DBG_ASSERT( maNumGroupLimits.GetSize() == 3,
+ "XclExpPCField::WriteSxnumgroup - missing numeric grouping limits" );
+ maNumGroupLimits.Save( rStrm );
+ }
+}
+
+void XclExpPCField::WriteSxgroupinfo( XclExpStream& rStrm )
+{
+ DBG_ASSERT( IsStdGroupField() != maGroupOrder.empty(),
+ "XclExpPCField::WriteSxgroupinfo - missing grouping info" );
+ if( IsStdGroupField() && !maGroupOrder.empty() )
+ {
+ rStrm.StartRecord( EXC_ID_SXGROUPINFO, 2 * maGroupOrder.size() );
+ for( ScfUInt16Vec::const_iterator aIt = maGroupOrder.begin(), aEnd = maGroupOrder.end(); aIt != aEnd; ++aIt )
+ rStrm << *aIt;
+ rStrm.EndRecord();
+ }
+}
+
+void XclExpPCField::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maFieldInfo;
+}
+
+// ============================================================================
+
+XclExpPivotCache::XclExpPivotCache( const XclExpRoot& rRoot, const ScDPObject& rDPObj, sal_uInt16 nListIdx ) :
+ XclExpRoot( rRoot ),
+ mnListIdx( nListIdx ),
+ mbValid( false )
+{
+ // source from sheet only
+ if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
+ {
+ /* maOrigSrcRange: Range received from the DataPilot object.
+ maExpSrcRange: Range written to the DCONREF record.
+ maDocSrcRange: Range used to get source data from Calc document.
+ This range may be shorter than maExpSrcRange to improve export
+ performance (#i22541#). */
+ maOrigSrcRange = maExpSrcRange = maDocSrcRange = pSrcDesc->GetSourceRange();
+ maSrcRangeName = pSrcDesc->GetRangeName();
+
+ // internal sheet data only
+ SCTAB nScTab = maExpSrcRange.aStart.Tab();
+ if( (nScTab == maExpSrcRange.aEnd.Tab()) && GetTabInfo().IsExportTab( nScTab ) )
+ {
+ // ValidateRange() restricts source range to valid Excel limits
+ if( GetAddressConverter().ValidateRange( maExpSrcRange, true ) )
+ {
+ // #i22541# skip empty cell areas (performance)
+ SCCOL nDocCol1, nDocCol2;
+ SCROW nDocRow1, nDocRow2;
+ GetDoc().GetDataStart( nScTab, nDocCol1, nDocRow1 );
+ GetDoc().GetPrintArea( nScTab, nDocCol2, nDocRow2, false );
+ SCCOL nSrcCol1 = maExpSrcRange.aStart.Col();
+ SCROW nSrcRow1 = maExpSrcRange.aStart.Row();
+ SCCOL nSrcCol2 = maExpSrcRange.aEnd.Col();
+ SCROW nSrcRow2 = maExpSrcRange.aEnd.Row();
+
+ // #i22541# do not store index list for too big ranges
+ if( 2 * (nDocRow2 - nDocRow1) < (nSrcRow2 - nSrcRow1) )
+ ::set_flag( maPCInfo.mnFlags, EXC_SXDB_SAVEDATA, false );
+
+ // Excel must refresh tables to make drilldown working
+ ::set_flag( maPCInfo.mnFlags, EXC_SXDB_REFRESH_LOAD );
+
+ // adjust row indexes, keep one row of empty area to surely have the empty cache item
+ if( nSrcRow1 < nDocRow1 )
+ nSrcRow1 = nDocRow1 - 1;
+ if( nSrcRow2 > nDocRow2 )
+ nSrcRow2 = nDocRow2 + 1;
+
+ maDocSrcRange.aStart.SetCol( ::std::max( nDocCol1, nSrcCol1 ) );
+ maDocSrcRange.aStart.SetRow( nSrcRow1 );
+ maDocSrcRange.aEnd.SetCol( ::std::min( nDocCol2, nSrcCol2 ) );
+ maDocSrcRange.aEnd.SetRow( nSrcRow2 );
+
+ GetDoc().GetName( nScTab, maTabName );
+ maPCInfo.mnSrcRecs = static_cast< sal_uInt32 >( maExpSrcRange.aEnd.Row() - maExpSrcRange.aStart.Row() );
+ maPCInfo.mnStrmId = nListIdx + 1;
+ maPCInfo.mnSrcType = EXC_SXDB_SRC_SHEET;
+
+ AddFields( rDPObj );
+
+ mbValid = true;
+ }
+ }
+ }
+}
+
+bool XclExpPivotCache::HasItemIndexList() const
+{
+ return ::get_flag( maPCInfo.mnFlags, EXC_SXDB_SAVEDATA );
+}
+
+sal_uInt16 XclExpPivotCache::GetFieldCount() const
+{
+ return static_cast< sal_uInt16 >( maFieldList.GetSize() );
+}
+
+const XclExpPCField* XclExpPivotCache::GetField( sal_uInt16 nFieldIdx ) const
+{
+ return maFieldList.GetRecord( nFieldIdx ).get();
+}
+
+bool XclExpPivotCache::HasAddFields() const
+{
+ // pivot cache can be shared, if there are no additional cache fields
+ return maPCInfo.mnStdFields < maPCInfo.mnTotalFields;
+}
+
+bool XclExpPivotCache::HasEqualDataSource( const ScDPObject& rDPObj ) const
+{
+ /* For now, only sheet sources are supported, therefore it is enough to
+ compare the ScSheetSourceDesc. Later, there should be done more complicated
+ comparisons regarding the source type of rDPObj and this cache. */
+ if( const ScSheetSourceDesc* pSrcDesc = rDPObj.GetSheetDesc() )
+ return pSrcDesc->GetSourceRange() == maOrigSrcRange;
+ return false;
+}
+
+void XclExpPivotCache::Save( XclExpStream& rStrm )
+{
+ DBG_ASSERT( mbValid, "XclExpPivotCache::Save - invalid pivot cache" );
+ // SXIDSTM
+ XclExpUInt16Record( EXC_ID_SXIDSTM, maPCInfo.mnStrmId ).Save( rStrm );
+ // SXVS
+ XclExpUInt16Record( EXC_ID_SXVS, EXC_SXVS_SHEET ).Save( rStrm );
+
+ if (maSrcRangeName.getLength())
+ // DCONNAME
+ WriteDConName(rStrm);
+ else
+ // DCONREF
+ WriteDconref(rStrm);
+
+ // create the pivot cache storage stream
+ WriteCacheStream();
+}
+
+void XclExpPivotCache::SaveXml( XclExpXmlStream&
+#ifdef XLSX_PIVOT_CACHE
+ rStrm
+#endif
+)
+{
+ DBG_ASSERT( mbValid, "XclExpPivotCache::Save - invalid pivot cache" );
+#ifdef XLSX_PIVOT_CACHE /* <pivotCache> without xl/pivotCaches/ cacheStream
+ results in a broken .xlsx */
+ sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
+ OUString sId = OUStringBuffer()
+ .appendAscii("rId")
+ .append( rStrm.GetUniqueIdOUString() )
+ .makeStringAndClear();
+ rWorkbook->startElement( XML_pivotCache,
+ XML_cacheId, OString::valueOf( (sal_Int32)maPCInfo.mnStrmId ).getStr(),
+ FSNS( XML_r, XML_id ), XclXmlUtils::ToOString( sId ).getStr(),
+ FSEND );
+ // SXIDSTM
+ XclExpUInt16Record( EXC_ID_SXIDSTM, maPCInfo.mnStrmId ).SaveXml( rStrm );
+ // SXVS
+ XclExpUInt16Record( EXC_ID_SXVS, EXC_SXVS_SHEET ).SaveXml( rStrm );
+ // DCONREF
+ // OOXTODO: WriteDconref( rStrm );
+ // create the pivot cache storage stream
+ // OOXTODO: WriteCacheStream();
+ rWorkbook->endElement( XML_pivotCache );
+#endif /* XLSX_PIVOT_CACHE */
+}
+
+// private --------------------------------------------------------------------
+
+XclExpPCField* XclExpPivotCache::GetFieldAcc( sal_uInt16 nFieldIdx )
+{
+ return maFieldList.GetRecord( nFieldIdx ).get();
+}
+
+XclExpPCField* XclExpPivotCache::GetFieldAcc( const String& rFieldName )
+{
+ XclExpPCField* pField = 0;
+ for( size_t nPos = 0, nSize = maFieldList.GetSize(); !pField && (nPos < nSize); ++nPos )
+ if( maFieldList.GetRecord( nPos )->GetFieldName() == rFieldName )
+ pField = maFieldList.GetRecord( nPos ).get();
+ return pField;
+}
+
+void XclExpPivotCache::AddFields( const ScDPObject& rDPObj )
+{
+ AddStdFields( rDPObj );
+ maPCInfo.mnStdFields = GetFieldCount();
+ AddGroupFields( rDPObj );
+ AddCalcFields( rDPObj );
+ maPCInfo.mnTotalFields = GetFieldCount();
+};
+
+void XclExpPivotCache::AddStdFields( const ScDPObject& rDPObj )
+{
+ // if item index list is not written, used shortened source range (maDocSrcRange) for performance
+ const ScRange& rRange = HasItemIndexList() ? maExpSrcRange : maDocSrcRange;
+ // create a standard pivot cache field for each source column
+ for( SCCOL nScCol = rRange.aStart.Col(), nEndScCol = rRange.aEnd.Col(); nScCol <= nEndScCol; ++nScCol )
+ {
+ ScRange aColRange( rRange );
+ aColRange.aStart.SetCol( nScCol );
+ aColRange.aEnd.SetCol( nScCol );
+ maFieldList.AppendNewRecord( new XclExpPCField(
+ GetRoot(), *this, GetFieldCount(), rDPObj, aColRange ) );
+ }
+}
+
+void XclExpPivotCache::AddGroupFields( const ScDPObject& rDPObj )
+{
+ if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
+ {
+ if( const ScDPDimensionSaveData* pSaveDimData = pSaveData->GetExistingDimensionData() )
+ {
+ // loop over all existing standard fields to find their group fields
+ for( sal_uInt16 nFieldIdx = 0; nFieldIdx < maPCInfo.mnStdFields; ++nFieldIdx )
+ {
+ if( XclExpPCField* pCurrStdField = GetFieldAcc( nFieldIdx ) )
+ {
+ const ScDPSaveGroupDimension* pGroupDim = pSaveDimData->GetGroupDimForBase( pCurrStdField->GetFieldName() );
+ XclExpPCField* pLastGroupField = pCurrStdField;
+ while( pGroupDim )
+ {
+ // insert the new grouping field
+ XclExpPCFieldRef xNewGroupField( new XclExpPCField(
+ GetRoot(), *this, GetFieldCount(), rDPObj, *pGroupDim, *pCurrStdField ) );
+ maFieldList.AppendRecord( xNewGroupField );
+
+ // register new grouping field at current grouping field, building a chain
+ pLastGroupField->SetGroupChildField( *xNewGroupField );
+
+ // next grouping dimension
+ pGroupDim = pSaveDimData->GetGroupDimForBase( pGroupDim->GetGroupDimName() );
+ pLastGroupField = xNewGroupField.get();
+ }
+ }
+ }
+ }
+ }
+}
+
+void XclExpPivotCache::AddCalcFields( const ScDPObject& /*rDPObj*/ )
+{
+ // not supported
+}
+
+void XclExpPivotCache::WriteDconref( XclExpStream& rStrm ) const
+{
+ XclExpString aRef( XclExpUrlHelper::EncodeUrl( GetRoot(), EMPTY_STRING, &maTabName ) );
+ rStrm.StartRecord( EXC_ID_DCONREF, 7 + aRef.GetSize() );
+ rStrm << static_cast< sal_uInt16 >( maExpSrcRange.aStart.Row() )
+ << static_cast< sal_uInt16 >( maExpSrcRange.aEnd.Row() )
+ << static_cast< sal_uInt8 >( maExpSrcRange.aStart.Col() )
+ << static_cast< sal_uInt8 >( maExpSrcRange.aEnd.Col() )
+ << aRef
+ << sal_uInt8( 0 );
+ rStrm.EndRecord();
+}
+
+void XclExpPivotCache::WriteDConName( XclExpStream& rStrm ) const
+{
+ XclExpString aName(maSrcRangeName);
+ rStrm.StartRecord(EXC_ID_DCONNAME, aName.GetSize() + 2);
+ rStrm << aName << sal_uInt16(0);
+ rStrm.EndRecord();
+}
+
+void XclExpPivotCache::WriteCacheStream()
+{
+ SotStorageRef xSvStrg = OpenStorage( EXC_STORAGE_PTCACHE );
+ SotStorageStreamRef xSvStrm = OpenStream( xSvStrg, ScfTools::GetHexStr( maPCInfo.mnStrmId ) );
+ if( xSvStrm.Is() )
+ {
+ XclExpStream aStrm( *xSvStrm, GetRoot() );
+ // SXDB
+ WriteSxdb( aStrm );
+ // SXDBEX
+ WriteSxdbex( aStrm );
+ // field list (SXFIELD and items)
+ maFieldList.Save( aStrm );
+ // index table (list of SXINDEXLIST)
+ WriteSxindexlistList( aStrm );
+ // EOF
+ XclExpEmptyRecord( EXC_ID_EOF ).Save( aStrm );
+ }
+}
+
+void XclExpPivotCache::WriteSxdb( XclExpStream& rStrm ) const
+{
+ rStrm.StartRecord( EXC_ID_SXDB, 21 );
+ rStrm << maPCInfo;
+ rStrm.EndRecord();
+}
+
+void XclExpPivotCache::WriteSxdbex( XclExpStream& rStrm ) const
+{
+ rStrm.StartRecord( EXC_ID_SXDBEX, 12 );
+ rStrm << EXC_SXDBEX_CREATION_DATE
+ << sal_uInt32( 0 ); // number of SXFORMULA records
+ rStrm.EndRecord();
+}
+
+void XclExpPivotCache::WriteSxindexlistList( XclExpStream& rStrm ) const
+{
+ if( HasItemIndexList() )
+ {
+ sal_Size nRecSize = 0;
+ size_t nPos, nSize = maFieldList.GetSize();
+ for( nPos = 0; nPos < nSize; ++nPos )
+ nRecSize += maFieldList.GetRecord( nPos )->GetIndexSize();
+
+ for( sal_uInt32 nSrcRow = 0; nSrcRow < maPCInfo.mnSrcRecs; ++nSrcRow )
+ {
+ rStrm.StartRecord( EXC_ID_SXINDEXLIST, nRecSize );
+ for( nPos = 0; nPos < nSize; ++nPos )
+ maFieldList.GetRecord( nPos )->WriteIndex( rStrm, nSrcRow );
+ rStrm.EndRecord();
+ }
+ }
+}
+
+// ============================================================================
+// Pivot table
+// ============================================================================
+
+namespace {
+
+// ----------------------------------------------------------------------------
+
+/** Returns a display string for a data field containing the field name and aggregation function. */
+String lclGetDataFieldCaption( const String& rFieldName, GeneralFunction eFunc )
+{
+ String aCaption;
+
+ sal_uInt16 nResIdx = 0;
+ using namespace ::com::sun::star::sheet;
+ switch( eFunc )
+ {
+ case GeneralFunction_SUM: nResIdx = STR_FUN_TEXT_SUM; break;
+ case GeneralFunction_COUNT: nResIdx = STR_FUN_TEXT_COUNT; break;
+ case GeneralFunction_AVERAGE: nResIdx = STR_FUN_TEXT_AVG; break;
+ case GeneralFunction_MAX: nResIdx = STR_FUN_TEXT_MAX; break;
+ case GeneralFunction_MIN: nResIdx = STR_FUN_TEXT_MIN; break;
+ case GeneralFunction_PRODUCT: nResIdx = STR_FUN_TEXT_PRODUCT; break;
+ case GeneralFunction_COUNTNUMS: nResIdx = STR_FUN_TEXT_COUNT; break;
+ case GeneralFunction_STDEV: nResIdx = STR_FUN_TEXT_STDDEV; break;
+ case GeneralFunction_STDEVP: nResIdx = STR_FUN_TEXT_STDDEV; break;
+ case GeneralFunction_VAR: nResIdx = STR_FUN_TEXT_VAR; break;
+ case GeneralFunction_VARP: nResIdx = STR_FUN_TEXT_VAR; break;
+ default:;
+ }
+ if( nResIdx )
+ aCaption.Assign( ScGlobal::GetRscString( nResIdx ) ).AppendAscii( RTL_CONSTASCII_STRINGPARAM( " - " ) );
+ aCaption.Append( rFieldName );
+ return aCaption;
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace
+
+// ============================================================================
+
+XclExpPTItem::XclExpPTItem( const XclExpPCField& rCacheField, sal_uInt16 nCacheIdx ) :
+ XclExpRecord( EXC_ID_SXVI, 8 ),
+ mpCacheItem( rCacheField.GetItem( nCacheIdx ) )
+{
+ maItemInfo.mnType = EXC_SXVI_TYPE_DATA;
+ maItemInfo.mnCacheIdx = nCacheIdx;
+ maItemInfo.maVisName.mbUseCache = mpCacheItem != 0;
+}
+
+XclExpPTItem::XclExpPTItem( sal_uInt16 nItemType, sal_uInt16 nCacheIdx, bool bUseCache ) :
+ XclExpRecord( EXC_ID_SXVI, 8 ),
+ mpCacheItem( 0 )
+{
+ maItemInfo.mnType = nItemType;
+ maItemInfo.mnCacheIdx = nCacheIdx;
+ maItemInfo.maVisName.mbUseCache = bUseCache;
+}
+
+const String& XclExpPTItem::GetItemName() const
+{
+ return mpCacheItem ? mpCacheItem->ConvertToText() : EMPTY_STRING;
+}
+
+void XclExpPTItem::SetPropertiesFromMember( const ScDPSaveMember& rSaveMem )
+{
+ ::set_flag( maItemInfo.mnFlags, EXC_SXVI_HIDDEN, !rSaveMem.GetIsVisible() );
+ ::set_flag( maItemInfo.mnFlags, EXC_SXVI_HIDEDETAIL, !rSaveMem.GetShowDetails() );
+
+ // visible name
+ const OUString* pVisName = rSaveMem.GetLayoutName();
+ if (pVisName && !pVisName->equals(GetItemName()))
+ maItemInfo.SetVisName(*pVisName);
+}
+
+void XclExpPTItem::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << maItemInfo;
+}
+
+// ============================================================================
+
+XclExpPTField::XclExpPTField( const XclExpPivotTable& rPTable, sal_uInt16 nCacheIdx ) :
+ mrPTable( rPTable ),
+ mpCacheField( rPTable.GetCacheField( nCacheIdx ) )
+{
+ maFieldInfo.mnCacheIdx = nCacheIdx;
+
+ // create field items
+ if( mpCacheField )
+ for( sal_uInt16 nItemIdx = 0, nItemCount = mpCacheField->GetItemCount(); nItemIdx < nItemCount; ++nItemIdx )
+ maItemList.AppendNewRecord( new XclExpPTItem( *mpCacheField, nItemIdx ) );
+ maFieldInfo.mnItemCount = static_cast< sal_uInt16 >( maItemList.GetSize() );
+}
+
+// data access ----------------------------------------------------------------
+
+const String& XclExpPTField::GetFieldName() const
+{
+ return mpCacheField ? mpCacheField->GetFieldName() : EMPTY_STRING;
+}
+
+sal_uInt16 XclExpPTField::GetFieldIndex() const
+{
+ // field index always equal to cache index
+ return maFieldInfo.mnCacheIdx;
+}
+
+sal_uInt16 XclExpPTField::GetLastDataInfoIndex() const
+{
+ DBG_ASSERT( !maDataInfoVec.empty(), "XclExpPTField::GetLastDataInfoIndex - no data info found" );
+ // will return 0xFFFF for empty vector -> ok
+ return static_cast< sal_uInt16 >( maDataInfoVec.size() - 1 );
+}
+
+sal_uInt16 XclExpPTField::GetItemIndex( const String& rName, sal_uInt16 nDefaultIdx ) const
+{
+ for( size_t nPos = 0, nSize = maItemList.GetSize(); nPos < nSize; ++nPos )
+ if( maItemList.GetRecord( nPos )->GetItemName() == rName )
+ return static_cast< sal_uInt16 >( nPos );
+ return nDefaultIdx;
+}
+
+// fill data --------------------------------------------------------------
+
+/**
+ * Calc's subtotal names are escaped with backslashes ('\'), while Excel's
+ * are not escaped at all.
+ */
+static OUString lcl_convertCalcSubtotalName(const OUString& rName)
+{
+ OUStringBuffer aBuf;
+ const sal_Unicode* p = rName.getStr();
+ sal_Int32 n = rName.getLength();
+ bool bEscaped = false;
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ const sal_Unicode c = p[i];
+ if (!bEscaped && c == sal_Unicode('\\'))
+ {
+ bEscaped = true;
+ continue;
+ }
+
+ aBuf.append(c);
+ bEscaped = false;
+ }
+ return aBuf.makeStringAndClear();
+}
+
+void XclExpPTField::SetPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
+{
+ // orientation
+ DataPilotFieldOrientation eOrient = static_cast< DataPilotFieldOrientation >( rSaveDim.GetOrientation() );
+ DBG_ASSERT( eOrient != DataPilotFieldOrientation_DATA, "XclExpPTField::SetPropertiesFromDim - called for data field" );
+ maFieldInfo.AddApiOrient( eOrient );
+
+ // show empty items
+ ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SHOWALL, rSaveDim.GetShowEmpty() );
+
+ // visible name
+ const OUString* pLayoutName = rSaveDim.GetLayoutName();
+ if (pLayoutName && !pLayoutName->equals(GetFieldName()))
+ maFieldInfo.SetVisName(*pLayoutName);
+
+ const rtl::OUString* pSubtotalName = rSaveDim.GetSubtotalName();
+ if (pSubtotalName)
+ {
+ OUString aSubName = lcl_convertCalcSubtotalName(*pSubtotalName);
+ maFieldExtInfo.mpFieldTotalName.reset(new rtl::OUString(aSubName));
+ }
+
+ // subtotals
+ XclPTSubtotalVec aSubtotals;
+ aSubtotals.reserve( static_cast< size_t >( rSaveDim.GetSubTotalsCount() ) );
+ for( long nSubtIdx = 0, nSubtCount = rSaveDim.GetSubTotalsCount(); nSubtIdx < nSubtCount; ++nSubtIdx )
+ aSubtotals.push_back( rSaveDim.GetSubTotalFunc( nSubtIdx ) );
+ maFieldInfo.SetSubtotals( aSubtotals );
+
+ // sorting
+ if( const DataPilotFieldSortInfo* pSortInfo = rSaveDim.GetSortInfo() )
+ {
+ maFieldExtInfo.SetApiSortMode( pSortInfo->Mode );
+ if( pSortInfo->Mode == ::com::sun::star::sheet::DataPilotFieldSortMode::DATA )
+ maFieldExtInfo.mnSortField = mrPTable.GetDataFieldIndex( pSortInfo->Field, EXC_SXVDEX_SORT_OWN );
+ ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SORT_ASC, pSortInfo->IsAscending );
+ }
+
+ // auto show
+ if( const DataPilotFieldAutoShowInfo* pShowInfo = rSaveDim.GetAutoShowInfo() )
+ {
+ ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_AUTOSHOW, pShowInfo->IsEnabled );
+ maFieldExtInfo.SetApiAutoShowMode( pShowInfo->ShowItemsMode );
+ maFieldExtInfo.SetApiAutoShowCount( pShowInfo->ItemCount );
+ maFieldExtInfo.mnShowField = mrPTable.GetDataFieldIndex( pShowInfo->DataField, EXC_SXVDEX_SHOW_NONE );
+ }
+
+ // layout
+ if( const DataPilotFieldLayoutInfo* pLayoutInfo = rSaveDim.GetLayoutInfo() )
+ {
+ maFieldExtInfo.SetApiLayoutMode( pLayoutInfo->LayoutMode );
+ ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_LAYOUT_BLANK, pLayoutInfo->AddEmptyLines );
+ }
+
+ // special page field properties
+ if( eOrient == DataPilotFieldOrientation_PAGE )
+ {
+ maPageInfo.mnField = GetFieldIndex();
+
+ // selected item
+ if( rSaveDim.HasCurrentPage() )
+ maPageInfo.mnSelItem = GetItemIndex( rSaveDim.GetCurrentPage(), EXC_SXPI_ALLITEMS );
+ else
+ maPageInfo.mnSelItem = EXC_SXPI_ALLITEMS;
+ }
+
+ // item properties
+ const ScDPSaveDimension::MemberList &rMembers = rSaveDim.GetMembers();
+ for (ScDPSaveDimension::MemberList::const_iterator i=rMembers.begin(); i != rMembers.end() ; ++i)
+ if( XclExpPTItem* pItem = GetItemAcc( (*i)->GetName() ) )
+ pItem->SetPropertiesFromMember( **i );
+}
+
+void XclExpPTField::SetDataPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
+{
+ maDataInfoVec.push_back( XclPTDataFieldInfo() );
+ XclPTDataFieldInfo& rDataInfo = maDataInfoVec.back();
+ rDataInfo.mnField = GetFieldIndex();
+
+ // orientation
+ maFieldInfo.AddApiOrient( DataPilotFieldOrientation_DATA );
+
+ // aggregation function
+ GeneralFunction eFunc = static_cast< GeneralFunction >( rSaveDim.GetFunction() );
+ rDataInfo.SetApiAggFunc( eFunc );
+
+ // visible name
+ const rtl::OUString* pVisName = rSaveDim.GetLayoutName();
+ if (pVisName)
+ rDataInfo.SetVisName(*pVisName);
+ else
+ rDataInfo.SetVisName( lclGetDataFieldCaption( GetFieldName(), eFunc ) );
+
+ // result field reference
+ if( const DataPilotFieldReference* pFieldRef = rSaveDim.GetReferenceValue() )
+ {
+ rDataInfo.SetApiRefType( pFieldRef->ReferenceType );
+ rDataInfo.SetApiRefItemType( pFieldRef->ReferenceItemType );
+ if( const XclExpPTField* pRefField = mrPTable.GetField( pFieldRef->ReferenceField ) )
+ {
+ rDataInfo.mnRefField = pRefField->GetFieldIndex();
+ if( pFieldRef->ReferenceItemType == ::com::sun::star::sheet::DataPilotFieldReferenceItemType::NAMED )
+ rDataInfo.mnRefItem = pRefField->GetItemIndex( pFieldRef->ReferenceItemName, 0 );
+ }
+ }
+}
+
+void XclExpPTField::AppendSubtotalItems()
+{
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_DEFAULT ) AppendSubtotalItem( EXC_SXVI_TYPE_DEFAULT );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_SUM ) AppendSubtotalItem( EXC_SXVI_TYPE_SUM );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_COUNT ) AppendSubtotalItem( EXC_SXVI_TYPE_COUNT );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_AVERAGE ) AppendSubtotalItem( EXC_SXVI_TYPE_AVERAGE );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_MAX ) AppendSubtotalItem( EXC_SXVI_TYPE_MAX );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_MIN ) AppendSubtotalItem( EXC_SXVI_TYPE_MIN );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_PROD ) AppendSubtotalItem( EXC_SXVI_TYPE_PROD );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_COUNTNUM ) AppendSubtotalItem( EXC_SXVI_TYPE_COUNTNUM );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_STDDEV ) AppendSubtotalItem( EXC_SXVI_TYPE_STDDEV );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_STDDEVP ) AppendSubtotalItem( EXC_SXVI_TYPE_STDDEVP );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_VAR ) AppendSubtotalItem( EXC_SXVI_TYPE_VAR );
+ if( maFieldInfo.mnSubtotals & EXC_SXVD_SUBT_VARP ) AppendSubtotalItem( EXC_SXVI_TYPE_VARP );
+}
+
+// records --------------------------------------------------------------------
+
+void XclExpPTField::WriteSxpiEntry( XclExpStream& rStrm ) const
+{
+ rStrm << maPageInfo;
+}
+
+void XclExpPTField::WriteSxdi( XclExpStream& rStrm, sal_uInt16 nDataInfoIdx ) const
+{
+ DBG_ASSERT( nDataInfoIdx < maDataInfoVec.size(), "XclExpPTField::WriteSxdi - data field not found" );
+ if( nDataInfoIdx < maDataInfoVec.size() )
+ {
+ rStrm.StartRecord( EXC_ID_SXDI, 12 );
+ rStrm << maDataInfoVec[ nDataInfoIdx ];
+ rStrm.EndRecord();
+ }
+}
+
+void XclExpPTField::Save( XclExpStream& rStrm )
+{
+ // SXVD
+ WriteSxvd( rStrm );
+ // list of SXVI records
+ maItemList.Save( rStrm );
+ // SXVDEX
+ WriteSxvdex( rStrm );
+}
+
+// private --------------------------------------------------------------------
+
+XclExpPTItem* XclExpPTField::GetItemAcc( const String& rName )
+{
+ XclExpPTItem* pItem = 0;
+ for( size_t nPos = 0, nSize = maItemList.GetSize(); !pItem && (nPos < nSize); ++nPos )
+ if( maItemList.GetRecord( nPos )->GetItemName() == rName )
+ pItem = maItemList.GetRecord( nPos ).get();
+ return pItem;
+}
+
+void XclExpPTField::AppendSubtotalItem( sal_uInt16 nItemType )
+{
+ maItemList.AppendNewRecord( new XclExpPTItem( nItemType, EXC_SXVI_DEFAULT_CACHE, true ) );
+ ++maFieldInfo.mnItemCount;
+}
+
+void XclExpPTField::WriteSxvd( XclExpStream& rStrm ) const
+{
+ rStrm.StartRecord( EXC_ID_SXVD, 10 );
+ rStrm << maFieldInfo;
+ rStrm.EndRecord();
+}
+
+void XclExpPTField::WriteSxvdex( XclExpStream& rStrm ) const
+{
+ rStrm.StartRecord( EXC_ID_SXVDEX, 20 );
+ rStrm << maFieldExtInfo;
+ rStrm.EndRecord();
+}
+
+// ============================================================================
+
+XclExpPivotTable::XclExpPivotTable( const XclExpRoot& rRoot, const ScDPObject& rDPObj, const XclExpPivotCache& rPCache ) :
+ XclExpRoot( rRoot ),
+ mrPCache( rPCache ),
+ maDataOrientField( *this, EXC_SXIVD_DATA ),
+ mnOutScTab( 0 ),
+ mbValid( false ),
+ mbFilterBtn( false )
+{
+ const ScRange& rOutScRange = rDPObj.GetOutRange();
+ if( GetAddressConverter().ConvertRange( maPTInfo.maOutXclRange, rOutScRange, true ) )
+ {
+ // DataPilot properties -----------------------------------------------
+
+ // pivot table properties from DP object
+ mnOutScTab = rOutScRange.aStart.Tab();
+ maPTInfo.maTableName = rDPObj.GetName();
+ maPTInfo.mnCacheIdx = mrPCache.GetCacheIndex();
+
+ maPTViewEx9Info.Init( rDPObj );
+
+ if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
+ {
+ // additional properties from ScDPSaveData
+ SetPropertiesFromDP( *pSaveData );
+
+ // loop over all dimensions ---------------------------------------
+
+ /* 1) Default-construct all pivot table fields for all pivot cache fields. */
+ for( sal_uInt16 nFieldIdx = 0, nFieldCount = mrPCache.GetFieldCount(); nFieldIdx < nFieldCount; ++nFieldIdx )
+ maFieldList.AppendNewRecord( new XclExpPTField( *this, nFieldIdx ) );
+
+ boost::ptr_vector<ScDPSaveDimension>::const_iterator iter;
+ const boost::ptr_vector<ScDPSaveDimension>& rDimList = pSaveData->GetDimensions();
+
+ /* 2) First process all data dimensions, they are needed for extended
+ settings of row/column/page fields (sorting/auto show). */
+ for (iter = rDimList.begin(); iter != rDimList.end(); ++iter)
+ if (iter->GetOrientation() == DataPilotFieldOrientation_DATA)
+ SetDataFieldPropertiesFromDim(*iter);
+
+ /* 3) Row/column/page/hidden fields. */
+ for (iter = rDimList.begin(); iter != rDimList.end(); ++iter)
+ if (iter->GetOrientation() != DataPilotFieldOrientation_DATA)
+ SetFieldPropertiesFromDim(*iter);
+
+ // Finalize -------------------------------------------------------
+
+ Finalize();
+ mbValid = true;
+ }
+ }
+}
+
+const XclExpPCField* XclExpPivotTable::GetCacheField( sal_uInt16 nCacheIdx ) const
+{
+ return mrPCache.GetField( nCacheIdx );
+}
+
+const XclExpPTField* XclExpPivotTable::GetField( sal_uInt16 nFieldIdx ) const
+{
+ return (nFieldIdx == EXC_SXIVD_DATA) ? &maDataOrientField : maFieldList.GetRecord( nFieldIdx ).get();
+}
+
+const XclExpPTField* XclExpPivotTable::GetField( const String& rName ) const
+{
+ return const_cast< XclExpPivotTable* >( this )->GetFieldAcc( rName );
+}
+
+sal_uInt16 XclExpPivotTable::GetDataFieldIndex( const String& rName, sal_uInt16 nDefaultIdx ) const
+{
+ for( XclPTDataFieldPosVec::const_iterator aIt = maDataFields.begin(), aEnd = maDataFields.end(); aIt != aEnd; ++aIt )
+ if( const XclExpPTField* pField = GetField( aIt->first ) )
+ if( pField->GetFieldName() == rName )
+ return static_cast< sal_uInt16 >( aIt - maDataFields.begin() );
+ return nDefaultIdx;
+}
+
+void XclExpPivotTable::Save( XclExpStream& rStrm )
+{
+ if( mbValid )
+ {
+ // SXVIEW
+ WriteSxview( rStrm );
+ // pivot table fields (SXVD, SXVDEX, and item records)
+ maFieldList.Save( rStrm );
+ // SXIVD records for row and column fields
+ WriteSxivd( rStrm, maRowFields );
+ WriteSxivd( rStrm, maColFields );
+ // SXPI
+ WriteSxpi( rStrm );
+ // list of SXDI records containing data field info
+ WriteSxdiList( rStrm );
+ // SXLI records
+ WriteSxli( rStrm, maPTInfo.mnDataRows, maPTInfo.mnRowFields );
+ WriteSxli( rStrm, maPTInfo.mnDataCols, maPTInfo.mnColFields );
+ // SXEX
+ WriteSxex( rStrm );
+ // QSISXTAG
+ WriteQsiSxTag( rStrm );
+ // SXVIEWEX9
+ WriteSxViewEx9( rStrm );
+ }
+}
+
+void XclExpPivotTable::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( !mbValid )
+ return;
+ sax_fastparser::FSHelperPtr aPivotTableDefinition = rStrm.CreateOutputStream(
+ XclXmlUtils::GetStreamName( "xl/", "pivotTables/pivotTable", mnOutScTab+1),
+ XclXmlUtils::GetStreamName( "../", "pivotTables/pivotTable", mnOutScTab+1),
+ rStrm.GetCurrentStream()->getOutputStream(),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml",
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable");
+ rStrm.PushStream( aPivotTableDefinition );
+
+ aPivotTableDefinition->startElement( XML_pivotTableDefinition,
+ XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
+ XML_name, XclXmlUtils::ToOString( maPTInfo.maTableName ).getStr(),
+ XML_cacheId, OString::valueOf( (sal_Int32) maPTInfo.mnCacheIdx ).getStr(),
+ XML_dataOnRows, XclXmlUtils::ToPsz( maPTInfo.mnDataAxis == EXC_SXVD_AXIS_COL ),
+ XML_dataPosition, OString::valueOf( (sal_Int32) maPTInfo.mnDataPos ).getStr(),
+ XML_autoFormatId, OString::valueOf( (sal_Int32) maPTInfo.mnAutoFmtIdx ).getStr(),
+ // OOXTODO: XML_applyNumberFormats, [ SXVIEW fAtrNum (maPTInfo.mnFlags) ]
+ // OOXTODO: XML_applyBorderFormats, [ SXVIEW fAtrBdr (maPTInfo.mnFlags) ]
+ // OOXTODO: XML_applyFontFormats, [ SXVIEW fAtrFnt (maPTInfo.mnFlags) ]
+ // OOXTODO: XML_applyPatternFormats, [ SXVIEW fAtrPat (maPTInfo.mnFlags) ]
+ // OOXTODO: XML_applyAlignmentFormats, [ SXVIEW fAtrAlc (maPTInfo.mnFlags) ]
+ // OOXTODO: XML_applyWidthHeightFormats, [ SXVIEW fAtrProc (maPTInfo.mnFlags) ]
+ XML_dataCaption, XclXmlUtils::ToOString( maPTInfo.maDataName ).getStr(),
+ // OOXTODO: XML_grandTotalCaption, [ SxViewEx9 chGrand ]
+ // OOXTODO: XML_errorCaption, [ SXEx stError ]
+ // OOXTODO: XML_showError, [ SXEx fDisplayErrorString ]
+ // OOXTODO: XML_missingCaption, [ SXEx stDisplayNull ]
+ // OOXTODO: XML_showMissing, [ SXEx fDisplayNullString ]
+ // OOXTODO: XML_pageStyle, [ SXEx stPageFieldStyle ]
+ // OOXTODO: XML_pivotTableStyle, [ SXEx stTableStyle ]
+ // OOXTODO: XML_vacatedStyle, [ SXEx stVacateStyle ]
+ // OOXTODO: XML_tag, [ SXEx stTag ]
+ // OOXTODO: XML_updatedVersion, [ app-dependent ]
+ // OOXTODO: XML_minRefreshableVersion, [ app-dependent ]
+ // OOXTODO: XML_asteriskTotals, [ QsiSXTag/SXView9Save fHideTotAnnotation ]
+ // OOXTODO: XML_showItems, [ ??? ]
+ // OOXTODO: XML_editData, [ ??? ]
+ // OOXTODO: XML_disableFieldList, [ SXEx fEnableFieldDialog? ]
+ // OOXTODO: XML_showCalcMbrs, [ ??? ]
+ // OOXTODO: XML_visualTotals, [ ??? ]
+ // OOXTODO: XML_showMultipleLabel, [ SXEx fMergeLabels? ]
+ // OOXTODO: XML_showDataDropDown, [ SXEx fEnableDrillDown? ]
+ // OOXTODO: XML_showDrill, [ ??? ]
+ // OOXTODO: XML_printDrill, [ ??? ]
+ // OOXTODO: XML_showMemberPropertyTips,
+ // OOXTODO: XML_showDataTips,
+ // OOXTODO: XML_enableWizard,
+ XML_enableDrill, XclXmlUtils::ToPsz( maPTExtInfo.mnFlags & EXC_SXEX_DRILLDOWN ), // ???
+ // OOXTODO: XML_enableFieldProperties, [ SXEx fEnableFieldDialog (maPTExtInfo.mnFlags) ]
+ // OOXTODO: XML_preserveFormatting, [ SXEx fPreserveFormatting (maPTExtInfo.mnFlags) ]
+ // OOXTODO: XML_pageWrap, [ SXEx cWrapPage (maPTExtInfo.mnFlags) ]
+ // OOXTODO: XML_pageOverThenDown, [ SXEx fAcrossPageLay (maPTExtInfo.mnFlags) ]
+ // OOXTODO: XML_subtotalHiddenItems, [ SXEx fSubtotalHiddenPageItems (maPTExtInfo.mnFlags) ]
+ XML_rowGrandTotals, XclXmlUtils::ToPsz( maPTInfo.mnFlags & EXC_SXVIEW_ROWGRAND ),
+ XML_colGrandTotals, XclXmlUtils::ToPsz( maPTInfo.mnFlags & EXC_SXVIEW_COLGRAND ),
+ // OOXTODO: XML_fieldPrintTitles,
+ // OOXTODO: XML_itemPrintTitles,
+ // OOXTODO: XML_mergeItem,
+ // OOXTODO: XML_showDropZones,
+ // OOXTODO: XML_createdVersion,
+ // OOXTODO: XML_indent,
+ // OOXTODO: XML_showEmptyRow,
+ // OOXTODO: XML_showEmptyCol,
+ // OOXTODO: XML_showHeaders,
+ // OOXTODO: XML_compact,
+ // OOXTODO: XML_outline,
+ // OOXTODO: XML_outlineData,
+ // OOXTODO: XML_compactData,
+ // OOXTODO: XML_published,
+ // OOXTODO: XML_gridDropZones,
+ // OOXTODO: XML_immersive,
+ // OOXTODO: XML_multipleFieldFilters,
+ // OOXTODO: XML_chartFormat,
+ // OOXTODO: XML_rowHeaderCaption,
+ // OOXTODO: XML_colHeaderCaption,
+ // OOXTODO: XML_fieldListSortAscending,
+ // OOXTODO: XML_mdxSubqueries,
+ // OOXTODO: XML_customListSort,
+ FSEND );
+
+ aPivotTableDefinition->singleElement( XML_location,
+ XML_ref, XclXmlUtils::ToOString( maPTInfo.maOutXclRange ).getStr(),
+ XML_firstHeaderRow, OString::valueOf( (sal_Int32) maPTInfo.mnFirstHeadRow ).getStr(),
+ XML_firstDataRow, OString::valueOf( (sal_Int32) maPTInfo.maDataXclPos.mnRow ).getStr(),
+ XML_firstDataCol, OString::valueOf( (sal_Int32) maPTInfo.maDataXclPos.mnCol ).getStr(),
+ XML_rowPageCount, OString::valueOf( (sal_Int32) maPTInfo.mnDataRows ).getStr(), // OOXTODO?
+ XML_colPageCount, OString::valueOf( (sal_Int32) maPTInfo.mnDataCols ).getStr(), // OOXTODO?
+ FSEND );
+
+ // OOXTODO: XML_pivotFields
+
+ // maPTInfo.mnFields?
+ if( maPTInfo.mnRowFields )
+ {
+ aPivotTableDefinition->startElement( XML_rowFields,
+ XML_count, OString::valueOf( (sal_Int32) maPTInfo.mnRowFields ).getStr(),
+ FSEND );
+ aPivotTableDefinition->endElement( XML_rowFields );
+ }
+
+ // OOXTODO: XML_rowItems
+
+ if( maPTInfo.mnColFields )
+ {
+ aPivotTableDefinition->startElement( XML_colFields,
+ XML_count, OString::valueOf( (sal_Int32) maPTInfo.mnColFields ).getStr(),
+ FSEND );
+ aPivotTableDefinition->endElement( XML_colFields );
+ }
+
+ // OOXTODO: XML_colItems
+
+ if( maPTInfo.mnPageFields )
+ {
+ aPivotTableDefinition->startElement( XML_pageFields,
+ XML_count, OString::valueOf( (sal_Int32) maPTInfo.mnPageFields ).getStr(),
+ FSEND );
+ aPivotTableDefinition->endElement( XML_pageFields );
+ }
+
+ if( maPTInfo.mnDataFields )
+ {
+ aPivotTableDefinition->startElement( XML_dataFields,
+ XML_count, OString::valueOf( (sal_Int32) maPTInfo.mnDataFields ).getStr(),
+ FSEND );
+ aPivotTableDefinition->endElement( XML_dataFields );
+ }
+
+ // OOXTODO: XML_formats, XML_conditionalFormats, XML_chartFormats,
+ // XML_pivotHierarchies, XML_pivotTableStyleInfo, XML_filters,
+ // XML_rowHierarchiesUsage, XML_colHierarchiesUsage, XML_ext
+
+ aPivotTableDefinition->endElement( XML_pivotTableDefinition );
+
+ rStrm.PopStream();
+}
+
+// private --------------------------------------------------------------------
+
+XclExpPTField* XclExpPivotTable::GetFieldAcc( const String& rName )
+{
+ XclExpPTField* pField = 0;
+ for( size_t nPos = 0, nSize = maFieldList.GetSize(); !pField && (nPos < nSize); ++nPos )
+ if( maFieldList.GetRecord( nPos )->GetFieldName() == rName )
+ pField = maFieldList.GetRecord( nPos ).get();
+ return pField;
+}
+
+XclExpPTField* XclExpPivotTable::GetFieldAcc( const ScDPSaveDimension& rSaveDim )
+{
+ // data field orientation field?
+ if( rSaveDim.IsDataLayout() )
+ return &maDataOrientField;
+
+ // a real dimension
+ String aFieldName( rSaveDim.GetName() );
+ return aFieldName.Len() ? GetFieldAcc( aFieldName ) : 0;
+}
+
+// fill data --------------------------------------------------------------
+
+void XclExpPivotTable::SetPropertiesFromDP( const ScDPSaveData& rSaveData )
+{
+ ::set_flag( maPTInfo.mnFlags, EXC_SXVIEW_ROWGRAND, rSaveData.GetRowGrand() );
+ ::set_flag( maPTInfo.mnFlags, EXC_SXVIEW_COLGRAND, rSaveData.GetColumnGrand() );
+ ::set_flag( maPTExtInfo.mnFlags, EXC_SXEX_DRILLDOWN, rSaveData.GetDrillDown() );
+ mbFilterBtn = rSaveData.GetFilterButton();
+ const ScDPSaveDimension* pDim = rSaveData.GetExistingDataLayoutDimension();
+ if (!pDim)
+ return;
+
+ const rtl::OUString* pLayoutName = pDim->GetLayoutName();
+ if (pLayoutName)
+ maPTInfo.maDataName = *pLayoutName;
+ else
+ maPTInfo.maDataName = ScGlobal::GetRscString(STR_PIVOT_DATA);
+}
+
+void XclExpPivotTable::SetFieldPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
+{
+ if( XclExpPTField* pField = GetFieldAcc( rSaveDim ) )
+ {
+ // field properties
+ pField->SetPropertiesFromDim( rSaveDim );
+
+ // update the corresponding field position list
+ DataPilotFieldOrientation eOrient = static_cast< DataPilotFieldOrientation >( rSaveDim.GetOrientation() );
+ sal_uInt16 nFieldIdx = pField->GetFieldIndex();
+ bool bDataLayout = nFieldIdx == EXC_SXIVD_DATA;
+ bool bMultiData = maDataFields.size() > 1;
+
+ if( !bDataLayout || bMultiData ) switch( eOrient )
+ {
+ case DataPilotFieldOrientation_ROW:
+ maRowFields.push_back( nFieldIdx );
+ if( bDataLayout )
+ maPTInfo.mnDataAxis = EXC_SXVD_AXIS_ROW;
+ break;
+ case DataPilotFieldOrientation_COLUMN:
+ maColFields.push_back( nFieldIdx );
+ if( bDataLayout )
+ maPTInfo.mnDataAxis = EXC_SXVD_AXIS_COL;
+ break;
+ case DataPilotFieldOrientation_PAGE:
+ maPageFields.push_back( nFieldIdx );
+ DBG_ASSERT( !bDataLayout, "XclExpPivotTable::SetFieldPropertiesFromDim - wrong orientation for data fields" );
+ break;
+ case DataPilotFieldOrientation_DATA:
+ DBG_ERRORFILE( "XclExpPivotTable::SetFieldPropertiesFromDim - called for data field" );
+ break;
+ default:;
+ }
+ }
+}
+
+void XclExpPivotTable::SetDataFieldPropertiesFromDim( const ScDPSaveDimension& rSaveDim )
+{
+ if( XclExpPTField* pField = GetFieldAcc( rSaveDim ) )
+ {
+ // field properties
+ pField->SetDataPropertiesFromDim( rSaveDim );
+ // update the data field position list
+ maDataFields.push_back( XclPTDataFieldPos( pField->GetFieldIndex(), pField->GetLastDataInfoIndex() ) );
+ }
+}
+
+void XclExpPivotTable::Finalize()
+{
+ // field numbers
+ maPTInfo.mnFields = static_cast< sal_uInt16 >( maFieldList.GetSize() );
+ maPTInfo.mnRowFields = static_cast< sal_uInt16 >( maRowFields.size() );
+ maPTInfo.mnColFields = static_cast< sal_uInt16 >( maColFields.size() );
+ maPTInfo.mnPageFields = static_cast< sal_uInt16 >( maPageFields.size() );
+ maPTInfo.mnDataFields = static_cast< sal_uInt16 >( maDataFields.size() );
+
+ maPTExtInfo.mnPagePerRow = maPTInfo.mnPageFields;
+ maPTExtInfo.mnPagePerCol = (maPTInfo.mnPageFields > 0) ? 1 : 0;
+
+ // subtotal items
+ for( size_t nPos = 0, nSize = maFieldList.GetSize(); nPos < nSize; ++nPos )
+ maFieldList.GetRecord( nPos )->AppendSubtotalItems();
+
+ // find data field orientation field
+ maPTInfo.mnDataPos = EXC_SXVIEW_DATALAST;
+ const ScfUInt16Vec* pFieldVec = 0;
+ switch( maPTInfo.mnDataAxis )
+ {
+ case EXC_SXVD_AXIS_ROW: pFieldVec = &maRowFields; break;
+ case EXC_SXVD_AXIS_COL: pFieldVec = &maColFields; break;
+ }
+
+ if( pFieldVec && !pFieldVec->empty() && (pFieldVec->back() != EXC_SXIVD_DATA) )
+ {
+ ScfUInt16Vec::const_iterator aIt = ::std::find( pFieldVec->begin(), pFieldVec->end(), EXC_SXIVD_DATA );
+ if( aIt != pFieldVec->end() )
+ maPTInfo.mnDataPos = static_cast< sal_uInt16 >( aIt - pFieldVec->begin() );
+ }
+
+ // single data field is always row oriented
+ if( maPTInfo.mnDataAxis == EXC_SXVD_AXIS_NONE )
+ maPTInfo.mnDataAxis = EXC_SXVD_AXIS_ROW;
+
+ // update output range (initialized in ctor)
+ sal_uInt16& rnXclCol1 = maPTInfo.maOutXclRange.maFirst.mnCol;
+ sal_uInt32& rnXclRow1 = maPTInfo.maOutXclRange.maFirst.mnRow;
+ sal_uInt16& rnXclCol2 = maPTInfo.maOutXclRange.maLast.mnCol;
+ sal_uInt32& rnXclRow2 = maPTInfo.maOutXclRange.maLast.mnRow;
+ // exclude page fields from output range
+ rnXclRow1 = rnXclRow1 + maPTInfo.mnPageFields;
+ // exclude filter button from output range
+ if( mbFilterBtn )
+ ++rnXclRow1;
+ // exclude empty row between (filter button and/or page fields) and table
+ if( mbFilterBtn || maPTInfo.mnPageFields )
+ ++rnXclRow1;
+
+ // data area
+ sal_uInt16& rnDataXclCol = maPTInfo.maDataXclPos.mnCol;
+ sal_uInt32& rnDataXclRow = maPTInfo.maDataXclPos.mnRow;
+ rnDataXclCol = rnXclCol1 + maPTInfo.mnRowFields;
+ rnDataXclRow = rnXclRow1 + maPTInfo.mnColFields + 1;
+ if( maDataFields.empty() )
+ ++rnDataXclRow;
+
+ bool bExtraHeaderRow = (0 == maPTViewEx9Info.mnGridLayout && maPTInfo.mnColFields == 0);
+ if (bExtraHeaderRow)
+ // Insert an extra row only when there is no column field.
+ ++rnDataXclRow;
+
+ rnXclCol2 = ::std::max( rnXclCol2, rnDataXclCol );
+ rnXclRow2 = ::std::max( rnXclRow2, rnDataXclRow );
+ maPTInfo.mnDataCols = rnXclCol2 - rnDataXclCol + 1;
+ maPTInfo.mnDataRows = rnXclRow2 - rnDataXclRow + 1;
+
+ // first heading
+ maPTInfo.mnFirstHeadRow = rnXclRow1;
+ if (bExtraHeaderRow)
+ maPTInfo.mnFirstHeadRow += 2;
+}
+
+// records ----------------------------------------------------------------
+
+void XclExpPivotTable::WriteSxview( XclExpStream& rStrm ) const
+{
+ rStrm.StartRecord( EXC_ID_SXVIEW, 46 + maPTInfo.maTableName.Len() + maPTInfo.maDataName.Len() );
+ rStrm << maPTInfo;
+ rStrm.EndRecord();
+}
+
+void XclExpPivotTable::WriteSxivd( XclExpStream& rStrm, const ScfUInt16Vec& rFields ) const
+{
+ if( !rFields.empty() )
+ {
+ rStrm.StartRecord( EXC_ID_SXIVD, rFields.size() * 2 );
+ for( ScfUInt16Vec::const_iterator aIt = rFields.begin(), aEnd = rFields.end(); aIt != aEnd; ++aIt )
+ rStrm << *aIt;
+ rStrm.EndRecord();
+ }
+}
+
+void XclExpPivotTable::WriteSxpi( XclExpStream& rStrm ) const
+{
+ if( !maPageFields.empty() )
+ {
+ rStrm.StartRecord( EXC_ID_SXPI, maPageFields.size() * 6 );
+ rStrm.SetSliceSize( 6 );
+ for( ScfUInt16Vec::const_iterator aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
+ {
+ XclExpPTFieldRef xField = maFieldList.GetRecord( *aIt );
+ if( xField )
+ xField->WriteSxpiEntry( rStrm );
+ }
+ rStrm.EndRecord();
+ }
+}
+
+void XclExpPivotTable::WriteSxdiList( XclExpStream& rStrm ) const
+{
+ for( XclPTDataFieldPosVec::const_iterator aIt = maDataFields.begin(), aEnd = maDataFields.end(); aIt != aEnd; ++aIt )
+ {
+ XclExpPTFieldRef xField = maFieldList.GetRecord( aIt->first );
+ if( xField )
+ xField->WriteSxdi( rStrm, aIt->second );
+ }
+}
+
+void XclExpPivotTable::WriteSxli( XclExpStream& rStrm, sal_uInt16 nLineCount, sal_uInt16 nIndexCount ) const
+{
+ if( nLineCount > 0 )
+ {
+ sal_uInt16 nLineSize = 8 + 2 * nIndexCount;
+ rStrm.StartRecord( EXC_ID_SXLI, nLineSize * nLineCount );
+
+ /* Excel expects the records to be filled completely, do not
+ set a segment size... */
+// rStrm.SetSliceSize( nLineSize );
+
+ for( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
+ {
+ // Excel XP needs a partly initialized SXLI record
+ rStrm << sal_uInt16( 0 ) // number of equal index entries
+ << EXC_SXVI_TYPE_DATA
+ << nIndexCount
+ << EXC_SXLI_DEFAULTFLAGS;
+ rStrm.WriteZeroBytes( 2 * nIndexCount );
+ }
+ rStrm.EndRecord();
+ }
+}
+
+void XclExpPivotTable::WriteSxex( XclExpStream& rStrm ) const
+{
+ rStrm.StartRecord( EXC_ID_SXEX, 24 );
+ rStrm << maPTExtInfo;
+ rStrm.EndRecord();
+}
+
+void XclExpPivotTable::WriteQsiSxTag( XclExpStream& rStrm ) const
+{
+ rStrm.StartRecord( 0x0802, 32 );
+
+ sal_uInt16 nRecordType = 0x0802;
+ sal_uInt16 nDummyFlags = 0x0000;
+ sal_uInt16 nTableType = 1; // 0 = query table : 1 = pivot table
+
+ rStrm << nRecordType << nDummyFlags << nTableType;
+
+ // General flags
+ bool bEnableRefresh = true;
+ bool bPCacheInvalid = false;
+ bool bOlapPTReport = false;
+
+ sal_uInt16 nFlags = 0x0000;
+ if (bEnableRefresh) nFlags |= 0x0001;
+ if (bPCacheInvalid) nFlags |= 0x0002;
+ if (bOlapPTReport) nFlags |= 0x0004;
+ rStrm << nFlags;
+
+ // Feature-specific options. The value differs depending on the table
+ // type, but we assume the table type is always pivot table.
+ sal_uInt32 nOptions = 0x00000000;
+ bool bNoStencil = false;
+ bool bHideTotal = false;
+ bool bEmptyRows = false;
+ bool bEmptyCols = false;
+ if (bNoStencil) nOptions |= 0x00000001;
+ if (bHideTotal) nOptions |= 0x00000002;
+ if (bEmptyRows) nOptions |= 0x00000008;
+ if (bEmptyCols) nOptions |= 0x00000010;
+ rStrm << nOptions;
+
+ enum ExcelVersion
+ {
+ Excel2000 = 0,
+ ExcelXP = 1,
+ Excel2003 = 2,
+ Excel2007 = 3
+ };
+ ExcelVersion eXclVer = Excel2000;
+ sal_uInt8 nOffsetBytes = 16;
+ rStrm << static_cast<sal_uInt8>(eXclVer) // version table last refreshed
+ << static_cast<sal_uInt8>(eXclVer) // minimum version to refresh
+ << nOffsetBytes
+ << static_cast<sal_uInt8>(eXclVer); // first version created
+
+ rStrm << XclExpString(maPTInfo.maTableName);
+ rStrm << static_cast<sal_uInt16>(0x0001); // no idea what this is for.
+
+ rStrm.EndRecord();
+}
+
+void XclExpPivotTable::WriteSxViewEx9( XclExpStream& rStrm ) const
+{
+ // Until we sync the autoformat ids only export if using grid header layout
+ // That could only have been set via xls import so far.
+ if ( 0 == maPTViewEx9Info.mnGridLayout )
+ {
+ rStrm.StartRecord( EXC_ID_SXVIEWEX9, 17 );
+ rStrm << maPTViewEx9Info;
+ rStrm.EndRecord();
+ }
+}
+
+// ============================================================================
+
+namespace {
+
+const SCTAB EXC_PTMGR_PIVOTCACHES = SCTAB_MAX;
+
+/** Record wrapper class to write the pivot caches or pivot tables. */
+class XclExpPivotRecWrapper : public XclExpRecordBase
+{
+public:
+ explicit XclExpPivotRecWrapper( XclExpPivotTableManager& rPTMgr, SCTAB nScTab );
+ virtual void Save( XclExpStream& rStrm );
+ virtual void SaveXml( XclExpXmlStream& rStrm );
+private:
+ XclExpPivotTableManager& mrPTMgr;
+ SCTAB mnScTab;
+};
+
+XclExpPivotRecWrapper::XclExpPivotRecWrapper( XclExpPivotTableManager& rPTMgr, SCTAB nScTab ) :
+ mrPTMgr( rPTMgr ),
+ mnScTab( nScTab )
+{
+}
+
+void XclExpPivotRecWrapper::Save( XclExpStream& rStrm )
+{
+ if( mnScTab == EXC_PTMGR_PIVOTCACHES )
+ mrPTMgr.WritePivotCaches( rStrm );
+ else
+ mrPTMgr.WritePivotTables( rStrm, mnScTab );
+}
+
+void XclExpPivotRecWrapper::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( mnScTab == EXC_PTMGR_PIVOTCACHES )
+ mrPTMgr.WritePivotCachesXml( rStrm );
+ else
+ mrPTMgr.WritePivotTablesXml( rStrm, mnScTab );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpPivotTableManager::XclExpPivotTableManager( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mbShareCaches( true )
+{
+}
+
+void XclExpPivotTableManager::CreatePivotTables()
+{
+ if( ScDPCollection* pDPColl = GetDoc().GetDPCollection() )
+ for( size_t nDPObj = 0, nCount = pDPColl->GetCount(); nDPObj < nCount; ++nDPObj )
+ if( ScDPObject* pDPObj = (*pDPColl)[ nDPObj ] )
+ if( const XclExpPivotCache* pPCache = CreatePivotCache( *pDPObj ) )
+ maPTableList.AppendNewRecord( new XclExpPivotTable( GetRoot(), *pDPObj, *pPCache ) );
+}
+
+XclExpRecordRef XclExpPivotTableManager::CreatePivotCachesRecord()
+{
+ return XclExpRecordRef( new XclExpPivotRecWrapper( *this, EXC_PTMGR_PIVOTCACHES ) );
+}
+
+XclExpRecordRef XclExpPivotTableManager::CreatePivotTablesRecord( SCTAB nScTab )
+{
+ return XclExpRecordRef( new XclExpPivotRecWrapper( *this, nScTab ) );
+}
+
+void XclExpPivotTableManager::WritePivotCaches( XclExpStream& rStrm )
+{
+ maPCacheList.Save( rStrm );
+}
+
+void XclExpPivotTableManager::WritePivotCachesXml( XclExpXmlStream&
+#ifdef XLSX_PIVOT_CACHE
+ rStrm
+#endif
+)
+{
+#ifdef XLSX_PIVOT_CACHE /* <pivotCache> without xl/pivotCaches/ cacheStream
+ results in a broken .xlsx */
+ if( maPCacheList.IsEmpty() )
+ return;
+ sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
+ rWorkbook->startElement( XML_pivotCaches, FSEND );
+ maPCacheList.SaveXml( rStrm );
+ rWorkbook->endElement( XML_pivotCaches );
+#endif /* XLSX_PIVOT_CACHE */
+}
+
+void XclExpPivotTableManager::WritePivotTables( XclExpStream& rStrm, SCTAB nScTab )
+{
+ for( size_t nPos = 0, nSize = maPTableList.GetSize(); nPos < nSize; ++nPos )
+ {
+ XclExpPivotTableRef xPTable = maPTableList.GetRecord( nPos );
+ if( xPTable->GetScTab() == nScTab )
+ xPTable->Save( rStrm );
+ }
+}
+
+void XclExpPivotTableManager::WritePivotTablesXml( XclExpXmlStream& rStrm, SCTAB nScTab )
+{
+ for( size_t nPos = 0, nSize = maPTableList.GetSize(); nPos < nSize; ++nPos )
+ {
+ XclExpPivotTableRef xPTable = maPTableList.GetRecord( nPos );
+ if( xPTable->GetScTab() == nScTab )
+ xPTable->SaveXml( rStrm );
+ }
+}
+
+// private --------------------------------------------------------------------
+
+const XclExpPivotCache* XclExpPivotTableManager::CreatePivotCache( const ScDPObject& rDPObj )
+{
+ // try to find a pivot cache with the same data source
+ /* #i25110# In Excel, the pivot cache contains additional fields
+ (i.e. grouping info, calculated fields). If the passed DataPilot object
+ or the found cache contains this data, do not share the cache with
+ multiple pivot tables. */
+ if( mbShareCaches )
+ {
+ if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() )
+ {
+ const ScDPDimensionSaveData* pDimSaveData = pSaveData->GetExistingDimensionData();
+ // no dimension save data at all or save data does not contain grouping info
+ if( !pDimSaveData || !pDimSaveData->HasGroupDimensions() )
+ {
+ // check all existing pivot caches
+ for( size_t nPos = 0, nSize = maPCacheList.GetSize(); nPos < nSize; ++nPos )
+ {
+ XclExpPivotCacheRef xPCache = maPCacheList.GetRecord( nPos );
+ // pivot cache does not have grouping info and source data is equal
+ if( !xPCache->HasAddFields() && xPCache->HasEqualDataSource( rDPObj ) )
+ return xPCache.get();
+ }
+ }
+ }
+ }
+
+ // create a new pivot cache
+ sal_uInt16 nNewCacheIdx = static_cast< sal_uInt16 >( maPCacheList.GetSize() );
+ XclExpPivotCacheRef xNewPCache( new XclExpPivotCache( GetRoot(), rDPObj, nNewCacheIdx ) );
+ if( xNewPCache->IsValid() )
+ {
+ maPCacheList.AppendRecord( xNewPCache );
+ return xNewPCache.get();
+ }
+
+ return 0;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xerecord.cxx b/sc/source/filter/excel/xerecord.cxx
new file mode 100644
index 000000000000..f210efd1a4a1
--- /dev/null
+++ b/sc/source/filter/excel/xerecord.cxx
@@ -0,0 +1,304 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xerecord.hxx"
+#include "xeroot.hxx"
+
+using namespace ::oox;
+
+// Base classes to export Excel records =======================================
+
+XclExpRecordBase::~XclExpRecordBase()
+{
+}
+
+void XclExpRecordBase::Save( XclExpStream& /*rStrm*/ )
+{
+}
+
+void XclExpRecordBase::SaveXml( XclExpXmlStream& /*rStrm*/ )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpDelegatingRecord::XclExpDelegatingRecord( XclExpRecordBase* pRecord ) :
+ mpRecord( pRecord )
+{
+}
+
+XclExpDelegatingRecord::~XclExpDelegatingRecord()
+{
+ // Do Nothing; we use Delegating Record for other objects we "know" will
+ // survive...
+}
+
+void XclExpDelegatingRecord::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( mpRecord )
+ mpRecord->SaveXml( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpXmlElementRecord::XclExpXmlElementRecord( sal_Int32 nElement, void (*pAttributes)( XclExpXmlStream& rStrm) )
+ : mnElement( nElement ), mpAttributes( pAttributes )
+{
+}
+
+XclExpXmlElementRecord::~XclExpXmlElementRecord()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpXmlStartElementRecord::XclExpXmlStartElementRecord( sal_Int32 nElement, void (*pAttributes)( XclExpXmlStream& rStrm) )
+ : XclExpXmlElementRecord( nElement, pAttributes )
+{
+}
+
+XclExpXmlStartElementRecord::~XclExpXmlStartElementRecord()
+{
+}
+
+void XclExpXmlStartElementRecord::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rStream = rStrm.GetCurrentStream();
+ if( ! mpAttributes )
+ {
+ rStream->startElement( mnElement, FSEND );
+ }
+ else
+ {
+ rStream->write( "<" )->writeId( mnElement );
+ (*mpAttributes)( rStrm );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpXmlEndElementRecord::XclExpXmlEndElementRecord( sal_Int32 nElement )
+ : XclExpXmlElementRecord( nElement )
+{
+}
+
+XclExpXmlEndElementRecord::~XclExpXmlEndElementRecord()
+{
+}
+
+void XclExpXmlEndElementRecord::SaveXml( XclExpXmlStream& rStrm )
+{
+ rStrm.GetCurrentStream()->endElement( mnElement );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpXmlStartSingleElementRecord::XclExpXmlStartSingleElementRecord( sal_Int32 nElement, void (*pAttributes)( XclExpXmlStream& rStrm) )
+ : XclExpXmlElementRecord( nElement, pAttributes )
+{
+}
+
+XclExpXmlStartSingleElementRecord::~XclExpXmlStartSingleElementRecord()
+{
+}
+
+void XclExpXmlStartSingleElementRecord::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rStream = rStrm.GetCurrentStream();
+ rStream->write( "<" )->writeId( mnElement );
+ if( mpAttributes )
+ (*mpAttributes)( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpXmlEndSingleElementRecord::XclExpXmlEndSingleElementRecord()
+{
+}
+
+XclExpXmlEndSingleElementRecord::~XclExpXmlEndSingleElementRecord()
+{
+}
+
+void XclExpXmlEndSingleElementRecord::SaveXml( XclExpXmlStream& rStrm )
+{
+ rStrm.GetCurrentStream()->write( "/>" );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpRecord::XclExpRecord( sal_uInt16 nRecId, sal_Size nRecSize ) :
+ mnRecSize( nRecSize ),
+ mnRecId( nRecId )
+{
+}
+
+XclExpRecord::~XclExpRecord()
+{
+}
+
+void XclExpRecord::SetRecHeader( sal_uInt16 nRecId, sal_Size nRecSize )
+{
+ SetRecId( nRecId );
+ SetRecSize( nRecSize );
+}
+
+void XclExpRecord::WriteBody( XclExpStream& /*rStrm*/ )
+{
+}
+
+void XclExpRecord::Save( XclExpStream& rStrm )
+{
+ DBG_ASSERT( mnRecId != EXC_ID_UNKNOWN, "XclExpRecord::Save - record ID uninitialized" );
+ rStrm.StartRecord( mnRecId, mnRecSize );
+ WriteBody( rStrm );
+ rStrm.EndRecord();
+}
+
+// ----------------------------------------------------------------------------
+
+template<>
+void XclExpValueRecord<double>::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( mnAttribute == -1 )
+ return;
+ rStrm.WriteAttributes(
+ mnAttribute, rtl::OString::valueOf( maValue ).getStr(),
+ FSEND );
+}
+
+// ----------------------------------------------------------------------------
+
+void XclExpBoolRecord::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << static_cast< sal_uInt16 >( mbValue ? 1 : 0 );
+}
+
+void XclExpBoolRecord::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( mnAttribute == -1 )
+ return;
+
+ rStrm.WriteAttributes(
+ // HACK: HIDEOBJ (excdoc.cxx) should be its own object to handle XML_showObjects
+ mnAttribute, mnAttribute == XML_showObjects ? "all" : XclXmlUtils::ToPsz( mbValue ),
+ FSEND );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpDummyRecord::XclExpDummyRecord( sal_uInt16 nRecId, const void* pRecData, sal_Size nRecSize ) :
+ XclExpRecord( nRecId )
+{
+ SetData( pRecData, nRecSize );
+}
+
+void XclExpDummyRecord::SetData( const void* pRecData, sal_Size nRecSize )
+{
+ mpData = pRecData;
+ SetRecSize( pRecData ? nRecSize : 0 );
+}
+
+void XclExpDummyRecord::WriteBody( XclExpStream& rStrm )
+{
+ rStrm.Write( mpData, GetRecSize() );
+}
+
+// Future records =============================================================
+
+XclExpFutureRecord::XclExpFutureRecord( XclFutureRecType eRecType, sal_uInt16 nRecId, sal_Size nRecSize ) :
+ XclExpRecord( nRecId, nRecSize ),
+ meRecType( eRecType )
+{
+}
+
+void XclExpFutureRecord::Save( XclExpStream& rStrm )
+{
+ rStrm.StartRecord( GetRecId(), GetRecSize() + ((meRecType == EXC_FUTUREREC_UNUSEDREF) ? 12 : 4) );
+ rStrm << GetRecId() << sal_uInt16( 0 );
+ if( meRecType == EXC_FUTUREREC_UNUSEDREF )
+ rStrm.WriteZeroBytes( 8 );
+ WriteBody( rStrm );
+ rStrm.EndRecord();
+}
+
+// ============================================================================
+
+XclExpSubStream::XclExpSubStream( sal_uInt16 nSubStrmType ) :
+ mnSubStrmType( nSubStrmType )
+{
+}
+
+void XclExpSubStream::Save( XclExpStream& rStrm )
+{
+ // BOF record
+ switch( rStrm.GetRoot().GetBiff() )
+ {
+ case EXC_BIFF2:
+ rStrm.StartRecord( EXC_ID2_BOF, 4 );
+ rStrm << sal_uInt16( 7 ) << mnSubStrmType;
+ rStrm.EndRecord();
+ break;
+ case EXC_BIFF3:
+ rStrm.StartRecord( EXC_ID3_BOF, 6 );
+ rStrm << sal_uInt16( 0 ) << mnSubStrmType << sal_uInt16( 2104 );
+ rStrm.EndRecord();
+ break;
+ case EXC_BIFF4:
+ rStrm.StartRecord( EXC_ID4_BOF, 6 );
+ rStrm << sal_uInt16( 0 ) << mnSubStrmType << sal_uInt16( 1705 );
+ rStrm.EndRecord();
+ break;
+ case EXC_BIFF5:
+ rStrm.StartRecord( EXC_ID5_BOF, 8 );
+ rStrm << EXC_BOF_BIFF5 << mnSubStrmType << sal_uInt16( 4915 ) << sal_uInt16( 1994 );
+ rStrm.EndRecord();
+ break;
+ case EXC_BIFF8:
+ rStrm.StartRecord( EXC_ID5_BOF, 16 );
+ rStrm << EXC_BOF_BIFF8 << mnSubStrmType << sal_uInt16( 3612 ) << sal_uInt16( 1996 );
+ rStrm << sal_uInt32( 1 ) << sal_uInt32( 6 );
+ rStrm.EndRecord();
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+
+ // substream records
+ XclExpRecordList<>::Save( rStrm );
+
+ // EOF record
+ rStrm.StartRecord( EXC_ID_EOF, 0 );
+ rStrm.EndRecord();
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xeroot.cxx b/sc/source/filter/excel/xeroot.cxx
new file mode 100644
index 000000000000..d72f9c77d61d
--- /dev/null
+++ b/sc/source/filter/excel/xeroot.cxx
@@ -0,0 +1,319 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <rtl/random.h>
+#include <sfx2/docfile.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <unotools/saveopt.hxx>
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/eitem.hxx>
+#include "xecontent.hxx"
+#include "xltracer.hxx"
+#include "xeescher.hxx"
+#include "xeformula.hxx"
+#include "xehelper.hxx"
+#include "xelink.hxx"
+#include "xename.hxx"
+#include "xepivot.hxx"
+#include "xestyle.hxx"
+#include "xeroot.hxx"
+
+#include "excrecds.hxx" // for filter manager
+#include "tabprotection.hxx"
+#include "document.hxx"
+#include "scextopt.hxx"
+
+using namespace ::com::sun::star;
+
+// Global data ================================================================
+
+XclExpRootData::XclExpRootData( XclBiff eBiff, SfxMedium& rMedium,
+ SotStorageRef xRootStrg, ScDocument& rDoc, rtl_TextEncoding eTextEnc ) :
+ XclRootData( eBiff, rMedium, xRootStrg, rDoc, eTextEnc, true )
+{
+ SvtSaveOptions aSaveOpt;
+ mbRelUrl = mrMedium.IsRemote() ? aSaveOpt.IsSaveRelINet() : aSaveOpt.IsSaveRelFSys();
+}
+
+XclExpRootData::~XclExpRootData()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpRoot::XclExpRoot( XclExpRootData& rExpRootData ) :
+ XclRoot( rExpRootData ),
+ mrExpData( rExpRootData )
+{
+}
+
+XclExpTabInfo& XclExpRoot::GetTabInfo() const
+{
+ DBG_ASSERT( mrExpData.mxTabInfo, "XclExpRoot::GetTabInfo - missing object (wrong BIFF?)" );
+ return *mrExpData.mxTabInfo;
+}
+
+XclExpAddressConverter& XclExpRoot::GetAddressConverter() const
+{
+ DBG_ASSERT( mrExpData.mxAddrConv, "XclExpRoot::GetAddressConverter - missing object (wrong BIFF?)" );
+ return *mrExpData.mxAddrConv;
+}
+
+XclExpFormulaCompiler& XclExpRoot::GetFormulaCompiler() const
+{
+ DBG_ASSERT( mrExpData.mxFmlaComp, "XclExpRoot::GetFormulaCompiler - missing object (wrong BIFF?)" );
+ return *mrExpData.mxFmlaComp;
+}
+
+XclExpProgressBar& XclExpRoot::GetProgressBar() const
+{
+ DBG_ASSERT( mrExpData.mxProgress, "XclExpRoot::GetProgressBar - missing object (wrong BIFF?)" );
+ return *mrExpData.mxProgress;
+}
+
+XclExpSst& XclExpRoot::GetSst() const
+{
+ DBG_ASSERT( mrExpData.mxSst, "XclExpRoot::GetSst - missing object (wrong BIFF?)" );
+ return *mrExpData.mxSst;
+}
+
+XclExpPalette& XclExpRoot::GetPalette() const
+{
+ DBG_ASSERT( mrExpData.mxPalette, "XclExpRoot::GetPalette - missing object (wrong BIFF?)" );
+ return *mrExpData.mxPalette;
+}
+
+XclExpFontBuffer& XclExpRoot::GetFontBuffer() const
+{
+ DBG_ASSERT( mrExpData.mxFontBfr, "XclExpRoot::GetFontBuffer - missing object (wrong BIFF?)" );
+ return *mrExpData.mxFontBfr;
+}
+
+XclExpNumFmtBuffer& XclExpRoot::GetNumFmtBuffer() const
+{
+ DBG_ASSERT( mrExpData.mxNumFmtBfr, "XclExpRoot::GetNumFmtBuffer - missing object (wrong BIFF?)" );
+ return *mrExpData.mxNumFmtBfr;
+}
+
+XclExpXFBuffer& XclExpRoot::GetXFBuffer() const
+{
+ DBG_ASSERT( mrExpData.mxXFBfr, "XclExpRoot::GetXFBuffer - missing object (wrong BIFF?)" );
+ return *mrExpData.mxXFBfr;
+}
+
+XclExpLinkManager& XclExpRoot::GetGlobalLinkManager() const
+{
+ DBG_ASSERT( mrExpData.mxGlobLinkMgr, "XclExpRoot::GetGlobalLinkManager - missing object (wrong BIFF?)" );
+ return *mrExpData.mxGlobLinkMgr;
+}
+
+XclExpLinkManager& XclExpRoot::GetLocalLinkManager() const
+{
+ DBG_ASSERT( GetLocalLinkMgrRef(), "XclExpRoot::GetLocalLinkManager - missing object (wrong BIFF?)" );
+ return *GetLocalLinkMgrRef();
+}
+
+XclExpNameManager& XclExpRoot::GetNameManager() const
+{
+ DBG_ASSERT( mrExpData.mxNameMgr, "XclExpRoot::GetNameManager - missing object (wrong BIFF?)" );
+ return *mrExpData.mxNameMgr;
+}
+
+XclExpObjectManager& XclExpRoot::GetObjectManager() const
+{
+ DBG_ASSERT( mrExpData.mxObjMgr, "XclExpRoot::GetObjectManager - missing object (wrong BIFF?)" );
+ return *mrExpData.mxObjMgr;
+}
+
+XclExpFilterManager& XclExpRoot::GetFilterManager() const
+{
+ DBG_ASSERT( mrExpData.mxFilterMgr, "XclExpRoot::GetFilterManager - missing object (wrong BIFF?)" );
+ return *mrExpData.mxFilterMgr;
+}
+
+XclExpPivotTableManager& XclExpRoot::GetPivotTableManager() const
+{
+ DBG_ASSERT( mrExpData.mxPTableMgr, "XclExpRoot::GetPivotTableManager - missing object (wrong BIFF?)" );
+ return *mrExpData.mxPTableMgr;
+}
+
+void XclExpRoot::InitializeConvert()
+{
+ mrExpData.mxTabInfo.reset( new XclExpTabInfo( GetRoot() ) );
+ mrExpData.mxAddrConv.reset( new XclExpAddressConverter( GetRoot() ) );
+ mrExpData.mxFmlaComp.reset( new XclExpFormulaCompiler( GetRoot() ) );
+ mrExpData.mxProgress.reset( new XclExpProgressBar( GetRoot() ) );
+
+ GetProgressBar().Initialize();
+}
+
+void XclExpRoot::InitializeGlobals()
+{
+ SetCurrScTab( SCTAB_GLOBAL );
+
+ if( GetBiff() >= EXC_BIFF5 )
+ {
+ mrExpData.mxPalette.reset( new XclExpPalette( GetRoot() ) );
+ mrExpData.mxFontBfr.reset( new XclExpFontBuffer( GetRoot() ) );
+ mrExpData.mxNumFmtBfr.reset( new XclExpNumFmtBuffer( GetRoot() ) );
+ mrExpData.mxXFBfr.reset( new XclExpXFBuffer( GetRoot() ) );
+ mrExpData.mxGlobLinkMgr.reset( new XclExpLinkManager( GetRoot() ) );
+ mrExpData.mxNameMgr.reset( new XclExpNameManager( GetRoot() ) );
+ }
+
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ mrExpData.mxSst.reset( new XclExpSst );
+ mrExpData.mxObjMgr.reset( new XclExpObjectManager( GetRoot() ) );
+ mrExpData.mxFilterMgr.reset( new XclExpFilterManager( GetRoot() ) );
+ mrExpData.mxPTableMgr.reset( new XclExpPivotTableManager( GetRoot() ) );
+ // BIFF8: only one link manager for all sheets
+ mrExpData.mxLocLinkMgr = mrExpData.mxGlobLinkMgr;
+ }
+
+ GetXFBuffer().Initialize();
+ GetNameManager().Initialize();
+}
+
+void XclExpRoot::InitializeTable( SCTAB nScTab )
+{
+ SetCurrScTab( nScTab );
+ if( GetBiff() == EXC_BIFF5 )
+ {
+ // local link manager per sheet
+ mrExpData.mxLocLinkMgr.reset( new XclExpLinkManager( GetRoot() ) );
+ }
+}
+
+void XclExpRoot::InitializeSave()
+{
+ GetPalette().Finalize();
+ GetXFBuffer().Finalize();
+}
+
+XclExpRecordRef XclExpRoot::CreateRecord( sal_uInt16 nRecId ) const
+{
+ XclExpRecordRef xRec;
+ switch( nRecId )
+ {
+ case EXC_ID_PALETTE: xRec = mrExpData.mxPalette; break;
+ case EXC_ID_FONTLIST: xRec = mrExpData.mxFontBfr; break;
+ case EXC_ID_FORMATLIST: xRec = mrExpData.mxNumFmtBfr; break;
+ case EXC_ID_XFLIST: xRec = mrExpData.mxXFBfr; break;
+ case EXC_ID_SST: xRec = mrExpData.mxSst; break;
+ case EXC_ID_EXTERNSHEET: xRec = GetLocalLinkMgrRef(); break;
+ case EXC_ID_NAME: xRec = mrExpData.mxNameMgr; break;
+ }
+ DBG_ASSERT( xRec, "XclExpRoot::CreateRecord - unknown record ID or missing object" );
+ return xRec;
+}
+
+bool XclExpRoot::IsDocumentEncrypted() const
+{
+ // We need to encrypt the content when the document structure is protected.
+ const ScDocProtection* pDocProt = GetDoc().GetDocProtection();
+ if (pDocProt && pDocProt->isProtected() && pDocProt->isOptionEnabled(ScDocProtection::STRUCTURE))
+ return true;
+
+ if ( GetEncryptionData().getLength() > 0 )
+ // Password is entered directly into the save dialog.
+ return true;
+
+ return false;
+}
+
+uno::Sequence< beans::NamedValue > XclExpRoot::GenerateEncryptionData( const ::rtl::OUString& aPass ) const
+{
+ uno::Sequence< beans::NamedValue > aEncryptionData;
+
+ if ( aPass.getLength() > 0 && aPass.getLength() < 16 )
+ {
+ TimeValue aTime;
+ osl_getSystemTime( &aTime );
+ rtlRandomPool aRandomPool = rtl_random_createPool ();
+ rtl_random_addBytes ( aRandomPool, &aTime, 8 );
+
+ sal_uInt8 pnDocId[16];
+ rtl_random_getBytes( aRandomPool, pnDocId, 16 );
+
+ rtl_random_destroyPool( aRandomPool );
+
+ sal_uInt16 pnPasswd[16];
+ memset( pnPasswd, 0, sizeof( pnPasswd ) );
+ for (xub_StrLen nChar = 0; nChar < aPass.getLength(); ++nChar )
+ pnPasswd[nChar] = aPass.getStr()[nChar];
+
+ ::msfilter::MSCodec_Std97 aCodec;
+ aCodec.InitKey( pnPasswd, pnDocId );
+ aEncryptionData = aCodec.GetEncryptionData();
+ }
+
+ return aEncryptionData;
+}
+
+uno::Sequence< beans::NamedValue > XclExpRoot::GetEncryptionData() const
+{
+ uno::Sequence< beans::NamedValue > aEncryptionData;
+ SFX_ITEMSET_ARG( GetMedium().GetItemSet(), pEncryptionDataItem, SfxUnoAnyItem, SID_ENCRYPTIONDATA, false );
+ if ( pEncryptionDataItem )
+ pEncryptionDataItem->GetValue() >>= aEncryptionData;
+ else
+ {
+ // try to get the encryption data from the password
+ SFX_ITEMSET_ARG( GetMedium().GetItemSet(), pPasswordItem, SfxStringItem, SID_PASSWORD, false );
+ if ( pPasswordItem && pPasswordItem->GetValue().Len() )
+ aEncryptionData = GenerateEncryptionData( pPasswordItem->GetValue() );
+ }
+
+ return aEncryptionData;
+}
+
+uno::Sequence< beans::NamedValue > XclExpRoot::GenerateDefaultEncryptionData() const
+{
+ uno::Sequence< beans::NamedValue > aEncryptionData;
+ if ( GetDefaultPassword().Len() > 0 )
+ aEncryptionData = GenerateEncryptionData( GetDefaultPassword() );
+
+ return aEncryptionData;
+}
+
+XclExpRootData::XclExpLinkMgrRef XclExpRoot::GetLocalLinkMgrRef() const
+{
+ return IsInGlobals() ? mrExpData.mxGlobLinkMgr : mrExpData.mxLocLinkMgr;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx
new file mode 100644
index 000000000000..4e2798e06ee9
--- /dev/null
+++ b/sc/source/filter/excel/xestream.cxx
@@ -0,0 +1,1221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <utility>
+
+#include <rtl/ustring.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/random.h>
+#include <sax/fshelper.hxx>
+#include <unotools/streamwrap.hxx>
+
+#include "precompiled_sc.hxx"
+#include "docuno.hxx"
+#include "xestream.hxx"
+#include "xladdress.hxx"
+#include "xlstring.hxx"
+#include "xeroot.hxx"
+#include "xestyle.hxx"
+#include "xcl97rec.hxx"
+#include "rangelst.hxx"
+#include "compiler.hxx"
+
+#include <../../ui/inc/docsh.hxx>
+#include <../../ui/inc/viewdata.hxx>
+#include <excdoc.hxx>
+
+#include <oox/token/tokens.hxx>
+#include <formula/grammar.hxx>
+#include <oox/export/drawingml.hxx>
+#include <oox/xls/excelvbaproject.hxx>
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/app.hxx>
+#include <cppuhelper/implementationentry.hxx>
+
+#define DEBUG_XL_ENCRYPTION 0
+
+using ::com::sun::star::beans::PropertyValue;
+using ::com::sun::star::embed::XStorage;
+using ::com::sun::star::io::XOutputStream;
+using ::com::sun::star::io::XStream;
+using ::com::sun::star::lang::XComponent;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::lang::XServiceInfo;
+using ::com::sun::star::lang::XSingleServiceFactory;
+using ::com::sun::star::registry::InvalidRegistryException;
+using ::com::sun::star::registry::XRegistryKey;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::XInterface;
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::utl::OStreamWrapper;
+using ::std::vector;
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::uno;
+using namespace ::formula;
+using namespace ::oox;
+
+// ============================================================================
+
+XclExpStream::XclExpStream( SvStream& rOutStrm, const XclExpRoot& rRoot, sal_uInt16 nMaxRecSize ) :
+ mrStrm( rOutStrm ),
+ mrRoot( rRoot ),
+ mnMaxRecSize( nMaxRecSize ),
+ mnCurrMaxSize( 0 ),
+ mnMaxSliceSize( 0 ),
+ mnHeaderSize( 0 ),
+ mnCurrSize( 0 ),
+ mnSliceSize( 0 ),
+ mnPredictSize( 0 ),
+ mnLastSizePos( 0 ),
+ mbInRec( false )
+{
+ if( mnMaxRecSize == 0 )
+ mnMaxRecSize = (mrRoot.GetBiff() <= EXC_BIFF5) ? EXC_MAXRECSIZE_BIFF5 : EXC_MAXRECSIZE_BIFF8;
+ mnMaxContSize = mnMaxRecSize;
+}
+
+XclExpStream::~XclExpStream()
+{
+ mrStrm.Flush();
+}
+
+void XclExpStream::StartRecord( sal_uInt16 nRecId, sal_Size nRecSize )
+{
+ DBG_ASSERT( !mbInRec, "XclExpStream::StartRecord - another record still open" );
+ DisableEncryption();
+ mnMaxContSize = mnCurrMaxSize = mnMaxRecSize;
+ mnPredictSize = nRecSize;
+ mbInRec = true;
+ InitRecord( nRecId );
+ SetSliceSize( 0 );
+ EnableEncryption();
+}
+
+void XclExpStream::EndRecord()
+{
+ DBG_ASSERT( mbInRec, "XclExpStream::EndRecord - no record open" );
+ DisableEncryption();
+ UpdateRecSize();
+ mrStrm.Seek( STREAM_SEEK_TO_END );
+ mbInRec = false;
+}
+
+void XclExpStream::SetSliceSize( sal_uInt16 nSize )
+{
+ mnMaxSliceSize = nSize;
+ mnSliceSize = 0;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_Int8 nValue )
+{
+ PrepareWrite( 1 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm << nValue;
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_uInt8 nValue )
+{
+ PrepareWrite( 1 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm << nValue;
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_Int16 nValue )
+{
+ PrepareWrite( 2 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm << nValue;
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_uInt16 nValue )
+{
+ PrepareWrite( 2 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm << nValue;
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_Int32 nValue )
+{
+ PrepareWrite( 4 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm << nValue;
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( sal_uInt32 nValue )
+{
+ PrepareWrite( 4 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, nValue);
+ else
+ mrStrm << nValue;
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( float fValue )
+{
+ PrepareWrite( 4 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, fValue);
+ else
+ mrStrm << fValue;
+ return *this;
+}
+
+XclExpStream& XclExpStream::operator<<( double fValue )
+{
+ PrepareWrite( 8 );
+ if (mbUseEncrypter && HasValidEncrypter())
+ mxEncrypter->Encrypt(mrStrm, fValue);
+ else
+ mrStrm << fValue;
+ return *this;
+}
+
+sal_Size XclExpStream::Write( const void* pData, sal_Size nBytes )
+{
+ sal_Size nRet = 0;
+ if( pData && (nBytes > 0) )
+ {
+ if( mbInRec )
+ {
+ const sal_uInt8* pBuffer = reinterpret_cast< const sal_uInt8* >( pData );
+ sal_Size nBytesLeft = nBytes;
+ bool bValid = true;
+
+ while( bValid && (nBytesLeft > 0) )
+ {
+ sal_Size nWriteLen = ::std::min< sal_Size >( PrepareWrite(), nBytesLeft );
+ sal_Size nWriteRet = nWriteLen;
+ if (mbUseEncrypter && HasValidEncrypter())
+ {
+ DBG_ASSERT(nWriteLen > 0, "XclExpStream::Write: write length is 0!");
+ vector<sal_uInt8> aBytes(nWriteLen);
+ memcpy(&aBytes[0], pBuffer, nWriteLen);
+ mxEncrypter->EncryptBytes(mrStrm, aBytes);
+ // TODO: How do I check if all the bytes have been successfully written ?
+ }
+ else
+ {
+ nWriteRet = mrStrm.Write( pBuffer, nWriteLen );
+ bValid = (nWriteLen == nWriteRet);
+ DBG_ASSERT( bValid, "XclExpStream::Write - stream write error" );
+ }
+ pBuffer += nWriteRet;
+ nRet += nWriteRet;
+ nBytesLeft -= nWriteRet;
+ UpdateSizeVars( nWriteRet );
+ }
+ }
+ else
+ nRet = mrStrm.Write( pData, nBytes );
+ }
+ return nRet;
+}
+
+void XclExpStream::WriteZeroBytes( sal_Size nBytes )
+{
+ if( mbInRec )
+ {
+ sal_Size nBytesLeft = nBytes;
+ while( nBytesLeft > 0 )
+ {
+ sal_Size nWriteLen = ::std::min< sal_Size >( PrepareWrite(), nBytesLeft );
+ WriteRawZeroBytes( nWriteLen );
+ nBytesLeft -= nWriteLen;
+ UpdateSizeVars( nWriteLen );
+ }
+ }
+ else
+ WriteRawZeroBytes( nBytes );
+}
+
+void XclExpStream::WriteZeroBytesToRecord( sal_Size nBytes )
+{
+ if (!mbInRec)
+ // not in record.
+ return;
+
+ sal_uInt8 nZero = 0;
+ for (sal_Size i = 0; i < nBytes; ++i)
+ *this << nZero;
+}
+
+sal_Size XclExpStream::CopyFromStream( SvStream& rInStrm, sal_Size nBytes )
+{
+ sal_Size nStrmPos = rInStrm.Tell();
+ rInStrm.Seek( STREAM_SEEK_TO_END );
+ sal_Size nStrmSize = rInStrm.Tell();
+ rInStrm.Seek( nStrmPos );
+
+ sal_Size nBytesLeft = ::std::min( nBytes, nStrmSize - nStrmPos );
+ sal_Size nRet = 0;
+ if( nBytesLeft > 0 )
+ {
+ const sal_Size nMaxBuffer = 4096;
+ sal_uInt8* pBuffer = new sal_uInt8[ ::std::min( nBytesLeft, nMaxBuffer ) ];
+ bool bValid = true;
+
+ while( bValid && (nBytesLeft > 0) )
+ {
+ sal_Size nWriteLen = ::std::min( nBytesLeft, nMaxBuffer );
+ rInStrm.Read( pBuffer, nWriteLen );
+ sal_Size nWriteRet = Write( pBuffer, nWriteLen );
+ bValid = (nWriteLen == nWriteRet);
+ nRet += nWriteRet;
+ nBytesLeft -= nWriteRet;
+ }
+ delete[] pBuffer;
+ }
+ return nRet;
+}
+
+void XclExpStream::WriteUnicodeBuffer( const ScfUInt16Vec& rBuffer, sal_uInt8 nFlags )
+{
+ SetSliceSize( 0 );
+ nFlags &= EXC_STRF_16BIT; // repeat only 16bit flag
+ sal_uInt16 nCharLen = nFlags ? 2 : 1;
+
+ ScfUInt16Vec::const_iterator aEnd = rBuffer.end();
+ for( ScfUInt16Vec::const_iterator aIter = rBuffer.begin(); aIter != aEnd; ++aIter )
+ {
+ if( mbInRec && (mnCurrSize + nCharLen > mnCurrMaxSize) )
+ {
+ StartContinue();
+ operator<<( nFlags );
+ }
+ if( nCharLen == 2 )
+ operator<<( *aIter );
+ else
+ operator<<( static_cast< sal_uInt8 >( *aIter ) );
+ }
+}
+
+// Xcl has an obscure sense of whether starting a new record or not,
+// and crashes if it encounters the string header at the very end of a record.
+// Thus we add 1 to give some room, seems like they do it that way but with another count (10?)
+void XclExpStream::WriteByteString( const ByteString& rString, sal_uInt16 nMaxLen, bool b16BitCount )
+{
+ SetSliceSize( 0 );
+ sal_Size nLen = ::std::min< sal_Size >( rString.Len(), nMaxLen );
+ if( !b16BitCount )
+ nLen = ::std::min< sal_Size >( nLen, 0xFF );
+
+ sal_uInt16 nLeft = PrepareWrite();
+ sal_uInt16 nLenFieldSize = b16BitCount ? 2 : 1;
+ if( mbInRec && (nLeft <= nLenFieldSize) )
+ StartContinue();
+
+ if( b16BitCount )
+ operator<<( static_cast< sal_uInt16 >( nLen ) );
+ else
+ operator<<( static_cast< sal_uInt8 >( nLen ) );
+ Write( rString.GetBuffer(), nLen );
+}
+
+void XclExpStream::WriteCharBuffer( const ScfUInt8Vec& rBuffer )
+{
+ SetSliceSize( 0 );
+ Write( &rBuffer[ 0 ], rBuffer.size() );
+}
+
+void XclExpStream::SetEncrypter( XclExpEncrypterRef xEncrypter )
+{
+ mxEncrypter = xEncrypter;
+}
+
+bool XclExpStream::HasValidEncrypter() const
+{
+ return mxEncrypter && mxEncrypter->IsValid();
+}
+
+void XclExpStream::EnableEncryption( bool bEnable )
+{
+ mbUseEncrypter = bEnable && HasValidEncrypter();
+}
+
+void XclExpStream::DisableEncryption()
+{
+ EnableEncryption(false);
+}
+
+sal_Size XclExpStream::SetSvStreamPos( sal_Size nPos )
+{
+ DBG_ASSERT( !mbInRec, "XclExpStream::SetSvStreamPos - not allowed inside of a record" );
+ return mbInRec ? 0 : mrStrm.Seek( nPos );
+}
+
+// private --------------------------------------------------------------------
+
+void XclExpStream::InitRecord( sal_uInt16 nRecId )
+{
+ mrStrm.Seek( STREAM_SEEK_TO_END );
+ mrStrm << nRecId;
+
+ mnLastSizePos = mrStrm.Tell();
+ mnHeaderSize = static_cast< sal_uInt16 >( ::std::min< sal_Size >( mnPredictSize, mnCurrMaxSize ) );
+ mrStrm << mnHeaderSize;
+ mnCurrSize = mnSliceSize = 0;
+}
+
+void XclExpStream::UpdateRecSize()
+{
+ if( mnCurrSize != mnHeaderSize )
+ {
+ mrStrm.Seek( mnLastSizePos );
+ mrStrm << mnCurrSize;
+ }
+}
+
+void XclExpStream::UpdateSizeVars( sal_Size nSize )
+{
+ DBG_ASSERT( mnCurrSize + nSize <= mnCurrMaxSize, "XclExpStream::UpdateSizeVars - record overwritten" );
+ mnCurrSize = mnCurrSize + static_cast< sal_uInt16 >( nSize );
+
+ if( mnMaxSliceSize > 0 )
+ {
+ DBG_ASSERT( mnSliceSize + nSize <= mnMaxSliceSize, "XclExpStream::UpdateSizeVars - slice overwritten" );
+ mnSliceSize = mnSliceSize + static_cast< sal_uInt16 >( nSize );
+ if( mnSliceSize >= mnMaxSliceSize )
+ mnSliceSize = 0;
+ }
+}
+
+void XclExpStream::StartContinue()
+{
+ UpdateRecSize();
+ mnCurrMaxSize = mnMaxContSize;
+ mnPredictSize -= mnCurrSize;
+ InitRecord( EXC_ID_CONT );
+}
+
+void XclExpStream::PrepareWrite( sal_uInt16 nSize )
+{
+ if( mbInRec )
+ {
+ if( (mnCurrSize + nSize > mnCurrMaxSize) ||
+ ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
+ StartContinue();
+ UpdateSizeVars( nSize );
+ }
+}
+
+sal_uInt16 XclExpStream::PrepareWrite()
+{
+ sal_uInt16 nRet = 0;
+ if( mbInRec )
+ {
+ if( (mnCurrSize >= mnCurrMaxSize) ||
+ ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) )
+ StartContinue();
+ UpdateSizeVars( 0 );
+
+ nRet = (mnMaxSliceSize > 0) ? (mnMaxSliceSize - mnSliceSize) : (mnCurrMaxSize - mnCurrSize);
+ }
+ return nRet;
+}
+
+void XclExpStream::WriteRawZeroBytes( sal_Size nBytes )
+{
+ const sal_uInt32 nData = 0;
+ sal_Size nBytesLeft = nBytes;
+ while( nBytesLeft >= sizeof( nData ) )
+ {
+ mrStrm << nData;
+ nBytesLeft -= sizeof( nData );
+ }
+ if( nBytesLeft )
+ mrStrm.Write( &nData, nBytesLeft );
+}
+
+// ============================================================================
+
+XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot& rRoot ) :
+ mrRoot(rRoot),
+ mnOldPos(STREAM_SEEK_TO_END),
+ mbValid(false)
+{
+ Sequence< NamedValue > aEncryptionData = rRoot.GetEncryptionData();
+ if( !aEncryptionData.hasElements() )
+ // Empty password. Get the default biff8 password.
+ aEncryptionData = rRoot.GenerateDefaultEncryptionData();
+ Init( aEncryptionData );
+}
+
+XclExpBiff8Encrypter::~XclExpBiff8Encrypter()
+{
+}
+
+bool XclExpBiff8Encrypter::IsValid() const
+{
+ return mbValid;
+}
+
+void XclExpBiff8Encrypter::GetSaltDigest( sal_uInt8 pnSaltDigest[16] ) const
+{
+ if ( sizeof( mpnSaltDigest ) == 16 )
+ memcpy( pnSaltDigest, mpnSaltDigest, 16 );
+}
+
+void XclExpBiff8Encrypter::GetSalt( sal_uInt8 pnSalt[16] ) const
+{
+ if ( sizeof( mpnSalt ) == 16 )
+ memcpy( pnSalt, mpnSalt, 16 );
+}
+
+void XclExpBiff8Encrypter::GetDocId( sal_uInt8 pnDocId[16] ) const
+{
+ if ( sizeof( mpnDocId ) == 16 )
+ memcpy( pnDocId, mpnDocId, 16 );
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt8 nData )
+{
+ vector<sal_uInt8> aByte(1);
+ aByte[0] = nData;
+ EncryptBytes(rStrm, aByte);
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt16 nData )
+{
+ ::std::vector<sal_uInt8> pnBytes(2);
+ pnBytes[0] = nData & 0xFF;
+ pnBytes[1] = (nData >> 8) & 0xFF;
+ EncryptBytes(rStrm, pnBytes);
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt32 nData )
+{
+ ::std::vector<sal_uInt8> pnBytes(4);
+ pnBytes[0] = nData & 0xFF;
+ pnBytes[1] = (nData >> 8) & 0xFF;
+ pnBytes[2] = (nData >> 16) & 0xFF;
+ pnBytes[3] = (nData >> 24) & 0xFF;
+ EncryptBytes(rStrm, pnBytes);
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, float fValue )
+{
+ ::std::vector<sal_uInt8> pnBytes(4);
+ memcpy(&pnBytes[0], &fValue, 4);
+ EncryptBytes(rStrm, pnBytes);
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, double fValue )
+{
+ ::std::vector<sal_uInt8> pnBytes(8);
+ memcpy(&pnBytes[0], &fValue, 8);
+ EncryptBytes(rStrm, pnBytes);
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int8 nData )
+{
+ Encrypt(rStrm, static_cast<sal_uInt8>(nData));
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int16 nData )
+{
+ Encrypt(rStrm, static_cast<sal_uInt16>(nData));
+}
+
+void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int32 nData )
+{
+ Encrypt(rStrm, static_cast<sal_uInt32>(nData));
+}
+
+void XclExpBiff8Encrypter::Init( const Sequence< NamedValue >& rEncryptionData )
+{
+ mbValid = false;
+
+ if( maCodec.InitCodec( rEncryptionData ) )
+ {
+ maCodec.GetDocId( mpnDocId );
+
+ // generate the salt here
+ TimeValue aTime;
+ osl_getSystemTime( &aTime );
+ rtlRandomPool aRandomPool = rtl_random_createPool ();
+ rtl_random_addBytes( aRandomPool, &aTime, 8 );
+ rtl_random_getBytes( aRandomPool, mpnSalt, 16 );
+ rtl_random_destroyPool( aRandomPool );
+
+ memset( mpnSaltDigest, 0, sizeof( mpnSaltDigest ) );
+
+ // generate salt hash.
+ ::msfilter::MSCodec_Std97 aCodec;
+ aCodec.InitCodec( rEncryptionData );
+ aCodec.CreateSaltDigest( mpnSalt, mpnSaltDigest );
+
+ // verify to make sure it's in good shape.
+ mbValid = maCodec.VerifyKey( mpnSalt, mpnSaltDigest );
+ }
+}
+
+sal_uInt32 XclExpBiff8Encrypter::GetBlockPos( sal_Size nStrmPos ) const
+{
+ return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
+}
+
+sal_uInt16 XclExpBiff8Encrypter::GetOffsetInBlock( sal_Size nStrmPos ) const
+{
+ return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
+}
+
+void XclExpBiff8Encrypter::EncryptBytes( SvStream& rStrm, vector<sal_uInt8>& aBytes )
+{
+ sal_Size nStrmPos = rStrm.Tell();
+ sal_uInt16 nBlockOffset = GetOffsetInBlock(nStrmPos);
+ sal_uInt32 nBlockPos = GetBlockPos(nStrmPos);
+
+#if DEBUG_XL_ENCRYPTION
+ fprintf(stdout, "XclExpBiff8Encrypter::EncryptBytes: stream pos = %ld offset in block = %d block pos = %ld\n",
+ nStrmPos, nBlockOffset, nBlockPos);
+#endif
+
+ sal_uInt16 nSize = static_cast< sal_uInt16 >( aBytes.size() );
+ if (nSize == 0)
+ return;
+
+#if DEBUG_XL_ENCRYPTION
+ fprintf(stdout, "RAW: ");
+ for (sal_uInt16 i = 0; i < nSize; ++i)
+ fprintf(stdout, "%2.2X ", aBytes[i]);
+ fprintf(stdout, "\n");
+#endif
+
+ if (mnOldPos != nStrmPos)
+ {
+ sal_uInt16 nOldOffset = GetOffsetInBlock(mnOldPos);
+ sal_uInt32 nOldBlockPos = GetBlockPos(mnOldPos);
+
+ if ( (nBlockPos != nOldBlockPos) || (nBlockOffset < nOldOffset) )
+ {
+ maCodec.InitCipher(nBlockPos);
+ nOldOffset = 0;
+ }
+
+ if (nBlockOffset > nOldOffset)
+ maCodec.Skip(nBlockOffset - nOldOffset);
+ }
+
+ sal_uInt16 nBytesLeft = nSize;
+ sal_uInt16 nPos = 0;
+ while (nBytesLeft > 0)
+ {
+ sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - nBlockOffset;
+ sal_uInt16 nEncBytes = ::std::min(nBlockLeft, nBytesLeft);
+
+ bool bRet = maCodec.Encode(&aBytes[nPos], nEncBytes, &aBytes[nPos], nEncBytes);
+ DBG_ASSERT(bRet, "XclExpBiff8Encrypter::EncryptBytes: encryption failed!!");
+ bRet = bRet; // to remove a silly compiler warning.
+
+ sal_Size nRet = rStrm.Write(&aBytes[nPos], nEncBytes);
+ DBG_ASSERT(nRet == nEncBytes, "XclExpBiff8Encrypter::EncryptBytes: fail to write to stream!!");
+ nRet = nRet; // to remove a silly compiler warning.
+
+ nStrmPos = rStrm.Tell();
+ nBlockOffset = GetOffsetInBlock(nStrmPos);
+ nBlockPos = GetBlockPos(nStrmPos);
+ if (nBlockOffset == 0)
+ maCodec.InitCipher(nBlockPos);
+
+ nBytesLeft -= nEncBytes;
+ nPos += nEncBytes;
+ }
+ mnOldPos = nStrmPos;
+}
+
+static const char* lcl_GetErrorString( sal_uInt16 nScErrCode )
+{
+ sal_uInt8 nXclErrCode = XclTools::GetXclErrorCode( nScErrCode );
+ switch( nXclErrCode )
+ {
+ case EXC_ERR_NULL: return "#NULL!";
+ case EXC_ERR_DIV0: return "#DIV/0!";
+ case EXC_ERR_VALUE: return "#VALUE!";
+ case EXC_ERR_REF: return "#REF!";
+ case EXC_ERR_NAME: return "#NAME?";
+ case EXC_ERR_NUM: return "#NUM!";
+ case EXC_ERR_NA:
+ default: return "#N/A";
+ }
+}
+
+void XclXmlUtils::GetFormulaTypeAndValue( ScFormulaCell& rCell, const char*& rsType, OUString& rsValue )
+{
+ switch( rCell.GetFormatType() )
+ {
+ case NUMBERFORMAT_NUMBER:
+ {
+ // either value or error code
+ sal_uInt16 nScErrCode = rCell.GetErrCode();
+ if( nScErrCode )
+ {
+ rsType = "e";
+ rsValue = ToOUString( lcl_GetErrorString( nScErrCode ) );
+ }
+ else
+ {
+ rsType = "n";
+ rsValue = OUString::valueOf( rCell.GetValue() );
+ }
+ }
+ break;
+
+ case NUMBERFORMAT_TEXT:
+ {
+ rsType = "str";
+ String aResult;
+ rCell.GetString( aResult );
+ rsValue = ToOUString( aResult );
+ }
+ break;
+
+ case NUMBERFORMAT_LOGICAL:
+ {
+ rsType = "b";
+ rsValue = ToOUString( rCell.GetValue() == 0.0 ? "0" : "1" );
+ }
+ break;
+
+ default:
+ {
+ rsType = "inlineStr";
+ String aResult;
+ rCell.GetString( aResult );
+ rsValue = ToOUString( aResult );
+ }
+ break;
+ }
+}
+
+rtl::OUString XclXmlUtils::GetStreamName( const char* sStreamDir, const char* sStream, sal_Int32 nId )
+{
+ OUStringBuffer sBuf;
+ if( sStreamDir )
+ sBuf.appendAscii( sStreamDir );
+ sBuf.appendAscii( sStream );
+ if( nId )
+ sBuf.append( nId );
+ if( strstr(sStream, "vml") )
+ sBuf.appendAscii( ".vml" );
+ else
+ sBuf.appendAscii( ".xml" );
+ return sBuf.makeStringAndClear();
+}
+
+OString XclXmlUtils::ToOString( const Color& rColor )
+{
+ char buf[9];
+ sprintf( buf, "%.2X%.2X%.2X%.2X", rColor.GetTransparency(), rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
+ buf[8] = '\0';
+ return OString( buf );
+}
+
+OString XclXmlUtils::ToOString( const OUString& s )
+{
+ return OUStringToOString( s, RTL_TEXTENCODING_UTF8 );
+}
+
+OString XclXmlUtils::ToOString( const String& s )
+{
+ return OString( s.GetBuffer(), s.Len(), RTL_TEXTENCODING_UTF8 );
+}
+
+OString XclXmlUtils::ToOString( const ScAddress& rAddress )
+{
+ String sAddress;
+ rAddress.Format( sAddress, SCA_VALID, NULL, ScAddress::Details( FormulaGrammar::CONV_XL_A1 ) );
+ return ToOString( sAddress );
+}
+
+OString XclXmlUtils::ToOString( const ScfUInt16Vec& rBuffer )
+{
+ const sal_uInt16* pBuffer = &rBuffer [0];
+ return OString( pBuffer, rBuffer.size(), RTL_TEXTENCODING_UTF8 );
+}
+
+OString XclXmlUtils::ToOString( const ScRange& rRange )
+{
+ String sRange;
+ rRange.Format( sRange, SCA_VALID, NULL, ScAddress::Details( FormulaGrammar::CONV_XL_A1 ) );
+ return ToOString( sRange );
+}
+
+OString XclXmlUtils::ToOString( const ScRangeList& rRangeList )
+{
+ String s;
+ rRangeList.Format( s, SCA_VALID, NULL, FormulaGrammar::CONV_XL_A1, ' ' );
+ return ToOString( s );
+}
+
+static ScAddress lcl_ToAddress( const XclAddress& rAddress )
+{
+ ScAddress aAddress;
+
+ // For some reason, ScRange::Format() returns omits row numbers if
+ // the row is >= MAXROW or the column is >= MAXCOL, and Excel doesn't
+ // like "A:IV" (i.e. no row numbers). Prevent this.
+ // KOHEI: Find out if the above comment is still true.
+ aAddress.SetRow( std::min<sal_Int32>( rAddress.mnRow, MAXROW ) );
+ aAddress.SetCol( static_cast<sal_Int16>(std::min<sal_Int32>( rAddress.mnCol, MAXCOL )) );
+
+ return aAddress;
+}
+
+OString XclXmlUtils::ToOString( const XclAddress& rAddress )
+{
+ return ToOString( lcl_ToAddress( rAddress ) );
+}
+
+OString XclXmlUtils::ToOString( const XclExpString& s )
+{
+ DBG_ASSERT( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
+ return ToOString( s.GetUnicodeBuffer() );
+}
+
+static ScRange lcl_ToRange( const XclRange& rRange )
+{
+ ScRange aRange;
+
+ aRange.aStart = lcl_ToAddress( rRange.maFirst );
+ aRange.aEnd = lcl_ToAddress( rRange.maLast );
+
+ return aRange;
+}
+
+rtl::OString XclXmlUtils::ToOString( const XclRange& rRange )
+{
+ return ToOString( lcl_ToRange( rRange ) );
+}
+
+rtl::OString XclXmlUtils::ToOString( const XclRangeList& rRanges )
+{
+ ScRangeList aRanges;
+ for( XclRangeList::const_iterator i = rRanges.begin(), end = rRanges.end();
+ i != end; ++i )
+ {
+ aRanges.Append( lcl_ToRange( *i ) );
+ }
+ return ToOString( aRanges );
+}
+
+OUString XclXmlUtils::ToOUString( const char* s )
+{
+ return OUString( s, (sal_Int32) strlen( s ), RTL_TEXTENCODING_ASCII_US );
+}
+
+OUString XclXmlUtils::ToOUString( const ScfUInt16Vec& rBuf, sal_Int32 nStart, sal_Int32 nLength )
+{
+ if( nLength == -1 || ( nLength > (rBuf.size() - nStart) ) )
+ nLength = (rBuf.size() - nStart);
+
+ return (nLength > 0) ? OUString( &rBuf[nStart], nLength ) : OUString();
+}
+
+OUString XclXmlUtils::ToOUString( const String& s )
+{
+ return OUString( s.GetBuffer(), s.Len() );
+}
+
+OUString XclXmlUtils::ToOUString( ScDocument& rDocument, const ScAddress& rAddress, ScTokenArray* pTokenArray )
+{
+ ScCompiler aCompiler( &rDocument, rAddress, *pTokenArray);
+ aCompiler.SetGrammar(FormulaGrammar::GRAM_ENGLISH_XL_A1);
+ String s;
+ aCompiler.CreateStringFromTokenArray( s );
+ return ToOUString( s );
+}
+
+OUString XclXmlUtils::ToOUString( const XclExpString& s )
+{
+ DBG_ASSERT( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" );
+ return ToOUString( s.GetUnicodeBuffer() );
+}
+
+const char* XclXmlUtils::ToPsz( bool b )
+{
+ return b ? "true" : "false";
+}
+
+sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int32 nValue )
+{
+ pStream->startElement( nElement, FSEND );
+ pStream->write( nValue );
+ pStream->endElement( nElement );
+
+ return pStream;
+}
+
+sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int64 nValue )
+{
+ pStream->startElement( nElement, FSEND );
+ pStream->write( nValue );
+ pStream->endElement( nElement );
+
+ return pStream;
+}
+
+sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, const char* sValue )
+{
+ pStream->startElement( nElement, FSEND );
+ pStream->write( sValue );
+ pStream->endElement( nElement );
+
+ return pStream;
+}
+
+static void lcl_WriteValue( sax_fastparser::FSHelperPtr& rStream, sal_Int32 nElement, const char* pValue )
+{
+ if( !pValue )
+ return;
+ rStream->singleElement( nElement,
+ XML_val, pValue,
+ FSEND );
+}
+
+static const char* lcl_GetUnderlineStyle( FontUnderline eUnderline, bool& bHaveUnderline )
+{
+ bHaveUnderline = true;
+ switch( eUnderline )
+ {
+ // OOXTODO: doubleAccounting, singleAccounting
+ // OOXTODO: what should be done with the other FontUnderline values?
+ case UNDERLINE_SINGLE: return "single";
+ case UNDERLINE_DOUBLE: return "double";
+ case UNDERLINE_NONE:
+ default: bHaveUnderline = false; return "none";
+ }
+}
+
+static const char* lcl_ToVerticalAlignmentRun( SvxEscapement eEscapement, bool& bHaveAlignment )
+{
+ bHaveAlignment = true;
+ switch( eEscapement )
+ {
+ case SVX_ESCAPEMENT_SUPERSCRIPT: return "superscript";
+ case SVX_ESCAPEMENT_SUBSCRIPT: return "subscript";
+ case SVX_ESCAPEMENT_OFF:
+ default: bHaveAlignment = false; return "baseline";
+ }
+}
+
+sax_fastparser::FSHelperPtr XclXmlUtils::WriteFontData( sax_fastparser::FSHelperPtr pStream, const XclFontData& rFontData, sal_Int32 nFontId )
+{
+ bool bHaveUnderline, bHaveVertAlign;
+ const char* pUnderline = lcl_GetUnderlineStyle( rFontData.GetScUnderline(), bHaveUnderline );
+ const char* pVertAlign = lcl_ToVerticalAlignmentRun( rFontData.GetScEscapement(), bHaveVertAlign );
+
+ lcl_WriteValue( pStream, nFontId, XclXmlUtils::ToOString( rFontData.maName ).getStr() );
+ lcl_WriteValue( pStream, XML_charset, rFontData.mnCharSet != 0 ? OString::valueOf( (sal_Int32) rFontData.mnCharSet ).getStr() : NULL );
+ lcl_WriteValue( pStream, XML_family, OString::valueOf( (sal_Int32) rFontData.mnFamily ).getStr() );
+ lcl_WriteValue( pStream, XML_b, rFontData.mnWeight > 400 ? XclXmlUtils::ToPsz( rFontData.mnWeight > 400 ) : NULL );
+ lcl_WriteValue( pStream, XML_i, rFontData.mbItalic ? XclXmlUtils::ToPsz( rFontData.mbItalic ) : NULL );
+ lcl_WriteValue( pStream, XML_strike, rFontData.mbStrikeout ? XclXmlUtils::ToPsz( rFontData.mbStrikeout ) : NULL );
+ lcl_WriteValue( pStream, XML_outline, rFontData.mbOutline ? XclXmlUtils::ToPsz( rFontData.mbOutline ) : NULL );
+ lcl_WriteValue( pStream, XML_shadow, rFontData.mbShadow ? XclXmlUtils::ToPsz( rFontData.mbShadow ) : NULL );
+ // OOXTODO: lcl_WriteValue( rStream, XML_condense, ); // mac compatibility setting
+ // OOXTODO: lcl_WriteValue( rStream, XML_extend, ); // compatibility setting
+ if( rFontData.maColor != Color( 0xFF, 0xFF, 0xFF, 0xFF ) )
+ pStream->singleElement( XML_color,
+ // OOXTODO: XML_auto, bool
+ // OOXTODO: XML_indexed, uint
+ XML_rgb, XclXmlUtils::ToOString( rFontData.maColor ).getStr(),
+ // OOXTODO: XML_theme, index into <clrScheme/>
+ // OOXTODO: XML_tint, double
+ FSEND );
+ lcl_WriteValue( pStream, XML_sz, OString::valueOf( (double) (rFontData.mnHeight / 20.0) ) ); // Twips->Pt
+ lcl_WriteValue( pStream, XML_u, bHaveUnderline ? pUnderline : NULL );
+ lcl_WriteValue( pStream, XML_vertAlign, bHaveVertAlign ? pVertAlign : NULL );
+
+ return pStream;
+}
+
+
+// ============================================================================
+
+XclExpXmlStream::XclExpXmlStream( const Reference< XComponentContext >& rCC )
+ : XmlFilterBase( rCC ),
+ mpRoot( NULL )
+{
+}
+
+XclExpXmlStream::~XclExpXmlStream()
+{
+}
+
+sax_fastparser::FSHelperPtr& XclExpXmlStream::GetCurrentStream()
+{
+ DBG_ASSERT( !maStreams.empty(), "XclExpXmlStream::GetCurrentStream - no current stream" );
+ return maStreams.top();
+}
+
+void XclExpXmlStream::PushStream( sax_fastparser::FSHelperPtr aStream )
+{
+ maStreams.push( aStream );
+}
+
+void XclExpXmlStream::PopStream()
+{
+ DBG_ASSERT( !maStreams.empty(), "XclExpXmlStream::PopStream - stack is empty!" );
+ maStreams.pop();
+}
+
+sax_fastparser::FSHelperPtr XclExpXmlStream::GetStreamForPath( const OUString& sPath )
+{
+ if( maOpenedStreamMap.find( sPath ) == maOpenedStreamMap.end() )
+ return sax_fastparser::FSHelperPtr();
+ return maOpenedStreamMap[ sPath ].second;
+}
+
+sax_fastparser::FSHelperPtr& XclExpXmlStream::WriteAttributes( sal_Int32 nAttribute, ... )
+{
+ sax_fastparser::FSHelperPtr& rStream = GetCurrentStream();
+
+ va_list args;
+ va_start( args, nAttribute );
+ do {
+ const char* pValue = va_arg( args, const char* );
+ if( pValue )
+ {
+ rStream->write( " " )
+ ->writeId( nAttribute )
+ ->write( "=\"" )
+ ->writeEscaped( pValue )
+ ->write( "\"" );
+ }
+
+ nAttribute = va_arg( args, sal_Int32 );
+ if( nAttribute == FSEND )
+ break;
+ } while( true );
+ va_end( args );
+
+ return rStream;
+}
+sax_fastparser::FSHelperPtr XclExpXmlStream::CreateOutputStream (
+ const OUString& sFullStream,
+ const OUString& sRelativeStream,
+ const Reference< XOutputStream >& xParentRelation,
+ const char* sContentType,
+ const char* sRelationshipType,
+ OUString* pRelationshipId )
+{
+ OUString sRelationshipId;
+ if (xParentRelation.is())
+ sRelationshipId = addRelation( xParentRelation, OUString::createFromAscii( sRelationshipType), sRelativeStream );
+ else
+ sRelationshipId = addRelation( OUString::createFromAscii( sRelationshipType ), sRelativeStream );
+
+ if( pRelationshipId )
+ *pRelationshipId = sRelationshipId;
+
+ sax_fastparser::FSHelperPtr p = openFragmentStreamWithSerializer( sFullStream, OUString::createFromAscii( sContentType ) );
+
+ maOpenedStreamMap[ sFullStream ] = std::make_pair( sRelationshipId, p );
+
+ return p;
+}
+
+bool XclExpXmlStream::importDocument() throw()
+{
+ return false;
+}
+
+oox::vml::Drawing* XclExpXmlStream::getVmlDrawing()
+{
+ return 0;
+}
+
+const oox::drawingml::Theme* XclExpXmlStream::getCurrentTheme() const
+{
+ return 0;
+}
+
+const oox::drawingml::table::TableStyleListPtr XclExpXmlStream::getTableStyles()
+{
+ return oox::drawingml::table::TableStyleListPtr();
+}
+
+oox::drawingml::chart::ChartConverter& XclExpXmlStream::getChartConverter()
+{
+ // DO NOT CALL
+ return * (oox::drawingml::chart::ChartConverter*) NULL;
+}
+
+ScDocShell* XclExpXmlStream::getDocShell()
+{
+ Reference< XInterface > xModel( getModel(), UNO_QUERY );
+
+ ScModelObj *pObj = dynamic_cast < ScModelObj* >( xModel.get() );
+
+ if ( pObj )
+ return reinterpret_cast < ScDocShell* >( pObj->GetEmbeddedObject() );
+
+ return 0;
+}
+
+bool XclExpXmlStream::exportDocument() throw()
+{
+ ScDocShell* pShell = getDocShell();
+ ScDocument* pDoc = pShell->GetDocument();
+ // NOTE: Don't use SotStorage or SvStream any more, and never call
+ // SfxMedium::GetOutStream() anywhere in the xlsx export filter code!
+ // Instead, write via XOutputStream instance.
+ SotStorageRef rStorage = static_cast<SotStorage*>(NULL);
+ XclExpObjList::ResetCounters();
+
+ XclExpRootData aData( EXC_BIFF8, *pShell->GetMedium (), rStorage, *pDoc, RTL_TEXTENCODING_DONTKNOW );
+ aData.meOutput = EXC_OUTPUT_XML_2007;
+ aData.maXclMaxPos.Set( EXC_MAXCOL_XML_2007, EXC_MAXROW_XML_2007, EXC_MAXTAB_XML_2007 );
+ aData.maMaxPos.SetCol( ::std::min( aData.maScMaxPos.Col(), aData.maXclMaxPos.Col() ) );
+ aData.maMaxPos.SetRow( ::std::min( aData.maScMaxPos.Row(), aData.maXclMaxPos.Row() ) );
+ aData.maMaxPos.SetTab( ::std::min( aData.maScMaxPos.Tab(), aData.maXclMaxPos.Tab() ) );
+
+ XclExpRoot aRoot( aData );
+
+ mpRoot = &aRoot;
+ aRoot.GetOldRoot().pER = &aRoot;
+ aRoot.GetOldRoot().eDateiTyp = Biff8;
+ // Get the viewsettings before processing
+ if( pShell->GetViewData() )
+ pShell->GetViewData()->WriteExtOptions( mpRoot->GetExtDocOptions() );
+
+ OUString const workbook = CREATE_OUSTRING( "xl/workbook.xml" );
+ PushStream( CreateOutputStream( workbook, workbook,
+ Reference <XOutputStream>(),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" ) );
+
+ // destruct at the end of the block
+ {
+ ExcDocument aDocRoot( aRoot );
+ aDocRoot.ReadDoc();
+ aDocRoot.WriteXml( *this );
+ }
+
+ mpRoot = NULL;
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// UNO stuff so that the filter is registered
+//////////////////////////////////////////////////////////////////////////
+
+#define IMPL_NAME "com.sun.star.comp.oox.ExcelFilterExport"
+
+OUString XlsxExport_getImplementationName()
+{
+ return OUString( RTL_CONSTASCII_USTRINGPARAM( IMPL_NAME ) );
+}
+
+::oox::ole::VbaProject* XclExpXmlStream::implCreateVbaProject() const
+{
+ return new ::oox::xls::ExcelVbaProject( getComponentContext(), Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) );
+}
+
+OUString XclExpXmlStream::implGetImplementationName() const
+{
+ return CREATE_OUSTRING( "TODO" );
+}
+
+
+Sequence< OUString > SAL_CALL XlsxExport_getSupportedServiceNames() throw()
+{
+ const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.ExportFilter" ) );
+ const Sequence< OUString > aSeq( &aServiceName, 1 );
+ return aSeq;
+}
+
+Reference< XInterface > SAL_CALL XlsxExport_createInstance(const Reference< XComponentContext > & rCC ) throw( Exception )
+{
+ return (cppu::OWeakObject*) new XclExpXmlStream( rCC );
+}
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( const sal_Char ** ppEnvTypeName, uno_Environment ** /* ppEnv */ )
+{
+ *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+}
+
+// ------------------------
+// - component_getFactory -
+// ------------------------
+::cppu::ImplementationEntry entries [] =
+{
+ {
+ XlsxExport_createInstance, XlsxExport_getImplementationName,
+ XlsxExport_getSupportedServiceNames, ::cppu::createSingleComponentFactory,
+ 0, 0
+ },
+ { 0, 0, 0, 0, 0, 0 }
+};
+
+SAL_DLLPUBLIC_EXPORT void* SAL_CALL component_getFactory( const sal_Char* pImplName, XMultiServiceFactory* pServiceManager, XRegistryKey* pRegistryKey )
+{
+ return ::cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey, entries );
+
+}
+
+#ifdef __cplusplus
+}
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xestring.cxx b/sc/source/filter/excel/xestring.cxx
new file mode 100644
index 000000000000..987b25dba294
--- /dev/null
+++ b/sc/source/filter/excel/xestring.cxx
@@ -0,0 +1,606 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <algorithm>
+#include <stdio.h>
+#include "xlstyle.hxx"
+#include "xestyle.hxx"
+#include "xestream.hxx"
+#include "xlstyle.hxx"
+#include "xestyle.hxx"
+#include "xestring.hxx"
+
+using namespace ::oox;
+
+using ::rtl::OString;
+using ::rtl::OUString;
+
+// ============================================================================
+
+namespace {
+
+// compare vectors
+
+/** Compares two vectors.
+ @return A negative value, if rLeft<rRight; or a positive value, if rLeft>rRight;
+ or 0, if rLeft==rRight. */
+template< typename Type >
+int lclCompareVectors( const ::std::vector< Type >& rLeft, const ::std::vector< Type >& rRight )
+{
+ int nResult = 0;
+
+ // 1st: compare all elements of the vectors
+ typedef typename ::std::vector< Type >::const_iterator CIT;
+ CIT aEndL = rLeft.end(), aEndR = rRight.end();
+ for( CIT aItL = rLeft.begin(), aItR = rRight.begin(); !nResult && (aItL != aEndL) && (aItR != aEndR); ++aItL, ++aItR )
+ nResult = static_cast< int >( *aItL ) - static_cast< int >( *aItR );
+
+ // 2nd: no differences found so far -> compare the vector sizes. Shorter vector is less
+ if( !nResult )
+ nResult = static_cast< int >( rLeft.size() ) - static_cast< int >( rRight.size() );
+
+ return nResult;
+}
+
+// hashing helpers
+
+/** Base class for value hashers.
+ @descr These function objects are used to hash any value to a sal_uInt32 value. */
+template< typename Type >
+struct XclHasher : public ::std::unary_function< Type, sal_uInt32 > {};
+
+template< typename Type >
+struct XclDirectHasher : public XclHasher< Type >
+{
+ inline sal_uInt32 operator()( Type nVal ) const { return nVal; }
+};
+
+struct XclFormatRunHasher : public XclHasher< const XclFormatRun& >
+{
+ inline sal_uInt32 operator()( const XclFormatRun& rRun ) const
+ { return (rRun.mnChar << 8) ^ rRun.mnFontIdx; }
+};
+
+/** Calculates a hash value from a vector.
+ @descr Uses the passed hasher function object to calculate hash values from
+ all vector elements. */
+template< typename Type, typename ValueHasher >
+sal_uInt16 lclHashVector( const ::std::vector< Type >& rVec, const ValueHasher& rHasher )
+{
+ sal_uInt32 nHash = rVec.size();
+ typedef typename ::std::vector< Type >::const_iterator CIT;
+ for( CIT aIt = rVec.begin(), aEnd = rVec.end(); aIt != aEnd; ++aIt )
+ (nHash *= 31) += rHasher( *aIt );
+ return static_cast< sal_uInt16 >( nHash ^ (nHash >> 16) );
+}
+
+/** Calculates a hash value from a vector. Uses XclDirectHasher to hash the vector elements. */
+template< typename Type >
+inline sal_uInt16 lclHashVector( const ::std::vector< Type >& rVec )
+{
+ return lclHashVector( rVec, XclDirectHasher< Type >() );
+}
+
+} // namespace
+
+// constructors ---------------------------------------------------------------
+
+XclExpString::XclExpString( XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ Init( 0, nFlags, nMaxLen, true );
+}
+
+XclExpString::XclExpString( const String& rString, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ Assign( rString, nFlags, nMaxLen );
+}
+
+XclExpString::XclExpString( const OUString& rString, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ Assign( rString, nFlags, nMaxLen );
+}
+
+// assign ---------------------------------------------------------------------
+
+void XclExpString::Assign( const String& rString, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ Build( rString.GetBuffer(), rString.Len(), nFlags, nMaxLen );
+}
+
+void XclExpString::Assign( const OUString& rString, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ Build( rString.getStr(), rString.getLength(), nFlags, nMaxLen );
+}
+
+void XclExpString::Assign( sal_Unicode cChar, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ Build( &cChar, 1, nFlags, nMaxLen );
+}
+
+void XclExpString::AssignByte(
+ const String& rString, rtl_TextEncoding eTextEnc, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ ByteString aByteStr( rString, eTextEnc ); // length may differ from length of rString
+ Build( aByteStr.GetBuffer(), aByteStr.Len(), nFlags, nMaxLen );
+}
+
+// append ---------------------------------------------------------------------
+
+void XclExpString::Append( const String& rString )
+{
+ BuildAppend( rString.GetBuffer(), rString.Len() );
+}
+
+void XclExpString::AppendByte( const String& rString, rtl_TextEncoding eTextEnc )
+{
+ if( rString.Len() > 0 )
+ {
+ ByteString aByteStr( rString, eTextEnc ); // length may differ from length of rString
+ BuildAppend( aByteStr.GetBuffer(), aByteStr.Len() );
+ }
+}
+
+void XclExpString::AppendByte( sal_Unicode cChar, rtl_TextEncoding eTextEnc )
+{
+ if( !cChar )
+ {
+ sal_Char cByteChar = 0;
+ BuildAppend( &cByteChar, 1 );
+ }
+ else
+ {
+ ByteString aByteStr( &cChar, 1, eTextEnc ); // length may be >1
+ BuildAppend( aByteStr.GetBuffer(), aByteStr.Len() );
+ }
+}
+
+// formatting runs ------------------------------------------------------------
+
+void XclExpString::SetFormats( const XclFormatRunVec& rFormats )
+{
+ maFormats = rFormats;
+#ifdef DBG_UTIL
+ if( IsRich() )
+ {
+ XclFormatRunVec::const_iterator aCurr = maFormats.begin();
+ XclFormatRunVec::const_iterator aPrev = aCurr;
+ XclFormatRunVec::const_iterator aEnd = maFormats.end();
+ for( ++aCurr; aCurr != aEnd; ++aCurr, ++aPrev )
+ DBG_ASSERT( aPrev->mnChar < aCurr->mnChar, "XclExpString::SetFormats - invalid char order" );
+ DBG_ASSERT( aPrev->mnChar <= mnLen, "XclExpString::SetFormats - invalid char index" );
+ }
+#endif
+ LimitFormatCount( mbIsBiff8 ? EXC_STR_MAXLEN : EXC_STR_MAXLEN_8BIT );
+}
+
+void XclExpString::AppendFormat( sal_uInt16 nChar, sal_uInt16 nFontIdx, bool bDropDuplicate )
+{
+ DBG_ASSERT( maFormats.empty() || (maFormats.back().mnChar < nChar), "XclExpString::AppendFormat - invalid char index" );
+ size_t nMaxSize = static_cast< size_t >( mbIsBiff8 ? EXC_STR_MAXLEN : EXC_STR_MAXLEN_8BIT );
+ if( maFormats.empty() || ((maFormats.size() < nMaxSize) && (!bDropDuplicate || (maFormats.back().mnFontIdx != nFontIdx))) )
+ maFormats.push_back( XclFormatRun( nChar, nFontIdx ) );
+}
+
+void XclExpString::AppendTrailingFormat( sal_uInt16 nFontIdx )
+{
+ AppendFormat( mnLen, nFontIdx, false );
+}
+
+void XclExpString::LimitFormatCount( sal_uInt16 nMaxCount )
+{
+ if( maFormats.size() > nMaxCount )
+ maFormats.erase( maFormats.begin() + nMaxCount, maFormats.end() );
+}
+
+sal_uInt16 XclExpString::RemoveLeadingFont()
+{
+ sal_uInt16 nFontIdx = EXC_FONT_NOTFOUND;
+ if( !maFormats.empty() && (maFormats.front().mnChar == 0) )
+ {
+ nFontIdx = maFormats.front().mnFontIdx;
+ maFormats.erase( maFormats.begin() );
+ }
+ return nFontIdx;
+}
+
+bool XclExpString::IsEqual( const XclExpString& rCmp ) const
+{
+ return
+ (mnLen == rCmp.mnLen) &&
+ (mbIsBiff8 == rCmp.mbIsBiff8) &&
+ (mbIsUnicode == rCmp.mbIsUnicode) &&
+ (mbWrapped == rCmp.mbWrapped) &&
+ (
+ ( mbIsBiff8 && (maUniBuffer == rCmp.maUniBuffer)) ||
+ (!mbIsBiff8 && (maCharBuffer == rCmp.maCharBuffer))
+ ) &&
+ (maFormats == rCmp.maFormats);
+}
+
+bool XclExpString::IsLessThan( const XclExpString& rCmp ) const
+{
+ int nResult = mbIsBiff8 ?
+ lclCompareVectors( maUniBuffer, rCmp.maUniBuffer ) :
+ lclCompareVectors( maCharBuffer, rCmp.maCharBuffer );
+ return (nResult != 0) ? (nResult < 0) : (maFormats < rCmp.maFormats);
+}
+
+// get data -------------------------------------------------------------------
+
+sal_uInt16 XclExpString::GetFormatsCount() const
+{
+ return static_cast< sal_uInt16 >( maFormats.size() );
+}
+
+sal_uInt8 XclExpString::GetFlagField() const
+{
+ return (mbIsUnicode ? EXC_STRF_16BIT : 0) | (IsWriteFormats() ? EXC_STRF_RICH : 0);
+}
+
+sal_uInt16 XclExpString::GetHeaderSize() const
+{
+ return
+ (mb8BitLen ? 1 : 2) + // length field
+ (IsWriteFlags() ? 1 : 0) + // flag field
+ (IsWriteFormats() ? 2 : 0); // richtext formattting count
+}
+
+sal_Size XclExpString::GetBufferSize() const
+{
+ return mnLen * (mbIsUnicode ? 2 : 1);
+}
+
+sal_Size XclExpString::GetSize() const
+{
+ return
+ GetHeaderSize() + // header
+ GetBufferSize() + // character buffer
+ (IsWriteFormats() ? (4 * GetFormatsCount()) : 0); // richtext formattting
+}
+
+sal_uInt16 XclExpString::GetChar( sal_uInt16 nCharIdx ) const
+{
+ DBG_ASSERT( nCharIdx < Len(), "XclExpString::GetChar - invalid character index" );
+ return static_cast< sal_uInt16 >( mbIsBiff8 ? maUniBuffer[ nCharIdx ] : maCharBuffer[ nCharIdx ] );
+}
+
+sal_uInt16 XclExpString::GetHash() const
+{
+ return
+ (mbIsBiff8 ? lclHashVector( maUniBuffer ) : lclHashVector( maCharBuffer )) ^
+ lclHashVector( maFormats, XclFormatRunHasher() );
+}
+
+// streaming ------------------------------------------------------------------
+
+void XclExpString::WriteLenField( XclExpStream& rStrm ) const
+{
+ if( mb8BitLen )
+ rStrm << static_cast< sal_uInt8 >( mnLen );
+ else
+ rStrm << mnLen;
+}
+
+void XclExpString::WriteFlagField( XclExpStream& rStrm ) const
+{
+ if( mbIsBiff8 )
+ {
+ PrepareWrite( rStrm, 1 );
+ rStrm << GetFlagField();
+ rStrm.SetSliceSize( 0 );
+ }
+}
+
+void XclExpString::WriteHeader( XclExpStream& rStrm ) const
+{
+ DBG_ASSERT( !mb8BitLen || (mnLen < 256), "XclExpString::WriteHeader - string too long" );
+ PrepareWrite( rStrm, GetHeaderSize() );
+ // length
+ WriteLenField( rStrm );
+ // flag field
+ if( IsWriteFlags() )
+ rStrm << GetFlagField();
+ // format run count
+ if( IsWriteFormats() )
+ rStrm << GetFormatsCount();
+ rStrm.SetSliceSize( 0 );
+}
+
+void XclExpString::WriteBuffer( XclExpStream& rStrm ) const
+{
+ if( mbIsBiff8 )
+ rStrm.WriteUnicodeBuffer( maUniBuffer, GetFlagField() );
+ else
+ rStrm.WriteCharBuffer( maCharBuffer );
+}
+
+void XclExpString::WriteFormats( XclExpStream& rStrm, bool bWriteSize ) const
+{
+ if( IsRich() )
+ {
+ XclFormatRunVec::const_iterator aIt = maFormats.begin(), aEnd = maFormats.end();
+ if( mbIsBiff8 )
+ {
+ if( bWriteSize )
+ rStrm << GetFormatsCount();
+ rStrm.SetSliceSize( 4 );
+ for( ; aIt != aEnd; ++aIt )
+ rStrm << aIt->mnChar << aIt->mnFontIdx;
+ }
+ else
+ {
+ if( bWriteSize )
+ rStrm << static_cast< sal_uInt8 >( GetFormatsCount() );
+ rStrm.SetSliceSize( 2 );
+ for( ; aIt != aEnd; ++aIt )
+ rStrm << static_cast< sal_uInt8 >( aIt->mnChar ) << static_cast< sal_uInt8 >( aIt->mnFontIdx );
+ }
+ rStrm.SetSliceSize( 0 );
+ }
+}
+
+void XclExpString::Write( XclExpStream& rStrm ) const
+{
+ if (!mbSkipHeader)
+ WriteHeader( rStrm );
+ WriteBuffer( rStrm );
+ if( IsWriteFormats() ) // only in BIFF8 included in string
+ WriteFormats( rStrm );
+}
+
+void XclExpString::WriteHeaderToMem( sal_uInt8* pnMem ) const
+{
+ DBG_ASSERT( pnMem, "XclExpString::WriteHeaderToMem - no memory to write to" );
+ DBG_ASSERT( !mb8BitLen || (mnLen < 256), "XclExpString::WriteHeaderToMem - string too long" );
+ DBG_ASSERT( !IsWriteFormats(), "XclExpString::WriteHeaderToMem - formatted strings not supported" );
+ // length
+ if( mb8BitLen )
+ {
+ *pnMem = static_cast< sal_uInt8 >( mnLen );
+ ++pnMem;
+ }
+ else
+ {
+ ShortToSVBT16( mnLen, pnMem );
+ pnMem += 2;
+ }
+ // flag field
+ if( IsWriteFlags() )
+ *pnMem = GetFlagField();
+}
+
+void XclExpString::WriteBufferToMem( sal_uInt8* pnMem ) const
+{
+ DBG_ASSERT( pnMem, "XclExpString::WriteBufferToMem - no memory to write to" );
+ if( !IsEmpty() )
+ {
+ if( mbIsBiff8 )
+ {
+ for( ScfUInt16Vec::const_iterator aIt = maUniBuffer.begin(), aEnd = maUniBuffer.end(); aIt != aEnd; ++aIt )
+ {
+ sal_uInt16 nChar = *aIt;
+ *pnMem = static_cast< sal_uInt8 >( nChar );
+ ++pnMem;
+ if( mbIsUnicode )
+ {
+ *pnMem = static_cast< sal_uInt8 >( nChar >> 8 );
+ ++pnMem;
+ }
+ }
+ }
+ else
+ memcpy( pnMem, &maCharBuffer[ 0 ], mnLen );
+ }
+}
+
+void XclExpString::WriteToMem( sal_uInt8* pnMem ) const
+{
+ WriteHeaderToMem( pnMem );
+ WriteBufferToMem( pnMem + GetHeaderSize() );
+}
+
+static sal_uInt16 lcl_WriteRun( XclExpXmlStream& rStrm, const ScfUInt16Vec& rBuffer, sal_uInt16 nStart, sal_Int32 nLength, const XclExpFont* pFont )
+{
+ if( nLength == 0 )
+ return nStart;
+
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+
+ rWorksheet->startElement( XML_r, FSEND );
+ if( pFont )
+ {
+ const XclFontData& rFontData = pFont->GetFontData();
+ rWorksheet->startElement( XML_rPr, FSEND );
+ XclXmlUtils::WriteFontData( rWorksheet, rFontData, XML_rFont );
+ rWorksheet->endElement( XML_rPr );
+ }
+ rWorksheet->startElement( XML_t,
+ FSNS( XML_xml, XML_space ), "preserve",
+ FSEND );
+ rWorksheet->writeEscaped( XclXmlUtils::ToOUString( rBuffer, nStart, nLength ) );
+ rWorksheet->endElement( XML_t );
+ rWorksheet->endElement( XML_r );
+ return nStart + nLength;
+}
+
+void XclExpString::WriteXml( XclExpXmlStream& rStrm ) const
+{
+ sax_fastparser::FSHelperPtr rWorksheet = rStrm.GetCurrentStream();
+
+ if( !IsWriteFormats() )
+ {
+ rWorksheet->startElement( XML_t, FSEND );
+ rWorksheet->writeEscaped( XclXmlUtils::ToOUString( *this ) );
+ rWorksheet->endElement( XML_t );
+ }
+ else
+ {
+ XclExpFontBuffer& rFonts = rStrm.GetRoot().GetFontBuffer();
+ XclFormatRunVec::const_iterator aIt = maFormats.begin(), aEnd = maFormats.end();
+
+ sal_uInt16 nStart = 0;
+ const XclExpFont* pFont = NULL;
+ for ( ; aIt != aEnd; ++aIt )
+ {
+ nStart = lcl_WriteRun( rStrm, GetUnicodeBuffer(),
+ nStart, aIt->mnChar-nStart, pFont );
+ pFont = rFonts.GetFont( aIt->mnFontIdx );
+ }
+ lcl_WriteRun( rStrm, GetUnicodeBuffer(),
+ nStart, GetUnicodeBuffer().size() - nStart, pFont );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+bool XclExpString::IsWriteFlags() const
+{
+ return mbIsBiff8 && (!IsEmpty() || !mbSmartFlags);
+}
+
+bool XclExpString::IsWriteFormats() const
+{
+ return mbIsBiff8 && !mbSkipFormats && IsRich();
+}
+
+void XclExpString::SetStrLen( sal_Int32 nNewLen )
+{
+ sal_uInt16 nAllowedLen = (mb8BitLen && (mnMaxLen > 255)) ? 255 : mnMaxLen;
+ mnLen = limit_cast< sal_uInt16 >( nNewLen, 0, nAllowedLen );
+}
+
+void XclExpString::CharsToBuffer( const sal_Unicode* pcSource, sal_Int32 nBegin, sal_Int32 nLen )
+{
+ DBG_ASSERT( maUniBuffer.size() >= static_cast< size_t >( nBegin + nLen ),
+ "XclExpString::CharsToBuffer - char buffer invalid" );
+ ScfUInt16Vec::iterator aBeg = maUniBuffer.begin() + nBegin;
+ ScfUInt16Vec::iterator aEnd = aBeg + nLen;
+ const sal_Unicode* pcSrcChar = pcSource;
+ for( ScfUInt16Vec::iterator aIt = aBeg; aIt != aEnd; ++aIt, ++pcSrcChar )
+ {
+ *aIt = static_cast< sal_uInt16 >( *pcSrcChar );
+ if( *aIt & 0xFF00 )
+ mbIsUnicode = true;
+ }
+ if( !mbWrapped )
+ mbWrapped = ::std::find( aBeg, aEnd, EXC_LF ) != aEnd;
+}
+
+void XclExpString::CharsToBuffer( const sal_Char* pcSource, sal_Int32 nBegin, sal_Int32 nLen )
+{
+ DBG_ASSERT( maCharBuffer.size() >= static_cast< size_t >( nBegin + nLen ),
+ "XclExpString::CharsToBuffer - char buffer invalid" );
+ ScfUInt8Vec::iterator aBeg = maCharBuffer.begin() + nBegin;
+ ScfUInt8Vec::iterator aEnd = aBeg + nLen;
+ const sal_Char* pcSrcChar = pcSource;
+ for( ScfUInt8Vec::iterator aIt = aBeg; aIt != aEnd; ++aIt, ++pcSrcChar )
+ *aIt = static_cast< sal_uInt8 >( *pcSrcChar );
+ mbIsUnicode = false;
+ if( !mbWrapped )
+ mbWrapped = ::std::find( aBeg, aEnd, EXC_LF_C ) != aEnd;
+}
+
+void XclExpString::Init( sal_Int32 nCurrLen, XclStrFlags nFlags, sal_uInt16 nMaxLen, bool bBiff8 )
+{
+ mbIsBiff8 = bBiff8;
+ mbIsUnicode = bBiff8 && ::get_flag( nFlags, EXC_STR_FORCEUNICODE );
+ mb8BitLen = ::get_flag( nFlags, EXC_STR_8BITLENGTH );
+ mbSmartFlags = bBiff8 && ::get_flag( nFlags, EXC_STR_SMARTFLAGS );
+ mbSkipFormats = ::get_flag( nFlags, EXC_STR_SEPARATEFORMATS );
+ mbWrapped = false;
+ mbSkipHeader = ::get_flag( nFlags, EXC_STR_NOHEADER );
+ mnMaxLen = nMaxLen;
+ SetStrLen( nCurrLen );
+
+ maFormats.clear();
+ if( mbIsBiff8 )
+ {
+ maCharBuffer.clear();
+ maUniBuffer.resize( mnLen );
+ }
+ else
+ {
+ maUniBuffer.clear();
+ maCharBuffer.resize( mnLen );
+ }
+}
+
+void XclExpString::Build( const sal_Unicode* pcSource, sal_Int32 nCurrLen, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ Init( nCurrLen, nFlags, nMaxLen, true );
+ CharsToBuffer( pcSource, 0, mnLen );
+}
+
+void XclExpString::Build( const sal_Char* pcSource, sal_Int32 nCurrLen, XclStrFlags nFlags, sal_uInt16 nMaxLen )
+{
+ Init( nCurrLen, nFlags, nMaxLen, false );
+ CharsToBuffer( pcSource, 0, mnLen );
+}
+
+void XclExpString::InitAppend( sal_Int32 nAddLen )
+{
+ SetStrLen( static_cast< sal_Int32 >( mnLen ) + nAddLen );
+ if( mbIsBiff8 )
+ maUniBuffer.resize( mnLen );
+ else
+ maCharBuffer.resize( mnLen );
+}
+
+void XclExpString::BuildAppend( const sal_Unicode* pcSource, sal_Int32 nAddLen )
+{
+ DBG_ASSERT( mbIsBiff8, "XclExpString::BuildAppend - must not be called at byte strings" );
+ if( mbIsBiff8 )
+ {
+ sal_uInt16 nOldLen = mnLen;
+ InitAppend( nAddLen );
+ CharsToBuffer( pcSource, nOldLen, mnLen - nOldLen );
+ }
+}
+
+void XclExpString::BuildAppend( const sal_Char* pcSource, sal_Int32 nAddLen )
+{
+ DBG_ASSERT( !mbIsBiff8, "XclExpString::BuildAppend - must not be called at unicode strings" );
+ if( !mbIsBiff8 )
+ {
+ sal_uInt16 nOldLen = mnLen;
+ InitAppend( nAddLen );
+ CharsToBuffer( pcSource, nOldLen, mnLen - nOldLen );
+ }
+}
+
+void XclExpString::PrepareWrite( XclExpStream& rStrm, sal_uInt16 nBytes ) const
+{
+ rStrm.SetSliceSize( nBytes + (mbIsUnicode ? 2 : 1) );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xestyle.cxx b/sc/source/filter/excel/xestyle.cxx
new file mode 100644
index 000000000000..eb5075c189ca
--- /dev/null
+++ b/sc/source/filter/excel/xestyle.cxx
@@ -0,0 +1,2860 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xestyle.hxx"
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <vcl/font.hxx>
+#include <svl/zformat.hxx>
+#include <svl/languageoptions.hxx>
+#include <sfx2/printer.hxx>
+#include "scitems.hxx"
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/bolnitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/escpitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include "document.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "patattr.hxx"
+#include "attrib.hxx"
+#include "globstr.hrc"
+#include "xestring.hxx"
+
+#include <oox/token/tokens.hxx>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+using ::rtl::OString;
+using ::rtl::OUString;
+using namespace oox;
+
+// PALETTE record - color information =========================================
+
+namespace {
+
+sal_uInt32 lclGetWeighting( XclExpColorType eType )
+{
+ switch( eType )
+ {
+ case EXC_COLOR_CHARTLINE: return 1;
+ case EXC_COLOR_CELLBORDER:
+ case EXC_COLOR_CHARTAREA: return 2;
+ case EXC_COLOR_CELLTEXT:
+ case EXC_COLOR_CHARTTEXT:
+ case EXC_COLOR_CTRLTEXT: return 10;
+ case EXC_COLOR_TABBG:
+ case EXC_COLOR_CELLAREA: return 20;
+ case EXC_COLOR_GRID: return 50;
+ default: DBG_ERRORFILE( "lclGetWeighting - unknown color type" );
+ }
+ return 1;
+}
+
+sal_Int32 lclGetColorDistance( const Color& rColor1, const Color& rColor2 )
+{
+ sal_Int32 nDist = rColor1.GetRed() - rColor2.GetRed();
+ nDist *= nDist * 77;
+ sal_Int32 nDummy = rColor1.GetGreen() - rColor2.GetGreen();
+ nDist += nDummy * nDummy * 151;
+ nDummy = rColor1.GetBlue() - rColor2.GetBlue();
+ nDist += nDummy * nDummy * 28;
+ return nDist;
+}
+
+sal_uInt8 lclGetMergedColorComp( sal_uInt8 nComp1, sal_uInt32 nWeight1, sal_uInt8 nComp2, sal_uInt32 nWeight2 )
+{
+ sal_uInt8 nComp1Dist = ::std::min< sal_uInt8 >( nComp1, 0xFF - nComp1 );
+ sal_uInt8 nComp2Dist = ::std::min< sal_uInt8 >( nComp2, 0xFF - nComp2 );
+ if( nComp1Dist != nComp2Dist )
+ {
+ /* #i36945# One of the passed RGB components is nearer at the limits (0x00 or 0xFF).
+ Increase its weighting to prevent fading of the colors during reduction. */
+ const sal_uInt8& rnCompNearer = (nComp1Dist < nComp2Dist) ? nComp1 : nComp2;
+ sal_uInt32& rnWeight = (nComp1Dist < nComp2Dist) ? nWeight1 : nWeight2;
+ rnWeight *= ((rnCompNearer - 0x80L) * (rnCompNearer - 0x7FL) / 0x1000L + 1);
+ }
+ sal_uInt32 nWSum = nWeight1 + nWeight2;
+ return static_cast< sal_uInt8 >( (nComp1 * nWeight1 + nComp2 * nWeight2 + nWSum / 2) / nWSum );
+}
+
+void lclSetMixedColor( Color& rDest, const Color& rSrc1, const Color& rSrc2 )
+{
+ rDest.SetRed( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetRed() ) + rSrc2.GetRed()) / 2 ) );
+ rDest.SetGreen( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetGreen() ) + rSrc2.GetGreen()) / 2 ) );
+ rDest.SetBlue( static_cast< sal_uInt8 >( (static_cast< sal_uInt16 >( rSrc1.GetBlue() ) + rSrc2.GetBlue()) / 2 ) );
+}
+
+} // namespace
+
+// additional classes for color reduction -------------------------------------
+
+namespace {
+
+/** Represents an entry in a color list.
+
+ The color stores a weighting value, which increases the more the color is
+ used in the document. Heavy-weighted colors will change less than others on
+ color reduction.
+ */
+class XclListColor
+{
+ DECL_FIXEDMEMPOOL_NEWDEL( XclListColor )
+
+private:
+ Color maColor; /// The color value of this palette entry.
+ sal_uInt32 mnColorId; /// Unique color ID for color reduction.
+ sal_uInt32 mnWeight; /// Weighting for color reduction.
+ bool mbBaseColor; /// true = Handle as base color, (don't remove/merge).
+
+public:
+ explicit XclListColor( const Color& rColor, sal_uInt32 nColorId );
+
+ /** Returns the RGB color value of the color. */
+ inline const Color& GetColor() const { return maColor; }
+ /** Returns the unique ID of the color. */
+ inline sal_uInt32 GetColorId() const { return mnColorId; }
+ /** Returns the current weighting of the color. */
+ inline sal_uInt32 GetWeighting() const { return mnWeight; }
+ /** Returns true, if this color is a base color, i.e. it will not be removed or merged. */
+ inline bool IsBaseColor() const { return mbBaseColor; }
+
+ /** Adds the passed weighting to this color. */
+ inline void AddWeighting( sal_uInt32 nWeight ) { mnWeight += nWeight; }
+ /** Merges this color with rColor, regarding weighting settings. */
+ void Merge( const XclListColor& rColor );
+};
+
+IMPL_FIXEDMEMPOOL_NEWDEL( XclListColor, 100, 100 )
+
+XclListColor::XclListColor( const Color& rColor, sal_uInt32 nColorId ) :
+ maColor( rColor ),
+ mnColorId( nColorId ),
+ mnWeight( 0 )
+{
+ mbBaseColor =
+ ((rColor.GetRed() == 0x00) || (rColor.GetRed() == 0xFF)) &&
+ ((rColor.GetGreen() == 0x00) || (rColor.GetGreen() == 0xFF)) &&
+ ((rColor.GetBlue() == 0x00) || (rColor.GetBlue() == 0xFF));
+}
+
+void XclListColor::Merge( const XclListColor& rColor )
+{
+ sal_uInt32 nWeight2 = rColor.GetWeighting();
+ // do not change RGB value of base colors
+ if( !mbBaseColor )
+ {
+ maColor.SetRed( lclGetMergedColorComp( maColor.GetRed(), mnWeight, rColor.maColor.GetRed(), nWeight2 ) );
+ maColor.SetGreen( lclGetMergedColorComp( maColor.GetGreen(), mnWeight, rColor.maColor.GetGreen(), nWeight2 ) );
+ maColor.SetBlue( lclGetMergedColorComp( maColor.GetBlue(), mnWeight, rColor.maColor.GetBlue(), nWeight2 ) );
+ }
+ AddWeighting( nWeight2 );
+}
+
+// ----------------------------------------------------------------------------
+
+/** Data for each inserted original color, represented by a color ID. */
+struct XclColorIdData
+{
+ Color maColor; /// The original inserted color.
+ sal_uInt32 mnIndex; /// Maps current color ID to color list or export color vector.
+ /** Sets the contents of this struct. */
+ inline void Set( const Color& rColor, sal_uInt32 nIndex ) { maColor = rColor; mnIndex = nIndex; }
+};
+
+/** A color that will be written to the Excel file. */
+struct XclPaletteColor
+{
+ Color maColor; /// Resulting color to export.
+ bool mbUsed; /// true = Entry is used in the document.
+
+ inline explicit XclPaletteColor( const Color& rColor ) : maColor( rColor ), mbUsed( false ) {}
+ inline void SetColor( const Color& rColor ) { maColor = rColor; mbUsed = true; }
+};
+
+/** Maps a color list index to a palette index.
+ @descr Used to remap the color ID data vector from list indexes to palette indexes. */
+struct XclRemap
+{
+ sal_uInt32 mnPalIndex; /// Index to palette.
+ bool mbProcessed; /// true = List color already processed.
+
+ inline explicit XclRemap() : mnPalIndex( 0 ), mbProcessed( false ) {}
+ inline void SetIndex( sal_uInt32 nPalIndex )
+ { mnPalIndex = nPalIndex; mbProcessed = true; }
+};
+
+/** Stores the nearest palette color index of a list color. */
+struct XclNearest
+{
+ sal_uInt32 mnPalIndex; /// Index to nearest palette color.
+ sal_Int32 mnDist; /// Distance to palette color.
+
+ inline explicit XclNearest() : mnPalIndex( 0 ), mnDist( 0 ) {}
+};
+
+typedef ::std::vector< XclRemap > XclRemapVec;
+typedef ::std::vector< XclNearest > XclNearestVec;
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+class XclExpPaletteImpl
+{
+public:
+ explicit XclExpPaletteImpl( const XclDefaultPalette& rDefPal );
+
+ /** Inserts the color into the list and updates weighting.
+ @param nAutoDefault The Excel palette index for automatic color.
+ @return A unique ID for this color. */
+ sal_uInt32 InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault = 0 );
+ /** Returns the color ID representing a fixed Excel palette index (i.e. for auto colors). */
+ static sal_uInt32 GetColorIdFromIndex( sal_uInt16 nIndex );
+
+ /** Reduces the color list to the maximum count of the current BIFF version. */
+ void Finalize();
+
+ /** Returns the Excel palette index of the color with passed color ID. */
+ sal_uInt16 GetColorIndex( sal_uInt32 nColorId ) const;
+
+ /** Returns a foreground and background color for the two passed color IDs.
+ @descr If rnXclPattern contains a solid pattern, this function tries to find
+ the two best fitting colors and a mix pattern (25%, 50% or 75%) for nForeColorId.
+ This will result in a better approximation to the passed foreground color. */
+ void GetMixedColors(
+ sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
+ sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const;
+
+ /** Returns the RGB color data for a (non-zero-based) Excel palette entry.
+ @return The color from current or default palette or COL_AUTO, if nothing else found. */
+ ColorData GetColorData( sal_uInt16 nXclIndex ) const;
+ /** Returns the color for a (non-zero-based) Excel palette entry.
+ @return The color from current or default palette or COL_AUTO, if nothing else found. */
+ inline Color GetColor( sal_uInt16 nXclIndex ) const
+ { return Color( GetColorData( nXclIndex ) ); }
+
+ /** Returns true, if all colors of the palette are equal to default palette colors. */
+ bool IsDefaultPalette() const;
+ /** Writes the color list (contents of the palette record) to the passed stream. */
+ void WriteBody( XclExpStream& rStrm );
+ void SaveXml( XclExpXmlStream& rStrm );
+
+private:
+ /** Returns the Excel index of a 0-based color index. */
+ inline sal_uInt16 GetXclIndex( sal_uInt32 nIndex ) const
+ { return static_cast< sal_uInt16 >( nIndex + EXC_COLOR_USEROFFSET ); }
+
+ /** Returns the original inserted color represented by the color ID nColorId. */
+ const Color& GetOriginalColor( sal_uInt32 nColorId ) const;
+
+ /** Searches for rColor, returns the ordered insertion index for rColor in rnIndex. */
+ XclListColor* SearchListEntry( const Color& rColor, sal_uInt32& rnIndex );
+ /** Creates and inserts a new color list entry at the specified list position. */
+ XclListColor* CreateListEntry( const Color& rColor, sal_uInt32 nIndex );
+
+ /** Raw and fast reduction of the palette. */
+ void RawReducePalette( sal_uInt32 nPass );
+ /** Reduction of one color using advanced color merging based on color weighting. */
+ void ReduceLeastUsedColor();
+
+ /** Finds the least used color and returns its current list index. */
+ sal_uInt32 GetLeastUsedListColor() const;
+ /** Returns the list index of the color nearest to rColor.
+ @param nIgnore List index of a color which will be ignored.
+ @return The list index of the found color. */
+ sal_uInt32 GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const;
+ /** Returns the list index of the color nearest to the color with list index nIndex. */
+ sal_uInt32 GetNearestListColor( sal_uInt32 nIndex ) const;
+
+ /** Returns in rnIndex the palette index of the color nearest to rColor.
+ @param bDefaultOnly true = Searches for default colors only (colors never replaced).
+ @return The distance from passed color to found color. */
+ sal_Int32 GetNearestPaletteColor(
+ sal_uInt32& rnIndex,
+ const Color& rColor, bool bDefaultOnly ) const;
+ /** Returns in rnFirst and rnSecond the palette indexes of the two colors nearest to rColor.
+ @return The minimum distance from passed color to found colors. */
+ sal_Int32 GetNearPaletteColors(
+ sal_uInt32& rnFirst, sal_uInt32& rnSecond,
+ const Color& rColor ) const;
+
+private:
+ typedef boost::ptr_vector< XclListColor > XclListColorList;
+ typedef boost::shared_ptr< XclListColorList > XclListColorListRef;
+ typedef ::std::vector< XclColorIdData > XclColorIdDataVec;
+ typedef ::std::vector< XclPaletteColor > XclPaletteColorVec;
+
+ const XclDefaultPalette& mrDefPal; /// The default palette for the current BIFF version.
+ XclListColorListRef mxColorList; /// Working color list.
+ XclColorIdDataVec maColorIdDataVec; /// Data of all CIDs.
+ XclPaletteColorVec maPalette; /// Contains resulting colors to export.
+ sal_uInt32 mnLastIdx; /// Last insertion index for search opt.
+};
+
+// ----------------------------------------------------------------------------
+
+const sal_uInt32 EXC_PAL_INDEXBASE = 0xFFFF0000;
+const sal_uInt32 EXC_PAL_MAXRAWSIZE = 1024;
+
+XclExpPaletteImpl::XclExpPaletteImpl( const XclDefaultPalette& rDefPal ) :
+ mrDefPal( rDefPal ),
+ mxColorList( new XclListColorList ),
+ mnLastIdx( 0 )
+{
+ // initialize maPalette with default colors
+ sal_uInt16 nCount = static_cast< sal_uInt16 >( mrDefPal.GetColorCount() );
+ maPalette.reserve( nCount );
+ for( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx )
+ maPalette.push_back( XclPaletteColor( mrDefPal.GetDefColor( GetXclIndex( nIdx ) ) ) );
+
+ InsertColor( Color( COL_BLACK ), EXC_COLOR_CELLTEXT );
+}
+
+sal_uInt32 XclExpPaletteImpl::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
+{
+ if( rColor.GetColor() == COL_AUTO )
+ return GetColorIdFromIndex( nAutoDefault );
+
+ sal_uInt32 nFoundIdx = 0;
+ XclListColor* pEntry = SearchListEntry( rColor, nFoundIdx );
+ if( !pEntry || (pEntry->GetColor() != rColor) )
+ pEntry = CreateListEntry( rColor, nFoundIdx );
+ pEntry->AddWeighting( lclGetWeighting( eType ) );
+
+ return pEntry->GetColorId();
+}
+
+sal_uInt32 XclExpPaletteImpl::GetColorIdFromIndex( sal_uInt16 nIndex )
+{
+ return EXC_PAL_INDEXBASE | nIndex;
+}
+
+void XclExpPaletteImpl::Finalize()
+{
+// --- build initial color ID data vector (maColorIdDataVec) ---
+
+ sal_uInt32 nCount = mxColorList->size();
+ maColorIdDataVec.resize( nCount );
+ for( sal_uInt32 nIdx = 0; nIdx < nCount; ++nIdx )
+ {
+ const XclListColor& listColor = mxColorList->at( nIdx );
+ maColorIdDataVec[ listColor.GetColorId() ].Set( listColor.GetColor(), nIdx );
+ }
+
+// --- loop as long as current color count does not fit into palette of current BIFF ---
+
+ // phase 1: raw reduction (performance reasons, #i36945#)
+ sal_uInt32 nPass = 0;
+ while( mxColorList->size() > EXC_PAL_MAXRAWSIZE )
+ RawReducePalette( nPass++ );
+
+ // phase 2: precise reduction using advanced color merging based on color weighting
+ while( mxColorList->size() > mrDefPal.GetColorCount() )
+ ReduceLeastUsedColor();
+
+// --- use default palette and replace colors with nearest used colors ---
+
+ nCount = mxColorList->size();
+ XclRemapVec aRemapVec( nCount );
+ XclNearestVec aNearestVec( nCount );
+
+ // in each run: search the best fitting color and replace a default color with it
+ for( sal_uInt32 nRun = 0; nRun < nCount; ++nRun )
+ {
+ sal_uInt32 nIndex;
+ // find nearest unused default color for each unprocessed list color
+ for( nIndex = 0; nIndex < nCount; ++nIndex )
+ aNearestVec[ nIndex ].mnDist = aRemapVec[ nIndex ].mbProcessed ? SAL_MAX_INT32 :
+ GetNearestPaletteColor( aNearestVec[ nIndex ].mnPalIndex, mxColorList->at( nIndex ).GetColor(), true );
+ // find the list color which is nearest to a default color
+ sal_uInt32 nFound = 0;
+ for( nIndex = 1; nIndex < nCount; ++nIndex )
+ if( aNearestVec[ nIndex ].mnDist < aNearestVec[ nFound ].mnDist )
+ nFound = nIndex;
+ // replace default color with list color
+ sal_uInt32 nNearest = aNearestVec[ nFound ].mnPalIndex;
+ DBG_ASSERT( nNearest < maPalette.size(), "XclExpPaletteImpl::Finalize - algorithm error" );
+ maPalette[ nNearest ].SetColor( mxColorList->at( nFound ).GetColor() );
+ aRemapVec[ nFound ].SetIndex( nNearest );
+ }
+
+ // remap color ID data map (maColorIdDataVec) from list indexes to palette indexes
+ for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
+ aIt->mnIndex = aRemapVec[ aIt->mnIndex ].mnPalIndex;
+}
+
+sal_uInt16 XclExpPaletteImpl::GetColorIndex( sal_uInt32 nColorId ) const
+{
+ sal_uInt16 nRet = 0;
+ if( nColorId >= EXC_PAL_INDEXBASE )
+ nRet = static_cast< sal_uInt16 >( nColorId & ~EXC_PAL_INDEXBASE );
+ else if( nColorId < maColorIdDataVec.size() )
+ nRet = GetXclIndex( maColorIdDataVec[ nColorId ].mnIndex );
+ return nRet;
+}
+
+void XclExpPaletteImpl::GetMixedColors(
+ sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
+ sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
+{
+ rnXclForeIx = GetColorIndex( nForeColorId );
+ rnXclBackIx = GetColorIndex( nBackColorId );
+ if( (rnXclPattern != EXC_PATT_SOLID) || (nForeColorId >= maColorIdDataVec.size()) )
+ return;
+
+ // now we have solid pattern, and a defined foreground (background doesn't care for solid pattern)
+
+ sal_uInt32 nIndex1, nIndex2;
+ Color aForeColor( GetOriginalColor( nForeColorId ) );
+ sal_Int32 nFirstDist = GetNearPaletteColors( nIndex1, nIndex2, aForeColor );
+ if( (nIndex1 >= maPalette.size()) || (nIndex2 >= maPalette.size()) )
+ return;
+
+ Color aColorArr[ 5 ];
+ aColorArr[ 0 ] = maPalette[ nIndex1 ].maColor;
+ aColorArr[ 4 ] = maPalette[ nIndex2 ].maColor;
+ lclSetMixedColor( aColorArr[ 2 ], aColorArr[ 0 ], aColorArr[ 4 ] );
+ lclSetMixedColor( aColorArr[ 1 ], aColorArr[ 0 ], aColorArr[ 2 ] );
+ lclSetMixedColor( aColorArr[ 3 ], aColorArr[ 2 ], aColorArr[ 4 ] );
+
+ sal_Int32 nMinDist = nFirstDist;
+ sal_uInt32 nMinIndex = 0;
+ for( sal_uInt32 nCnt = 1; nCnt < 4; ++nCnt )
+ {
+ sal_Int32 nDist = lclGetColorDistance( aForeColor, aColorArr[ nCnt ] );
+ if( nDist < nMinDist )
+ {
+ nMinDist = nDist;
+ nMinIndex = nCnt;
+ }
+ }
+ rnXclForeIx = GetXclIndex( nIndex1 );
+ rnXclBackIx = GetXclIndex( nIndex2 );
+ if( nMinDist < nFirstDist )
+ {
+ switch( nMinIndex )
+ {
+ case 1: rnXclPattern = EXC_PATT_75_PERC; break;
+ case 2: rnXclPattern = EXC_PATT_50_PERC; break;
+ case 3: rnXclPattern = EXC_PATT_25_PERC; break;
+ }
+ }
+}
+
+ColorData XclExpPaletteImpl::GetColorData( sal_uInt16 nXclIndex ) const
+{
+ if( nXclIndex >= EXC_COLOR_USEROFFSET )
+ {
+ sal_uInt32 nIdx = nXclIndex - EXC_COLOR_USEROFFSET;
+ if( nIdx < maPalette.size() )
+ return maPalette[ nIdx ].maColor.GetColor();
+ }
+ return mrDefPal.GetDefColorData( nXclIndex );
+}
+
+bool XclExpPaletteImpl::IsDefaultPalette() const
+{
+ bool bDefault = true;
+ for( sal_uInt32 nIdx = 0, nSize = static_cast< sal_uInt32 >( maPalette.size() ); bDefault && (nIdx < nSize); ++nIdx )
+ bDefault = maPalette[ nIdx ].maColor == mrDefPal.GetDefColor( GetXclIndex( nIdx ) );
+ return bDefault;
+}
+
+void XclExpPaletteImpl::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << static_cast< sal_uInt16 >( maPalette.size() );
+ for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end(); aIt != aEnd; ++aIt )
+ rStrm << aIt->maColor;
+}
+
+void XclExpPaletteImpl::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( !maPalette.size() )
+ return;
+
+ sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
+ rStyleSheet->startElement( XML_colors, FSEND );
+ rStyleSheet->startElement( XML_indexedColors, FSEND );
+ for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end(); aIt != aEnd; ++aIt )
+ rStyleSheet->singleElement( XML_rgbColor,
+ XML_rgb, XclXmlUtils::ToOString( aIt->maColor ).getStr(),
+ FSEND );
+ rStyleSheet->endElement( XML_indexedColors );
+ rStyleSheet->endElement( XML_colors );
+}
+
+const Color& XclExpPaletteImpl::GetOriginalColor( sal_uInt32 nColorId ) const
+{
+ if( nColorId < maColorIdDataVec.size() )
+ return maColorIdDataVec[ nColorId ].maColor;
+ return maPalette[ 0 ].maColor;
+}
+
+XclListColor* XclExpPaletteImpl::SearchListEntry( const Color& rColor, sal_uInt32& rnIndex )
+{
+ rnIndex = mnLastIdx;
+ XclListColor* pEntry = NULL;
+
+ if (mxColorList->empty())
+ return NULL;
+
+ // search optimization for equal-colored objects occurring repeatedly
+ if (rnIndex < mxColorList->size())
+ {
+ pEntry = &(*mxColorList)[rnIndex];
+ if( pEntry->GetColor() == rColor )
+ return pEntry;
+ }
+
+ // binary search for color
+ sal_uInt32 nBegIdx = 0;
+ sal_uInt32 nEndIdx = mxColorList->size();
+ bool bFound = false;
+ while( !bFound && (nBegIdx < nEndIdx) )
+ {
+ rnIndex = (nBegIdx + nEndIdx) / 2;
+ pEntry = &(*mxColorList)[rnIndex];
+ bFound = pEntry->GetColor() == rColor;
+ if( !bFound )
+ {
+ if( pEntry->GetColor().GetColor() < rColor.GetColor() )
+ nBegIdx = rnIndex + 1;
+ else
+ nEndIdx = rnIndex;
+ }
+ }
+
+ // not found - use end of range as new insertion position
+ if( !bFound )
+ rnIndex = nEndIdx;
+
+ mnLastIdx = rnIndex;
+ return pEntry;
+}
+
+XclListColor* XclExpPaletteImpl::CreateListEntry( const Color& rColor, sal_uInt32 nIndex )
+{
+ XclListColor* pEntry = new XclListColor( rColor, mxColorList->size() );
+ XclListColorList::iterator itr = mxColorList->begin();
+ ::std::advance(itr, nIndex);
+ mxColorList->insert(itr, pEntry);
+ return pEntry;
+}
+
+void XclExpPaletteImpl::RawReducePalette( sal_uInt32 nPass )
+{
+ /* Fast palette reduction - in each call of this function one RGB component
+ of each color is reduced to a lower number of distinct values.
+ Pass 0: Blue is reduced to 128 distinct values.
+ Pass 1: Red is reduced to 128 distinct values.
+ Pass 2: Green is reduced to 128 distinct values.
+ Pass 3: Blue is reduced to 64 distinct values.
+ Pass 4: Red is reduced to 64 distinct values.
+ Pass 5: Green is reduced to 64 distinct values.
+ And so on...
+ */
+
+ XclListColorListRef xOldList = mxColorList;
+ mxColorList.reset( new XclListColorList );
+
+ // maps old list indexes to new list indexes, used to update maColorIdDataVec
+ ScfUInt32Vec aListIndexMap;
+ aListIndexMap.reserve( xOldList->size() );
+
+ // preparations
+ sal_uInt8 nR, nG, nB;
+ sal_uInt8& rnComp = ((nPass % 3 == 0) ? nB : ((nPass % 3 == 1) ? nR : nG));
+ nPass /= 3;
+ DBG_ASSERT( nPass < 7, "XclExpPaletteImpl::RawReducePalette - reduction not terminated" );
+
+ static const sal_uInt8 spnFactor2[] = { 0x81, 0x82, 0x84, 0x88, 0x92, 0xAA, 0xFF };
+ sal_uInt8 nFactor1 = static_cast< sal_uInt8 >( 0x02 << nPass );
+ sal_uInt8 nFactor2 = spnFactor2[ nPass ];
+ sal_uInt8 nFactor3 = static_cast< sal_uInt8 >( 0x40 >> nPass );
+
+ // process each color in the old color list
+ for( sal_uInt32 nIdx = 0, nCount = xOldList->size(); nIdx < nCount; ++nIdx )
+ {
+ // get the old list entry
+ const XclListColor* pOldEntry = &(xOldList->at( nIdx ));
+ nR = pOldEntry->GetColor().GetRed();
+ nG = pOldEntry->GetColor().GetGreen();
+ nB = pOldEntry->GetColor().GetBlue();
+
+ /* Calculate the new RGB component (rnComp points to one of nR, nG, nB).
+ Using integer arithmetic with its rounding errors, the results of
+ this calculation are always exactly in the range 0x00 to 0xFF
+ (simply cutting the lower bits would darken the colors slightly). */
+ sal_uInt32 nNewComp = rnComp;
+ nNewComp /= nFactor1;
+ nNewComp *= nFactor2;
+ nNewComp /= nFactor3;
+ rnComp = static_cast< sal_uInt8 >( nNewComp );
+ Color aNewColor( nR, nG, nB );
+
+ // find or insert the new color
+ sal_uInt32 nFoundIdx = 0;
+ XclListColor* pNewEntry = SearchListEntry( aNewColor, nFoundIdx );
+ if( !pNewEntry || (pNewEntry->GetColor() != aNewColor) )
+ pNewEntry = CreateListEntry( aNewColor, nFoundIdx );
+ pNewEntry->AddWeighting( pOldEntry->GetWeighting() );
+ aListIndexMap.push_back( nFoundIdx );
+ }
+
+ // update color ID data map (maps color IDs to color list indexes), replace old by new list indexes
+ for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
+ aIt->mnIndex = aListIndexMap[ aIt->mnIndex ];
+}
+
+void XclExpPaletteImpl::ReduceLeastUsedColor()
+{
+ // find a list color to remove
+ sal_uInt32 nRemove = GetLeastUsedListColor();
+ // find its nearest neighbor
+ sal_uInt32 nKeep = GetNearestListColor( nRemove );
+
+ // merge both colors to one color, remove one color from list
+ XclListColor* pKeepEntry = &mxColorList->at(nKeep);
+ XclListColor* pRemoveEntry = &mxColorList->at(nRemove);
+ if( pKeepEntry && pRemoveEntry )
+ {
+ // merge both colors (if pKeepEntry is a base color, it will not change)
+ pKeepEntry->Merge( *pRemoveEntry );
+ // remove the less used color, adjust nKeep index if kept color follows removed color
+ XclListColorList::iterator itr = mxColorList->begin();
+ ::std::advance(itr, nRemove);
+ mxColorList->erase(itr);
+ if( nKeep > nRemove ) --nKeep;
+
+ // recalculate color ID data map (maps color IDs to color list indexes)
+ for( XclColorIdDataVec::iterator aIt = maColorIdDataVec.begin(), aEnd = maColorIdDataVec.end(); aIt != aEnd; ++aIt )
+ {
+ if( aIt->mnIndex > nRemove )
+ --aIt->mnIndex;
+ else if( aIt->mnIndex == nRemove )
+ aIt->mnIndex = nKeep;
+ }
+ }
+}
+
+sal_uInt32 XclExpPaletteImpl::GetLeastUsedListColor() const
+{
+ sal_uInt32 nFound = 0;
+ sal_uInt32 nMinW = SAL_MAX_UINT32;
+
+ for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
+ {
+ XclListColor& pEntry = mxColorList->at( nIdx );
+ // ignore the base colors
+ if( !pEntry.IsBaseColor() && (pEntry.GetWeighting() < nMinW) )
+ {
+ nFound = nIdx;
+ nMinW = pEntry.GetWeighting();
+ }
+ }
+ return nFound;
+}
+
+sal_uInt32 XclExpPaletteImpl::GetNearestListColor( const Color& rColor, sal_uInt32 nIgnore ) const
+{
+ sal_uInt32 nFound = 0;
+ sal_Int32 nMinD = SAL_MAX_INT32;
+
+ for( sal_uInt32 nIdx = 0, nCount = mxColorList->size(); nIdx < nCount; ++nIdx )
+ {
+ if( nIdx != nIgnore )
+ {
+ if( XclListColor* pEntry = &mxColorList->at(nIdx) )
+ {
+ sal_Int32 nDist = lclGetColorDistance( rColor, pEntry->GetColor() );
+ if( nDist < nMinD )
+ {
+ nFound = nIdx;
+ nMinD = nDist;
+ }
+ }
+ }
+ }
+ return nFound;
+}
+
+sal_uInt32 XclExpPaletteImpl::GetNearestListColor( sal_uInt32 nIndex ) const
+{
+ if (nIndex >= mxColorList->size())
+ return 0;
+ XclListColor* pEntry = &mxColorList->at(nIndex);
+ return GetNearestListColor( pEntry->GetColor(), nIndex );
+}
+
+sal_Int32 XclExpPaletteImpl::GetNearestPaletteColor(
+ sal_uInt32& rnIndex, const Color& rColor, bool bDefaultOnly ) const
+{
+ rnIndex = 0;
+ sal_Int32 nDist = SAL_MAX_INT32;
+
+ for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end();
+ aIt != aEnd; ++aIt )
+ {
+ if( !bDefaultOnly || !aIt->mbUsed )
+ {
+ sal_Int32 nCurrDist = lclGetColorDistance( rColor, aIt->maColor );
+ if( nCurrDist < nDist )
+ {
+ rnIndex = aIt - maPalette.begin();
+ nDist = nCurrDist;
+ }
+ }
+ }
+ return nDist;
+}
+
+sal_Int32 XclExpPaletteImpl::GetNearPaletteColors(
+ sal_uInt32& rnFirst, sal_uInt32& rnSecond, const Color& rColor ) const
+{
+ rnFirst = rnSecond = 0;
+ sal_Int32 nDist1 = SAL_MAX_INT32;
+ sal_Int32 nDist2 = SAL_MAX_INT32;
+
+ for( XclPaletteColorVec::const_iterator aIt = maPalette.begin(), aEnd = maPalette.end();
+ aIt != aEnd; ++aIt )
+ {
+ sal_Int32 nCurrDist = lclGetColorDistance( rColor, aIt->maColor );
+ if( nCurrDist < nDist1 )
+ {
+ rnSecond = rnFirst;
+ nDist2 = nDist1;
+ rnFirst = aIt - maPalette.begin();
+ nDist1 = nCurrDist;
+ }
+ else if( nCurrDist < nDist2 )
+ {
+ rnSecond = aIt - maPalette.begin();
+ nDist2 = nCurrDist;
+ }
+ }
+ return nDist1;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpPalette::XclExpPalette( const XclExpRoot& rRoot ) :
+ XclDefaultPalette( rRoot ),
+ XclExpRecord( EXC_ID_PALETTE )
+{
+ mxImpl.reset( new XclExpPaletteImpl( *this ) );
+ SetRecSize( GetColorCount() * 4 + 2 );
+}
+
+XclExpPalette::~XclExpPalette()
+{
+}
+
+sal_uInt32 XclExpPalette::InsertColor( const Color& rColor, XclExpColorType eType, sal_uInt16 nAutoDefault )
+{
+ return mxImpl->InsertColor( rColor, eType, nAutoDefault );
+}
+
+sal_uInt32 XclExpPalette::GetColorIdFromIndex( sal_uInt16 nIndex )
+{
+ return XclExpPaletteImpl::GetColorIdFromIndex( nIndex );
+}
+
+void XclExpPalette::Finalize()
+{
+ mxImpl->Finalize();
+}
+
+sal_uInt16 XclExpPalette::GetColorIndex( sal_uInt32 nColorId ) const
+{
+ return mxImpl->GetColorIndex( nColorId );
+}
+
+void XclExpPalette::GetMixedColors(
+ sal_uInt16& rnXclForeIx, sal_uInt16& rnXclBackIx, sal_uInt8& rnXclPattern,
+ sal_uInt32 nForeColorId, sal_uInt32 nBackColorId ) const
+{
+ return mxImpl->GetMixedColors( rnXclForeIx, rnXclBackIx, rnXclPattern, nForeColorId, nBackColorId );
+}
+
+ColorData XclExpPalette::GetColorData( sal_uInt16 nXclIndex ) const
+{
+ return mxImpl->GetColorData( nXclIndex );
+}
+
+void XclExpPalette::Save( XclExpStream& rStrm )
+{
+ if( !mxImpl->IsDefaultPalette() )
+ XclExpRecord::Save( rStrm );
+}
+
+void XclExpPalette::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( !mxImpl->IsDefaultPalette() )
+ mxImpl->SaveXml( rStrm );
+}
+
+void XclExpPalette::WriteBody( XclExpStream& rStrm )
+{
+ mxImpl->WriteBody( rStrm );
+}
+
+// FONT record - font information =============================================
+
+namespace {
+
+typedef ::std::pair< sal_uInt16, sal_Int16 > WhichAndScript;
+
+sal_Int16 lclCheckFontItems( const SfxItemSet& rItemSet,
+ const WhichAndScript& rWAS1, const WhichAndScript& rWAS2, const WhichAndScript& rWAS3 )
+{
+ if( ScfTools::CheckItem( rItemSet, rWAS1.first, false ) ) return rWAS1.second;
+ if( ScfTools::CheckItem( rItemSet, rWAS2.first, false ) ) return rWAS2.second;
+ if( ScfTools::CheckItem( rItemSet, rWAS3.first, false ) ) return rWAS3.second;
+ return 0;
+};
+
+} // namespace
+
+sal_Int16 XclExpFontHelper::GetFirstUsedScript( const XclExpRoot& rRoot, const SfxItemSet& rItemSet )
+{
+ namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
+
+ /* #i17050# #i107170# We need to determine which font items are set in the
+ item set, and which script type we should prefer according to the
+ current language settings. */
+
+ static const WhichAndScript WAS_LATIN( ATTR_FONT, ::com::sun::star::i18n::ScriptType::LATIN );
+ static const WhichAndScript WAS_ASIAN( ATTR_CJK_FONT, ::com::sun::star::i18n::ScriptType::ASIAN );
+ static const WhichAndScript WAS_CMPLX( ATTR_CTL_FONT, ::com::sun::star::i18n::ScriptType::COMPLEX );
+
+ /* do not let a font from a parent style override an explicit
+ cell font. */
+
+ sal_Int16 nDefScript = rRoot.GetDefApiScript();
+ sal_Int16 nScript = 0;
+ const SfxItemSet* pCurrSet = &rItemSet;
+
+ while( (nScript == 0) && pCurrSet )
+ {
+ switch( nDefScript )
+ {
+ case ApiScriptType::LATIN:
+ nScript = lclCheckFontItems( *pCurrSet, WAS_LATIN, WAS_CMPLX, WAS_ASIAN );
+ break;
+ case ApiScriptType::ASIAN:
+ nScript = lclCheckFontItems( *pCurrSet, WAS_ASIAN, WAS_CMPLX, WAS_LATIN );
+ break;
+ case ApiScriptType::COMPLEX:
+ nScript = lclCheckFontItems( *pCurrSet, WAS_CMPLX, WAS_ASIAN, WAS_LATIN );
+ break;
+ default:
+ DBG_ERRORFILE( "XclExpFontHelper::GetFirstUsedScript - unknown script type" );
+ nScript = ApiScriptType::LATIN;
+ };
+ pCurrSet = pCurrSet->GetParent();
+ }
+
+ return nScript;
+}
+
+Font XclExpFontHelper::GetFontFromItemSet( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript )
+{
+ namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
+
+ // if WEAK is passed, guess script type from existing items in the item set
+ if( nScript == ApiScriptType::WEAK )
+ nScript = GetFirstUsedScript( rRoot, rItemSet );
+
+ // convert to core script type constants
+ sal_uInt8 nScScript = SCRIPTTYPE_LATIN;
+ switch( nScript )
+ {
+ case ApiScriptType::LATIN: nScScript = SCRIPTTYPE_LATIN; break;
+ case ApiScriptType::ASIAN: nScScript = SCRIPTTYPE_ASIAN; break;
+ case ApiScriptType::COMPLEX: nScScript = SCRIPTTYPE_COMPLEX; break;
+ default: DBG_ERRORFILE( "XclExpFontHelper::GetFontFromItemSet - unknown script type" );
+ }
+
+ // fill the font object
+ Font aFont;
+ ScPatternAttr::GetFont( aFont, rItemSet, SC_AUTOCOL_RAW, 0, 0, 0, nScScript );
+ return aFont;
+}
+
+bool XclExpFontHelper::CheckItems( const XclExpRoot& rRoot, const SfxItemSet& rItemSet, sal_Int16 nScript, bool bDeep )
+{
+ static const sal_uInt16 pnCommonIds[] = {
+ ATTR_FONT_UNDERLINE, ATTR_FONT_CROSSEDOUT, ATTR_FONT_CONTOUR,
+ ATTR_FONT_SHADOWED, ATTR_FONT_COLOR, ATTR_FONT_LANGUAGE, 0 };
+ static const sal_uInt16 pnLatinIds[] = {
+ ATTR_FONT, ATTR_FONT_HEIGHT, ATTR_FONT_WEIGHT, ATTR_FONT_POSTURE, 0 };
+ static const sal_uInt16 pnAsianIds[] = {
+ ATTR_CJK_FONT, ATTR_CJK_FONT_HEIGHT, ATTR_CJK_FONT_WEIGHT, ATTR_CJK_FONT_POSTURE, 0 };
+ static const sal_uInt16 pnComplexIds[] = {
+ ATTR_CTL_FONT, ATTR_CTL_FONT_HEIGHT, ATTR_CTL_FONT_WEIGHT, ATTR_CTL_FONT_POSTURE, 0 };
+
+ bool bUsed = ScfTools::CheckItems( rItemSet, pnCommonIds, bDeep );
+ if( !bUsed )
+ {
+ namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
+ // if WEAK is passed, guess script type from existing items in the item set
+ if( nScript == ApiScriptType::WEAK )
+ nScript = GetFirstUsedScript( rRoot, rItemSet );
+ // check the correct items
+ switch( nScript )
+ {
+ case ApiScriptType::LATIN: bUsed = ScfTools::CheckItems( rItemSet, pnLatinIds, bDeep ); break;
+ case ApiScriptType::ASIAN: bUsed = ScfTools::CheckItems( rItemSet, pnAsianIds, bDeep ); break;
+ case ApiScriptType::COMPLEX: bUsed = ScfTools::CheckItems( rItemSet, pnComplexIds, bDeep ); break;
+ default: DBG_ERRORFILE( "XclExpFontHelper::CheckItems - unknown script type" );
+ }
+ }
+ return bUsed;
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+sal_uInt32 lclCalcHash( const XclFontData& rFontData )
+{
+ sal_uInt32 nHash = rFontData.maName.Len();
+ nHash += rFontData.maColor.GetColor() * 2;
+ nHash += rFontData.mnWeight * 3;
+ nHash += rFontData.mnCharSet * 5;
+ nHash += rFontData.mnFamily * 7;
+ nHash += rFontData.mnHeight * 11;
+ nHash += rFontData.mnUnderline * 13;
+ nHash += rFontData.mnEscapem * 17;
+ if( rFontData.mbItalic ) nHash += 19;
+ if( rFontData.mbStrikeout ) nHash += 23;
+ if( rFontData.mbOutline ) nHash += 29;
+ if( rFontData.mbShadow ) nHash += 31;
+ return nHash;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpFont::XclExpFont( const XclExpRoot& rRoot,
+ const XclFontData& rFontData, XclExpColorType eColorType ) :
+ XclExpRecord( EXC_ID2_FONT, 14 ),
+ XclExpRoot( rRoot ),
+ maData( rFontData )
+{
+ // insert font color into palette
+ mnColorId = rRoot.GetPalette().InsertColor( rFontData.maColor, eColorType, EXC_COLOR_FONTAUTO );
+ // hash value for faster comparison
+ mnHash = lclCalcHash( maData );
+ // record size
+ sal_Size nStrLen = maData.maName.Len();
+ SetRecSize( ((GetBiff() == EXC_BIFF8) ? (nStrLen * 2 + 1) : nStrLen) + 15 );
+}
+
+bool XclExpFont::Equals( const XclFontData& rFontData, sal_uInt32 nHash ) const
+{
+ return (mnHash == nHash) && (maData == rFontData);
+}
+
+void XclExpFont::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
+ rStyleSheet->startElement( XML_font, FSEND );
+ XclXmlUtils::WriteFontData( rStyleSheet, maData, XML_name );
+ // OOXTODO: XML_scheme; //scheme/@val values: "major", "minor", "none"
+ rStyleSheet->endElement( XML_font );
+}
+
+// private --------------------------------------------------------------------
+
+void XclExpFont::WriteBody( XclExpStream& rStrm )
+{
+ sal_uInt16 nAttr = EXC_FONTATTR_NONE;
+ ::set_flag( nAttr, EXC_FONTATTR_ITALIC, maData.mbItalic );
+ ::set_flag( nAttr, EXC_FONTATTR_STRIKEOUT, maData.mbStrikeout );
+ ::set_flag( nAttr, EXC_FONTATTR_OUTLINE, maData.mbOutline );
+ ::set_flag( nAttr, EXC_FONTATTR_SHADOW, maData.mbShadow );
+
+ DBG_ASSERT( maData.maName.Len() < 256, "XclExpFont::WriteBody - font name too long" );
+ XclExpString aFontName;
+ if( GetBiff() <= EXC_BIFF5 )
+ aFontName.AssignByte( maData.maName, GetTextEncoding(), EXC_STR_8BITLENGTH );
+ else
+ aFontName.Assign( maData.maName, EXC_STR_FORCEUNICODE | EXC_STR_8BITLENGTH );
+
+ rStrm << maData.mnHeight
+ << nAttr
+ << GetPalette().GetColorIndex( mnColorId )
+ << maData.mnWeight
+ << maData.mnEscapem
+ << maData.mnUnderline
+ << maData.mnFamily
+ << maData.mnCharSet
+ << sal_uInt8( 0 )
+ << aFontName;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpBlindFont::XclExpBlindFont( const XclExpRoot& rRoot ) :
+ XclExpFont( rRoot, XclFontData(), EXC_COLOR_CELLTEXT )
+{
+}
+
+bool XclExpBlindFont::Equals( const XclFontData& /*rFontData*/, sal_uInt32 /*nHash*/ ) const
+{
+ return false;
+}
+
+void XclExpBlindFont::Save( XclExpStream& /*rStrm*/ )
+{
+ // do nothing
+}
+
+// ============================================================================
+
+XclExpFontBuffer::XclExpFontBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mnXclMaxSize( 0 )
+{
+ switch( GetBiff() )
+ {
+ case EXC_BIFF4: mnXclMaxSize = EXC_FONT_MAXCOUNT4; break;
+ case EXC_BIFF5: mnXclMaxSize = EXC_FONT_MAXCOUNT5; break;
+ case EXC_BIFF8: mnXclMaxSize = EXC_FONT_MAXCOUNT8; break;
+ default: DBG_ERROR_BIFF();
+ }
+ InitDefaultFonts();
+}
+
+const XclExpFont* XclExpFontBuffer::GetFont( sal_uInt16 nXclFont ) const
+{
+ return maFontList.GetRecord( nXclFont ).get();
+}
+
+const XclFontData& XclExpFontBuffer::GetAppFontData() const
+{
+ return maFontList.GetRecord( EXC_FONT_APP )->GetFontData(); // exists always
+}
+
+sal_uInt16 XclExpFontBuffer::Insert(
+ const XclFontData& rFontData, XclExpColorType eColorType, bool bAppFont )
+{
+ if( bAppFont )
+ {
+ XclExpFontRef xFont( new XclExpFont( GetRoot(), rFontData, eColorType ) );
+ maFontList.ReplaceRecord( xFont, EXC_FONT_APP );
+ // set width of '0' character for column width export
+ SetCharWidth( xFont->GetFontData() );
+ return EXC_FONT_APP;
+ }
+
+ size_t nPos = Find( rFontData );
+ if( nPos == EXC_FONTLIST_NOTFOUND )
+ {
+ // not found in buffer - create new font
+ size_t nSize = maFontList.GetSize();
+ if( nSize < mnXclMaxSize )
+ {
+ // possible to insert
+ maFontList.AppendNewRecord( new XclExpFont( GetRoot(), rFontData, eColorType ) );
+ nPos = nSize; // old size is last position now
+ }
+ else
+ {
+ // buffer is full - ignore new font, use default font
+ nPos = EXC_FONT_APP;
+ }
+ }
+ return static_cast< sal_uInt16 >( nPos );
+}
+
+sal_uInt16 XclExpFontBuffer::Insert(
+ const Font& rFont, XclExpColorType eColorType, bool bAppFont )
+{
+ return Insert( XclFontData( rFont ), eColorType, bAppFont );
+}
+
+sal_uInt16 XclExpFontBuffer::Insert(
+ const SvxFont& rFont, XclExpColorType eColorType, bool bAppFont )
+{
+ return Insert( XclFontData( rFont ), eColorType, bAppFont );
+}
+
+sal_uInt16 XclExpFontBuffer::Insert( const SfxItemSet& rItemSet,
+ sal_Int16 nScript, XclExpColorType eColorType, bool bAppFont )
+{
+ // #i17050# script type now provided by caller
+ Font aFont = XclExpFontHelper::GetFontFromItemSet( GetRoot(), rItemSet, nScript );
+ return Insert( aFont, eColorType, bAppFont );
+}
+
+sal_uInt16 XclExpFontBuffer::Insert( const ScPatternAttr& rPattern,
+ sal_Int16 nScript, XclExpColorType eColorType, bool bAppFont )
+{
+ return Insert( rPattern.GetItemSet(), nScript, eColorType, bAppFont );
+}
+
+void XclExpFontBuffer::Save( XclExpStream& rStrm )
+{
+ maFontList.Save( rStrm );
+}
+
+void XclExpFontBuffer::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( maFontList.IsEmpty() )
+ return;
+
+ sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
+ rStyleSheet->startElement( XML_fonts,
+ XML_count, OString::valueOf( (sal_Int32) maFontList.GetSize() ).getStr(),
+ FSEND );
+
+ maFontList.SaveXml( rStrm );
+
+ rStyleSheet->endElement( XML_fonts );
+}
+
+// private --------------------------------------------------------------------
+
+void XclExpFontBuffer::InitDefaultFonts()
+{
+ XclFontData aFontData;
+ aFontData.maName.AssignAscii( "Arial" );
+ aFontData.SetScFamily( FAMILY_DONTKNOW );
+ aFontData.SetFontEncoding( ScfTools::GetSystemTextEncoding() );
+ aFontData.SetScHeight( 200 ); // 200 twips = 10 pt
+ aFontData.SetScWeight( WEIGHT_NORMAL );
+
+ switch( GetBiff() )
+ {
+ case EXC_BIFF5:
+ {
+ maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
+ aFontData.SetScWeight( WEIGHT_BOLD );
+ maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
+ aFontData.SetScWeight( WEIGHT_NORMAL );
+ aFontData.SetScPosture( ITALIC_NORMAL );
+ maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
+ aFontData.SetScWeight( WEIGHT_BOLD );
+ maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
+ // the blind font with index 4
+ maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
+ // already add the first user defined font (Excel does it too)
+ aFontData.SetScWeight( WEIGHT_NORMAL );
+ aFontData.SetScPosture( ITALIC_NONE );
+ maFontList.AppendNewRecord( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
+ }
+ break;
+ case EXC_BIFF8:
+ {
+ XclExpFontRef xFont( new XclExpFont( GetRoot(), aFontData, EXC_COLOR_CELLTEXT ) );
+ maFontList.AppendRecord( xFont );
+ maFontList.AppendRecord( xFont );
+ maFontList.AppendRecord( xFont );
+ maFontList.AppendRecord( xFont );
+ if( GetOutput() == EXC_OUTPUT_BINARY )
+ // the blind font with index 4
+ maFontList.AppendNewRecord( new XclExpBlindFont( GetRoot() ) );
+ }
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+}
+
+size_t XclExpFontBuffer::Find( const XclFontData& rFontData )
+{
+ sal_uInt32 nHash = lclCalcHash( rFontData );
+ for( size_t nPos = 0, nSize = maFontList.GetSize(); nPos < nSize; ++nPos )
+ if( maFontList.GetRecord( nPos )->Equals( rFontData, nHash ) )
+ return nPos;
+ return EXC_FONTLIST_NOTFOUND;
+}
+
+// FORMAT record - number formats =============================================
+
+/** Predicate for search algorithm. */
+struct XclExpNumFmtPred
+{
+ sal_uLong mnScNumFmt;
+ inline explicit XclExpNumFmtPred( sal_uLong nScNumFmt ) : mnScNumFmt( nScNumFmt ) {}
+ inline bool operator()( const XclExpNumFmt& rFormat ) const
+ { return rFormat.mnScNumFmt == mnScNumFmt; }
+};
+
+// ----------------------------------------------------------------------------
+
+XclExpNumFmtBuffer::XclExpNumFmtBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ /* Compiler needs a hint, this doesn't work: new NfKeywordTable;
+ cannot convert from 'class String *' to 'class String (*)[54]'
+ The effective result here is class String (*)[54*1] */
+ mxFormatter( new SvNumberFormatter( rRoot.GetDoc().GetServiceManager(), LANGUAGE_ENGLISH_US ) ),
+ mpKeywordTable( new NfKeywordTable[ 1 ] ),
+ mnStdFmt( GetFormatter().GetStandardFormat( ScGlobal::eLnge ) )
+{
+ switch( GetBiff() )
+ {
+ case EXC_BIFF5: mnXclOffset = EXC_FORMAT_OFFSET5; break;
+ case EXC_BIFF8: mnXclOffset = EXC_FORMAT_OFFSET8; break;
+ default: DBG_ERROR_BIFF();
+ }
+
+ mxFormatter->FillKeywordTable( *mpKeywordTable, LANGUAGE_ENGLISH_US );
+ // remap codes unknown to Excel
+ (*mpKeywordTable)[ NF_KEY_NN ] = String( RTL_CONSTASCII_USTRINGPARAM( "DDD" ) );
+ (*mpKeywordTable)[ NF_KEY_NNN ] = String( RTL_CONSTASCII_USTRINGPARAM( "DDDD" ) );
+ // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
+ (*mpKeywordTable)[ NF_KEY_NNNN ] = String( RTL_CONSTASCII_USTRINGPARAM( "DDDD" ) );
+ // Export the Thai T NatNum modifier.
+ (*mpKeywordTable)[ NF_KEY_THAI_T ] = String( RTL_CONSTASCII_USTRINGPARAM( "T" ) );
+}
+
+XclExpNumFmtBuffer::~XclExpNumFmtBuffer()
+{
+ delete[] mpKeywordTable;
+}
+
+sal_uInt16 XclExpNumFmtBuffer::Insert( sal_uLong nScNumFmt )
+{
+ XclExpNumFmtVec::const_iterator aIt =
+ ::std::find_if( maFormatMap.begin(), maFormatMap.end(), XclExpNumFmtPred( nScNumFmt ) );
+ if( aIt != maFormatMap.end() )
+ return aIt->mnXclNumFmt;
+
+ size_t nSize = maFormatMap.size();
+ if( nSize < static_cast< size_t >( 0xFFFF - mnXclOffset ) )
+ {
+ sal_uInt16 nXclNumFmt = static_cast< sal_uInt16 >( nSize + mnXclOffset );
+ maFormatMap.push_back( XclExpNumFmt( nScNumFmt, nXclNumFmt ) );
+ return nXclNumFmt;
+ }
+
+ return 0;
+}
+
+void XclExpNumFmtBuffer::Save( XclExpStream& rStrm )
+{
+ for( XclExpNumFmtVec::const_iterator aIt = maFormatMap.begin(), aEnd = maFormatMap.end(); aIt != aEnd; ++aIt )
+ WriteFormatRecord( rStrm, *aIt );
+}
+
+void XclExpNumFmtBuffer::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( !maFormatMap.size() )
+ return;
+
+ sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
+ rStyleSheet->startElement( XML_numFmts,
+ XML_count, OString::valueOf( (sal_Int32) maFormatMap.size() ).getStr(),
+ FSEND );
+ for( XclExpNumFmtVec::const_iterator aIt = maFormatMap.begin(), aEnd = maFormatMap.end(); aIt != aEnd; ++aIt )
+ {
+ rStyleSheet->singleElement( XML_numFmt,
+ XML_numFmtId, OString::valueOf( sal_Int32(aIt->mnXclNumFmt) ).getStr(),
+ XML_formatCode, XclXmlUtils::ToOString( GetFormatCode( *aIt ) ).getStr(),
+ FSEND );
+ }
+ rStyleSheet->endElement( XML_numFmts );
+}
+
+void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, sal_uInt16 nXclNumFmt, const String& rFormatStr )
+{
+ XclExpString aExpStr;
+ if( GetBiff() <= EXC_BIFF5 )
+ aExpStr.AssignByte( rFormatStr, GetTextEncoding(), EXC_STR_8BITLENGTH );
+ else
+ aExpStr.Assign( rFormatStr );
+
+ rStrm.StartRecord( EXC_ID4_FORMAT, 2 + aExpStr.GetSize() );
+ rStrm << nXclNumFmt << aExpStr;
+ rStrm.EndRecord();
+}
+
+void XclExpNumFmtBuffer::WriteFormatRecord( XclExpStream& rStrm, const XclExpNumFmt& rFormat )
+{
+ WriteFormatRecord( rStrm, rFormat.mnXclNumFmt, GetFormatCode( rFormat ) );
+}
+
+String XclExpNumFmtBuffer::GetFormatCode( const XclExpNumFmt& rFormat )
+{
+ String aFormatStr;
+
+ if( const SvNumberformat* pEntry = GetFormatter().GetEntry( rFormat.mnScNumFmt ) )
+ {
+ if( pEntry->GetType() == NUMBERFORMAT_LOGICAL )
+ {
+ // build Boolean number format
+ Color* pColor = 0;
+ String aTemp;
+ const_cast< SvNumberformat* >( pEntry )->GetOutputString( 1.0, aTemp, &pColor );
+ aFormatStr.Append( '"' ).Append( aTemp ).AppendAscii( "\";\"" ).Append( aTemp ).AppendAscii( "\";\"" );
+ const_cast< SvNumberformat* >( pEntry )->GetOutputString( 0.0, aTemp, &pColor );
+ aFormatStr.Append( aTemp ).Append( '"' );
+ }
+ else
+ {
+ LanguageType eLang = pEntry->GetLanguage();
+ if( eLang != LANGUAGE_ENGLISH_US )
+ {
+ xub_StrLen nCheckPos;
+ short nType = NUMBERFORMAT_DEFINED;
+ sal_uInt32 nKey;
+ String aTemp( pEntry->GetFormatstring() );
+ mxFormatter->PutandConvertEntry( aTemp, nCheckPos, nType, nKey, eLang, LANGUAGE_ENGLISH_US );
+ DBG_ASSERT( nCheckPos == 0, "XclExpNumFmtBuffer::WriteFormatRecord - format code not convertible" );
+ pEntry = mxFormatter->GetEntry( nKey );
+ }
+
+ aFormatStr = pEntry->GetMappedFormatstring( *mpKeywordTable, *mxFormatter->GetLocaleData() );
+ if( aFormatStr.EqualsAscii( "Standard" ) )
+ aFormatStr.AssignAscii( "General" );
+ }
+ }
+ else
+ {
+ DBG_ERRORFILE( "XclExpNumFmtBuffer::WriteFormatRecord - format not found" );
+ aFormatStr.AssignAscii( "General" );
+ }
+
+ return aFormatStr;
+}
+
+// XF, STYLE record - Cell formatting =========================================
+
+bool XclExpCellProt::FillFromItemSet( const SfxItemSet& rItemSet, bool bStyle )
+{
+ const ScProtectionAttr& rProtItem = GETITEM( rItemSet, ScProtectionAttr, ATTR_PROTECTION );
+ mbLocked = rProtItem.GetProtection();
+ mbHidden = rProtItem.GetHideFormula() || rProtItem.GetHideCell();
+ return ScfTools::CheckItem( rItemSet, ATTR_PROTECTION, bStyle );
+}
+
+void XclExpCellProt::FillToXF3( sal_uInt16& rnProt ) const
+{
+ ::set_flag( rnProt, EXC_XF_LOCKED, mbLocked );
+ ::set_flag( rnProt, EXC_XF_HIDDEN, mbHidden );
+}
+
+void XclExpCellProt::SaveXml( XclExpXmlStream& rStrm ) const
+{
+ rStrm.GetCurrentStream()->singleElement( XML_protection,
+ XML_locked, XclXmlUtils::ToPsz( mbLocked ),
+ XML_hidden, XclXmlUtils::ToPsz( mbHidden ),
+ FSEND );
+}
+
+// ----------------------------------------------------------------------------
+
+bool XclExpCellAlign::FillFromItemSet(
+ const SfxItemSet& rItemSet, bool bForceLineBreak, XclBiff eBiff, bool bStyle )
+{
+ bool bUsed = false;
+ SvxCellHorJustify eHorAlign = GETITEMVALUE( rItemSet, SvxHorJustifyItem, ATTR_HOR_JUSTIFY, SvxCellHorJustify );
+ SvxCellVerJustify eVerAlign = GETITEMVALUE( rItemSet, SvxVerJustifyItem, ATTR_VER_JUSTIFY, SvxCellVerJustify );
+
+ switch( eBiff )
+ {
+ // ALL 'case's - run through!
+
+ case EXC_BIFF8: // attributes new in BIFF8
+ {
+ // text indent
+ long nTmpIndent = GETITEMVALUE( rItemSet, SfxUInt16Item, ATTR_INDENT, sal_Int32 );
+ (nTmpIndent += 100) /= 200; // 1 Excel unit == 10 pt == 200 twips
+ mnIndent = limit_cast< sal_uInt8 >( nTmpIndent, 0, 15 );
+ bUsed |= ScfTools::CheckItem( rItemSet, ATTR_INDENT, bStyle );
+
+ // shrink to fit
+ mbShrink = GETITEMVALUE( rItemSet, SfxBoolItem, ATTR_SHRINKTOFIT, sal_Bool );
+ bUsed |= ScfTools::CheckItem( rItemSet, ATTR_SHRINKTOFIT, bStyle );
+
+ // CTL text direction
+ SetScFrameDir( GETITEMVALUE( rItemSet, SvxFrameDirectionItem, ATTR_WRITINGDIR, SvxFrameDirection ) );
+ bUsed |= ScfTools::CheckItem( rItemSet, ATTR_WRITINGDIR, bStyle );
+ }
+
+ case EXC_BIFF5: // attributes new in BIFF5
+ case EXC_BIFF4: // attributes new in BIFF4
+ {
+ // vertical alignment
+ SetScVerAlign( eVerAlign );
+ bUsed |= ScfTools::CheckItem( rItemSet, ATTR_VER_JUSTIFY, bStyle );
+
+ // stacked/rotation
+ bool bStacked = GETITEMVALUE( rItemSet, SfxBoolItem, ATTR_STACKED, sal_Bool );
+ bUsed |= ScfTools::CheckItem( rItemSet, ATTR_STACKED, bStyle );
+ if( bStacked )
+ {
+ mnRotation = EXC_ROT_STACKED;
+ }
+ else
+ {
+ // rotation
+ sal_Int32 nScRot = GETITEMVALUE( rItemSet, SfxInt32Item, ATTR_ROTATE_VALUE, sal_Int32 );
+ mnRotation = XclTools::GetXclRotation( nScRot );
+ bUsed |= ScfTools::CheckItem( rItemSet, ATTR_ROTATE_VALUE, bStyle );
+ }
+ mnOrient = XclTools::GetXclOrientFromRot( mnRotation );
+ }
+
+ case EXC_BIFF3: // attributes new in BIFF3
+ {
+ // text wrap
+ mbLineBreak = bForceLineBreak || GETITEMBOOL( rItemSet, ATTR_LINEBREAK );
+ bUsed |= bForceLineBreak || ScfTools::CheckItem( rItemSet, ATTR_LINEBREAK, bStyle );
+ }
+
+ case EXC_BIFF2: // attributes new in BIFF2
+ {
+ // horizontal alignment
+ SetScHorAlign( eHorAlign );
+ bUsed |= ScfTools::CheckItem( rItemSet, ATTR_HOR_JUSTIFY, bStyle );
+ }
+
+ break;
+ default: DBG_ERROR_BIFF();
+ }
+
+ if (eBiff == EXC_BIFF8)
+ {
+ // Adjust for distributed alignments.
+ if (eHorAlign == SVX_HOR_JUSTIFY_BLOCK)
+ {
+ SvxCellJustifyMethod eHorJustMethod = GETITEMVALUE(
+ rItemSet, SvxJustifyMethodItem, ATTR_HOR_JUSTIFY_METHOD, SvxCellJustifyMethod);
+ if (eHorJustMethod == SVX_JUSTIFY_METHOD_DISTRIBUTE)
+ mnHorAlign = EXC_XF_HOR_DISTRIB;
+ }
+
+ if (eVerAlign == SVX_VER_JUSTIFY_BLOCK)
+ {
+ SvxCellJustifyMethod eVerJustMethod = GETITEMVALUE(
+ rItemSet, SvxJustifyMethodItem, ATTR_VER_JUSTIFY_METHOD, SvxCellJustifyMethod);
+ if (eVerJustMethod == SVX_JUSTIFY_METHOD_DISTRIBUTE)
+ mnVerAlign = EXC_XF_VER_DISTRIB;
+ }
+ }
+
+ return bUsed;
+}
+
+void XclExpCellAlign::FillToXF5( sal_uInt16& rnAlign ) const
+{
+ ::insert_value( rnAlign, mnHorAlign, 0, 3 );
+ ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
+ ::insert_value( rnAlign, mnVerAlign, 4, 3 );
+ ::insert_value( rnAlign, mnOrient, 8, 2 );
+}
+
+void XclExpCellAlign::FillToXF8( sal_uInt16& rnAlign, sal_uInt16& rnMiscAttrib ) const
+{
+ ::insert_value( rnAlign, mnHorAlign, 0, 3 );
+ ::set_flag( rnAlign, EXC_XF_LINEBREAK, mbLineBreak );
+ ::insert_value( rnAlign, mnVerAlign, 4, 3 );
+ ::insert_value( rnAlign, mnRotation, 8, 8 );
+ ::insert_value( rnMiscAttrib, mnIndent, 0, 4 );
+ ::set_flag( rnMiscAttrib, EXC_XF8_SHRINK, mbShrink );
+ ::insert_value( rnMiscAttrib, mnTextDir, 6, 2 );
+}
+
+static const char* ToHorizontalAlignment( sal_uInt8 nHorAlign )
+{
+ switch( nHorAlign )
+ {
+ case EXC_XF_HOR_GENERAL: return "general";
+ case EXC_XF_HOR_LEFT: return "left";
+ case EXC_XF_HOR_CENTER: return "center";
+ case EXC_XF_HOR_RIGHT: return "right";
+ case EXC_XF_HOR_FILL: return "fill";
+ case EXC_XF_HOR_JUSTIFY: return "justify";
+ case EXC_XF_HOR_CENTER_AS: return "centerContinuous";
+ case EXC_XF_HOR_DISTRIB: return "distributed";
+ }
+ return "*unknown*";
+}
+
+static const char* ToVerticalAlignment( sal_uInt8 nVerAlign )
+{
+ switch( nVerAlign )
+ {
+ case EXC_XF_VER_TOP: return "top";
+ case EXC_XF_VER_CENTER: return "center";
+ case EXC_XF_VER_BOTTOM: return "bottom";
+ case EXC_XF_VER_JUSTIFY: return "justify";
+ case EXC_XF_VER_DISTRIB: return "distributed";
+ }
+ return "*unknown*";
+}
+
+void XclExpCellAlign::SaveXml( XclExpXmlStream& rStrm ) const
+{
+ rStrm.GetCurrentStream()->singleElement( XML_alignment,
+ XML_horizontal, ToHorizontalAlignment( mnHorAlign ),
+ XML_vertical, ToVerticalAlignment( mnVerAlign ),
+ XML_textRotation, OString::valueOf( (sal_Int32) mnRotation ).getStr(),
+ XML_wrapText, XclXmlUtils::ToPsz( mbLineBreak ),
+ XML_indent, OString::valueOf( (sal_Int32) mnIndent ).getStr(),
+ // OOXTODO: XML_relativeIndent, mnIndent?
+ // OOXTODO: XML_justifyLastLine,
+ XML_shrinkToFit, XclXmlUtils::ToPsz( mbShrink ),
+ // OOXTODO: XML_readingOrder,
+ FSEND );
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+void lclGetBorderLine(
+ sal_uInt8& rnXclLine, sal_uInt32& rnColorId,
+ const ::editeng::SvxBorderLine* pLine, XclExpPalette& rPalette, XclBiff eBiff )
+{
+ rnXclLine = EXC_LINE_NONE;
+ if( pLine )
+ {
+ sal_uInt16 nOuterWidth = pLine->GetOutWidth();
+ sal_uInt16 nDistance = pLine->GetDistance();
+ if( nDistance > 0 )
+ rnXclLine = EXC_LINE_DOUBLE;
+ else if( nOuterWidth > DEF_LINE_WIDTH_2 )
+ rnXclLine = EXC_LINE_THICK;
+ else if( nOuterWidth > DEF_LINE_WIDTH_1 )
+ {
+ rnXclLine = EXC_LINE_MEDIUM;
+ if ( pLine->GetStyle( ) == ::editeng::DASHED )
+ rnXclLine = EXC_LINE_MEDIUMDASHED;
+ }
+ else if( nOuterWidth > DEF_LINE_WIDTH_0 )
+ {
+ rnXclLine = EXC_LINE_THIN;
+ switch ( pLine->GetStyle( ) )
+ {
+ case ::editeng::DASHED:
+ rnXclLine = EXC_LINE_DASHED;
+ break;
+ case ::editeng::DOTTED:
+ rnXclLine = EXC_LINE_DOTTED;
+ break;
+ default:
+ break;
+ }
+ }
+ else if( nOuterWidth > 0 )
+ rnXclLine = EXC_LINE_HAIR;
+ else
+ rnXclLine = EXC_LINE_NONE;
+ }
+ if( (eBiff == EXC_BIFF2) && (rnXclLine != EXC_LINE_NONE) )
+ rnXclLine = EXC_LINE_THIN;
+
+ rnColorId = (pLine && (rnXclLine != EXC_LINE_NONE)) ?
+ rPalette.InsertColor( pLine->GetColor(), EXC_COLOR_CELLBORDER ) :
+ XclExpPalette::GetColorIdFromIndex( 0 );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpCellBorder::XclExpCellBorder() :
+ mnLeftColorId( XclExpPalette::GetColorIdFromIndex( mnLeftColor ) ),
+ mnRightColorId( XclExpPalette::GetColorIdFromIndex( mnRightColor ) ),
+ mnTopColorId( XclExpPalette::GetColorIdFromIndex( mnTopColor ) ),
+ mnBottomColorId( XclExpPalette::GetColorIdFromIndex( mnBottomColor ) ),
+ mnDiagColorId( XclExpPalette::GetColorIdFromIndex( mnDiagColor ) )
+{
+}
+
+bool XclExpCellBorder::FillFromItemSet(
+ const SfxItemSet& rItemSet, XclExpPalette& rPalette, XclBiff eBiff, bool bStyle )
+{
+ bool bUsed = false;
+
+ switch( eBiff )
+ {
+ // ALL 'case's - run through!
+
+ case EXC_BIFF8: // attributes new in BIFF8
+ {
+ const SvxLineItem& rTLBRItem = GETITEM( rItemSet, SvxLineItem, ATTR_BORDER_TLBR );
+ sal_uInt8 nTLBRLine;
+ sal_uInt32 nTLBRColorId;
+ lclGetBorderLine( nTLBRLine, nTLBRColorId, rTLBRItem.GetLine(), rPalette, eBiff );
+ mbDiagTLtoBR = (nTLBRLine != EXC_LINE_NONE);
+
+ const SvxLineItem& rBLTRItem = GETITEM( rItemSet, SvxLineItem, ATTR_BORDER_BLTR );
+ sal_uInt8 nBLTRLine;
+ sal_uInt32 nBLTRColorId;
+ lclGetBorderLine( nBLTRLine, nBLTRColorId, rBLTRItem.GetLine(), rPalette, eBiff );
+ mbDiagBLtoTR = (nBLTRLine != EXC_LINE_NONE);
+
+ if( ::ScHasPriority( rTLBRItem.GetLine(), rBLTRItem.GetLine() ) )
+ {
+ mnDiagLine = nTLBRLine;
+ mnDiagColorId = nTLBRColorId;
+ }
+ else
+ {
+ mnDiagLine = nBLTRLine;
+ mnDiagColorId = nBLTRColorId;
+ }
+
+ bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER_TLBR, bStyle ) ||
+ ScfTools::CheckItem( rItemSet, ATTR_BORDER_BLTR, bStyle );
+ }
+
+ case EXC_BIFF5:
+ case EXC_BIFF4:
+ case EXC_BIFF3:
+ case EXC_BIFF2:
+ {
+ const SvxBoxItem& rBoxItem = GETITEM( rItemSet, SvxBoxItem, ATTR_BORDER );
+ lclGetBorderLine( mnLeftLine, mnLeftColorId, rBoxItem.GetLeft(), rPalette, eBiff );
+ lclGetBorderLine( mnRightLine, mnRightColorId, rBoxItem.GetRight(), rPalette, eBiff );
+ lclGetBorderLine( mnTopLine, mnTopColorId, rBoxItem.GetTop(), rPalette, eBiff );
+ lclGetBorderLine( mnBottomLine, mnBottomColorId, rBoxItem.GetBottom(), rPalette, eBiff );
+ bUsed |= ScfTools::CheckItem( rItemSet, ATTR_BORDER, bStyle );
+ }
+
+ break;
+ default: DBG_ERROR_BIFF();
+ }
+
+ return bUsed;
+}
+
+void XclExpCellBorder::SetFinalColors( const XclExpPalette& rPalette )
+{
+ mnLeftColor = rPalette.GetColorIndex( mnLeftColorId );
+ mnRightColor = rPalette.GetColorIndex( mnRightColorId );
+ mnTopColor = rPalette.GetColorIndex( mnTopColorId );
+ mnBottomColor = rPalette.GetColorIndex( mnBottomColorId );
+ mnDiagColor = rPalette.GetColorIndex( mnDiagColorId );
+}
+
+
+void XclExpCellBorder::FillToXF5( sal_uInt32& rnBorder, sal_uInt32& rnArea ) const
+{
+ ::insert_value( rnBorder, mnTopLine, 0, 3 );
+ ::insert_value( rnBorder, mnLeftLine, 3, 3 );
+ ::insert_value( rnArea, mnBottomLine, 22, 3 );
+ ::insert_value( rnBorder, mnRightLine, 6, 3 );
+ ::insert_value( rnBorder, mnTopColor, 9, 7 );
+ ::insert_value( rnBorder, mnLeftColor, 16, 7 );
+ ::insert_value( rnArea, mnBottomColor, 25, 7 );
+ ::insert_value( rnBorder, mnRightColor, 23, 7 );
+}
+
+void XclExpCellBorder::FillToXF8( sal_uInt32& rnBorder1, sal_uInt32& rnBorder2 ) const
+{
+ ::insert_value( rnBorder1, mnLeftLine, 0, 4 );
+ ::insert_value( rnBorder1, mnRightLine, 4, 4 );
+ ::insert_value( rnBorder1, mnTopLine, 8, 4 );
+ ::insert_value( rnBorder1, mnBottomLine, 12, 4 );
+ ::insert_value( rnBorder1, mnLeftColor, 16, 7 );
+ ::insert_value( rnBorder1, mnRightColor, 23, 7 );
+ ::insert_value( rnBorder2, mnTopColor, 0, 7 );
+ ::insert_value( rnBorder2, mnBottomColor, 7, 7 );
+ ::insert_value( rnBorder2, mnDiagColor, 14, 7 );
+ ::insert_value( rnBorder2, mnDiagLine, 21, 4 );
+ ::set_flag( rnBorder1, EXC_XF_DIAGONAL_TL_TO_BR, mbDiagTLtoBR );
+ ::set_flag( rnBorder1, EXC_XF_DIAGONAL_BL_TO_TR, mbDiagBLtoTR );
+}
+
+void XclExpCellBorder::FillToCF8( sal_uInt16& rnLine, sal_uInt32& rnColor ) const
+{
+ ::insert_value( rnLine, mnLeftLine, 0, 4 );
+ ::insert_value( rnLine, mnRightLine, 4, 4 );
+ ::insert_value( rnLine, mnTopLine, 8, 4 );
+ ::insert_value( rnLine, mnBottomLine, 12, 4 );
+ ::insert_value( rnColor, mnLeftColor, 0, 7 );
+ ::insert_value( rnColor, mnRightColor, 7, 7 );
+ ::insert_value( rnColor, mnTopColor, 16, 7 );
+ ::insert_value( rnColor, mnBottomColor, 23, 7 );
+}
+
+static const char* ToLineStyle( sal_uInt8 nLineStyle )
+{
+ switch( nLineStyle )
+ {
+ case EXC_LINE_NONE: return "none";
+ case EXC_LINE_THIN: return "thin";
+ case EXC_LINE_MEDIUM: return "medium";
+ case EXC_LINE_THICK: return "thick";
+ case EXC_LINE_DOUBLE: return "double";
+ case EXC_LINE_HAIR: return "hair";
+ case EXC_LINE_DOTTED: return "dotted";
+ case EXC_LINE_DASHED: return "dashed";
+ case EXC_LINE_MEDIUMDASHED: return "mediumdashed";
+ }
+ return "*unknown*";
+}
+
+static void lcl_WriteBorder( XclExpXmlStream& rStrm, sal_Int32 nElement, sal_uInt8 nLineStyle, const Color& rColor )
+{
+ sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
+ if( nLineStyle == EXC_LINE_NONE )
+ rStyleSheet->singleElement( nElement, FSEND );
+ else if( rColor == Color( 0, 0, 0, 0 ) )
+ rStyleSheet->singleElement( nElement,
+ XML_style, ToLineStyle( nLineStyle ),
+ FSEND );
+ else
+ {
+ rStyleSheet->startElement( nElement,
+ XML_style, ToLineStyle( nLineStyle ),
+ FSEND );
+ rStyleSheet->singleElement( XML_color,
+ XML_rgb, XclXmlUtils::ToOString( rColor ).getStr(),
+ FSEND );
+ rStyleSheet->endElement( nElement );
+ }
+}
+
+void XclExpCellBorder::SaveXml( XclExpXmlStream& rStrm ) const
+{
+ sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
+
+ XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
+
+ rStyleSheet->startElement( XML_border,
+ XML_diagonalUp, XclXmlUtils::ToPsz( mbDiagBLtoTR ),
+ XML_diagonalDown, XclXmlUtils::ToPsz( mbDiagTLtoBR ),
+ // OOXTODO: XML_outline,
+ FSEND );
+ lcl_WriteBorder( rStrm, XML_left, mnLeftLine, rPalette.GetColor( mnLeftColor ) );
+ lcl_WriteBorder( rStrm, XML_right, mnRightLine, rPalette.GetColor( mnRightColor ) );
+ lcl_WriteBorder( rStrm, XML_top, mnTopLine, rPalette.GetColor( mnTopColor ) );
+ lcl_WriteBorder( rStrm, XML_bottom, mnBottomLine, rPalette.GetColor( mnBottomColor ) );
+ lcl_WriteBorder( rStrm, XML_diagonal, mnDiagLine, rPalette.GetColor( mnDiagColor ) );
+ // OOXTODO: XML_vertical, XML_horizontal
+ rStyleSheet->endElement( XML_border );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpCellArea::XclExpCellArea() :
+ mnForeColorId( XclExpPalette::GetColorIdFromIndex( mnForeColor ) ),
+ mnBackColorId( XclExpPalette::GetColorIdFromIndex( mnBackColor ) )
+{
+}
+
+bool XclExpCellArea::FillFromItemSet( const SfxItemSet& rItemSet, XclExpPalette& rPalette, bool bStyle )
+{
+ const SvxBrushItem& rBrushItem = GETITEM( rItemSet, SvxBrushItem, ATTR_BACKGROUND );
+ if( rBrushItem.GetColor().GetTransparency() )
+ {
+ mnPattern = EXC_PATT_NONE;
+ mnForeColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
+ mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWBACK );
+ }
+ else
+ {
+ mnPattern = EXC_PATT_SOLID;
+ mnForeColorId = rPalette.InsertColor( rBrushItem.GetColor(), EXC_COLOR_CELLAREA );
+ mnBackColorId = XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT );
+ }
+ return ScfTools::CheckItem( rItemSet, ATTR_BACKGROUND, bStyle );
+}
+
+void XclExpCellArea::SetFinalColors( const XclExpPalette& rPalette )
+{
+ rPalette.GetMixedColors( mnForeColor, mnBackColor, mnPattern, mnForeColorId, mnBackColorId );
+}
+
+void XclExpCellArea::FillToXF5( sal_uInt32& rnArea ) const
+{
+ ::insert_value( rnArea, mnPattern, 16, 6 );
+ ::insert_value( rnArea, mnForeColor, 0, 7 );
+ ::insert_value( rnArea, mnBackColor, 7, 7 );
+}
+
+void XclExpCellArea::FillToXF8( sal_uInt32& rnBorder2, sal_uInt16& rnArea ) const
+{
+ ::insert_value( rnBorder2, mnPattern, 26, 6 );
+ ::insert_value( rnArea, mnForeColor, 0, 7 );
+ ::insert_value( rnArea, mnBackColor, 7, 7 );
+}
+
+void XclExpCellArea::FillToCF8( sal_uInt16& rnPattern, sal_uInt16& rnColor ) const
+{
+ XclCellArea aTmp( *this );
+ if( !aTmp.IsTransparent() && (aTmp.mnBackColor == EXC_COLOR_WINDOWTEXT) )
+ aTmp.mnBackColor = 0;
+ if( aTmp.mnPattern == EXC_PATT_SOLID )
+ ::std::swap( aTmp.mnForeColor, aTmp.mnBackColor );
+ ::insert_value( rnColor, aTmp.mnForeColor, 0, 7 );
+ ::insert_value( rnColor, aTmp.mnBackColor, 7, 7 );
+ ::insert_value( rnPattern, aTmp.mnPattern, 10, 6 );
+}
+
+static const char* ToPatternType( sal_uInt8 nPattern )
+{
+ switch( nPattern )
+ {
+ case EXC_PATT_NONE: return "none";
+ case EXC_PATT_SOLID: return "solid";
+ case EXC_PATT_50_PERC: return "mediumGray";
+ case EXC_PATT_75_PERC: return "darkGray";
+ case EXC_PATT_25_PERC: return "lightGray";
+ case EXC_PATT_12_5_PERC: return "gray125";
+ case EXC_PATT_6_25_PERC: return "gray0625";
+ }
+ return "*unknown*";
+}
+
+void XclExpCellArea::SaveXml( XclExpXmlStream& rStrm ) const
+{
+ sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
+ rStyleSheet->startElement( XML_fill,
+ FSEND );
+
+ // OOXTODO: XML_gradientFill
+
+ XclExpPalette& rPalette = rStrm.GetRoot().GetPalette();
+
+ if( mnPattern == EXC_PATT_NONE || ( mnForeColor == 0 && mnBackColor == 0 ) )
+ rStyleSheet->singleElement( XML_patternFill,
+ XML_patternType, ToPatternType( mnPattern ),
+ FSEND );
+ else
+ {
+ rStyleSheet->startElement( XML_patternFill,
+ XML_patternType, ToPatternType( mnPattern ),
+ FSEND );
+ rStyleSheet->singleElement( XML_fgColor,
+ XML_rgb, XclXmlUtils::ToOString( rPalette.GetColor( mnForeColor ) ).getStr(),
+ FSEND );
+ rStyleSheet->singleElement( XML_bgColor,
+ XML_rgb, XclXmlUtils::ToOString( rPalette.GetColor( mnBackColor ) ).getStr(),
+ FSEND );
+ rStyleSheet->endElement( XML_patternFill );
+ }
+
+ rStyleSheet->endElement( XML_fill );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpXFId::XclExpXFId() :
+ mnXFId( XclExpXFBuffer::GetDefCellXFId() ),
+ mnXFIndex( EXC_XF_DEFAULTCELL )
+{
+}
+
+XclExpXFId::XclExpXFId( sal_uInt32 nXFId ) :
+ mnXFId( nXFId ),
+ mnXFIndex( EXC_XF_DEFAULTCELL )
+{
+}
+
+void XclExpXFId::ConvertXFIndex( const XclExpRoot& rRoot )
+{
+ mnXFIndex = rRoot.GetXFBuffer().GetXFIndex( mnXFId );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpXF::XclExpXF(
+ const XclExpRoot& rRoot, const ScPatternAttr& rPattern, sal_Int16 nScript,
+ sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) :
+ XclXFBase( true ),
+ XclExpRoot( rRoot )
+{
+ mnParentXFId = GetXFBuffer().InsertStyle( rPattern.GetStyleSheet() );
+ Init( rPattern.GetItemSet(), nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak, false );
+}
+
+XclExpXF::XclExpXF( const XclExpRoot& rRoot, const SfxStyleSheetBase& rStyleSheet ) :
+ XclXFBase( false ),
+ XclExpRoot( rRoot ),
+ mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
+{
+ bool bDefStyle = (rStyleSheet.GetName() == ScGlobal::GetRscString( STR_STYLENAME_STANDARD ));
+ sal_Int16 nScript = bDefStyle ? GetDefApiScript() : ::com::sun::star::i18n::ScriptType::WEAK;
+ Init( const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet(), nScript,
+ NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false, bDefStyle );
+}
+
+XclExpXF::XclExpXF( const XclExpRoot& rRoot, bool bCellXF ) :
+ XclXFBase( bCellXF ),
+ XclExpRoot( rRoot ),
+ mnParentXFId( XclExpXFBuffer::GetXFIdFromIndex( EXC_XF_STYLEPARENT ) )
+{
+ InitDefault();
+}
+
+bool XclExpXF::Equals( const ScPatternAttr& rPattern,
+ sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
+{
+ return IsCellXF() && (mpItemSet == &rPattern.GetItemSet()) &&
+ (!bForceLineBreak || maAlignment.mbLineBreak) &&
+ ((nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) || (mnScNumFmt == nForceScNumFmt)) &&
+ ((nForceXclFont == EXC_FONT_NOTFOUND) || (mnXclFont == nForceXclFont));
+}
+
+bool XclExpXF::Equals( const SfxStyleSheetBase& rStyleSheet ) const
+{
+ return IsStyleXF() && (mpItemSet == &const_cast< SfxStyleSheetBase& >( rStyleSheet ).GetItemSet());
+}
+
+void XclExpXF::SetFinalColors()
+{
+ maBorder.SetFinalColors( GetPalette() );
+ maArea.SetFinalColors( GetPalette() );
+}
+
+bool XclExpXF::Equals( const XclExpXF& rCmpXF ) const
+{
+ return XclXFBase::Equals( rCmpXF ) &&
+ (maProtection == rCmpXF.maProtection) && (maAlignment == rCmpXF.maAlignment) &&
+ (maBorder == rCmpXF.maBorder) && (maArea == rCmpXF.maArea) &&
+ (mnXclFont == rCmpXF.mnXclFont) && (mnXclNumFmt == rCmpXF.mnXclNumFmt) &&
+ (mnParentXFId == rCmpXF.mnParentXFId);
+}
+
+void XclExpXF::InitDefault()
+{
+ SetRecHeader( EXC_ID5_XF, (GetBiff() == EXC_BIFF8) ? 20 : 16 );
+ mpItemSet = 0;
+ mnScNumFmt = NUMBERFORMAT_ENTRY_NOT_FOUND;
+ mnXclFont = mnXclNumFmt = 0;
+}
+
+void XclExpXF::Init( const SfxItemSet& rItemSet, sal_Int16 nScript,
+ sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak, bool bDefStyle )
+{
+ InitDefault();
+ mpItemSet = &rItemSet;
+
+ // cell protection
+ mbProtUsed = maProtection.FillFromItemSet( rItemSet, IsStyleXF() );
+
+ // font
+ if( nForceXclFont == EXC_FONT_NOTFOUND )
+ {
+ mnXclFont = GetFontBuffer().Insert( rItemSet, nScript, EXC_COLOR_CELLTEXT, bDefStyle );
+ mbFontUsed = XclExpFontHelper::CheckItems( GetRoot(), rItemSet, nScript, IsStyleXF() );
+ }
+ else
+ {
+ mnXclFont = nForceXclFont;
+ mbFontUsed = true;
+ }
+
+ // number format
+ mnScNumFmt = (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) ?
+ GETITEMVALUE( rItemSet, SfxUInt32Item, ATTR_VALUE_FORMAT, sal_uLong ) : nForceScNumFmt;
+ mnXclNumFmt = GetNumFmtBuffer().Insert( mnScNumFmt );
+ mbFmtUsed = ScfTools::CheckItem( rItemSet, ATTR_VALUE_FORMAT, IsStyleXF() );
+
+ // alignment
+ mbAlignUsed = maAlignment.FillFromItemSet( rItemSet, bForceLineBreak, GetBiff(), IsStyleXF() );
+
+ // cell border
+ mbBorderUsed = maBorder.FillFromItemSet( rItemSet, GetPalette(), GetBiff(), IsStyleXF() );
+
+ // background area
+ mbAreaUsed = maArea.FillFromItemSet( rItemSet, GetPalette(), IsStyleXF() );
+
+ // set all b***Used flags to true in "Default"/"Normal" style
+ if( bDefStyle )
+ SetAllUsedFlags( true );
+}
+
+sal_uInt8 XclExpXF::GetUsedFlags() const
+{
+ sal_uInt8 nUsedFlags = 0;
+ /* In cell XFs a set bit means a used attribute, in style XFs a cleared bit.
+ "mbCellXF == mb***Used" evaluates to correct value in cell and style XFs. */
+ ::set_flag( nUsedFlags, EXC_XF_DIFF_PROT, mbCellXF == mbProtUsed );
+ ::set_flag( nUsedFlags, EXC_XF_DIFF_FONT, mbCellXF == mbFontUsed );
+ ::set_flag( nUsedFlags, EXC_XF_DIFF_VALFMT, mbCellXF == mbFmtUsed );
+ ::set_flag( nUsedFlags, EXC_XF_DIFF_ALIGN, mbCellXF == mbAlignUsed );
+ ::set_flag( nUsedFlags, EXC_XF_DIFF_BORDER, mbCellXF == mbBorderUsed );
+ ::set_flag( nUsedFlags, EXC_XF_DIFF_AREA, mbCellXF == mbAreaUsed );
+ return nUsedFlags;
+}
+
+void XclExpXF::WriteBody5( XclExpStream& rStrm )
+{
+ sal_uInt16 nTypeProt = 0, nAlign = 0;
+ sal_uInt32 nArea = 0, nBorder = 0;
+
+ ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
+ ::insert_value( nTypeProt, mnParent, 4, 12 );
+ ::insert_value( nAlign, GetUsedFlags(), 10, 6 );
+
+ maProtection.FillToXF3( nTypeProt );
+ maAlignment.FillToXF5( nAlign );
+ maBorder.FillToXF5( nBorder, nArea );
+ maArea.FillToXF5( nArea );
+
+ rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nArea << nBorder;
+}
+
+void XclExpXF::WriteBody8( XclExpStream& rStrm )
+{
+ sal_uInt16 nTypeProt = 0, nAlign = 0, nMiscAttrib = 0, nArea = 0;
+ sal_uInt32 nBorder1 = 0, nBorder2 = 0;
+
+ ::set_flag( nTypeProt, EXC_XF_STYLE, IsStyleXF() );
+ ::insert_value( nTypeProt, mnParent, 4, 12 );
+ ::insert_value( nMiscAttrib, GetUsedFlags(), 10, 6 );
+
+ maProtection.FillToXF3( nTypeProt );
+ maAlignment.FillToXF8( nAlign, nMiscAttrib );
+ maBorder.FillToXF8( nBorder1, nBorder2 );
+ maArea.FillToXF8( nBorder2, nArea );
+
+ rStrm << mnXclFont << mnXclNumFmt << nTypeProt << nAlign << nMiscAttrib << nBorder1 << nBorder2 << nArea;
+}
+
+void XclExpXF::WriteBody( XclExpStream& rStrm )
+{
+ XclExpXFId aParentId( mnParentXFId );
+ aParentId.ConvertXFIndex( GetRoot() );
+ mnParent = aParentId.mnXFIndex;
+ switch( GetBiff() )
+ {
+ case EXC_BIFF5: WriteBody5( rStrm ); break;
+ case EXC_BIFF8: WriteBody8( rStrm ); break;
+ default: DBG_ERROR_BIFF();
+ }
+}
+
+void XclExpXF::SetXmlIds( sal_uInt32 nBorderId, sal_uInt32 nFillId )
+{
+ mnBorderId = nBorderId;
+ mnFillId = nFillId;
+}
+
+void XclExpXF::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
+
+ sal_Int32 nXfId = 0;
+ if( IsCellXF() )
+ {
+ sal_uInt16 nXFIndex = rStrm.GetRoot().GetXFBuffer().GetXFIndex( mnParentXFId );
+ nXfId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( nXFIndex );
+ }
+
+ rStyleSheet->startElement( XML_xf,
+ XML_numFmtId, OString::valueOf( (sal_Int32) mnXclNumFmt ).getStr(),
+ XML_fontId, OString::valueOf( (sal_Int32) mnXclFont ).getStr(),
+ XML_fillId, OString::valueOf( (sal_Int32) mnFillId ).getStr(),
+ XML_borderId, OString::valueOf( (sal_Int32) mnBorderId ).getStr(),
+ XML_xfId, IsStyleXF() ? NULL : OString::valueOf( nXfId ).getStr(),
+ // OOXTODO: XML_quotePrefix,
+ // OOXTODO: XML_pivotButton,
+ // OOXTODO: XML_applyNumberFormat, ;
+ XML_applyFont, XclXmlUtils::ToPsz( mbFontUsed ),
+ // OOXTODO: XML_applyFill,
+ XML_applyBorder, XclXmlUtils::ToPsz( mbBorderUsed ),
+ XML_applyAlignment, XclXmlUtils::ToPsz( mbAlignUsed ),
+ XML_applyProtection, XclXmlUtils::ToPsz( mbProtUsed ),
+ FSEND );
+ if( mbAlignUsed )
+ maAlignment.SaveXml( rStrm );
+ if( mbProtUsed )
+ maProtection.SaveXml( rStrm );
+ // OOXTODO: XML_extLst
+ rStyleSheet->endElement( XML_xf );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpDefaultXF::XclExpDefaultXF( const XclExpRoot& rRoot, bool bCellXF ) :
+ XclExpXF( rRoot, bCellXF )
+{
+}
+
+void XclExpDefaultXF::SetFont( sal_uInt16 nXclFont )
+{
+ mnXclFont = nXclFont;
+ mbFontUsed = true;
+}
+
+void XclExpDefaultXF::SetNumFmt( sal_uInt16 nXclNumFmt )
+{
+ mnXclNumFmt = nXclNumFmt;
+ mbFmtUsed = true;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpStyle::XclExpStyle( sal_uInt32 nXFId, const String& rStyleName ) :
+ XclExpRecord( EXC_ID_STYLE, 4 ),
+ maName( rStyleName ),
+ maXFId( nXFId ),
+ mnStyleId( EXC_STYLE_USERDEF ),
+ mnLevel( EXC_STYLE_NOLEVEL )
+{
+ DBG_ASSERT( maName.Len(), "XclExpStyle::XclExpStyle - empty style name" );
+#ifdef DBG_UTIL
+ sal_uInt8 nStyleId, nLevel; // do not use members for debug tests
+ DBG_ASSERT( !XclTools::GetBuiltInStyleId( nStyleId, nLevel, maName ),
+ "XclExpStyle::XclExpStyle - this is a built-in style" );
+#endif
+}
+
+XclExpStyle::XclExpStyle( sal_uInt32 nXFId, sal_uInt8 nStyleId, sal_uInt8 nLevel ) :
+ XclExpRecord( EXC_ID_STYLE, 4 ),
+ maXFId( nXFId ),
+ mnStyleId( nStyleId ),
+ mnLevel( nLevel )
+{
+}
+
+void XclExpStyle::WriteBody( XclExpStream& rStrm )
+{
+ maXFId.ConvertXFIndex( rStrm.GetRoot() );
+ ::set_flag( maXFId.mnXFIndex, EXC_STYLE_BUILTIN, IsBuiltIn() );
+ rStrm << maXFId.mnXFIndex;
+
+ if( IsBuiltIn() )
+ {
+ rStrm << mnStyleId << mnLevel;
+ }
+ else
+ {
+ XclExpString aNameEx;
+ if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
+ aNameEx.Assign( maName );
+ else
+ aNameEx.AssignByte( maName, rStrm.GetRoot().GetTextEncoding(), EXC_STR_8BITLENGTH );
+ rStrm << aNameEx;
+ }
+}
+
+static const char* lcl_StyleNameFromId( sal_Int32 nStyleId )
+{
+ switch( nStyleId )
+ {
+ case 0: return "Normal";
+ case 3: return "Comma";
+ case 4: return "Currency";
+ case 5: return "Percent";
+ case 6: return "Comma [0]";
+ case 7: return "Currency [0]";
+ }
+ return "*unknown*";
+}
+
+void XclExpStyle::SaveXml( XclExpXmlStream& rStrm )
+{
+ OString sName;
+ if( IsBuiltIn() )
+ {
+ sName = OString( lcl_StyleNameFromId( mnStyleId ) );
+ }
+ else
+ sName = XclXmlUtils::ToOString( maName );
+ sal_Int32 nXFId = rStrm.GetRoot().GetXFBuffer().GetXmlStyleIndex( maXFId.mnXFId );
+ rStrm.GetCurrentStream()->singleElement( XML_cellStyle,
+ XML_name, sName.getStr(),
+ XML_xfId, OString::valueOf( nXFId ).getStr(),
+/* mso-excel 2007 complains when it finds builtinId >= 55, it is not
+ * bothered by multiple 54 values. */
+#define CELL_STYLE_MAX_BUILTIN_ID 55
+ XML_builtinId, OString::valueOf( std::min( static_cast<sal_Int32>( CELL_STYLE_MAX_BUILTIN_ID - 1 ), static_cast <sal_Int32>( mnStyleId ) ) ).getStr(),
+ // OOXTODO: XML_iLevel,
+ // OOXTODO: XML_hidden,
+ XML_customBuiltin, XclXmlUtils::ToPsz( ! IsBuiltIn() ),
+ FSEND );
+ // OOXTODO: XML_extLst
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+const sal_uInt32 EXC_XFLIST_INDEXBASE = 0xFFFE0000;
+/** Maximum count of XF records to store in the XF list (performance). */
+const sal_uInt32 EXC_XFLIST_HARDLIMIT = 256 * 1024;
+
+bool lclIsBuiltInStyle( const String& rStyleName )
+{
+ return
+ XclTools::IsBuiltInStyleName( rStyleName ) ||
+ XclTools::IsCondFormatStyleName( rStyleName );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpXFBuffer::XclExpBuiltInInfo::XclExpBuiltInInfo() :
+ mnStyleId( EXC_STYLE_USERDEF ),
+ mnLevel( EXC_STYLE_NOLEVEL ),
+ mbPredefined( true ),
+ mbHasStyleRec( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+/** Predicate for search algorithm. */
+struct XclExpBorderPred
+{
+ const XclExpCellBorder&
+ mrBorder;
+ inline explicit XclExpBorderPred( const XclExpCellBorder& rBorder ) : mrBorder( rBorder ) {}
+ bool operator()( const XclExpCellBorder& rBorder ) const;
+};
+
+bool XclExpBorderPred::operator()( const XclExpCellBorder& rBorder ) const
+{
+ return
+ mrBorder.mnLeftColor == rBorder.mnLeftColor &&
+ mrBorder.mnRightColor == rBorder.mnRightColor &&
+ mrBorder.mnTopColor == rBorder.mnTopColor &&
+ mrBorder.mnBottomColor == rBorder.mnBottomColor &&
+ mrBorder.mnDiagColor == rBorder.mnDiagColor &&
+ mrBorder.mnLeftLine == rBorder.mnLeftLine &&
+ mrBorder.mnRightLine == rBorder.mnRightLine &&
+ mrBorder.mnTopLine == rBorder.mnTopLine &&
+ mrBorder.mnBottomLine == rBorder.mnBottomLine &&
+ mrBorder.mnDiagLine == rBorder.mnDiagLine &&
+ mrBorder.mbDiagTLtoBR == rBorder.mbDiagTLtoBR &&
+ mrBorder.mbDiagBLtoTR == rBorder.mbDiagBLtoTR &&
+ mrBorder.mnLeftColorId == rBorder.mnLeftColorId &&
+ mrBorder.mnRightColorId == rBorder.mnRightColorId &&
+ mrBorder.mnTopColorId == rBorder.mnTopColorId &&
+ mrBorder.mnBottomColorId == rBorder.mnBottomColorId &&
+ mrBorder.mnDiagColorId == rBorder.mnDiagColorId;
+}
+
+struct XclExpFillPred
+{
+ const XclExpCellArea&
+ mrFill;
+ inline explicit XclExpFillPred( const XclExpCellArea& rFill ) : mrFill( rFill ) {}
+ bool operator()( const XclExpCellArea& rFill ) const;
+};
+
+bool XclExpFillPred::operator()( const XclExpCellArea& rFill ) const
+{
+ return
+ mrFill.mnForeColor == rFill.mnForeColor &&
+ mrFill.mnBackColor == rFill.mnBackColor &&
+ mrFill.mnPattern == rFill.mnPattern &&
+ mrFill.mnForeColorId == rFill.mnForeColorId &&
+ mrFill.mnBackColorId == rFill.mnBackColorId;
+}
+
+XclExpXFBuffer::XclExpXFBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+void XclExpXFBuffer::Initialize()
+{
+ InsertDefaultRecords();
+ InsertUserStyles();
+}
+
+sal_uInt32 XclExpXFBuffer::Insert( const ScPatternAttr* pPattern, sal_Int16 nScript )
+{
+ return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, EXC_FONT_NOTFOUND, false );
+}
+
+sal_uInt32 XclExpXFBuffer::InsertWithFont( const ScPatternAttr* pPattern, sal_Int16 nScript,
+ sal_uInt16 nForceXclFont, bool bForceLineBreak )
+{
+ return InsertCellXF( pPattern, nScript, NUMBERFORMAT_ENTRY_NOT_FOUND, nForceXclFont, bForceLineBreak );
+}
+
+sal_uInt32 XclExpXFBuffer::InsertWithNumFmt( const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uLong nForceScNumFmt, bool bForceLineBreak )
+{
+ return InsertCellXF( pPattern, nScript, nForceScNumFmt, EXC_FONT_NOTFOUND, bForceLineBreak );
+}
+
+sal_uInt32 XclExpXFBuffer::InsertStyle( const SfxStyleSheetBase* pStyleSheet )
+{
+ return pStyleSheet ? InsertStyleXF( *pStyleSheet ) : GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
+}
+
+sal_uInt32 XclExpXFBuffer::GetXFIdFromIndex( sal_uInt16 nXFIndex )
+{
+ return EXC_XFLIST_INDEXBASE | nXFIndex;
+}
+
+sal_uInt32 XclExpXFBuffer::GetDefCellXFId()
+{
+ return GetXFIdFromIndex( EXC_XF_DEFAULTCELL );
+}
+
+const XclExpXF* XclExpXFBuffer::GetXFById( sal_uInt32 nXFId ) const
+{
+ return maXFList.GetRecord( nXFId ).get();
+}
+
+void XclExpXFBuffer::Finalize()
+{
+ for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
+ maXFList.GetRecord( nPos )->SetFinalColors();
+
+ sal_uInt32 nTotalCount = static_cast< sal_uInt32 >( maXFList.GetSize() );
+ sal_uInt32 nId;
+ maXFIndexVec.resize( nTotalCount, EXC_XF_DEFAULTCELL );
+ maStyleIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
+ maCellIndexes.resize( nTotalCount, EXC_XF_DEFAULTCELL );
+
+ XclExpBuiltInMap::const_iterator aBuiltInEnd = maBuiltInMap.end();
+ /* nMaxBuiltInXFId used to decide faster whether an XF record is
+ user-defined. If the current XF ID is greater than this value,
+ maBuiltInMap doesn't need to be searched. */
+ sal_uInt32 nMaxBuiltInXFId = maBuiltInMap.empty() ? 0 : maBuiltInMap.rbegin()->first;
+
+ // *** map all built-in XF records (cell and style) *** -------------------
+
+ // do not change XF order -> std::map<> iterates elements in ascending order
+ for( XclExpBuiltInMap::const_iterator aIt = maBuiltInMap.begin(); aIt != aBuiltInEnd; ++aIt )
+ AppendXFIndex( aIt->first );
+
+ // *** insert all user-defined style XF records, without reduce *** -------
+
+ sal_uInt32 nStyleXFCount = 0; // counts up to EXC_XF_MAXSTYLECOUNT limit
+
+ for( nId = 0; nId < nTotalCount; ++nId )
+ {
+ XclExpXFRef xXF = maXFList.GetRecord( nId );
+ if( xXF->IsStyleXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
+ {
+ if( nStyleXFCount < EXC_XF_MAXSTYLECOUNT )
+ {
+ // maximum count of styles not reached
+ AppendXFIndex( nId );
+ ++nStyleXFCount;
+ }
+ else
+ {
+ /* Maximum count of styles reached - do not append more
+ pointers to XFs; use default style XF instead; do not break
+ the loop to initialize all maXFIndexVec elements. */
+ maXFIndexVec[ nId ] = EXC_XF_DEFAULTSTYLE;
+ }
+ }
+ }
+
+ // *** insert all cell XF records *** -------------------------------------
+
+ // start position to search for equal inserted XF records
+ size_t nSearchStart = maSortedXFList.GetSize();
+
+ // break the loop if XF limit reached - maXFIndexVec is already initialized with default index
+ XclExpXFRef xDefCellXF = maXFList.GetRecord( EXC_XF_DEFAULTCELL );
+ for( nId = 0; (nId < nTotalCount) && (maSortedXFList.GetSize() < EXC_XF_MAXCOUNT); ++nId )
+ {
+ XclExpXFRef xXF = maXFList.GetRecord( nId );
+ if( xXF->IsCellXF() && ((nId > nMaxBuiltInXFId) || (maBuiltInMap.find( nId ) == aBuiltInEnd)) )
+ {
+ // try to find an XF record equal to *xXF, which is already inserted
+ sal_uInt16 nFoundIndex = EXC_XF_NOTFOUND;
+
+ // first try if it is equal to the default cell XF
+ if( xDefCellXF->Equals( *xXF ) )
+ {
+ nFoundIndex = EXC_XF_DEFAULTCELL;
+ }
+ else for( size_t nSearchPos = nSearchStart, nSearchEnd = maSortedXFList.GetSize();
+ (nSearchPos < nSearchEnd) && (nFoundIndex == EXC_XF_NOTFOUND); ++nSearchPos )
+ {
+ if( maSortedXFList.GetRecord( nSearchPos )->Equals( *xXF ) )
+ nFoundIndex = static_cast< sal_uInt16 >( nSearchPos );
+ }
+
+ if( nFoundIndex != EXC_XF_NOTFOUND )
+ // equal XF already in the list, use its resulting XF index
+ maXFIndexVec[ nId ] = nFoundIndex;
+ else
+ AppendXFIndex( nId );
+ }
+ }
+
+ sal_uInt16 nXmlStyleIndex = 0;
+ sal_uInt16 nXmlCellIndex = 0;
+
+ size_t nXFCount = maSortedXFList.GetSize();
+ for( size_t i = 0; i < nXFCount; ++i )
+ {
+ XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
+ if( xXF->IsStyleXF() )
+ maStyleIndexes[ i ] = nXmlStyleIndex++;
+ else
+ maCellIndexes[ i ] = nXmlCellIndex++;
+ }
+}
+
+sal_uInt16 XclExpXFBuffer::GetXFIndex( sal_uInt32 nXFId ) const
+{
+ sal_uInt16 nXFIndex = EXC_XF_DEFAULTSTYLE;
+ if( nXFId >= EXC_XFLIST_INDEXBASE )
+ nXFIndex = static_cast< sal_uInt16 >( nXFId & ~EXC_XFLIST_INDEXBASE );
+ else if( nXFId < maXFIndexVec.size() )
+ nXFIndex = maXFIndexVec[ nXFId ];
+ return nXFIndex;
+}
+
+sal_Int32 XclExpXFBuffer::GetXmlStyleIndex( sal_uInt32 nXFIndex ) const
+{
+ DBG_ASSERT( nXFIndex < maStyleIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
+ if( nXFIndex > maStyleIndexes.size() )
+ return 0; // should be caught/debugged via above assert; return "valid" index.
+ return maStyleIndexes[ nXFIndex ];
+}
+
+sal_Int32 XclExpXFBuffer::GetXmlCellIndex( sal_uInt32 nXFIndex ) const
+{
+ DBG_ASSERT( nXFIndex < maCellIndexes.size(), "XclExpXFBuffer::GetXmlStyleIndex - invalid index!" );
+ if( nXFIndex > maCellIndexes.size() )
+ return 0; // should be caught/debugged via above assert; return "valid" index.
+ return maCellIndexes[ nXFIndex ];
+}
+
+void XclExpXFBuffer::Save( XclExpStream& rStrm )
+{
+ // save all XF records contained in the maSortedXFList vector (sorted by XF index)
+ maSortedXFList.Save( rStrm );
+ // save all STYLE records
+ maStyleList.Save( rStrm );
+}
+
+static void lcl_GetCellCounts( const XclExpRecordList< XclExpXF >& rXFList, sal_Int32& rCells, sal_Int32& rStyles )
+{
+ rCells = 0;
+ rStyles = 0;
+ size_t nXFCount = rXFList.GetSize();
+ for( size_t i = 0; i < nXFCount; ++i )
+ {
+ XclExpRecordList< XclExpXF >::RecordRefType xXF = rXFList.GetRecord( i );
+ if( xXF->IsCellXF() )
+ ++rCells;
+ else if( xXF->IsStyleXF() )
+ ++rStyles;
+ }
+}
+
+void XclExpXFBuffer::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rStyleSheet = rStrm.GetCurrentStream();
+
+ rStyleSheet->startElement( XML_fills,
+ XML_count, OString::valueOf( (sal_Int32) maFills.size() ).getStr(),
+ FSEND );
+ for( XclExpFillList::iterator aIt = maFills.begin(), aEnd = maFills.end();
+ aIt != aEnd; ++aIt )
+ {
+ aIt->SaveXml( rStrm );
+ }
+ rStyleSheet->endElement( XML_fills );
+
+ rStyleSheet->startElement( XML_borders,
+ XML_count, OString::valueOf( (sal_Int32) maBorders.size() ).getStr(),
+ FSEND );
+ for( XclExpBorderList::iterator aIt = maBorders.begin(), aEnd = maBorders.end();
+ aIt != aEnd; ++aIt )
+ {
+ aIt->SaveXml( rStrm );
+ }
+ rStyleSheet->endElement( XML_borders );
+
+ // save all XF records contained in the maSortedXFList vector (sorted by XF index)
+ sal_Int32 nCells, nStyles;
+ lcl_GetCellCounts( maSortedXFList, nCells, nStyles );
+
+ if( nStyles > 0 )
+ {
+ rStyleSheet->startElement( XML_cellStyleXfs,
+ XML_count, OString::valueOf( nStyles ).getStr(),
+ FSEND );
+ size_t nXFCount = maSortedXFList.GetSize();
+ for( size_t i = 0; i < nXFCount; ++i )
+ {
+ XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
+ if( ! xXF->IsStyleXF() )
+ continue;
+ SaveXFXml( rStrm, *xXF );
+ }
+ rStyleSheet->endElement( XML_cellStyleXfs );
+ }
+
+ if( nCells > 0 )
+ {
+ rStyleSheet->startElement( XML_cellXfs,
+ XML_count, OString::valueOf( nCells ).getStr(),
+ FSEND );
+ size_t nXFCount = maSortedXFList.GetSize();
+ for( size_t i = 0; i < nXFCount; ++i )
+ {
+ XclExpXFList::RecordRefType xXF = maSortedXFList.GetRecord( i );
+ if( ! xXF->IsCellXF() )
+ continue;
+ SaveXFXml( rStrm, *xXF );
+ }
+ rStyleSheet->endElement( XML_cellXfs );
+ }
+
+ // save all STYLE records
+ rStyleSheet->startElement( XML_cellStyles,
+ XML_count, OString::valueOf( (sal_Int32) maStyleList.GetSize() ).getStr(),
+ FSEND );
+ maStyleList.SaveXml( rStrm );
+ rStyleSheet->endElement( XML_cellStyles );
+}
+
+void XclExpXFBuffer::SaveXFXml( XclExpXmlStream& rStrm, XclExpXF& rXF )
+{
+ XclExpBorderList::iterator aBorderPos =
+ std::find_if( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) );
+ DBG_ASSERT( aBorderPos != maBorders.end(), "XclExpXFBuffer::SaveXml - Invalid @borderId!" );
+ XclExpFillList::iterator aFillPos =
+ std::find_if( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) );
+ DBG_ASSERT( aFillPos != maFills.end(), "XclExpXFBuffer::SaveXml - Invalid @fillId!" );
+
+ sal_Int32 nBorderId = 0, nFillId = 0;
+ if( aBorderPos != maBorders.end() )
+ nBorderId = std::distance( maBorders.begin(), aBorderPos );
+ if( aFillPos != maFills.end() )
+ nFillId = std::distance( maFills.begin(), aFillPos );
+
+ rXF.SetXmlIds( nBorderId, nFillId );
+ rXF.SaveXml( rStrm );
+}
+
+sal_uInt32 XclExpXFBuffer::FindXF( const ScPatternAttr& rPattern,
+ sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak ) const
+{
+ for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
+ if( maXFList.GetRecord( nPos )->Equals( rPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak ) )
+ return static_cast< sal_uInt32 >( nPos );
+ return EXC_XFID_NOTFOUND;
+}
+
+sal_uInt32 XclExpXFBuffer::FindXF( const SfxStyleSheetBase& rStyleSheet ) const
+{
+ for( size_t nPos = 0, nSize = maXFList.GetSize(); nPos < nSize; ++nPos )
+ if( maXFList.GetRecord( nPos )->Equals( rStyleSheet ) )
+ return static_cast< sal_uInt32 >( nPos );
+ return EXC_XFID_NOTFOUND;
+}
+
+sal_uInt32 XclExpXFBuffer::FindBuiltInXF( sal_uInt8 nStyleId, sal_uInt8 nLevel ) const
+{
+ for( XclExpBuiltInMap::const_iterator aIt = maBuiltInMap.begin(), aEnd = maBuiltInMap.end(); aIt != aEnd; ++aIt )
+ if( (aIt->second.mnStyleId == nStyleId) && (aIt->second.mnLevel == nLevel) )
+ return aIt->first;
+ return EXC_XFID_NOTFOUND;
+}
+
+sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int16 nScript,
+ sal_uLong nForceScNumFmt, sal_uInt16 nForceXclFont, bool bForceLineBreak )
+{
+ const ScPatternAttr* pDefPattern = GetDoc().GetDefPattern();
+ if( !pPattern )
+ pPattern = pDefPattern;
+
+ // special handling for default cell formatting
+ if( (pPattern == pDefPattern) && !bForceLineBreak &&
+ (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) &&
+ (nForceXclFont == EXC_FONT_NOTFOUND) )
+ {
+ // Is it the first try to insert the default cell format?
+ bool& rbPredefined = maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined;
+ if( rbPredefined )
+ {
+ // replace default cell pattern
+ XclExpXFRef xNewXF( new XclExpXF( GetRoot(), *pPattern, nScript ) );
+ maXFList.ReplaceRecord( xNewXF, EXC_XF_DEFAULTCELL );
+ rbPredefined = false;
+ }
+ return GetDefCellXFId();
+ }
+
+ sal_uInt32 nXFId = FindXF( *pPattern, nForceScNumFmt, nForceXclFont, bForceLineBreak );
+ if( nXFId == EXC_XFID_NOTFOUND )
+ {
+ // not found - insert new cell XF
+ if( maXFList.GetSize() < EXC_XFLIST_HARDLIMIT )
+ {
+ maXFList.AppendNewRecord( new XclExpXF(
+ GetRoot(), *pPattern, nScript, nForceScNumFmt, nForceXclFont, bForceLineBreak ) );
+ // do not set nXFId before the AppendNewRecord() call - it may insert 2 XFs (style+cell)
+ nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() - 1 );
+ }
+ else
+ {
+ // list full - fall back to default cell XF
+ nXFId = GetDefCellXFId();
+ }
+ }
+ return nXFId;
+}
+
+sal_uInt32 XclExpXFBuffer::InsertStyleXF( const SfxStyleSheetBase& rStyleSheet )
+{
+ // *** try, if it is a built-in style - create new XF or replace existing predefined XF ***
+
+ sal_uInt8 nStyleId, nLevel;
+ if( XclTools::GetBuiltInStyleId( nStyleId, nLevel, rStyleSheet.GetName() ) )
+ {
+ // try to find the built-in XF record (if already created in InsertDefaultRecords())
+ sal_uInt32 nXFId = FindBuiltInXF( nStyleId, nLevel );
+ if( nXFId == EXC_XFID_NOTFOUND )
+ {
+ // built-in style XF not yet created - do it now
+ XclExpXFRef xXF( new XclExpXF( GetRoot(), rStyleSheet ) );
+ nXFId = AppendBuiltInXFWithStyle( xXF, nStyleId, nLevel );
+ // this new XF record is not predefined
+ maBuiltInMap[ nXFId ].mbPredefined = false;
+ }
+ else
+ {
+ DBG_ASSERT( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::InsertStyleXF - built-in XF not found" );
+ // XF record still predefined? -> Replace with real XF
+ bool& rbPredefined = maBuiltInMap[ nXFId ].mbPredefined;
+ if( rbPredefined )
+ {
+ // replace predefined built-in style (ReplaceRecord() deletes old record)
+ maXFList.ReplaceRecord( XclExpXFRef( new XclExpXF( GetRoot(), rStyleSheet ) ), nXFId );
+ rbPredefined = false;
+ }
+ }
+
+ // STYLE already inserted? (may be not, i.e. for RowLevel/ColLevel or Hyperlink styles)
+ bool& rbHasStyleRec = maBuiltInMap[ nXFId ].mbHasStyleRec;
+ if( !rbHasStyleRec )
+ {
+ maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
+ rbHasStyleRec = true;
+ }
+
+ return nXFId;
+ }
+
+ // *** try to find the XF record of a user-defined style ***
+
+ sal_uInt32 nXFId = FindXF( rStyleSheet );
+ if( nXFId == EXC_XFID_NOTFOUND )
+ {
+ // not found - insert new style XF and STYLE
+ nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
+ if( nXFId < EXC_XFLIST_HARDLIMIT )
+ {
+ maXFList.AppendNewRecord( new XclExpXF( GetRoot(), rStyleSheet ) );
+ // create the STYLE record
+ if( rStyleSheet.GetName().Len() )
+ maStyleList.AppendNewRecord( new XclExpStyle( nXFId, rStyleSheet.GetName() ) );
+ }
+ else
+ // list full - fall back to default style XF
+ nXFId = GetXFIdFromIndex( EXC_XF_DEFAULTSTYLE );
+ }
+ return nXFId;
+}
+
+void XclExpXFBuffer::InsertUserStyles()
+{
+ SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SFX_STYLE_FAMILY_PARA );
+ for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
+ if( pStyleSheet->IsUserDefined() && !lclIsBuiltInStyle( pStyleSheet->GetName() ) )
+ InsertStyleXF( *pStyleSheet );
+}
+
+sal_uInt32 XclExpXFBuffer::AppendBuiltInXF( XclExpXFRef xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
+{
+ sal_uInt32 nXFId = static_cast< sal_uInt32 >( maXFList.GetSize() );
+ maXFList.AppendRecord( xXF );
+ XclExpBuiltInInfo& rInfo = maBuiltInMap[ nXFId ];
+ rInfo.mnStyleId = nStyleId;
+ rInfo.mnLevel = nLevel;
+ rInfo.mbPredefined = true;
+ return nXFId;
+}
+
+sal_uInt32 XclExpXFBuffer::AppendBuiltInXFWithStyle( XclExpXFRef xXF, sal_uInt8 nStyleId, sal_uInt8 nLevel )
+{
+ sal_uInt32 nXFId = AppendBuiltInXF( xXF, nStyleId, nLevel );
+ maStyleList.AppendNewRecord( new XclExpStyle( nXFId, nStyleId, nLevel ) );
+ maBuiltInMap[ nXFId ].mbHasStyleRec = true; // mark existing STYLE record
+ return nXFId;
+}
+
+static XclExpCellArea lcl_GetPatternFill_None()
+{
+ XclExpCellArea aFill;
+ aFill.mnPattern = EXC_PATT_NONE;
+ return aFill;
+}
+
+static XclExpCellArea lcl_GetPatternFill_Gray125()
+{
+ XclExpCellArea aFill;
+ aFill.mnPattern = EXC_PATT_12_5_PERC;
+ aFill.mnForeColor = 0;
+ aFill.mnBackColor = 0;
+ return aFill;
+}
+
+void XclExpXFBuffer::InsertDefaultRecords()
+{
+ maFills.push_back( lcl_GetPatternFill_None() );
+ maFills.push_back( lcl_GetPatternFill_Gray125() );
+
+ // index 0: default style
+ if( SfxStyleSheetBase* pDefStyleSheet = GetStyleSheetPool().Find( ScGlobal::GetRscString( STR_STYLENAME_STANDARD ), SFX_STYLE_FAMILY_PARA ) )
+ {
+ XclExpXFRef xDefStyle( new XclExpXF( GetRoot(), *pDefStyleSheet ) );
+ sal_uInt32 nXFId = AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
+ // mark this XF as not predefined, prevents overwriting
+ maBuiltInMap[ nXFId ].mbPredefined = false;
+ }
+ else
+ {
+ DBG_ERRORFILE( "XclExpXFBuffer::InsertDefaultRecords - default style not found" );
+ XclExpXFRef xDefStyle( new XclExpDefaultXF( GetRoot(), false ) );
+ xDefStyle->SetAllUsedFlags( true );
+ AppendBuiltInXFWithStyle( xDefStyle, EXC_STYLE_NORMAL );
+ }
+
+ // index 1-14: RowLevel and ColLevel styles (without STYLE records)
+ XclExpDefaultXF aLevelStyle( GetRoot(), false );
+ // RowLevel_1, ColLevel_1
+ aLevelStyle.SetFont( 1 );
+ AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, 0 );
+ AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, 0 );
+ // RowLevel_2, ColLevel_2
+ aLevelStyle.SetFont( 2 );
+ AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, 1 );
+ AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, 1 );
+ // RowLevel_3, ColLevel_3 ... RowLevel_7, ColLevel_7
+ aLevelStyle.SetFont( 0 );
+ for( sal_uInt8 nLevel = 2; nLevel < EXC_STYLE_LEVELCOUNT; ++nLevel )
+ {
+ AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_ROWLEVEL, nLevel );
+ AppendBuiltInXF( XclExpXFRef( new XclExpDefaultXF( aLevelStyle ) ), EXC_STYLE_COLLEVEL, nLevel );
+ }
+
+ // index 15: default hard cell format, placeholder to be able to add more built-in styles
+ maXFList.AppendNewRecord( new XclExpDefaultXF( GetRoot(), true ) );
+ maBuiltInMap[ EXC_XF_DEFAULTCELL ].mbPredefined = true;
+
+ // index 16-20: other built-in styles
+ XclExpDefaultXF aFormatStyle( GetRoot(), false );
+ aFormatStyle.SetFont( 1 );
+ aFormatStyle.SetNumFmt( 43 );
+ AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_COMMA );
+ aFormatStyle.SetNumFmt( 41 );
+ AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_COMMA_0 );
+ aFormatStyle.SetNumFmt( 44 );
+ AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_CURRENCY );
+ aFormatStyle.SetNumFmt( 42 );
+ AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_CURRENCY_0 );
+ aFormatStyle.SetNumFmt( 9 );
+ AppendBuiltInXFWithStyle( XclExpXFRef( new XclExpDefaultXF( aFormatStyle ) ), EXC_STYLE_PERCENT );
+
+ // other built-in style XF records (i.e. Hyperlink styles) are created on demand
+
+ /* Insert the real default hard cell format -> 0 is document default pattern.
+ Do it here (and not already above) to really have all built-in styles. */
+ Insert( 0, GetDefApiScript() );
+}
+
+void XclExpXFBuffer::AppendXFIndex( sal_uInt32 nXFId )
+{
+ DBG_ASSERT( nXFId < maXFIndexVec.size(), "XclExpXFBuffer::AppendXFIndex - XF ID out of range" );
+ maXFIndexVec[ nXFId ] = static_cast< sal_uInt16 >( maSortedXFList.GetSize() );
+ XclExpXFRef xXF = maXFList.GetRecord( nXFId );
+ AddBorderAndFill( *xXF );
+ maSortedXFList.AppendRecord( xXF );
+ DBG_ASSERT( maXFList.HasRecord( nXFId ), "XclExpXFBuffer::AppendXFIndex - XF not found" );
+}
+
+void XclExpXFBuffer::AddBorderAndFill( const XclExpXF& rXF )
+{
+ if( std::find_if( maBorders.begin(), maBorders.end(), XclExpBorderPred( rXF.GetBorderData() ) ) == maBorders.end() )
+ {
+ maBorders.push_back( rXF.GetBorderData() );
+ }
+
+ if( std::find_if( maFills.begin(), maFills.end(), XclExpFillPred( rXF.GetAreaData() ) ) == maFills.end() )
+ {
+ maFills.push_back( rXF.GetAreaData() );
+ }
+}
+
+// ============================================================================
+
+XclExpXmlStyleSheet::XclExpXmlStyleSheet( const XclExpRoot& rRoot )
+ : XclExpRoot( rRoot )
+{
+}
+
+void XclExpXmlStyleSheet::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr aStyleSheet = rStrm.CreateOutputStream(
+ OUString(RTL_CONSTASCII_USTRINGPARAM( "xl/styles.xml") ),
+ OUString(RTL_CONSTASCII_USTRINGPARAM( "styles.xml" )),
+ rStrm.GetCurrentStream()->getOutputStream(),
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" );
+ rStrm.PushStream( aStyleSheet );
+
+ aStyleSheet->startElement( XML_styleSheet,
+ XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
+ FSEND );
+
+ CreateRecord( EXC_ID_FORMATLIST )->SaveXml( rStrm );
+ CreateRecord( EXC_ID_FONTLIST )->SaveXml( rStrm );
+ CreateRecord( EXC_ID_XFLIST )->SaveXml( rStrm );
+ CreateRecord( EXC_ID_PALETTE )->SaveXml( rStrm );
+
+ aStyleSheet->endElement( XML_styleSheet );
+
+ rStrm.PopStream();
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xetable.cxx b/sc/source/filter/excel/xetable.cxx
new file mode 100644
index 000000000000..09f9752caea2
--- /dev/null
+++ b/sc/source/filter/excel/xetable.cxx
@@ -0,0 +1,2443 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xetable.hxx"
+
+#include <map>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include "scitems.hxx"
+#include <svl/intitem.hxx>
+#include "document.hxx"
+#include "dociter.hxx"
+#include "olinetab.hxx"
+#include "cell.hxx"
+#include "patattr.hxx"
+#include "attrib.hxx"
+#include "xehelper.hxx"
+#include "xecontent.hxx"
+#include "xeescher.hxx"
+
+using namespace ::oox;
+
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
+
+// ============================================================================
+// Helper records for cell records
+// ============================================================================
+
+XclExpStringRec::XclExpStringRec( const XclExpRoot& rRoot, const String& rResult ) :
+ XclExpRecord( EXC_ID3_STRING ),
+ mxResult( XclExpStringHelper::CreateString( rRoot, rResult ) )
+{
+ DBG_ASSERT( (rRoot.GetBiff() <= EXC_BIFF5) || (mxResult->Len() > 0),
+ "XclExpStringRec::XclExpStringRec - empty result not allowed in BIFF8+" );
+ SetRecSize( mxResult->GetSize() );
+}
+
+void XclExpStringRec::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << *mxResult;
+}
+
+// Additional records for special formula ranges ==============================
+
+XclExpRangeFmlaBase::XclExpRangeFmlaBase(
+ sal_uInt16 nRecId, sal_uInt32 nRecSize, const ScAddress& rScPos ) :
+ XclExpRecord( nRecId, nRecSize ),
+ maXclRange( ScAddress::UNINITIALIZED ),
+ maBaseXclPos( ScAddress::UNINITIALIZED )
+{
+ maBaseXclPos.Set( static_cast< sal_uInt16 >( rScPos.Col() ), static_cast< sal_uInt16 >( rScPos.Row() ) );
+ maXclRange.maFirst = maXclRange.maLast = maBaseXclPos;
+}
+
+XclExpRangeFmlaBase::XclExpRangeFmlaBase(
+ sal_uInt16 nRecId, sal_uInt32 nRecSize, const ScRange& rScRange ) :
+ XclExpRecord( nRecId, nRecSize ),
+ maXclRange( ScAddress::UNINITIALIZED ),
+ maBaseXclPos( ScAddress::UNINITIALIZED )
+{
+ maXclRange.Set(
+ static_cast< sal_uInt16 >( rScRange.aStart.Col() ),
+ static_cast< sal_uInt16 >( rScRange.aStart.Row() ),
+ static_cast< sal_uInt16 >( rScRange.aEnd.Col() ),
+ static_cast< sal_uInt16 >( rScRange.aEnd.Row() ) );
+ maBaseXclPos = maXclRange.maFirst;
+}
+
+bool XclExpRangeFmlaBase::IsBasePos( sal_uInt16 nXclCol, sal_uInt32 nXclRow ) const
+{
+ return (maBaseXclPos.mnCol == nXclCol) && (maBaseXclPos.mnRow == nXclRow);
+}
+
+void XclExpRangeFmlaBase::Extend( const ScAddress& rScPos )
+{
+ sal_uInt16 nXclCol = static_cast< sal_uInt16 >( rScPos.Col() );
+ sal_uInt32 nXclRow = static_cast< sal_uInt32 >( rScPos.Row() );
+ maXclRange.maFirst.mnCol = ::std::min( maXclRange.maFirst.mnCol, nXclCol );
+ maXclRange.maFirst.mnRow = ::std::min( maXclRange.maFirst.mnRow, nXclRow );
+ maXclRange.maLast.mnCol = ::std::max( maXclRange.maLast.mnCol, nXclCol );
+ maXclRange.maLast.mnRow = ::std::max( maXclRange.maLast.mnRow, nXclRow );
+}
+
+void XclExpRangeFmlaBase::WriteRangeAddress( XclExpStream& rStrm ) const
+{
+ maXclRange.Write( rStrm, false );
+}
+
+// Array formulas =============================================================
+
+XclExpArray::XclExpArray( XclTokenArrayRef xTokArr, const ScRange& rScRange ) :
+ XclExpRangeFmlaBase( EXC_ID3_ARRAY, 14 + xTokArr->GetSize(), rScRange ),
+ mxTokArr( xTokArr )
+{
+}
+
+XclTokenArrayRef XclExpArray::CreateCellTokenArray( const XclExpRoot& rRoot ) const
+{
+ return rRoot.GetFormulaCompiler().CreateSpecialRefFormula( EXC_TOKID_EXP, maBaseXclPos );
+}
+
+bool XclExpArray::IsVolatile() const
+{
+ return mxTokArr->IsVolatile();
+}
+
+void XclExpArray::WriteBody( XclExpStream& rStrm )
+{
+ WriteRangeAddress( rStrm );
+ sal_uInt16 nFlags = EXC_ARRAY_DEFAULTFLAGS;
+ ::set_flag( nFlags, EXC_ARRAY_RECALC_ALWAYS, IsVolatile() );
+ rStrm << nFlags << sal_uInt32( 0 ) << *mxTokArr;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpArrayBuffer::XclExpArrayBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+XclExpArrayRef XclExpArrayBuffer::CreateArray( const ScTokenArray& rScTokArr, const ScRange& rScRange )
+{
+ const ScAddress& rScPos = rScRange.aStart;
+ XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_MATRIX, rScTokArr, &rScPos );
+
+ DBG_ASSERT( maRecMap.find( rScPos ) == maRecMap.end(), "XclExpArrayBuffer::CreateArray - array exists already" );
+ XclExpArrayRef& rxRec = maRecMap[ rScPos ];
+ rxRec.reset( new XclExpArray( xTokArr, rScRange ) );
+ return rxRec;
+}
+
+XclExpArrayRef XclExpArrayBuffer::FindArray( const ScTokenArray& rScTokArr ) const
+{
+ XclExpArrayRef xRec;
+ // try to extract a matrix reference token
+ if( rScTokArr.GetLen() == 1 )
+ {
+ const formula::FormulaToken* pToken = rScTokArr.GetArray()[ 0 ];
+ if( pToken && (pToken->GetOpCode() == ocMatRef) )
+ {
+ const ScSingleRefData& rRef = static_cast<const ScToken*>(pToken)->GetSingleRef();
+ ScAddress aBasePos( rRef.nCol, rRef.nRow, GetCurrScTab() );
+ XclExpArrayMap::const_iterator aIt = maRecMap.find( aBasePos );
+ if( aIt != maRecMap.end() )
+ xRec = aIt->second;
+ }
+ }
+ return xRec;
+}
+
+// Shared formulas ============================================================
+
+XclExpShrfmla::XclExpShrfmla( XclTokenArrayRef xTokArr, const ScAddress& rScPos ) :
+ XclExpRangeFmlaBase( EXC_ID_SHRFMLA, 10 + xTokArr->GetSize(), rScPos ),
+ mxTokArr( xTokArr ),
+ mnUsedCount( 1 )
+{
+}
+
+void XclExpShrfmla::ExtendRange( const ScAddress& rScPos )
+{
+ Extend( rScPos );
+ ++mnUsedCount;
+}
+
+XclTokenArrayRef XclExpShrfmla::CreateCellTokenArray( const XclExpRoot& rRoot ) const
+{
+ return rRoot.GetFormulaCompiler().CreateSpecialRefFormula( EXC_TOKID_EXP, maBaseXclPos );
+}
+
+bool XclExpShrfmla::IsVolatile() const
+{
+ return mxTokArr->IsVolatile();
+}
+
+void XclExpShrfmla::WriteBody( XclExpStream& rStrm )
+{
+ WriteRangeAddress( rStrm );
+ rStrm << sal_uInt8( 0 ) << mnUsedCount << *mxTokArr;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpShrfmlaBuffer::XclExpShrfmlaBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+XclExpShrfmlaRef XclExpShrfmlaBuffer::CreateOrExtendShrfmla(
+ const ScTokenArray& rScTokArr, const ScAddress& rScPos )
+{
+ XclExpShrfmlaRef xRec;
+ if( const ScTokenArray* pShrdScTokArr = XclTokenArrayHelper::GetSharedFormula( GetRoot(), rScTokArr ) )
+ {
+ XclExpShrfmlaMap::iterator aIt = maRecMap.find( pShrdScTokArr );
+ if( aIt == maRecMap.end() )
+ {
+ // create a new record
+ XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_SHARED, *pShrdScTokArr, &rScPos );
+ xRec.reset( new XclExpShrfmla( xTokArr, rScPos ) );
+ maRecMap[ pShrdScTokArr ] = xRec;
+ }
+ else
+ {
+ // extend existing record
+ DBG_ASSERT( aIt->second, "XclExpShrfmlaBuffer::CreateOrExtendShrfmla - missing record" );
+ xRec = aIt->second;
+ xRec->ExtendRange( rScPos );
+ }
+ }
+ return xRec;
+}
+
+// Multiple operations ========================================================
+
+XclExpTableop::XclExpTableop( const ScAddress& rScPos,
+ const XclMultipleOpRefs& rRefs, sal_uInt8 nScMode ) :
+ XclExpRangeFmlaBase( EXC_ID3_TABLEOP, 16, rScPos ),
+ mnLastAppXclCol( static_cast< sal_uInt16 >( rScPos.Col() ) ),
+ mnColInpXclCol( static_cast< sal_uInt16 >( rRefs.maColFirstScPos.Col() ) ),
+ mnColInpXclRow( static_cast< sal_uInt16 >( rRefs.maColFirstScPos.Row() ) ),
+ mnRowInpXclCol( static_cast< sal_uInt16 >( rRefs.maRowFirstScPos.Col() ) ),
+ mnRowInpXclRow( static_cast< sal_uInt16 >( rRefs.maRowFirstScPos.Row() ) ),
+ mnScMode( nScMode ),
+ mbValid( false )
+{
+}
+
+bool XclExpTableop::TryExtend( const ScAddress& rScPos, const XclMultipleOpRefs& rRefs )
+{
+ sal_uInt16 nXclCol = static_cast< sal_uInt16 >( rScPos.Col() );
+ sal_uInt16 nXclRow = static_cast< sal_uInt16 >( rScPos.Row() );
+
+ bool bOk = IsAppendable( nXclCol, nXclRow );
+ if( bOk )
+ {
+ SCCOL nFirstScCol = static_cast< SCCOL >( maXclRange.maFirst.mnCol );
+ SCROW nFirstScRow = static_cast< SCROW >( maXclRange.maFirst.mnRow );
+ SCCOL nColInpScCol = static_cast< SCCOL >( mnColInpXclCol );
+ SCROW nColInpScRow = static_cast< SCROW >( mnColInpXclRow );
+ SCCOL nRowInpScCol = static_cast< SCCOL >( mnRowInpXclCol );
+ SCROW nRowInpScRow = static_cast< SCROW >( mnRowInpXclRow );
+
+ bOk = ((mnScMode == 2) == rRefs.mbDblRefMode) &&
+ (rScPos.Tab() == rRefs.maFmlaScPos.Tab()) &&
+ (nColInpScCol == rRefs.maColFirstScPos.Col()) &&
+ (nColInpScRow == rRefs.maColFirstScPos.Row()) &&
+ (rScPos.Tab() == rRefs.maColFirstScPos.Tab()) &&
+ (rScPos.Tab() == rRefs.maColRelScPos.Tab());
+
+ if( bOk ) switch( mnScMode )
+ {
+ case 0:
+ bOk = (rScPos.Col() == rRefs.maFmlaScPos.Col()) &&
+ (nFirstScRow == rRefs.maFmlaScPos.Row() + 1) &&
+ (nFirstScCol == rRefs.maColRelScPos.Col() + 1) &&
+ (rScPos.Row() == rRefs.maColRelScPos.Row());
+ break;
+ case 1:
+ bOk = (nFirstScCol == rRefs.maFmlaScPos.Col() + 1) &&
+ (rScPos.Row() == rRefs.maFmlaScPos.Row()) &&
+ (rScPos.Col() == rRefs.maColRelScPos.Col()) &&
+ (nFirstScRow == rRefs.maColRelScPos.Row() + 1);
+ break;
+ case 2:
+ bOk = (nFirstScCol == rRefs.maFmlaScPos.Col() + 1) &&
+ (nFirstScRow == rRefs.maFmlaScPos.Row() + 1) &&
+ (nFirstScCol == rRefs.maColRelScPos.Col() + 1) &&
+ (rScPos.Row() == rRefs.maColRelScPos.Row()) &&
+ (nRowInpScCol == rRefs.maRowFirstScPos.Col()) &&
+ (nRowInpScRow == rRefs.maRowFirstScPos.Row()) &&
+ (rScPos.Tab() == rRefs.maRowFirstScPos.Tab()) &&
+ (rScPos.Col() == rRefs.maRowRelScPos.Col()) &&
+ (nFirstScRow == rRefs.maRowRelScPos.Row() + 1) &&
+ (rScPos.Tab() == rRefs.maRowRelScPos.Tab());
+ break;
+ default:
+ bOk = false;
+ }
+
+ if( bOk )
+ {
+ // extend the cell range
+ DBG_ASSERT( IsAppendable( nXclCol, nXclRow ), "XclExpTableop::TryExtend - wrong cell address" );
+ Extend( rScPos );
+ mnLastAppXclCol = nXclCol;
+ }
+ }
+
+ return bOk;
+}
+
+void XclExpTableop::Finalize()
+{
+ // is the range complete? (last appended cell is in last column)
+ mbValid = maXclRange.maLast.mnCol == mnLastAppXclCol;
+ // if last row is incomplete, try to shorten the used range
+ if( !mbValid && (maXclRange.maFirst.mnRow < maXclRange.maLast.mnRow) )
+ {
+ --maXclRange.maLast.mnRow;
+ mbValid = true;
+ }
+
+ // check if referred cells are outside of own range
+ if( mbValid ) switch( mnScMode )
+ {
+ case 0:
+ mbValid = (mnColInpXclCol + 1 < maXclRange.maFirst.mnCol) || (mnColInpXclCol > maXclRange.maLast.mnCol) ||
+ (mnColInpXclRow < maXclRange.maFirst.mnRow) || (mnColInpXclRow > maXclRange.maLast.mnRow);
+ break;
+ case 1:
+ mbValid = (mnColInpXclCol < maXclRange.maFirst.mnCol) || (mnColInpXclCol > maXclRange.maLast.mnCol) ||
+ (mnColInpXclRow + 1 < maXclRange.maFirst.mnRow) || (mnColInpXclRow > maXclRange.maLast.mnRow);
+ break;
+ case 2:
+ mbValid = ((mnColInpXclCol + 1 < maXclRange.maFirst.mnCol) || (mnColInpXclCol > maXclRange.maLast.mnCol) ||
+ (mnColInpXclRow + 1 < maXclRange.maFirst.mnRow) || (mnColInpXclRow > maXclRange.maLast.mnRow)) &&
+ ((mnRowInpXclCol + 1 < maXclRange.maFirst.mnCol) || (mnRowInpXclCol > maXclRange.maLast.mnCol) ||
+ (mnRowInpXclRow + 1 < maXclRange.maFirst.mnRow) || (mnRowInpXclRow > maXclRange.maLast.mnRow));
+ break;
+ }
+}
+
+XclTokenArrayRef XclExpTableop::CreateCellTokenArray( const XclExpRoot& rRoot ) const
+{
+ XclExpFormulaCompiler& rFmlaComp = rRoot.GetFormulaCompiler();
+ return mbValid ?
+ rFmlaComp.CreateSpecialRefFormula( EXC_TOKID_TBL, maBaseXclPos ) :
+ rFmlaComp.CreateErrorFormula( EXC_ERR_NA );
+}
+
+bool XclExpTableop::IsVolatile() const
+{
+ return true;
+}
+
+void XclExpTableop::Save( XclExpStream& rStrm )
+{
+ if( mbValid )
+ XclExpRangeFmlaBase::Save( rStrm );
+}
+
+bool XclExpTableop::IsAppendable( sal_uInt16 nXclCol, sal_uInt16 nXclRow ) const
+{
+ return ((nXclCol == mnLastAppXclCol + 1) && (nXclRow == maXclRange.maFirst.mnRow)) ||
+ ((nXclCol == mnLastAppXclCol + 1) && (nXclCol <= maXclRange.maLast.mnCol) && (nXclRow == maXclRange.maLast.mnRow)) ||
+ ((mnLastAppXclCol == maXclRange.maLast.mnCol) && (nXclCol == maXclRange.maFirst.mnCol) && (nXclRow == maXclRange.maLast.mnRow + 1));
+}
+
+void XclExpTableop::WriteBody( XclExpStream& rStrm )
+{
+ sal_uInt16 nFlags = EXC_TABLEOP_DEFAULTFLAGS;
+ ::set_flag( nFlags, EXC_TABLEOP_RECALC_ALWAYS, IsVolatile() );
+ switch( mnScMode )
+ {
+ case 1: ::set_flag( nFlags, EXC_TABLEOP_ROW ); break;
+ case 2: ::set_flag( nFlags, EXC_TABLEOP_BOTH ); break;
+ }
+
+ WriteRangeAddress( rStrm );
+ rStrm << nFlags;
+ if( mnScMode == 2 )
+ rStrm << mnRowInpXclRow << mnRowInpXclCol << mnColInpXclRow << mnColInpXclCol;
+ else
+ rStrm << mnColInpXclRow << mnColInpXclCol << sal_uInt32( 0 );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpTableopBuffer::XclExpTableopBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+XclExpTableopRef XclExpTableopBuffer::CreateOrExtendTableop(
+ const ScTokenArray& rScTokArr, const ScAddress& rScPos )
+{
+ XclExpTableopRef xRec;
+
+ // try to extract cell references of a multiple operations formula
+ XclMultipleOpRefs aRefs;
+ if( XclTokenArrayHelper::GetMultipleOpRefs( aRefs, rScTokArr ) )
+ {
+ // try to find an existing TABLEOP record for this cell position
+ for( size_t nPos = 0, nSize = maTableopList.GetSize(); !xRec && (nPos < nSize); ++nPos )
+ {
+ XclExpTableopRef xTempRec = maTableopList.GetRecord( nPos );
+ if( xTempRec->TryExtend( rScPos, aRefs ) )
+ xRec = xTempRec;
+ }
+
+ // no record found, or found record not extensible
+ if( !xRec )
+ xRec = TryCreate( rScPos, aRefs );
+ }
+
+ return xRec;
+}
+
+void XclExpTableopBuffer::Finalize()
+{
+ for( size_t nPos = 0, nSize = maTableopList.GetSize(); nPos < nSize; ++nPos )
+ maTableopList.GetRecord( nPos )->Finalize();
+}
+
+XclExpTableopRef XclExpTableopBuffer::TryCreate( const ScAddress& rScPos, const XclMultipleOpRefs& rRefs )
+{
+ sal_uInt8 nScMode = 0;
+ bool bOk = (rScPos.Tab() == rRefs.maFmlaScPos.Tab()) &&
+ (rScPos.Tab() == rRefs.maColFirstScPos.Tab()) &&
+ (rScPos.Tab() == rRefs.maColRelScPos.Tab());
+
+ if( bOk )
+ {
+ if( rRefs.mbDblRefMode )
+ {
+ nScMode = 2;
+ bOk = (rScPos.Col() == rRefs.maFmlaScPos.Col() + 1) &&
+ (rScPos.Row() == rRefs.maFmlaScPos.Row() + 1) &&
+ (rScPos.Col() == rRefs.maColRelScPos.Col() + 1) &&
+ (rScPos.Row() == rRefs.maColRelScPos.Row()) &&
+ (rScPos.Tab() == rRefs.maRowFirstScPos.Tab()) &&
+ (rScPos.Col() == rRefs.maRowRelScPos.Col()) &&
+ (rScPos.Row() == rRefs.maRowRelScPos.Row() + 1) &&
+ (rScPos.Tab() == rRefs.maRowRelScPos.Tab());
+ }
+ else if( (rScPos.Col() == rRefs.maFmlaScPos.Col()) &&
+ (rScPos.Row() == rRefs.maFmlaScPos.Row() + 1) &&
+ (rScPos.Col() == rRefs.maColRelScPos.Col() + 1) &&
+ (rScPos.Row() == rRefs.maColRelScPos.Row()) )
+ {
+ nScMode = 0;
+ }
+ else if( (rScPos.Col() == rRefs.maFmlaScPos.Col() + 1) &&
+ (rScPos.Row() == rRefs.maFmlaScPos.Row()) &&
+ (rScPos.Col() == rRefs.maColRelScPos.Col()) &&
+ (rScPos.Row() == rRefs.maColRelScPos.Row() + 1) )
+ {
+ nScMode = 1;
+ }
+ else
+ {
+ bOk = false;
+ }
+ }
+
+ XclExpTableopRef xRec;
+ if( bOk )
+ {
+ xRec.reset( new XclExpTableop( rScPos, rRefs, nScMode ) );
+ maTableopList.AppendRecord( xRec );
+ }
+
+ return xRec;
+}
+
+// ============================================================================
+// Cell records
+// ============================================================================
+
+XclExpCellBase::XclExpCellBase(
+ sal_uInt16 nRecId, sal_Size nContSize, const XclAddress& rXclPos ) :
+ XclExpRecord( nRecId, nContSize + 4 ),
+ maXclPos( rXclPos )
+{
+}
+
+bool XclExpCellBase::IsMultiLineText() const
+{
+ return false;
+}
+
+bool XclExpCellBase::TryMerge( const XclExpCellBase& /*rCell*/ )
+{
+ return false;
+}
+
+void XclExpCellBase::GetBlankXFIndexes( ScfUInt16Vec& /*rXFIndexes*/ ) const
+{
+ // default: do nothing
+}
+
+void XclExpCellBase::RemoveUnusedBlankCells( const ScfUInt16Vec& /*rXFIndexes*/ )
+{
+ // default: do nothing
+}
+
+// Single cell records ========================================================
+
+XclExpSingleCellBase::XclExpSingleCellBase(
+ sal_uInt16 nRecId, sal_Size nContSize, const XclAddress& rXclPos, sal_uInt32 nXFId ) :
+ XclExpCellBase( nRecId, 2, rXclPos ),
+ maXFId( nXFId ),
+ mnContSize( nContSize )
+{
+}
+
+XclExpSingleCellBase::XclExpSingleCellBase( const XclExpRoot& rRoot,
+ sal_uInt16 nRecId, sal_Size nContSize, const XclAddress& rXclPos,
+ const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uInt32 nForcedXFId ) :
+ XclExpCellBase( nRecId, 2, rXclPos ),
+ maXFId( nForcedXFId ),
+ mnContSize( nContSize )
+{
+ if( GetXFId() == EXC_XFID_NOTFOUND )
+ SetXFId( rRoot.GetXFBuffer().Insert( pPattern, nScript ) );
+}
+
+sal_uInt16 XclExpSingleCellBase::GetLastXclCol() const
+{
+ return GetXclCol();
+}
+
+sal_uInt32 XclExpSingleCellBase::GetFirstXFId() const
+{
+ return GetXFId();
+}
+
+bool XclExpSingleCellBase::IsEmpty() const
+{
+ return false;
+}
+
+void XclExpSingleCellBase::ConvertXFIndexes( const XclExpRoot& rRoot )
+{
+ maXFId.ConvertXFIndex( rRoot );
+}
+
+void XclExpSingleCellBase::Save( XclExpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( rStrm.GetRoot().GetBiff() >= EXC_BIFF3 );
+ AddRecSize( mnContSize );
+ XclExpCellBase::Save( rStrm );
+}
+
+void XclExpSingleCellBase::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << static_cast<sal_uInt16> (GetXclRow()) << GetXclCol() << maXFId.mnXFIndex;
+ WriteContents( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+IMPL_FIXEDMEMPOOL_NEWDEL( XclExpNumberCell, 256, 256 )
+
+XclExpNumberCell::XclExpNumberCell(
+ const XclExpRoot& rRoot, const XclAddress& rXclPos,
+ const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, double fValue ) :
+ // #i41210# always use latin script for number cells - may look wrong for special number formats...
+ XclExpSingleCellBase( rRoot, EXC_ID3_NUMBER, 8, rXclPos, pPattern, ApiScriptType::LATIN, nForcedXFId ),
+ mfValue( fValue )
+{
+}
+
+static OString lcl_GetStyleId( XclExpXmlStream& rStrm, sal_uInt32 nXFIndex )
+{
+ return OString::valueOf( rStrm.GetRoot().GetXFBuffer()
+ .GetXmlCellIndex( nXFIndex ) );
+}
+
+static OString lcl_GetStyleId( XclExpXmlStream& rStrm, const XclExpCellBase& rCell )
+{
+ sal_uInt32 nXFId = rCell.GetFirstXFId();
+ sal_uInt16 nXFIndex = rStrm.GetRoot().GetXFBuffer().GetXFIndex( nXFId );
+ return lcl_GetStyleId( rStrm, nXFIndex );
+}
+
+void XclExpNumberCell::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_c,
+ XML_r, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
+ XML_s, lcl_GetStyleId( rStrm, *this ).getStr(),
+ XML_t, "n",
+ // OOXTODO: XML_cm, XML_vm, XML_ph
+ FSEND );
+ rWorksheet->startElement( XML_v, FSEND );
+ rWorksheet->write( mfValue );
+ rWorksheet->endElement( XML_v );
+ rWorksheet->endElement( XML_c );
+}
+
+void XclExpNumberCell::WriteContents( XclExpStream& rStrm )
+{
+ rStrm << mfValue;
+}
+
+// ----------------------------------------------------------------------------
+
+IMPL_FIXEDMEMPOOL_NEWDEL( XclExpBooleanCell, 256, 256 )
+
+XclExpBooleanCell::XclExpBooleanCell(
+ const XclExpRoot rRoot, const XclAddress& rXclPos,
+ const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, bool bValue ) :
+ // #i41210# always use latin script for boolean cells
+ XclExpSingleCellBase( rRoot, EXC_ID3_BOOLERR, 2, rXclPos, pPattern, ApiScriptType::LATIN, nForcedXFId ),
+ mbValue( bValue )
+{
+}
+
+void XclExpBooleanCell::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_c,
+ XML_r, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
+ XML_s, lcl_GetStyleId( rStrm, *this ).getStr(),
+ XML_t, "b",
+ // OOXTODO: XML_cm, XML_vm, XML_ph
+ FSEND );
+ rWorksheet->startElement( XML_v, FSEND );
+ rWorksheet->write( mbValue ? "1" : "0" );
+ rWorksheet->endElement( XML_v );
+ rWorksheet->endElement( XML_c );
+}
+
+void XclExpBooleanCell::WriteContents( XclExpStream& rStrm )
+{
+ rStrm << sal_uInt16( mbValue ? 1 : 0 ) << EXC_BOOLERR_BOOL;
+}
+
+IMPL_FIXEDMEMPOOL_NEWDEL( XclExpLabelCell, 256, 256 )
+
+XclExpLabelCell::XclExpLabelCell(
+ const XclExpRoot& rRoot, const XclAddress& rXclPos,
+ const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, const ScStringCell& rCell ) :
+ XclExpSingleCellBase( EXC_ID3_LABEL, 0, rXclPos, nForcedXFId )
+{
+ sal_uInt16 nMaxLen = (rRoot.GetBiff() == EXC_BIFF8) ? EXC_STR_MAXLEN : EXC_LABEL_MAXLEN;
+ XclExpStringRef xText = XclExpStringHelper::CreateCellString( rRoot, rCell, pPattern, EXC_STR_DEFAULT, nMaxLen );
+ Init( rRoot, pPattern, xText );
+}
+
+XclExpLabelCell::XclExpLabelCell(
+ const XclExpRoot& rRoot, const XclAddress& rXclPos,
+ const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
+ const ScEditCell& rCell, XclExpHyperlinkHelper& rLinkHelper ) :
+ XclExpSingleCellBase( EXC_ID3_LABEL, 0, rXclPos, nForcedXFId )
+{
+ sal_uInt16 nMaxLen = (rRoot.GetBiff() == EXC_BIFF8) ? EXC_STR_MAXLEN : EXC_LABEL_MAXLEN;
+ XclExpStringRef xText = XclExpStringHelper::CreateCellString( rRoot, rCell, pPattern, rLinkHelper, EXC_STR_DEFAULT, nMaxLen );
+ Init( rRoot, pPattern, xText );
+}
+
+bool XclExpLabelCell::IsMultiLineText() const
+{
+ return mbLineBreak || mxText->IsWrapped();
+}
+
+void XclExpLabelCell::Init( const XclExpRoot& rRoot,
+ const ScPatternAttr* pPattern, XclExpStringRef xText )
+{
+ DBG_ASSERT( xText && xText->Len(), "XclExpLabelCell::XclExpLabelCell - empty string passed" );
+ mxText = xText;
+ mnSstIndex = 0;
+
+ // create the cell format
+ sal_uInt16 nXclFont = mxText->RemoveLeadingFont();
+ if( GetXFId() == EXC_XFID_NOTFOUND )
+ {
+ DBG_ASSERT( nXclFont != EXC_FONT_NOTFOUND, "XclExpLabelCell::Init - leading font not found" );
+ bool bForceLineBreak = mxText->IsWrapped();
+ SetXFId( rRoot.GetXFBuffer().InsertWithFont( pPattern, ApiScriptType::WEAK, nXclFont, bForceLineBreak ) );
+ }
+
+ // get auto-wrap attribute from cell format
+ const XclExpXF* pXF = rRoot.GetXFBuffer().GetXFById( GetXFId() );
+ mbLineBreak = pXF && pXF->GetAlignmentData().mbLineBreak;
+
+ // initialize the record contents
+ switch( rRoot.GetBiff() )
+ {
+ case EXC_BIFF5:
+ // BIFF5-BIFF7: create a LABEL or RSTRING record
+ DBG_ASSERT( mxText->Len() <= EXC_LABEL_MAXLEN, "XclExpLabelCell::XclExpLabelCell - string too long" );
+ SetContSize( mxText->GetSize() );
+ // formatted string is exported in an RSTRING record
+ if( mxText->IsRich() )
+ {
+ DBG_ASSERT( mxText->GetFormatsCount() <= EXC_LABEL_MAXLEN, "XclExpLabelCell::WriteContents - too many formats" );
+ mxText->LimitFormatCount( EXC_LABEL_MAXLEN );
+ SetRecId( EXC_ID_RSTRING );
+ SetContSize( GetContSize() + 1 + 2 * mxText->GetFormatsCount() );
+ }
+ break;
+ case EXC_BIFF8:
+ // BIFF8+: create a LABELSST record
+ mnSstIndex = rRoot.GetSst().Insert( xText );
+ SetRecId( EXC_ID_LABELSST );
+ SetContSize( 4 );
+ break;
+ default: DBG_ERROR_BIFF();
+ }
+}
+
+void XclExpLabelCell::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_c,
+ XML_r, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
+ XML_s, lcl_GetStyleId( rStrm, *this ).getStr(),
+ XML_t, "s",
+ // OOXTODO: XML_cm, XML_vm, XML_ph
+ FSEND );
+ rWorksheet->startElement( XML_v, FSEND );
+ rWorksheet->write( (sal_Int32) mnSstIndex );
+ rWorksheet->endElement( XML_v );
+ rWorksheet->endElement( XML_c );
+}
+
+void XclExpLabelCell::WriteContents( XclExpStream& rStrm )
+{
+ switch( rStrm.GetRoot().GetBiff() )
+ {
+ case EXC_BIFF5:
+ rStrm << *mxText;
+ if( mxText->IsRich() )
+ {
+ rStrm << static_cast< sal_uInt8 >( mxText->GetFormatsCount() );
+ mxText->WriteFormats( rStrm );
+ }
+ break;
+ case EXC_BIFF8:
+ rStrm << mnSstIndex;
+ break;
+ default: DBG_ERROR_BIFF();
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+IMPL_FIXEDMEMPOOL_NEWDEL( XclExpFormulaCell, 256, 256 )
+
+XclExpFormulaCell::XclExpFormulaCell(
+ const XclExpRoot& rRoot, const XclAddress& rXclPos,
+ const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
+ const ScFormulaCell& rScFmlaCell,
+ XclExpArrayBuffer& rArrayBfr,
+ XclExpShrfmlaBuffer& rShrfmlaBfr,
+ XclExpTableopBuffer& rTableopBfr ) :
+ XclExpSingleCellBase( EXC_ID2_FORMULA, 0, rXclPos, nForcedXFId ),
+ mrScFmlaCell( const_cast< ScFormulaCell& >( rScFmlaCell ) )
+{
+ // *** Find result number format overwriting cell number format *** -------
+
+ if( GetXFId() == EXC_XFID_NOTFOUND )
+ {
+ SvNumberFormatter& rFormatter = rRoot.GetFormatter();
+ XclExpNumFmtBuffer& rNumFmtBfr = rRoot.GetNumFmtBuffer();
+
+ // current cell number format
+ sal_uLong nScNumFmt = pPattern ?
+ GETITEMVALUE( pPattern->GetItemSet(), SfxUInt32Item, ATTR_VALUE_FORMAT, sal_uLong ) :
+ rNumFmtBfr.GetStandardFormat();
+
+ // alternative number format passed to XF buffer
+ sal_uLong nAltScNumFmt = NUMBERFORMAT_ENTRY_NOT_FOUND;
+ /* Xcl doesn't know Boolean number formats, we write
+ "TRUE";"FALSE" (language dependent). Don't do it for automatic
+ formula formats, because Excel gets them right. */
+ /* #i8640# Don't set text format, if we have string results. */
+ short nFormatType = mrScFmlaCell.GetFormatType();
+ if( ((nScNumFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0) &&
+ (nFormatType != NUMBERFORMAT_LOGICAL) &&
+ (nFormatType != NUMBERFORMAT_TEXT) )
+ nAltScNumFmt = mrScFmlaCell.GetStandardFormat( rFormatter, nScNumFmt );
+ /* If cell number format is Boolean and automatic formula
+ format is Boolean don't write that ugly special format. */
+ else if( (nFormatType == NUMBERFORMAT_LOGICAL) &&
+ (rFormatter.GetType( nScNumFmt ) == NUMBERFORMAT_LOGICAL) )
+ nAltScNumFmt = rNumFmtBfr.GetStandardFormat();
+
+ // #i41420# find script type according to result type (always latin for numeric results)
+ sal_Int16 nScript = ApiScriptType::LATIN;
+ bool bForceLineBreak = false;
+ if( nFormatType == NUMBERFORMAT_TEXT )
+ {
+ String aResult;
+ mrScFmlaCell.GetString( aResult );
+ bForceLineBreak = mrScFmlaCell.IsMultilineResult();
+ nScript = XclExpStringHelper::GetLeadingScriptType( rRoot, aResult );
+ }
+ SetXFId( rRoot.GetXFBuffer().InsertWithNumFmt( pPattern, nScript, nAltScNumFmt, bForceLineBreak ) );
+ }
+
+ // *** Convert the formula token array *** --------------------------------
+
+ ScAddress aScPos( static_cast< SCCOL >( rXclPos.mnCol ), static_cast< SCROW >( rXclPos.mnRow ), rRoot.GetCurrScTab() );
+ const ScTokenArray& rScTokArr = *mrScFmlaCell.GetCode();
+
+ // first try to create multiple operations
+ mxAddRec = rTableopBfr.CreateOrExtendTableop( rScTokArr, aScPos );
+
+ // no multiple operation found - try to create matrix formula
+ if( !mxAddRec ) switch( static_cast< ScMatrixMode >( mrScFmlaCell.GetMatrixFlag() ) )
+ {
+ case MM_FORMULA:
+ {
+ // origin of the matrix - find the used matrix range
+ SCCOL nMatWidth;
+ SCROW nMatHeight;
+ mrScFmlaCell.GetMatColsRows( nMatWidth, nMatHeight );
+ DBG_ASSERT( nMatWidth && nMatHeight, "XclExpFormulaCell::XclExpFormulaCell - empty matrix" );
+ ScRange aMatScRange( aScPos );
+ ScAddress& rMatEnd = aMatScRange.aEnd;
+ rMatEnd.IncCol( static_cast< SCsCOL >( nMatWidth - 1 ) );
+ rMatEnd.IncRow( static_cast< SCsROW >( nMatHeight - 1 ) );
+ // reduce to valid range (range keeps valid, because start position IS valid)
+ rRoot.GetAddressConverter().ValidateRange( aMatScRange, true );
+ // create the ARRAY record
+ mxAddRec = rArrayBfr.CreateArray( rScTokArr, aMatScRange );
+ }
+ break;
+ case MM_REFERENCE:
+ {
+ // other formula cell covered by a matrix - find the ARRAY record
+ mxAddRec = rArrayBfr.FindArray( rScTokArr );
+ // should always be found, if Calc document is not broken
+ DBG_ASSERT( mxAddRec, "XclExpFormulaCell::XclExpFormulaCell - no matrix found" );
+ }
+ break;
+ default:;
+ }
+
+ // no matrix found - try to create shared formula
+ if( !mxAddRec )
+ mxAddRec = rShrfmlaBfr.CreateOrExtendShrfmla( rScTokArr, aScPos );
+
+ // no shared formula found - create a simple cell formula
+ if( !mxAddRec )
+ mxTokArr = rRoot.GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CELL, rScTokArr, &aScPos );
+}
+
+void XclExpFormulaCell::Save( XclExpStream& rStrm )
+{
+ // create token array for FORMULA cells with additional record
+ if( mxAddRec )
+ mxTokArr = mxAddRec->CreateCellTokenArray( rStrm.GetRoot() );
+
+ // FORMULA record itself
+ DBG_ASSERT( mxTokArr, "XclExpFormulaCell::Save - missing token array" );
+ if( !mxTokArr )
+ mxTokArr = rStrm.GetRoot().GetFormulaCompiler().CreateErrorFormula( EXC_ERR_NA );
+ SetContSize( 16 + mxTokArr->GetSize() );
+ XclExpSingleCellBase::Save( rStrm );
+
+ // additional record (ARRAY, SHRFMLA, or TABLEOP), only for first FORMULA record
+ if( mxAddRec && mxAddRec->IsBasePos( GetXclCol(), GetXclRow() ) )
+ mxAddRec->Save( rStrm );
+
+ // STRING record for string result
+ if( mxStringRec )
+ mxStringRec->Save( rStrm );
+}
+
+void XclExpFormulaCell::SaveXml( XclExpXmlStream& rStrm )
+{
+ const char* sType = NULL;
+ OUString sValue;
+
+ XclXmlUtils::GetFormulaTypeAndValue( mrScFmlaCell, sType, sValue );
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_c,
+ XML_r, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
+ XML_s, lcl_GetStyleId( rStrm, *this ).getStr(),
+ XML_t, sType,
+ // OOXTODO: XML_cm, XML_vm, XML_ph
+ FSEND );
+
+ rWorksheet->startElement( XML_f,
+ // OOXTODO: XML_t, ST_CellFormulaType
+ XML_aca, XclXmlUtils::ToPsz( (mxTokArr && mxTokArr->IsVolatile()) || (mxAddRec && mxAddRec->IsVolatile()) ),
+ // OOXTODO: XML_ref, ST_Ref
+ // OOXTODO: XML_dt2D, bool
+ // OOXTODO: XML_dtr, bool
+ // OOXTODO: XML_del1, bool
+ // OOXTODO: XML_del2, bool
+ // OOXTODO: XML_r1, ST_CellRef
+ // OOXTODO: XML_r2, ST_CellRef
+ // OOXTODO: XML_ca, bool
+ // OOXTODO: XML_si, uint
+ // OOXTODO: XML_bx bool
+ FSEND );
+ rWorksheet->writeEscaped( XclXmlUtils::ToOUString( *mrScFmlaCell.GetDocument(), mrScFmlaCell.aPos, mrScFmlaCell.GetCode() ) );
+ rWorksheet->endElement( XML_f );
+ if( strcmp( sType, "inlineStr" ) == 0 )
+ {
+ rWorksheet->startElement( XML_is, FSEND );
+ rWorksheet->startElement( XML_t, FSEND );
+ rWorksheet->writeEscaped( sValue );
+ rWorksheet->endElement( XML_t );
+ rWorksheet->endElement( XML_is );
+ }
+ else
+ {
+ rWorksheet->startElement( XML_v, FSEND );
+ rWorksheet->writeEscaped( sValue );
+ rWorksheet->endElement( XML_v );
+ }
+ rWorksheet->endElement( XML_c );
+}
+
+void XclExpFormulaCell::WriteContents( XclExpStream& rStrm )
+{
+ // result of the formula
+ switch( mrScFmlaCell.GetFormatType() )
+ {
+ case NUMBERFORMAT_NUMBER:
+ {
+ // either value or error code
+ sal_uInt16 nScErrCode = mrScFmlaCell.GetErrCode();
+ if( nScErrCode )
+ rStrm << EXC_FORMULA_RES_ERROR << sal_uInt8( 0 )
+ << XclTools::GetXclErrorCode( nScErrCode )
+ << sal_uInt8( 0 ) << sal_uInt16( 0 )
+ << sal_uInt16( 0xFFFF );
+ else
+ rStrm << mrScFmlaCell.GetValue();
+ }
+ break;
+
+ case NUMBERFORMAT_TEXT:
+ {
+ String aResult;
+ mrScFmlaCell.GetString( aResult );
+ if( aResult.Len() || (rStrm.GetRoot().GetBiff() <= EXC_BIFF5) )
+ {
+ rStrm << EXC_FORMULA_RES_STRING;
+ mxStringRec.reset( new XclExpStringRec( rStrm.GetRoot(), aResult ) );
+ }
+ else
+ rStrm << EXC_FORMULA_RES_EMPTY; // BIFF8 only
+ rStrm << sal_uInt8( 0 ) << sal_uInt32( 0 ) << sal_uInt16( 0xFFFF );
+ }
+ break;
+
+ case NUMBERFORMAT_LOGICAL:
+ {
+ sal_uInt8 nXclValue = (mrScFmlaCell.GetValue() == 0.0) ? 0 : 1;
+ rStrm << EXC_FORMULA_RES_BOOL << sal_uInt8( 0 )
+ << nXclValue << sal_uInt8( 0 ) << sal_uInt16( 0 )
+ << sal_uInt16( 0xFFFF );
+ }
+ break;
+
+ default:
+ rStrm << mrScFmlaCell.GetValue();
+ }
+
+ // flags and formula token array
+ sal_uInt16 nFlags = EXC_FORMULA_DEFAULTFLAGS;
+ ::set_flag( nFlags, EXC_FORMULA_RECALC_ALWAYS, mxTokArr->IsVolatile() || (mxAddRec && mxAddRec->IsVolatile()) );
+ ::set_flag( nFlags, EXC_FORMULA_SHARED, mxAddRec && (mxAddRec->GetRecId() == EXC_ID_SHRFMLA) );
+ rStrm << nFlags << sal_uInt32( 0 ) << *mxTokArr;
+}
+
+// Multiple cell records ======================================================
+
+XclExpMultiCellBase::XclExpMultiCellBase(
+ sal_uInt16 nRecId, sal_uInt16 nMulRecId, sal_Size nContSize, const XclAddress& rXclPos ) :
+ XclExpCellBase( nRecId, 0, rXclPos ),
+ mnMulRecId( nMulRecId ),
+ mnContSize( nContSize )
+{
+}
+
+sal_uInt16 XclExpMultiCellBase::GetLastXclCol() const
+{
+ return GetXclCol() + GetCellCount() - 1;
+}
+
+sal_uInt32 XclExpMultiCellBase::GetFirstXFId() const
+{
+ return maXFIds.empty() ? XclExpXFBuffer::GetDefCellXFId() : maXFIds.front().mnXFId;
+}
+
+bool XclExpMultiCellBase::IsEmpty() const
+{
+ return maXFIds.empty();
+}
+
+void XclExpMultiCellBase::ConvertXFIndexes( const XclExpRoot& rRoot )
+{
+ for( XclExpMultiXFIdDeq::iterator aIt = maXFIds.begin(), aEnd = maXFIds.end(); aIt != aEnd; ++aIt )
+ aIt->ConvertXFIndex( rRoot );
+}
+
+void XclExpMultiCellBase::Save( XclExpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( rStrm.GetRoot().GetBiff() >= EXC_BIFF3 );
+
+ XclExpMultiXFIdDeq::const_iterator aEnd = maXFIds.end();
+ XclExpMultiXFIdDeq::const_iterator aRangeBeg = maXFIds.begin();
+ XclExpMultiXFIdDeq::const_iterator aRangeEnd = aRangeBeg;
+ sal_uInt16 nBegXclCol = GetXclCol();
+ sal_uInt16 nEndXclCol = nBegXclCol;
+
+ while( aRangeEnd != aEnd )
+ {
+ // find begin of next used XF range
+ aRangeBeg = aRangeEnd;
+ nBegXclCol = nEndXclCol;
+ while( (aRangeBeg != aEnd) && (aRangeBeg->mnXFIndex == EXC_XF_NOTFOUND) )
+ {
+ nBegXclCol = nBegXclCol + aRangeBeg->mnCount;
+ ++aRangeBeg;
+ }
+ // find end of next used XF range
+ aRangeEnd = aRangeBeg;
+ nEndXclCol = nBegXclCol;
+ while( (aRangeEnd != aEnd) && (aRangeEnd->mnXFIndex != EXC_XF_NOTFOUND) )
+ {
+ nEndXclCol = nEndXclCol + aRangeEnd->mnCount;
+ ++aRangeEnd;
+ }
+
+ // export this range as a record
+ if( aRangeBeg != aRangeEnd )
+ {
+ sal_uInt16 nCount = nEndXclCol - nBegXclCol;
+ bool bIsMulti = nCount > 1;
+ sal_Size nTotalSize = GetRecSize() + (2 + mnContSize) * nCount;
+ if( bIsMulti ) nTotalSize += 2;
+
+ rStrm.StartRecord( bIsMulti ? mnMulRecId : GetRecId(), nTotalSize );
+ rStrm << static_cast<sal_uInt16> (GetXclRow()) << nBegXclCol;
+
+ sal_uInt16 nRelCol = nBegXclCol - GetXclCol();
+ for( XclExpMultiXFIdDeq::const_iterator aIt = aRangeBeg; aIt != aRangeEnd; ++aIt )
+ {
+ for( sal_uInt16 nIdx = 0; nIdx < aIt->mnCount; ++nIdx )
+ {
+ rStrm << aIt->mnXFIndex;
+ WriteContents( rStrm, nRelCol );
+ ++nRelCol;
+ }
+ }
+ if( bIsMulti )
+ rStrm << static_cast< sal_uInt16 >( nEndXclCol - 1 );
+ rStrm.EndRecord();
+ }
+ }
+}
+
+void XclExpMultiCellBase::SaveXml( XclExpXmlStream& rStrm )
+{
+ XclExpMultiXFIdDeq::const_iterator aEnd = maXFIds.end();
+ XclExpMultiXFIdDeq::const_iterator aRangeBeg = maXFIds.begin();
+ XclExpMultiXFIdDeq::const_iterator aRangeEnd = aRangeBeg;
+ sal_uInt16 nBegXclCol = GetXclCol();
+ sal_uInt16 nEndXclCol = nBegXclCol;
+
+ while( aRangeEnd != aEnd )
+ {
+ // find begin of next used XF range
+ aRangeBeg = aRangeEnd;
+ nBegXclCol = nEndXclCol;
+ while( (aRangeBeg != aEnd) && (aRangeBeg->mnXFIndex == EXC_XF_NOTFOUND) )
+ {
+ nBegXclCol = nBegXclCol + aRangeBeg->mnCount;
+ ++aRangeBeg;
+ }
+ // find end of next used XF range
+ aRangeEnd = aRangeBeg;
+ nEndXclCol = nBegXclCol;
+ while( (aRangeEnd != aEnd) && (aRangeEnd->mnXFIndex != EXC_XF_NOTFOUND) )
+ {
+ nEndXclCol = nEndXclCol + aRangeEnd->mnCount;
+ ++aRangeEnd;
+ }
+
+ // export this range as a record
+ if( aRangeBeg != aRangeEnd )
+ {
+ sal_uInt16 nRelColIdx = nBegXclCol - GetXclCol();
+ sal_Int32 nRelCol = 0;
+ for( XclExpMultiXFIdDeq::const_iterator aIt = aRangeBeg; aIt != aRangeEnd; ++aIt )
+ {
+ for( sal_uInt16 nIdx = 0; nIdx < aIt->mnCount; ++nIdx )
+ {
+ WriteXmlContents(
+ rStrm,
+ XclAddress( static_cast<sal_uInt16>(nBegXclCol + nRelCol), GetXclRow() ),
+ aIt->mnXFIndex,
+ nRelColIdx );
+ ++nRelCol;
+ ++nRelColIdx;
+ }
+ }
+ }
+ }
+}
+
+sal_uInt16 XclExpMultiCellBase::GetCellCount() const
+{
+ sal_uInt16 nCount = 0;
+ for( XclExpMultiXFIdDeq::const_iterator aIt = maXFIds.begin(), aEnd = maXFIds.end(); aIt != aEnd; ++aIt )
+ nCount = nCount + aIt->mnCount;
+ return nCount;
+}
+
+void XclExpMultiCellBase::AppendXFId( const XclExpMultiXFId& rXFId )
+{
+ if( maXFIds.empty() || (maXFIds.back().mnXFId != rXFId.mnXFId) )
+ maXFIds.push_back( rXFId );
+ else
+ maXFIds.back().mnCount = maXFIds.back().mnCount + rXFId.mnCount;
+}
+
+void XclExpMultiCellBase::AppendXFId( const XclExpRoot& rRoot,
+ const ScPatternAttr* pPattern, sal_uInt16 nScript, sal_uInt32 nForcedXFId, sal_uInt16 nCount )
+{
+ sal_uInt32 nXFId = (nForcedXFId == EXC_XFID_NOTFOUND) ?
+ rRoot.GetXFBuffer().Insert( pPattern, nScript ) : nForcedXFId;
+ AppendXFId( XclExpMultiXFId( nXFId, nCount ) );
+}
+
+bool XclExpMultiCellBase::TryMergeXFIds( const XclExpMultiCellBase& rCell )
+{
+ if( GetLastXclCol() + 1 == rCell.GetXclCol() )
+ {
+ maXFIds.insert( maXFIds.end(), rCell.maXFIds.begin(), rCell.maXFIds.end() );
+ return true;
+ }
+ return false;
+}
+
+void XclExpMultiCellBase::GetXFIndexes( ScfUInt16Vec& rXFIndexes ) const
+{
+ DBG_ASSERT( GetLastXclCol() < rXFIndexes.size(), "XclExpMultiCellBase::GetXFIndexes - vector too small" );
+ ScfUInt16Vec::iterator aDestIt = rXFIndexes.begin() + GetXclCol();
+ for( XclExpMultiXFIdDeq::const_iterator aIt = maXFIds.begin(), aEnd = maXFIds.end(); aIt != aEnd; ++aIt )
+ {
+ ::std::fill( aDestIt, aDestIt + aIt->mnCount, aIt->mnXFIndex );
+ aDestIt += aIt->mnCount;
+ }
+}
+
+void XclExpMultiCellBase::RemoveUnusedXFIndexes( const ScfUInt16Vec& rXFIndexes )
+{
+ // save last column before calling maXFIds.clear()
+ sal_uInt16 nLastXclCol = GetLastXclCol();
+ DBG_ASSERT( nLastXclCol < rXFIndexes.size(), "XclExpMultiCellBase::RemoveUnusedXFIndexes - XF index vector too small" );
+
+ // build new XF index vector, containing passed XF indexes
+ maXFIds.clear();
+ XclExpMultiXFId aXFId( 0 );
+ for( ScfUInt16Vec::const_iterator aIt = rXFIndexes.begin() + GetXclCol(), aEnd = rXFIndexes.begin() + nLastXclCol + 1; aIt != aEnd; ++aIt )
+ {
+ // AppendXFId() tests XclExpXFIndex::mnXFId, set it too
+ aXFId.mnXFId = aXFId.mnXFIndex = *aIt;
+ AppendXFId( aXFId );
+ }
+
+ // remove leading and trailing unused XF indexes
+ if( !maXFIds.empty() && (maXFIds.front().mnXFIndex == EXC_XF_NOTFOUND) )
+ {
+ SetXclCol( GetXclCol() + maXFIds.front().mnCount );
+ maXFIds.pop_front();
+ }
+ if( !maXFIds.empty() && (maXFIds.back().mnXFIndex == EXC_XF_NOTFOUND) )
+ maXFIds.pop_back();
+
+ // The Save() function will skip all XF indexes equal to EXC_XF_NOTFOUND.
+}
+
+// ----------------------------------------------------------------------------
+
+IMPL_FIXEDMEMPOOL_NEWDEL( XclExpBlankCell, 256, 256 )
+
+XclExpBlankCell::XclExpBlankCell( const XclAddress& rXclPos, const XclExpMultiXFId& rXFId ) :
+ XclExpMultiCellBase( EXC_ID3_BLANK, EXC_ID_MULBLANK, 0, rXclPos )
+{
+ DBG_ASSERT( rXFId.mnCount > 0, "XclExpBlankCell::XclExpBlankCell - invalid count" );
+ AppendXFId( rXFId );
+}
+
+XclExpBlankCell::XclExpBlankCell(
+ const XclExpRoot& rRoot, const XclAddress& rXclPos, sal_uInt16 nLastXclCol,
+ const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId ) :
+ XclExpMultiCellBase( EXC_ID3_BLANK, EXC_ID_MULBLANK, 0, rXclPos )
+{
+ DBG_ASSERT( rXclPos.mnCol <= nLastXclCol, "XclExpBlankCell::XclExpBlankCell - invalid column range" );
+ // #i46627# use default script type instead of ApiScriptType::WEAK
+ AppendXFId( rRoot, pPattern, rRoot.GetDefApiScript(), nForcedXFId, nLastXclCol - rXclPos.mnCol + 1 );
+}
+
+bool XclExpBlankCell::TryMerge( const XclExpCellBase& rCell )
+{
+ const XclExpBlankCell* pBlankCell = dynamic_cast< const XclExpBlankCell* >( &rCell );
+ return pBlankCell && TryMergeXFIds( *pBlankCell );
+}
+
+void XclExpBlankCell::GetBlankXFIndexes( ScfUInt16Vec& rXFIndexes ) const
+{
+ GetXFIndexes( rXFIndexes );
+}
+
+void XclExpBlankCell::RemoveUnusedBlankCells( const ScfUInt16Vec& rXFIndexes )
+{
+ RemoveUnusedXFIndexes( rXFIndexes );
+}
+
+void XclExpBlankCell::WriteContents( XclExpStream& /*rStrm*/, sal_uInt16 /*nRelCol*/ )
+{
+}
+
+void XclExpBlankCell::WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 /* nRelCol */ )
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->singleElement( XML_c,
+ XML_r, XclXmlUtils::ToOString( rAddress ).getStr(),
+ XML_s, lcl_GetStyleId( rStrm, nXFId ).getStr(),
+ FSEND );
+}
+
+// ----------------------------------------------------------------------------
+
+IMPL_FIXEDMEMPOOL_NEWDEL( XclExpRkCell, 256, 256 )
+
+XclExpRkCell::XclExpRkCell(
+ const XclExpRoot& rRoot, const XclAddress& rXclPos,
+ const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, sal_Int32 nRkValue ) :
+ XclExpMultiCellBase( EXC_ID_RK, EXC_ID_MULRK, 4, rXclPos )
+{
+ // #i41210# always use latin script for number cells - may look wrong for special number formats...
+ AppendXFId( rRoot, pPattern, ApiScriptType::LATIN, nForcedXFId );
+ maRkValues.push_back( nRkValue );
+}
+
+bool XclExpRkCell::TryMerge( const XclExpCellBase& rCell )
+{
+ const XclExpRkCell* pRkCell = dynamic_cast< const XclExpRkCell* >( &rCell );
+ if( pRkCell && TryMergeXFIds( *pRkCell ) )
+ {
+ maRkValues.insert( maRkValues.end(), pRkCell->maRkValues.begin(), pRkCell->maRkValues.end() );
+ return true;
+ }
+ return false;
+}
+
+void XclExpRkCell::WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 nRelCol )
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_c,
+ XML_r, XclXmlUtils::ToOString( rAddress ).getStr(),
+ XML_s, lcl_GetStyleId( rStrm, nXFId ).getStr(),
+ XML_t, "n",
+ // OOXTODO: XML_cm, XML_vm, XML_ph
+ FSEND );
+ rWorksheet->startElement( XML_v, FSEND );
+ rWorksheet->write( XclTools::GetDoubleFromRK( maRkValues[ nRelCol ] ) );
+ rWorksheet->endElement( XML_v );
+ rWorksheet->endElement( XML_c );
+}
+
+void XclExpRkCell::WriteContents( XclExpStream& rStrm, sal_uInt16 nRelCol )
+{
+ DBG_ASSERT( nRelCol < maRkValues.size(), "XclExpRkCell::WriteContents - overflow error" );
+ rStrm << maRkValues[ nRelCol ];
+}
+
+// ============================================================================
+// Rows and Columns
+// ============================================================================
+
+XclExpOutlineBuffer::XclExpOutlineBuffer( const XclExpRoot& rRoot, bool bRows ) :
+ mpScOLArray( 0 ),
+ maLevelInfos( SC_OL_MAXDEPTH ),
+ mnCurrLevel( 0 ),
+ mbCurrCollapse( false )
+{
+ if( const ScOutlineTable* pOutlineTable = rRoot.GetDoc().GetOutlineTable( rRoot.GetCurrScTab() ) )
+ mpScOLArray = bRows ? pOutlineTable->GetRowArray() : pOutlineTable->GetColArray();
+
+ if( mpScOLArray )
+ for( sal_uInt16 nLevel = 0; nLevel < SC_OL_MAXDEPTH; ++nLevel )
+ if( ScOutlineEntry* pEntry = mpScOLArray->GetEntryByPos( nLevel, 0 ) )
+ maLevelInfos[ nLevel ].mnScEndPos = pEntry->GetEnd();
+}
+
+void XclExpOutlineBuffer::UpdateColRow( SCCOLROW nScPos )
+{
+ if( mpScOLArray )
+ {
+ // find open level index for passed position
+ sal_uInt16 nNewOpenScLevel = 0; // new open level (0-based Calc index)
+ sal_uInt8 nNewLevel = 0; // new open level (1-based Excel index)
+
+ if( mpScOLArray->FindTouchedLevel( nScPos, nScPos, nNewOpenScLevel ) )
+ nNewLevel = static_cast< sal_uInt8 >( nNewOpenScLevel + 1 );
+ // else nNewLevel keeps 0 to show that there are no groups
+
+ mbCurrCollapse = false;
+ if( nNewLevel >= mnCurrLevel )
+ {
+ // new level(s) opened, or no level closed - update all level infos
+ for( sal_uInt16 nScLevel = 0; nScLevel <= nNewOpenScLevel; ++nScLevel )
+ {
+ /* In each level: check if a new group is started (there may be
+ neighbored groups without gap - therefore check ALL levels). */
+ if( maLevelInfos[ nScLevel ].mnScEndPos < nScPos )
+ {
+ if( ScOutlineEntry* pEntry = mpScOLArray->GetEntryByPos( nScLevel, nScPos ) )
+ {
+ maLevelInfos[ nScLevel ].mnScEndPos = pEntry->GetEnd();
+ maLevelInfos[ nScLevel ].mbHidden = pEntry->IsHidden();
+ }
+ }
+ }
+ }
+ else
+ {
+ // level(s) closed - check if any of the closed levels are collapsed
+ // Calc uses 0-based level indexes
+ sal_uInt16 nOldOpenScLevel = mnCurrLevel - 1;
+ for( sal_uInt16 nScLevel = nNewOpenScLevel + 1; !mbCurrCollapse && (nScLevel <= nOldOpenScLevel); ++nScLevel )
+ mbCurrCollapse = maLevelInfos[ nScLevel ].mbHidden;
+ }
+
+ // cache new opened level
+ mnCurrLevel = nNewLevel;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpGuts::XclExpGuts( const XclExpRoot& rRoot ) :
+ XclExpRecord( EXC_ID_GUTS, 8 ),
+ mnColLevels( 0 ),
+ mnColWidth( 0 ),
+ mnRowLevels( 0 ),
+ mnRowWidth( 0 )
+{
+ if( const ScOutlineTable* pOutlineTable = rRoot.GetDoc().GetOutlineTable( rRoot.GetCurrScTab() ) )
+ {
+ // column outline groups
+ if( const ScOutlineArray* pColArray = pOutlineTable->GetColArray() )
+ mnColLevels = ulimit_cast< sal_uInt16 >( pColArray->GetDepth(), EXC_OUTLINE_MAX );
+ if( mnColLevels )
+ {
+ ++mnColLevels;
+ mnColWidth = 12 * mnColLevels + 5;
+ }
+
+ // row outline groups
+ if( const ScOutlineArray* pRowArray = pOutlineTable->GetRowArray() )
+ mnRowLevels = ulimit_cast< sal_uInt16 >( pRowArray->GetDepth(), EXC_OUTLINE_MAX );
+ if( mnRowLevels )
+ {
+ ++mnRowLevels;
+ mnRowWidth = 12 * mnRowLevels + 5;
+ }
+ }
+}
+
+void XclExpGuts::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << mnRowWidth << mnColWidth << mnRowLevels << mnColLevels;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpDimensions::XclExpDimensions( const XclExpRoot& rRoot ) :
+ mnFirstUsedXclRow( 0 ),
+ mnFirstFreeXclRow( 0 ),
+ mnFirstUsedXclCol( 0 ),
+ mnFirstFreeXclCol( 0 )
+{
+ switch( rRoot.GetBiff() )
+ {
+ case EXC_BIFF2: SetRecHeader( EXC_ID2_DIMENSIONS, 8 ); break;
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ case EXC_BIFF5: SetRecHeader( EXC_ID3_DIMENSIONS, 10 ); break;
+ case EXC_BIFF8: SetRecHeader( EXC_ID3_DIMENSIONS, 14 ); break;
+ default: DBG_ERROR_BIFF();
+ }
+}
+
+void XclExpDimensions::SetDimensions(
+ sal_uInt16 nFirstUsedXclCol, sal_uInt32 nFirstUsedXclRow,
+ sal_uInt16 nFirstFreeXclCol, sal_uInt32 nFirstFreeXclRow )
+{
+ mnFirstUsedXclRow = nFirstUsedXclRow;
+ mnFirstFreeXclRow = nFirstFreeXclRow;
+ mnFirstUsedXclCol = nFirstUsedXclCol;
+ mnFirstFreeXclCol = nFirstFreeXclCol;
+}
+
+void XclExpDimensions::SaveXml( XclExpXmlStream& rStrm )
+{
+ ScRange aRange;
+ aRange.aStart.SetRow( (SCROW) mnFirstUsedXclRow );
+ aRange.aStart.SetCol( (SCCOL) mnFirstUsedXclCol );
+
+ if( mnFirstFreeXclRow != mnFirstUsedXclRow && mnFirstFreeXclCol != mnFirstUsedXclCol )
+ {
+ aRange.aEnd.SetRow( (SCROW) (mnFirstFreeXclRow-1) );
+ aRange.aEnd.SetCol( (SCCOL) (mnFirstFreeXclCol-1) );
+ }
+
+ rStrm.GetCurrentStream()->singleElement( XML_dimension,
+ XML_ref, XclXmlUtils::ToOString( aRange ).getStr(),
+ FSEND );
+}
+
+void XclExpDimensions::WriteBody( XclExpStream& rStrm )
+{
+ XclBiff eBiff = rStrm.GetRoot().GetBiff();
+ if( eBiff == EXC_BIFF8 )
+ rStrm << mnFirstUsedXclRow << mnFirstFreeXclRow;
+ else
+ rStrm << static_cast< sal_uInt16 >( mnFirstUsedXclRow ) << static_cast< sal_uInt16 >( mnFirstFreeXclRow );
+ rStrm << mnFirstUsedXclCol << mnFirstFreeXclCol;
+ if( eBiff >= EXC_BIFF3 )
+ rStrm << sal_uInt16( 0 );
+}
+
+// ============================================================================
+
+namespace {
+
+double lclGetCorrectedColWidth( const XclExpRoot& rRoot, sal_uInt16 nXclColWidth )
+{
+ long nFontHt = rRoot.GetFontBuffer().GetAppFontData().mnHeight;
+ return nXclColWidth - XclTools::GetXclDefColWidthCorrection( nFontHt );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpDefcolwidth::XclExpDefcolwidth( const XclExpRoot& rRoot ) :
+ XclExpUInt16Record( EXC_ID_DEFCOLWIDTH, EXC_DEFCOLWIDTH_DEF ),
+ XclExpRoot( rRoot )
+{
+}
+
+bool XclExpDefcolwidth::IsDefWidth( sal_uInt16 nXclColWidth ) const
+{
+ double fNewColWidth = lclGetCorrectedColWidth( GetRoot(), nXclColWidth );
+ // exactly matched, if difference is less than 1/16 of a character to the left or to the right
+ return Abs( static_cast< long >( GetValue() * 256.0 - fNewColWidth + 0.5 ) ) < 16;
+}
+
+void XclExpDefcolwidth::SetDefWidth( sal_uInt16 nXclColWidth )
+{
+ double fNewColWidth = lclGetCorrectedColWidth( GetRoot(), nXclColWidth );
+ SetValue( limit_cast< sal_uInt16 >( fNewColWidth / 256.0 + 0.5 ) );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpColinfo::XclExpColinfo( const XclExpRoot& rRoot,
+ SCCOL nScCol, SCROW nLastScRow, XclExpColOutlineBuffer& rOutlineBfr ) :
+ XclExpRecord( EXC_ID_COLINFO, 12 ),
+ XclExpRoot( rRoot ),
+ mnWidth( 0 ),
+ mnFlags( 0 ),
+ mnFirstXclCol( static_cast< sal_uInt16 >( nScCol ) ),
+ mnLastXclCol( static_cast< sal_uInt16 >( nScCol ) )
+{
+ ScDocument& rDoc = GetDoc();
+ SCTAB nScTab = GetCurrScTab();
+
+ // column default format
+ maXFId.mnXFId = GetXFBuffer().Insert(
+ rDoc.GetMostUsedPattern( nScCol, 0, nLastScRow, nScTab ), GetDefApiScript() );
+
+ // column width
+ sal_uInt16 nScWidth = rDoc.GetColWidth( nScCol, nScTab );
+ mnWidth = XclTools::GetXclColumnWidth( nScWidth, GetCharWidth() );
+
+ // column flags
+ ::set_flag( mnFlags, EXC_COLINFO_HIDDEN, rDoc.ColHidden(nScCol, nScTab) );
+
+ // outline data
+ rOutlineBfr.Update( nScCol );
+ ::set_flag( mnFlags, EXC_COLINFO_COLLAPSED, rOutlineBfr.IsCollapsed() );
+ ::insert_value( mnFlags, rOutlineBfr.GetLevel(), 8, 3 );
+}
+
+sal_uInt16 XclExpColinfo::ConvertXFIndexes()
+{
+ maXFId.ConvertXFIndex( GetRoot() );
+ return maXFId.mnXFIndex;
+}
+
+bool XclExpColinfo::IsDefault( const XclExpDefcolwidth& rDefColWidth ) const
+{
+ return (maXFId.mnXFIndex == EXC_XF_DEFAULTCELL) && (mnFlags == 0) && rDefColWidth.IsDefWidth( mnWidth );
+}
+
+bool XclExpColinfo::TryMerge( const XclExpColinfo& rColInfo )
+{
+ if( (maXFId.mnXFIndex == rColInfo.maXFId.mnXFIndex) &&
+ (mnWidth == rColInfo.mnWidth) &&
+ (mnFlags == rColInfo.mnFlags) &&
+ (mnLastXclCol + 1 == rColInfo.mnFirstXclCol) )
+ {
+ mnLastXclCol = rColInfo.mnLastXclCol;
+ return true;
+ }
+ return false;
+}
+
+void XclExpColinfo::WriteBody( XclExpStream& rStrm )
+{
+ // if last column is equal to last possible column, Excel adds one more
+ sal_uInt16 nLastXclCol = mnLastXclCol;
+ if( nLastXclCol == static_cast< sal_uInt16 >( rStrm.GetRoot().GetMaxPos().Col() ) )
+ ++nLastXclCol;
+
+ rStrm << mnFirstXclCol
+ << nLastXclCol
+ << mnWidth
+ << maXFId.mnXFIndex
+ << mnFlags
+ << sal_uInt16( 0 );
+}
+
+void XclExpColinfo::SaveXml( XclExpXmlStream& rStrm )
+{
+ // if last column is equal to last possible column, Excel adds one more
+ sal_uInt16 nLastXclCol = mnLastXclCol;
+ if( nLastXclCol == static_cast< sal_uInt16 >( rStrm.GetRoot().GetMaxPos().Col() ) )
+ ++nLastXclCol;
+
+ rStrm.GetCurrentStream()->singleElement( XML_col,
+ // OOXTODO: XML_bestFit,
+ XML_collapsed, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_COLINFO_COLLAPSED ) ),
+ // OOXTODO: XML_customWidth,
+ XML_hidden, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_COLINFO_HIDDEN ) ),
+ XML_max, OString::valueOf( (sal_Int32) (nLastXclCol+1) ).getStr(),
+ XML_min, OString::valueOf( (sal_Int32) (mnFirstXclCol+1) ).getStr(),
+ // OOXTODO: XML_outlineLevel,
+ // OOXTODO: XML_phonetic,
+ XML_style, lcl_GetStyleId( rStrm, maXFId.mnXFIndex ).getStr(),
+ XML_width, OString::valueOf( (double) (mnWidth / 255.0) ).getStr(),
+ FSEND );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpColinfoBuffer::XclExpColinfoBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ maDefcolwidth( rRoot ),
+ maOutlineBfr( rRoot )
+{
+}
+
+void XclExpColinfoBuffer::Initialize( SCROW nLastScRow )
+{
+
+ for( sal_uInt16 nScCol = 0, nLastScCol = GetMaxPos().Col(); nScCol <= nLastScCol; ++nScCol )
+ maColInfos.AppendNewRecord( new XclExpColinfo( GetRoot(), nScCol, nLastScRow, maOutlineBfr ) );
+}
+
+void XclExpColinfoBuffer::Finalize( ScfUInt16Vec& rXFIndexes )
+{
+ rXFIndexes.clear();
+ rXFIndexes.reserve( maColInfos.GetSize() );
+
+ size_t nPos, nSize;
+
+ // do not cache the record list size, it may change in the loop
+ for( nPos = 0; nPos < maColInfos.GetSize(); ++nPos )
+ {
+ XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
+ xRec->ConvertXFIndexes();
+
+ // try to merge with previous record
+ if( nPos > 0 )
+ {
+ XclExpColinfoRef xPrevRec = maColInfos.GetRecord( nPos - 1 );
+ if( xPrevRec->TryMerge( *xRec ) )
+ // adjust nPos to get the next COLINFO record at the same position
+ maColInfos.RemoveRecord( nPos-- );
+ }
+ }
+
+ // put XF indexes into passed vector, collect use count of all different widths
+ typedef ::std::map< sal_uInt16, sal_uInt16 > XclExpWidthMap;
+ XclExpWidthMap aWidthMap;
+ sal_uInt16 nMaxColCount = 0;
+ sal_uInt16 nMaxUsedWidth = 0;
+ for( nPos = 0, nSize = maColInfos.GetSize(); nPos < nSize; ++nPos )
+ {
+ XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
+ sal_uInt16 nColCount = xRec->GetColCount();
+
+ // add XF index to passed vector
+ rXFIndexes.resize( rXFIndexes.size() + nColCount, xRec->GetXFIndex() );
+
+ // collect use count of column width
+ sal_uInt16 nWidth = xRec->GetColWidth();
+ sal_uInt16& rnMapCount = aWidthMap[ nWidth ];
+ rnMapCount = rnMapCount + nColCount;
+ if( rnMapCount > nMaxColCount )
+ {
+ nMaxColCount = rnMapCount;
+ nMaxUsedWidth = nWidth;
+ }
+ }
+ maDefcolwidth.SetDefWidth( nMaxUsedWidth );
+
+ // remove all default COLINFO records
+ nPos = 0;
+ while( nPos < maColInfos.GetSize() )
+ {
+ XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
+ if( xRec->IsDefault( maDefcolwidth ) )
+ maColInfos.RemoveRecord( nPos );
+ else
+ ++nPos;
+ }
+}
+
+void XclExpColinfoBuffer::Save( XclExpStream& rStrm )
+{
+ // DEFCOLWIDTH
+ maDefcolwidth.Save( rStrm );
+ // COLINFO records
+ maColInfos.Save( rStrm );
+}
+
+void XclExpColinfoBuffer::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( maColInfos.IsEmpty() )
+ return;
+
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_cols,
+ FSEND );
+ maColInfos.SaveXml( rStrm );
+ rWorksheet->endElement( XML_cols );
+}
+
+// ============================================================================
+
+XclExpDefaultRowData::XclExpDefaultRowData() :
+ mnFlags( EXC_DEFROW_DEFAULTFLAGS ),
+ mnHeight( EXC_DEFROW_DEFAULTHEIGHT )
+{
+}
+
+XclExpDefaultRowData::XclExpDefaultRowData( const XclExpRow& rRow ) :
+ mnFlags( EXC_DEFROW_DEFAULTFLAGS ),
+ mnHeight( rRow.GetHeight() )
+{
+ ::set_flag( mnFlags, EXC_DEFROW_HIDDEN, rRow.IsHidden() );
+ ::set_flag( mnFlags, EXC_DEFROW_UNSYNCED, rRow.IsUnsynced() );
+}
+
+bool operator<( const XclExpDefaultRowData& rLeft, const XclExpDefaultRowData& rRight )
+{
+ return (rLeft.mnHeight < rRight.mnHeight) ||
+ ((rLeft.mnHeight == rRight.mnHeight) && (rLeft.mnFlags < rRight.mnFlags));
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpDefrowheight::XclExpDefrowheight() :
+ XclExpRecord( EXC_ID3_DEFROWHEIGHT, 4 )
+{
+}
+
+void XclExpDefrowheight::SetDefaultData( const XclExpDefaultRowData& rDefData )
+{
+ maDefData = rDefData;
+}
+
+void XclExpDefrowheight::WriteBody( XclExpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( rStrm.GetRoot().GetBiff() >= EXC_BIFF3 );
+ rStrm << maDefData.mnFlags << maDefData.mnHeight;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpRow::XclExpRow( const XclExpRoot& rRoot, sal_uInt32 nXclRow,
+ XclExpRowOutlineBuffer& rOutlineBfr, bool bAlwaysEmpty ) :
+ XclExpRecord( EXC_ID3_ROW, 16 ),
+ XclExpRoot( rRoot ),
+ mnXclRow( nXclRow ),
+ mnHeight( 0 ),
+ mnFlags( EXC_ROW_DEFAULTFLAGS ),
+ mnXFIndex( EXC_XF_DEFAULTCELL ),
+ mnOutlineLevel( 0 ),
+ mbAlwaysEmpty( bAlwaysEmpty ),
+ mbEnabled( true )
+{
+ SCTAB nScTab = GetCurrScTab();
+ SCROW nScRow = static_cast< SCROW >( mnXclRow );
+
+ // *** Row flags *** ------------------------------------------------------
+
+ sal_uInt8 nRowFlags = GetDoc().GetRowFlags( nScRow, nScTab );
+ bool bUserHeight = ::get_flag< sal_uInt8 >( nRowFlags, CR_MANUALSIZE );
+ bool bHidden = GetDoc().RowHidden(nScRow, nScTab);
+ ::set_flag( mnFlags, EXC_ROW_UNSYNCED, bUserHeight );
+ ::set_flag( mnFlags, EXC_ROW_HIDDEN, bHidden );
+
+ // *** Row height *** -----------------------------------------------------
+
+ // Always get the actual row height even if the manual size flag is not set,
+ // to correctly export the heights of rows with wrapped texts.
+
+ mnHeight = GetDoc().GetRowHeight(nScRow, nScTab, false);
+
+ // *** Outline data *** ---------------------------------------------------
+
+ rOutlineBfr.Update( nScRow );
+ ::set_flag( mnFlags, EXC_ROW_COLLAPSED, rOutlineBfr.IsCollapsed() );
+ ::insert_value( mnFlags, rOutlineBfr.GetLevel(), 0, 3 );
+ mnOutlineLevel = rOutlineBfr.GetLevel();
+
+ // *** Progress bar *** ---------------------------------------------------
+
+ XclExpProgressBar& rProgress = GetProgressBar();
+ rProgress.IncRowRecordCount();
+ rProgress.Progress();
+}
+
+void XclExpRow::AppendCell( XclExpCellRef xCell, bool bIsMergedBase )
+{
+ DBG_ASSERT( !mbAlwaysEmpty, "XclExpRow::AppendCell - row is marked to be always empty" );
+ // try to merge with last existing cell
+ InsertCell( xCell, maCellList.GetSize(), bIsMergedBase );
+}
+
+void XclExpRow::Finalize( const ScfUInt16Vec& rColXFIndexes )
+{
+ size_t nPos, nSize;
+
+ // *** Convert XF identifiers *** -----------------------------------------
+
+ // additionally collect the blank XF indexes
+ size_t nColCount = GetMaxPos().Col() + 1;
+ DBG_ASSERT( rColXFIndexes.size() == nColCount, "XclExpRow::Finalize - wrong column XF index count" );
+
+ ScfUInt16Vec aXFIndexes( nColCount, EXC_XF_NOTFOUND );
+ for( nPos = 0, nSize = maCellList.GetSize(); nPos < nSize; ++nPos )
+ {
+ XclExpCellRef xCell = maCellList.GetRecord( nPos );
+ xCell->ConvertXFIndexes( GetRoot() );
+ xCell->GetBlankXFIndexes( aXFIndexes );
+ }
+
+ // *** Fill gaps with BLANK/MULBLANK cell records *** ---------------------
+
+ /* This is needed because nonexistant cells in Calc are not formatted at all,
+ but in Excel they would have the column default format. Blank cells that
+ are equal to the respective column default are removed later in this function. */
+ if( !mbAlwaysEmpty )
+ {
+ // XF identifier representing default cell XF
+ XclExpMultiXFId aXFId( XclExpXFBuffer::GetDefCellXFId() );
+ aXFId.ConvertXFIndex( GetRoot() );
+
+ nPos = 0;
+ while( nPos <= maCellList.GetSize() ) // don't cache list size, may change in the loop
+ {
+ // get column index that follows previous cell
+ sal_uInt16 nFirstFreeXclCol = (nPos > 0) ? (maCellList.GetRecord( nPos - 1 )->GetLastXclCol() + 1) : 0;
+ // get own column index
+ sal_uInt16 nNextUsedXclCol = (nPos < maCellList.GetSize()) ? maCellList.GetRecord( nPos )->GetXclCol() : (GetMaxPos().Col() + 1);
+
+ // is there a gap?
+ if( nFirstFreeXclCol < nNextUsedXclCol )
+ {
+ aXFId.mnCount = nNextUsedXclCol - nFirstFreeXclCol;
+ XclExpCellRef xNewCell( new XclExpBlankCell( XclAddress( nFirstFreeXclCol, mnXclRow ), aXFId ) );
+ // insert the cell, InsertCell() may merge it with existing BLANK records
+ InsertCell( xNewCell, nPos, false );
+ // insert default XF indexes into aXFIndexes
+ ::std::fill( aXFIndexes.begin() + nFirstFreeXclCol,
+ aXFIndexes.begin() + nNextUsedXclCol, aXFId.mnXFIndex );
+ // don't step forward with nPos, InsertCell() may remove records
+ }
+ else
+ ++nPos;
+ }
+ }
+
+ // *** Find default row format *** ----------------------------------------
+
+ ScfUInt16Vec::iterator aCellBeg = aXFIndexes.begin(), aCellEnd = aXFIndexes.end(), aCellIt;
+ ScfUInt16Vec::const_iterator aColBeg = rColXFIndexes.begin(), aColIt;
+
+ // find most used XF index in the row
+ typedef ::std::map< sal_uInt16, size_t > XclExpXFIndexMap;
+ XclExpXFIndexMap aIndexMap;
+ sal_uInt16 nRowXFIndex = EXC_XF_DEFAULTCELL;
+ size_t nMaxXFCount = 0;
+ for( aCellIt = aCellBeg; aCellIt != aCellEnd; ++aCellIt )
+ {
+ if( *aCellIt != EXC_XF_NOTFOUND )
+ {
+ size_t& rnCount = aIndexMap[ *aCellIt ];
+ ++rnCount;
+ if( rnCount > nMaxXFCount )
+ {
+ nRowXFIndex = *aCellIt;
+ nMaxXFCount = rnCount;
+ }
+ }
+ }
+
+ // decide whether to use the row default XF index or column default XF indexes
+ bool bUseColDefXFs = nRowXFIndex == EXC_XF_DEFAULTCELL;
+ if( !bUseColDefXFs )
+ {
+ // count needed XF indexes for blank cells with and without row default XF index
+ size_t nXFCountWithRowDefXF = 0;
+ size_t nXFCountWithoutRowDefXF = 0;
+ for( aCellIt = aCellBeg, aColIt = aColBeg; aCellIt != aCellEnd; ++aCellIt, ++aColIt )
+ {
+ sal_uInt16 nXFIndex = *aCellIt;
+ if( nXFIndex != EXC_XF_NOTFOUND )
+ {
+ if( nXFIndex != nRowXFIndex )
+ ++nXFCountWithRowDefXF; // with row default XF index
+ if( nXFIndex != *aColIt )
+ ++nXFCountWithoutRowDefXF; // without row default XF index
+ }
+ }
+
+ // use column XF indexes if this would cause less or equal number of BLANK records
+ bUseColDefXFs = nXFCountWithoutRowDefXF <= nXFCountWithRowDefXF;
+ }
+
+ // *** Remove unused BLANK cell records *** -------------------------------
+
+ if( bUseColDefXFs )
+ {
+ // use column default XF indexes
+ // #i194#: remove cell XF indexes equal to column default XF indexes
+ for( aCellIt = aCellBeg, aColIt = aColBeg; aCellIt != aCellEnd; ++aCellIt, ++aColIt )
+ if( *aCellIt == *aColIt )
+ *aCellIt = EXC_XF_NOTFOUND;
+ }
+ else
+ {
+ // use row default XF index
+ mnXFIndex = nRowXFIndex;
+ ::set_flag( mnFlags, EXC_ROW_USEDEFXF );
+ // #98133#, #i194#, #i27407#: remove cell XF indexes equal to row default XF index
+ for( aCellIt = aCellBeg; aCellIt != aCellEnd; ++aCellIt )
+ if( *aCellIt == nRowXFIndex )
+ *aCellIt = EXC_XF_NOTFOUND;
+ }
+
+ // remove unused parts of BLANK/MULBLANK cell records
+ nPos = 0;
+ while( nPos < maCellList.GetSize() ) // do not cache list size, may change in the loop
+ {
+ XclExpCellRef xCell = maCellList.GetRecord( nPos );
+ xCell->RemoveUnusedBlankCells( aXFIndexes );
+ if( xCell->IsEmpty() )
+ maCellList.RemoveRecord( nPos );
+ else
+ ++nPos;
+ }
+
+ // progress bar includes disabled rows
+ GetProgressBar().Progress();
+}
+
+sal_uInt16 XclExpRow::GetFirstUsedXclCol() const
+{
+ return maCellList.IsEmpty() ? 0 : maCellList.GetFirstRecord()->GetXclCol();
+}
+
+sal_uInt16 XclExpRow::GetFirstFreeXclCol() const
+{
+ return maCellList.IsEmpty() ? 0 : (maCellList.GetLastRecord()->GetLastXclCol() + 1);
+}
+
+bool XclExpRow::IsDefaultable() const
+{
+ const sal_uInt16 nAllowedFlags = EXC_ROW_DEFAULTFLAGS | EXC_ROW_HIDDEN | EXC_ROW_UNSYNCED;
+ return !::get_flag( mnFlags, static_cast< sal_uInt16 >( ~nAllowedFlags ) ) && IsEmpty();
+}
+
+void XclExpRow::DisableIfDefault( const XclExpDefaultRowData& rDefRowData )
+{
+ mbEnabled = !IsDefaultable() ||
+ (mnHeight != rDefRowData.mnHeight) ||
+ (IsHidden() != rDefRowData.IsHidden()) ||
+ (IsUnsynced() != rDefRowData.IsUnsynced());
+}
+
+void XclExpRow::WriteCellList( XclExpStream& rStrm )
+{
+ DBG_ASSERT( mbEnabled || maCellList.IsEmpty(), "XclExpRow::WriteCellList - cells in disabled row" );
+ maCellList.Save( rStrm );
+}
+
+void XclExpRow::Save( XclExpStream& rStrm )
+{
+ if( mbEnabled )
+ XclExpRecord::Save( rStrm );
+}
+
+void XclExpRow::InsertCell( XclExpCellRef xCell, size_t nPos, bool bIsMergedBase )
+{
+ DBG_ASSERT( xCell, "XclExpRow::InsertCell - missing cell" );
+
+ /* If we have a multi-line text in a merged cell, and the resulting
+ row height has not been confirmed, we need to force the EXC_ROW_UNSYNCED
+ flag to be true to ensure Excel works correctly. */
+ if( bIsMergedBase && xCell->IsMultiLineText() )
+ ::set_flag( mnFlags, EXC_ROW_UNSYNCED );
+
+ // try to merge with previous cell, insert the new cell if not successful
+ XclExpCellRef xPrevCell = maCellList.GetRecord( nPos - 1 );
+ if( xPrevCell && xPrevCell->TryMerge( *xCell ) )
+ xCell = xPrevCell;
+ else
+ maCellList.InsertRecord( xCell, nPos++ );
+ // nPos points now to following cell
+
+ // try to merge with following cell, remove it if successful
+ XclExpCellRef xNextCell = maCellList.GetRecord( nPos );
+ if( xNextCell && xCell->TryMerge( *xNextCell ) )
+ maCellList.RemoveRecord( nPos );
+}
+
+void XclExpRow::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << static_cast< sal_uInt16 >(mnXclRow)
+ << GetFirstUsedXclCol()
+ << GetFirstFreeXclCol()
+ << mnHeight
+ << sal_uInt32( 0 )
+ << mnFlags
+ << mnXFIndex;
+}
+
+void XclExpRow::SaveXml( XclExpXmlStream& rStrm )
+{
+ if( !mbEnabled )
+ return;
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ bool haveFormat = ::get_flag( mnFlags, EXC_ROW_USEDEFXF );
+ rWorksheet->startElement( XML_row,
+ XML_r, OString::valueOf( (sal_Int32) (mnXclRow+1) ).getStr(),
+ // OOXTODO: XML_spans, optional
+ XML_s, haveFormat ? lcl_GetStyleId( rStrm, mnXFIndex ).getStr() : NULL,
+ XML_customFormat, XclXmlUtils::ToPsz( haveFormat ),
+ XML_ht, OString::valueOf( (double) mnHeight / 20.0 ).getStr(),
+ XML_hidden, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_ROW_HIDDEN ) ),
+ XML_customHeight, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_ROW_UNSYNCED ) ),
+ XML_outlineLevel, OString::valueOf( (sal_Int32) mnOutlineLevel ).getStr(),
+ XML_collapsed, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_ROW_COLLAPSED ) ),
+ // OOXTODO: XML_thickTop, bool
+ // OOXTODO: XML_thickBot, bool
+ // OOXTODO: XML_ph, bool
+ FSEND );
+ // OOXTODO: XML_extLst
+ maCellList.SaveXml( rStrm );
+ rWorksheet->endElement( XML_row );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpRowBuffer::XclExpRowBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ maOutlineBfr( rRoot ),
+ maDimensions( rRoot )
+{
+}
+
+void XclExpRowBuffer::AppendCell( XclExpCellRef xCell, bool bIsMergedBase )
+{
+ DBG_ASSERT( xCell, "XclExpRowBuffer::AppendCell - missing cell" );
+ GetOrCreateRow( xCell->GetXclRow(), false ).AppendCell( xCell, bIsMergedBase );
+}
+
+void XclExpRowBuffer::CreateRows( SCROW nFirstFreeScRow )
+{
+ if( nFirstFreeScRow > 0 )
+ GetOrCreateRow( static_cast< sal_uInt16 >( nFirstFreeScRow - 1 ), true );
+}
+
+void XclExpRowBuffer::Finalize( XclExpDefaultRowData& rDefRowData, const ScfUInt16Vec& rColXFIndexes )
+{
+ // *** Finalize all rows *** ----------------------------------------------
+
+ GetProgressBar().ActivateFinalRowsSegment();
+
+ RowMap::iterator itr, itrBeg = maRowMap.begin(), itrEnd = maRowMap.end();
+ for (itr = itrBeg; itr != itrEnd; ++itr)
+ itr->second->Finalize(rColXFIndexes);
+
+ // *** Default row format *** ---------------------------------------------
+
+ typedef ::std::map< XclExpDefaultRowData, size_t > XclExpDefRowDataMap;
+ XclExpDefRowDataMap aDefRowMap;
+
+ XclExpDefaultRowData aMaxDefData;
+ size_t nMaxDefCount = 0;
+ // only look for default format in existing rows, if there are more than unused
+ for (itr = itrBeg; itr != itrEnd; ++itr)
+ {
+ const RowRef& rRow = itr->second;
+ if (rRow->IsDefaultable())
+ {
+ XclExpDefaultRowData aDefData( *rRow );
+ size_t& rnDefCount = aDefRowMap[ aDefData ];
+ ++rnDefCount;
+ if( rnDefCount > nMaxDefCount )
+ {
+ nMaxDefCount = rnDefCount;
+ aMaxDefData = aDefData;
+ }
+ }
+ }
+
+ // return the default row format to caller
+ rDefRowData = aMaxDefData;
+
+ // *** Disable unused ROW records, find used area *** ---------------------
+
+ sal_uInt16 nFirstUsedXclCol = SAL_MAX_UINT16;
+ sal_uInt16 nFirstFreeXclCol = 0;
+ sal_uInt32 nFirstUsedXclRow = SAL_MAX_UINT32;
+ sal_uInt32 nFirstFreeXclRow = 0;
+
+ for (itr = itrBeg; itr != itrEnd; ++itr)
+ {
+ const RowRef& rRow = itr->second;
+ // disable unused rows
+ rRow->DisableIfDefault( aMaxDefData );
+
+ // find used column range
+ if( !rRow->IsEmpty() ) // empty rows return (0...0) as used range
+ {
+ nFirstUsedXclCol = ::std::min( nFirstUsedXclCol, rRow->GetFirstUsedXclCol() );
+ nFirstFreeXclCol = ::std::max( nFirstFreeXclCol, rRow->GetFirstFreeXclCol() );
+ }
+
+ // find used row range
+ if( rRow->IsEnabled() )
+ {
+ sal_uInt16 nXclRow = rRow->GetXclRow();
+ nFirstUsedXclRow = ::std::min< sal_uInt32 >( nFirstUsedXclRow, nXclRow );
+ nFirstFreeXclRow = ::std::max< sal_uInt32 >( nFirstFreeXclRow, nXclRow + 1 );
+ }
+ }
+
+ // adjust start position, if there are no or only empty/disabled ROW records
+ nFirstUsedXclCol = ::std::min( nFirstUsedXclCol, nFirstFreeXclCol );
+ nFirstUsedXclRow = ::std::min( nFirstUsedXclRow, nFirstFreeXclRow );
+
+ // initialize the DIMENSIONS record
+ maDimensions.SetDimensions(
+ nFirstUsedXclCol, nFirstUsedXclRow, nFirstFreeXclCol, nFirstFreeXclRow );
+}
+
+void XclExpRowBuffer::Save( XclExpStream& rStrm )
+{
+ // DIMENSIONS record
+ maDimensions.Save( rStrm );
+
+ // save in blocks of 32 rows, each block contains first all ROWs, then all cells
+ size_t nSize = maRowMap.size();
+ RowMap::iterator itr, itrBeg = maRowMap.begin(), itrEnd = maRowMap.end();
+ RowMap::iterator itrBlkStart = maRowMap.begin(), itrBlkEnd = maRowMap.begin();
+ sal_uInt16 nStartXclRow = (nSize == 0) ? 0 : itrBeg->second->GetXclRow();
+
+
+ for (itr = itrBeg; itr != itrEnd; ++itr)
+ {
+ // find end of row block
+ while( (itrBlkEnd != itrEnd) && (itrBlkEnd->second->GetXclRow() - nStartXclRow < EXC_ROW_ROWBLOCKSIZE) )
+ ++itrBlkEnd;
+
+ // write the ROW records
+ RowMap::iterator itRow;
+ for( itRow = itrBlkStart; itRow != itrBlkEnd; ++itRow )
+ itRow->second->Save( rStrm );
+
+ // write the cell records
+ for( itRow = itrBlkStart; itRow != itrBlkEnd; ++itRow )
+ itRow->second->WriteCellList( rStrm );
+
+ itrBlkStart = (itrBlkEnd == itrEnd) ? itrBlkEnd : itrBlkEnd++;
+ nStartXclRow += EXC_ROW_ROWBLOCKSIZE;
+ }
+}
+
+void XclExpRowBuffer::SaveXml( XclExpXmlStream& rStrm )
+{
+ sal_Int32 nNonEmpty = 0;
+ RowMap::iterator itr = maRowMap.begin(), itrEnd = maRowMap.end();
+ for (; itr != itrEnd; ++itr)
+ if (itr->second->IsEnabled())
+ ++nNonEmpty;
+
+ if (nNonEmpty == 0)
+ {
+ rStrm.GetCurrentStream()->singleElement( XML_sheetData, FSEND );
+ return;
+ }
+
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_sheetData, FSEND );
+ for (itr = maRowMap.begin(); itr != itrEnd; ++itr)
+ itr->second->SaveXml(rStrm);
+ rWorksheet->endElement( XML_sheetData );
+}
+
+XclExpDimensions* XclExpRowBuffer::GetDimensions()
+{
+ return &maDimensions;
+}
+
+XclExpRow& XclExpRowBuffer::GetOrCreateRow( sal_uInt32 nXclRow, bool bRowAlwaysEmpty )
+{
+ RowMap::iterator itr = maRowMap.find(nXclRow);
+ if (itr == maRowMap.end())
+ {
+ RowRef p(new XclExpRow(GetRoot(), nXclRow, maOutlineBfr, bRowAlwaysEmpty));
+ ::std::pair<RowMap::iterator, bool> r = maRowMap.insert(RowMap::value_type(nXclRow, p));
+ itr = r.first;
+ }
+ return *itr->second;
+}
+
+// ============================================================================
+// Cell Table
+// ============================================================================
+
+XclExpCellTable::XclExpCellTable( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ maColInfoBfr( rRoot ),
+ maRowBfr( rRoot ),
+ maArrayBfr( rRoot ),
+ maShrfmlaBfr( rRoot ),
+ maTableopBfr( rRoot ),
+ mxDefrowheight( new XclExpDefrowheight ),
+ mxGuts( new XclExpGuts( rRoot ) ),
+ mxNoteList( new XclExpNoteList ),
+ mxMergedcells( new XclExpMergedcells( rRoot ) ),
+ mxHyperlinkList( new XclExpHyperlinkList ),
+ mxDval( new XclExpDval( rRoot ) )
+{
+ ScDocument& rDoc = GetDoc();
+ SCTAB nScTab = GetCurrScTab();
+ SvNumberFormatter& rFormatter = GetFormatter();
+
+ // maximum sheet limits
+ SCCOL nMaxScCol = GetMaxPos().Col();
+ SCROW nMaxScRow = GetMaxPos().Row();
+
+ // find used area (non-empty cells)
+ SCCOL nLastUsedScCol;
+ SCROW nLastUsedScRow;
+ rDoc.GetTableArea( nScTab, nLastUsedScCol, nLastUsedScRow );
+
+ ScRange aUsedRange( 0, 0, nScTab, nLastUsedScCol, nLastUsedScRow, nScTab );
+ GetAddressConverter().ValidateRange( aUsedRange, true );
+ nLastUsedScCol = aUsedRange.aEnd.Col();
+ nLastUsedScRow = aUsedRange.aEnd.Row();
+
+ // first row without any set attributes (height/hidden/...)
+ SCROW nFirstUnflaggedScRow = rDoc.GetLastFlaggedRow( nScTab ) + 1;
+
+ // find range of outlines
+ SCROW nFirstUngroupedScRow = 0;
+ if( const ScOutlineTable* pOutlineTable = rDoc.GetOutlineTable( nScTab ) )
+ {
+ SCCOLROW nScStartPos, nScEndPos;
+ if( const ScOutlineArray* pRowArray = pOutlineTable->GetRowArray() )
+ {
+ pRowArray->GetRange( nScStartPos, nScEndPos );
+ // +1 because open/close button is in next row in Excel, +1 for "end->first unused"
+ nFirstUngroupedScRow = static_cast< SCROW >( nScEndPos + 2 );
+ }
+ }
+
+ // column settings
+ /* #i30411# Files saved with SO7/OOo1.x with nonstandard default column
+ formatting cause big Excel files, because all rows from row 1 to row
+ 32000 are exported. Now, if the used area goes exactly to row 32000,
+ use this row as default and ignore all rows >32000.
+ #i59220# Tolerance of +-128 rows for inserted/removed rows. */
+ if( (31871 <= nLastUsedScRow) && (nLastUsedScRow <= 32127) && (nFirstUnflaggedScRow < nLastUsedScRow) && (nFirstUngroupedScRow <= nLastUsedScRow) )
+ nMaxScRow = nLastUsedScRow;
+ maColInfoBfr.Initialize( nMaxScRow );
+
+ // range for cell iterator
+ SCCOL nLastIterScCol = nMaxScCol;
+ SCROW nLastIterScRow = ulimit_cast< SCROW >( nLastUsedScRow, nMaxScRow );
+ ScUsedAreaIterator aIt( &rDoc, nScTab, 0, 0, nLastIterScCol, nLastIterScRow );
+
+ // activate the correct segment and sub segment at the progress bar
+ GetProgressBar().ActivateCreateRowsSegment();
+
+ for( bool bIt = aIt.GetNext(); bIt; bIt = aIt.GetNext() )
+ {
+ SCCOL nScCol = aIt.GetStartCol();
+ SCROW nScRow = aIt.GetRow();
+ SCCOL nLastScCol = aIt.GetEndCol();
+ ScAddress aScPos( nScCol, nScRow, nScTab );
+
+ XclAddress aXclPos( static_cast< sal_uInt16 >( nScCol ), static_cast< sal_uInt32 >( nScRow ) );
+ sal_uInt16 nLastXclCol = static_cast< sal_uInt16 >( nLastScCol );
+
+ const ScBaseCell* pScCell = aIt.GetCell();
+ XclExpCellRef xCell;
+
+ const ScPatternAttr* pPattern = aIt.GetPattern();
+
+ // handle overlapped merged cells before creating the cell record
+ sal_uInt32 nMergeBaseXFId = EXC_XFID_NOTFOUND;
+ bool bIsMergedBase = false;
+ if( pPattern )
+ {
+ const SfxItemSet& rItemSet = pPattern->GetItemSet();
+ // base cell in a merged range
+ const ScMergeAttr& rMergeItem = GETITEM( rItemSet, ScMergeAttr, ATTR_MERGE );
+ bIsMergedBase = rMergeItem.IsMerged();
+ /* overlapped cell in a merged range; in Excel all merged cells
+ must contain same XF index, for correct border */
+ const ScMergeFlagAttr& rMergeFlagItem = GETITEM( rItemSet, ScMergeFlagAttr, ATTR_MERGE_FLAG );
+ if( rMergeFlagItem.IsOverlapped() )
+ nMergeBaseXFId = mxMergedcells->GetBaseXFId( aScPos );
+ }
+
+ String aAddNoteText; // additional text to be appended to a note
+
+ CellType eCellType = pScCell ? pScCell->GetCellType() : CELLTYPE_NONE;
+ switch( eCellType )
+ {
+ case CELLTYPE_VALUE:
+ {
+ double fValue = static_cast< const ScValueCell* >( pScCell )->GetValue();
+
+ // try to create a Boolean cell
+ if( pPattern && ((fValue == 0.0) || (fValue == 1.0)) )
+ {
+ sal_uLong nScNumFmt = GETITEMVALUE( pPattern->GetItemSet(), SfxUInt32Item, ATTR_VALUE_FORMAT, sal_uLong );
+ if( rFormatter.GetType( nScNumFmt ) == NUMBERFORMAT_LOGICAL )
+ xCell.reset( new XclExpBooleanCell(
+ GetRoot(), aXclPos, pPattern, nMergeBaseXFId, fValue != 0.0 ) );
+ }
+
+ // try to create an RK value (compressed floating-point number)
+ sal_Int32 nRkValue;
+ if( !xCell && XclTools::GetRKFromDouble( nRkValue, fValue ) )
+ xCell.reset( new XclExpRkCell(
+ GetRoot(), aXclPos, pPattern, nMergeBaseXFId, nRkValue ) );
+
+ // else: simple floating-point number cell
+ if( !xCell )
+ xCell.reset( new XclExpNumberCell(
+ GetRoot(), aXclPos, pPattern, nMergeBaseXFId, fValue ) );
+ }
+ break;
+
+ case CELLTYPE_STRING:
+ {
+ const ScStringCell& rScStrCell = *static_cast< const ScStringCell* >( pScCell );
+ xCell.reset( new XclExpLabelCell(
+ GetRoot(), aXclPos, pPattern, nMergeBaseXFId, rScStrCell ) );
+ }
+ break;
+
+ case CELLTYPE_EDIT:
+ {
+ const ScEditCell& rScEditCell = *static_cast< const ScEditCell* >( pScCell );
+ XclExpHyperlinkHelper aLinkHelper( GetRoot(), aScPos );
+ xCell.reset( new XclExpLabelCell(
+ GetRoot(), aXclPos, pPattern, nMergeBaseXFId, rScEditCell, aLinkHelper ) );
+
+ // add a single created HLINK record to the record list
+ if( aLinkHelper.HasLinkRecord() )
+ mxHyperlinkList->AppendRecord( aLinkHelper.GetLinkRecord() );
+ // add list of multiple URLs to the additional cell note text
+ if( aLinkHelper.HasMultipleUrls() )
+ ScGlobal::AddToken( aAddNoteText, aLinkHelper.GetUrlList(), '\n', 2 );
+ }
+ break;
+
+ case CELLTYPE_FORMULA:
+ {
+ const ScFormulaCell& rScFmlaCell = *static_cast< const ScFormulaCell* >( pScCell );
+ xCell.reset( new XclExpFormulaCell(
+ GetRoot(), aXclPos, pPattern, nMergeBaseXFId,
+ rScFmlaCell, maArrayBfr, maShrfmlaBfr, maTableopBfr ) );
+ }
+ break;
+
+ default:
+ DBG_ERRORFILE( "XclExpCellTable::XclExpCellTable - unknown cell type" );
+ // run-through!
+ case CELLTYPE_NONE:
+ case CELLTYPE_NOTE:
+ {
+ xCell.reset( new XclExpBlankCell(
+ GetRoot(), aXclPos, nLastXclCol, pPattern, nMergeBaseXFId ) );
+ }
+ break;
+ }
+
+ // insert the cell into the current row
+ if( xCell )
+ maRowBfr.AppendCell( xCell, bIsMergedBase );
+
+ // notes
+ const ScPostIt* pScNote = pScCell ? pScCell->GetNote() : 0;
+ if( pScNote || (aAddNoteText.Len() > 0) )
+ mxNoteList->AppendNewRecord( new XclExpNote( GetRoot(), aScPos, pScNote, aAddNoteText ) );
+
+ // other sheet contents
+ if( pPattern )
+ {
+ const SfxItemSet& rItemSet = pPattern->GetItemSet();
+
+ // base cell in a merged range
+ if( bIsMergedBase )
+ {
+ const ScMergeAttr& rMergeItem = GETITEM( rItemSet, ScMergeAttr, ATTR_MERGE );
+ ScRange aScRange( aScPos );
+ aScRange.aEnd.IncCol( rMergeItem.GetColMerge() - 1 );
+ aScRange.aEnd.IncRow( rMergeItem.GetRowMerge() - 1 );
+ sal_uInt32 nXFId = xCell ? xCell->GetFirstXFId() : EXC_XFID_NOTFOUND;
+ // blank cells merged vertically may occur repeatedly
+ DBG_ASSERT( (aScRange.aStart.Col() == aScRange.aEnd.Col()) || (nScCol == nLastScCol),
+ "XclExpCellTable::XclExpCellTable - invalid repeated blank merged cell" );
+ for( SCCOL nIndex = nScCol; nIndex <= nLastScCol; ++nIndex )
+ {
+ mxMergedcells->AppendRange( aScRange, nXFId );
+ aScRange.aStart.IncCol();
+ aScRange.aEnd.IncCol();
+ }
+ }
+
+ // data validation
+ if( ScfTools::CheckItem( rItemSet, ATTR_VALIDDATA, false ) )
+ {
+ sal_uLong nScHandle = GETITEMVALUE( rItemSet, SfxUInt32Item, ATTR_VALIDDATA, sal_uLong );
+ ScRange aScRange( aScPos );
+ aScRange.aEnd.SetCol( nLastScCol );
+ mxDval->InsertCellRange( aScRange, nScHandle );
+ }
+ }
+ }
+
+ // create missing row settings for rows anyhow flagged or with outlines
+ maRowBfr.CreateRows( ::std::max( nFirstUnflaggedScRow, nFirstUngroupedScRow ) );
+}
+
+void XclExpCellTable::Finalize()
+{
+ // Finalize multiple operations.
+ maTableopBfr.Finalize();
+
+ /* Finalize column buffer. This calculates column default XF indexes from
+ the XF identifiers and fills a vector with these XF indexes. */
+ ScfUInt16Vec aColXFIndexes;
+ maColInfoBfr.Finalize( aColXFIndexes );
+
+ /* Finalize row buffer. This calculates all cell XF indexes from the XF
+ identifiers. Then the XF index vector aColXFIndexes (filled above) is
+ used to calculate the row default formats. With this, all unneeded blank
+ cell records (equal to row default or column default) will be removed.
+ The function returns the (most used) default row format in aDefRowData. */
+ XclExpDefaultRowData aDefRowData;
+ maRowBfr.Finalize( aDefRowData, aColXFIndexes );
+
+ // Initialize the DEFROWHEIGHT record.
+ mxDefrowheight->SetDefaultData( aDefRowData );
+}
+
+XclExpRecordRef XclExpCellTable::CreateRecord( sal_uInt16 nRecId ) const
+{
+ XclExpRecordRef xRec;
+ switch( nRecId )
+ {
+ case EXC_ID3_DIMENSIONS: xRec.reset( new XclExpDelegatingRecord( const_cast<XclExpRowBuffer*>(&maRowBfr)->GetDimensions() ) ); break;
+ case EXC_ID2_DEFROWHEIGHT: xRec = mxDefrowheight; break;
+ case EXC_ID_GUTS: xRec = mxGuts; break;
+ case EXC_ID_NOTE: xRec = mxNoteList; break;
+ case EXC_ID_MERGEDCELLS: xRec = mxMergedcells; break;
+ case EXC_ID_HLINK: xRec = mxHyperlinkList; break;
+ case EXC_ID_DVAL: xRec = mxDval; break;
+ default: DBG_ERRORFILE( "XclExpCellTable::CreateRecord - unknown record id" );
+ }
+ return xRec;
+}
+
+void XclExpCellTable::Save( XclExpStream& rStrm )
+{
+ // DEFCOLWIDTH and COLINFOs
+ maColInfoBfr.Save( rStrm );
+ // ROWs and cell records
+ maRowBfr.Save( rStrm );
+}
+
+void XclExpCellTable::SaveXml( XclExpXmlStream& rStrm )
+{
+ maColInfoBfr.SaveXml( rStrm );
+ maRowBfr.SaveXml( rStrm );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xeview.cxx b/sc/source/filter/excel/xeview.cxx
new file mode 100644
index 000000000000..31c149135f49
--- /dev/null
+++ b/sc/source/filter/excel/xeview.cxx
@@ -0,0 +1,540 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xeview.hxx"
+#include "document.hxx"
+#include "scextopt.hxx"
+#include "viewopti.hxx"
+#include "xelink.hxx"
+#include "xestyle.hxx"
+
+using namespace ::oox;
+
+using ::rtl::OString;
+
+// Workbook view settings records =============================================
+
+XclExpWindow1::XclExpWindow1( const XclExpRoot& rRoot ) :
+ XclExpRecord( EXC_ID_WINDOW1, 18 ),
+ mnFlags( 0 ),
+ mnTabBarSize( 600 )
+{
+ const ScViewOptions& rViewOpt = rRoot.GetDoc().GetViewOptions();
+ ::set_flag( mnFlags, EXC_WIN1_HOR_SCROLLBAR, rViewOpt.GetOption( VOPT_HSCROLL ) );
+ ::set_flag( mnFlags, EXC_WIN1_VER_SCROLLBAR, rViewOpt.GetOption( VOPT_VSCROLL ) );
+ ::set_flag( mnFlags, EXC_WIN1_TABBAR, rViewOpt.GetOption( VOPT_TABCONTROLS ) );
+
+ double fTabBarWidth = rRoot.GetExtDocOptions().GetDocSettings().mfTabBarWidth;
+ if( (0.0 <= fTabBarWidth) && (fTabBarWidth <= 1.0) )
+ mnTabBarSize = static_cast< sal_uInt16 >( fTabBarWidth * 1000.0 + 0.5 );
+}
+
+void XclExpWindow1::SaveXml( XclExpXmlStream& rStrm )
+{
+ const XclExpTabInfo& rTabInfo = rStrm.GetRoot().GetTabInfo();
+
+ rStrm.GetCurrentStream()->singleElement( XML_workbookView,
+ // OOXTODO: XML_visibility, // ST_visibilty
+ // OOXTODO: XML_minimized, // bool
+ XML_showHorizontalScroll, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_WIN1_HOR_SCROLLBAR ) ),
+ XML_showVerticalScroll, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_WIN1_VER_SCROLLBAR ) ),
+ XML_showSheetTabs, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_WIN1_TABBAR ) ),
+ XML_xWindow, "0",
+ XML_yWindow, "0",
+ XML_windowWidth, OString::valueOf( (sal_Int32)0x4000 ).getStr(),
+ XML_windowHeight, OString::valueOf( (sal_Int32)0x2000 ).getStr(),
+ XML_tabRatio, OString::valueOf( (sal_Int32)mnTabBarSize ).getStr(),
+ XML_firstSheet, OString::valueOf( (sal_Int32)rTabInfo.GetFirstVisXclTab() ).getStr(),
+ XML_activeTab, OString::valueOf( (sal_Int32)rTabInfo.GetDisplayedXclTab() ).getStr(),
+ // OOXTODO: XML_autoFilterDateGrouping, // bool; AUTOFILTER12? 87Eh
+ FSEND );
+}
+
+void XclExpWindow1::WriteBody( XclExpStream& rStrm )
+{
+ const XclExpTabInfo& rTabInfo = rStrm.GetRoot().GetTabInfo();
+
+ rStrm << sal_uInt16( 0 ) // X position of the window
+ << sal_uInt16( 0 ) // Y position of the window
+ << sal_uInt16( 0x4000 ) // width of the window
+ << sal_uInt16( 0x2000 ) // height of the window
+ << mnFlags
+ << rTabInfo.GetDisplayedXclTab()
+ << rTabInfo.GetFirstVisXclTab()
+ << rTabInfo.GetXclSelectedCount()
+ << mnTabBarSize;
+}
+
+// Sheet view settings records ================================================
+
+XclExpWindow2::XclExpWindow2( const XclExpRoot& rRoot,
+ const XclTabViewData& rData, sal_uInt32 nGridColorId ) :
+ XclExpRecord( EXC_ID_WINDOW2, (rRoot.GetBiff() == EXC_BIFF8) ? 18 : 10 ),
+ maGridColor( rData.maGridColor ),
+ mnGridColorId( nGridColorId ),
+ mnFlags( 0 ),
+ maFirstXclPos( rData.maFirstXclPos ),
+ mnNormalZoom( rData.mnNormalZoom ),
+ mnPageZoom( rData.mnPageZoom )
+{
+ ::set_flag( mnFlags, EXC_WIN2_SHOWFORMULAS, rData.mbShowFormulas );
+ ::set_flag( mnFlags, EXC_WIN2_SHOWGRID, rData.mbShowGrid );
+ ::set_flag( mnFlags, EXC_WIN2_SHOWHEADINGS, rData.mbShowHeadings );
+ ::set_flag( mnFlags, EXC_WIN2_FROZEN, rData.mbFrozenPanes );
+ ::set_flag( mnFlags, EXC_WIN2_SHOWZEROS, rData.mbShowZeros );
+ ::set_flag( mnFlags, EXC_WIN2_DEFGRIDCOLOR, rData.mbDefGridColor );
+ ::set_flag( mnFlags, EXC_WIN2_MIRRORED, rData.mbMirrored );
+ ::set_flag( mnFlags, EXC_WIN2_SHOWOUTLINE, rData.mbShowOutline );
+ ::set_flag( mnFlags, EXC_WIN2_FROZENNOSPLIT, rData.mbFrozenPanes );
+ ::set_flag( mnFlags, EXC_WIN2_SELECTED, rData.mbSelected );
+ ::set_flag( mnFlags, EXC_WIN2_DISPLAYED, rData.mbDisplayed );
+ ::set_flag( mnFlags, EXC_WIN2_PAGEBREAKMODE, rData.mbPageMode );
+}
+
+void XclExpWindow2::WriteBody( XclExpStream& rStrm )
+{
+ const XclExpRoot& rRoot = rStrm.GetRoot();
+
+ rStrm << mnFlags
+ << maFirstXclPos;
+
+ switch( rRoot.GetBiff() )
+ {
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ case EXC_BIFF5:
+ rStrm << maGridColor;
+ break;
+ case EXC_BIFF8:
+ rStrm << rRoot.GetPalette().GetColorIndex( mnGridColorId )
+ << sal_uInt16( 0 )
+ << mnPageZoom
+ << mnNormalZoom
+ << sal_uInt32( 0 );
+ break;
+ default: DBG_ERROR_BIFF();
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpScl::XclExpScl( sal_uInt16 nZoom ) :
+ XclExpRecord( EXC_ID_SCL, 4 ),
+ mnNum( nZoom ),
+ mnDenom( 100 )
+{
+ Shorten( 2 );
+ Shorten( 5 );
+}
+
+void XclExpScl::Shorten( sal_uInt16 nFactor )
+{
+ while( (mnNum % nFactor == 0) && (mnDenom % nFactor == 0) )
+ {
+ mnNum = mnNum / nFactor;
+ mnDenom = mnDenom / nFactor;
+ }
+}
+
+void XclExpScl::WriteBody( XclExpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( rStrm.GetRoot().GetBiff() >= EXC_BIFF4 );
+ rStrm << mnNum << mnDenom;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpPane::XclExpPane( const XclTabViewData& rData ) :
+ XclExpRecord( EXC_ID_PANE, 10 ),
+ mnSplitX( rData.mnSplitX ),
+ mnSplitY( rData.mnSplitY ),
+ maSecondXclPos( rData.maSecondXclPos ),
+ mnActivePane( rData.mnActivePane )
+{
+ DBG_ASSERT( rData.IsSplit(), "XclExpPane::XclExpPane - no PANE record for unsplit view" );
+}
+
+static const char* lcl_GetActivePane( sal_uInt8 nActivePane )
+{
+ switch( nActivePane )
+ {
+ case EXC_PANE_TOPLEFT: return "topLeft"; //break;
+ case EXC_PANE_TOPRIGHT: return "topRight"; //break;
+ case EXC_PANE_BOTTOMLEFT: return "bottomLeft"; //break;
+ case EXC_PANE_BOTTOMRIGHT: return "bottomRight"; //break;
+ }
+ return "**error: lcl_GetActivePane";
+}
+
+void XclExpPane::SaveXml( XclExpXmlStream& rStrm )
+{
+ rStrm.GetCurrentStream()->singleElement( XML_pane,
+ XML_xSplit, OString::valueOf( (sal_Int32)mnSplitX ).getStr(),
+ XML_ySplit, OString::valueOf( (sal_Int32)mnSplitY ).getStr(),
+ XML_topLeftCell, XclXmlUtils::ToOString( maSecondXclPos ).getStr(),
+ XML_activePane, lcl_GetActivePane( mnActivePane ),
+ // OOXTODO: XML_state,
+ FSEND );
+}
+
+void XclExpPane::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << mnSplitX
+ << static_cast<sal_uInt16>( mnSplitY )
+ << maSecondXclPos
+ << mnActivePane;
+ if( rStrm.GetRoot().GetBiff() >= EXC_BIFF5 )
+ rStrm << sal_uInt8( 0 );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpSelection::XclExpSelection( const XclTabViewData& rData, sal_uInt8 nPane ) :
+ XclExpRecord( EXC_ID_SELECTION, 15 ),
+ mnPane( nPane )
+{
+ if( const XclSelectionData* pSelData = rData.GetSelectionData( nPane ) )
+ maSelData = *pSelData;
+
+ // find the cursor position in the selection list (or add it)
+ XclRangeList& rXclSel = maSelData.maXclSelection;
+ bool bFound = false;
+ for( XclRangeList::const_iterator aIt = rXclSel.begin(), aEnd = rXclSel.end(); !bFound && (aIt != aEnd); ++aIt )
+ if( (bFound = aIt->Contains( maSelData.maXclCursor )) == true )
+ maSelData.mnCursorIdx = static_cast< sal_uInt16 >( aIt - rXclSel.begin() );
+ /* Cursor cell not found in list? (e.g. inactive pane, or removed in
+ ConvertRangeList(), because Calc cursor on invalid pos)
+ -> insert the valid Excel cursor. */
+ if( !bFound )
+ {
+ maSelData.mnCursorIdx = static_cast< sal_uInt16 >( rXclSel.size() );
+ rXclSel.push_back( XclRange( maSelData.maXclCursor ) );
+ }
+}
+
+void XclExpSelection::SaveXml( XclExpXmlStream& rStrm )
+{
+ rStrm.GetCurrentStream()->singleElement( XML_selection,
+ XML_pane, lcl_GetActivePane( mnPane ),
+ XML_activeCell, XclXmlUtils::ToOString( maSelData.maXclCursor ).getStr(),
+ XML_activeCellId, OString::valueOf( (sal_Int32) maSelData.mnCursorIdx ).getStr(),
+ XML_sqref, XclXmlUtils::ToOString( maSelData.maXclSelection ).getStr(),
+ FSEND );
+}
+
+void XclExpSelection::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << mnPane // pane for this selection
+ << maSelData.maXclCursor // cell cursor
+ << maSelData.mnCursorIdx; // index to range containing cursor
+ maSelData.maXclSelection.Write( rStrm, false );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpTabBgColor::XclExpTabBgColor( const XclTabViewData& rTabViewData ) :
+ XclExpRecord( EXC_ID_SHEETEXT, 18 ),
+ mrTabViewData( rTabViewData )
+{
+}
+//TODO Fix savexml...
+/*void XclExpTabBgColor::SaveXml( XclExpXmlStream& rStrm )
+{
+}*/
+
+void XclExpTabBgColor::WriteBody( XclExpStream& rStrm )
+{
+ if ( mrTabViewData.IsDefaultTabBgColor() )
+ return;
+ sal_uInt16 rt = 0x0862; //rt
+ sal_uInt16 grbitFrt = 0x0000; //grbit must be set to 0
+ sal_uInt32 unused = 0x00000000; //Use twice...
+ sal_uInt32 cb = 0x00000014; // Record Size, may be larger in future...
+ sal_uInt16 reserved = 0x0000; //trailing bits are 0
+ sal_uInt16 TabBgColorIndex;
+ XclExpPalette& rPal = rStrm.GetRoot().GetPalette();
+ TabBgColorIndex = rPal.GetColorIndex(mrTabViewData.mnTabBgColorId);
+ if (TabBgColorIndex < 8 || TabBgColorIndex > 63 ) // only numbers 8 - 63 are valid numbers
+ TabBgColorIndex = 127; //Excel specs: 127 makes excel ignore tab color information.
+ rStrm << rt << grbitFrt << unused << unused << cb << TabBgColorIndex << reserved;
+}
+
+// Sheet view settings ========================================================
+
+namespace {
+
+/** Converts a Calc zoom factor into an Excel zoom factor. Returns 0 for a default zoom value. */
+sal_uInt16 lclGetXclZoom( long nScZoom, sal_uInt16 nDefXclZoom )
+{
+ sal_uInt16 nXclZoom = limit_cast< sal_uInt16 >( nScZoom, EXC_ZOOM_MIN, EXC_ZOOM_MAX );
+ return (nXclZoom == nDefXclZoom) ? 0 : nXclZoom;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclExpTabViewSettings::XclExpTabViewSettings( const XclExpRoot& rRoot, SCTAB nScTab ) :
+ XclExpRoot( rRoot ),
+ mnGridColorId( XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT ) )
+{
+ // *** sheet flags ***
+
+ const XclExpTabInfo& rTabInfo = GetTabInfo();
+ maData.mbSelected = rTabInfo.IsSelectedTab( nScTab );
+ maData.mbDisplayed = rTabInfo.IsDisplayedTab( nScTab );
+ maData.mbMirrored = rTabInfo.IsMirroredTab( nScTab );
+
+ const ScViewOptions& rViewOpt = GetDoc().GetViewOptions();
+ maData.mbShowFormulas = rViewOpt.GetOption( VOPT_FORMULAS );
+ maData.mbShowHeadings = rViewOpt.GetOption( VOPT_HEADER );
+ maData.mbShowZeros = rViewOpt.GetOption( VOPT_NULLVALS );
+ maData.mbShowOutline = rViewOpt.GetOption( VOPT_OUTLINER );
+
+ // *** sheet options: cursor, selection, splits, grid color, zoom ***
+
+ if( const ScExtTabSettings* pTabSett = GetExtDocOptions().GetTabSettings( nScTab ) )
+ {
+ const ScExtTabSettings& rTabSett = *pTabSett;
+ XclExpAddressConverter& rAddrConv = GetAddressConverter();
+
+ // first visible cell in top-left pane
+ if( (rTabSett.maFirstVis.Col() >= 0) && (rTabSett.maFirstVis.Row() >= 0) )
+ maData.maFirstXclPos = rAddrConv.CreateValidAddress( rTabSett.maFirstVis, false );
+
+ // first visible cell in additional pane(s)
+ if( (rTabSett.maSecondVis.Col() >= 0) && (rTabSett.maSecondVis.Row() >= 0) )
+ maData.maSecondXclPos = rAddrConv.CreateValidAddress( rTabSett.maSecondVis, false );
+
+ // active pane
+ switch( rTabSett.meActivePane )
+ {
+ case SCEXT_PANE_TOPLEFT: maData.mnActivePane = EXC_PANE_TOPLEFT; break;
+ case SCEXT_PANE_TOPRIGHT: maData.mnActivePane = EXC_PANE_TOPRIGHT; break;
+ case SCEXT_PANE_BOTTOMLEFT: maData.mnActivePane = EXC_PANE_BOTTOMLEFT; break;
+ case SCEXT_PANE_BOTTOMRIGHT: maData.mnActivePane = EXC_PANE_BOTTOMRIGHT; break;
+ }
+
+ // freeze/split position
+ maData.mbFrozenPanes = rTabSett.mbFrozenPanes;
+ if( maData.mbFrozenPanes )
+ {
+ /* Frozen panes: handle split position as row/column positions.
+ #i35812# Excel uses number of visible rows/columns, Calc uses position of freeze. */
+ SCCOL nFreezeScCol = rTabSett.maFreezePos.Col();
+ if( (0 < nFreezeScCol) && (nFreezeScCol <= GetXclMaxPos().Col()) )
+ maData.mnSplitX = static_cast< sal_uInt16 >( nFreezeScCol ) - maData.maFirstXclPos.mnCol;
+ SCROW nFreezeScRow = rTabSett.maFreezePos.Row();
+ if( (0 < nFreezeScRow) && (nFreezeScRow <= GetXclMaxPos().Row()) )
+ maData.mnSplitY = static_cast< sal_uInt32 >( nFreezeScRow ) - maData.maFirstXclPos.mnRow;
+ // if both splits are left out (address overflow), remove the frozen flag
+ maData.mbFrozenPanes = maData.IsSplit();
+
+ // #i20671# frozen panes: mostright/mostbottom pane is active regardless of cursor position
+ if( maData.HasPane( EXC_PANE_BOTTOMRIGHT ) )
+ maData.mnActivePane = EXC_PANE_BOTTOMRIGHT;
+ else if( maData.HasPane( EXC_PANE_TOPRIGHT ) )
+ maData.mnActivePane = EXC_PANE_TOPRIGHT;
+ else if( maData.HasPane( EXC_PANE_BOTTOMLEFT ) )
+ maData.mnActivePane = EXC_PANE_BOTTOMLEFT;
+ }
+ else
+ {
+ // split window: position is in twips
+ maData.mnSplitX = ulimit_cast< sal_uInt16 >( rTabSett.maSplitPos.X() );
+ maData.mnSplitY = ulimit_cast< sal_uInt32 >( rTabSett.maSplitPos.Y() );
+ }
+
+ // selection
+ CreateSelectionData( EXC_PANE_TOPLEFT, rTabSett.maCursor, rTabSett.maSelection );
+ CreateSelectionData( EXC_PANE_TOPRIGHT, rTabSett.maCursor, rTabSett.maSelection );
+ CreateSelectionData( EXC_PANE_BOTTOMLEFT, rTabSett.maCursor, rTabSett.maSelection );
+ CreateSelectionData( EXC_PANE_BOTTOMRIGHT, rTabSett.maCursor, rTabSett.maSelection );
+
+ // grid color
+ const Color& rGridColor = rTabSett.maGridColor;
+ maData.mbDefGridColor = rGridColor.GetColor() == COL_AUTO;
+ if( !maData.mbDefGridColor )
+ {
+ if( GetBiff() == EXC_BIFF8 )
+ mnGridColorId = GetPalette().InsertColor( rGridColor, EXC_COLOR_GRID );
+ else
+ maData.maGridColor = rGridColor;
+ }
+ maData.mbShowGrid = rTabSett.mbShowGrid;
+
+ // view mode and zoom
+ maData.mbPageMode = (GetBiff() == EXC_BIFF8) && rTabSett.mbPageMode;
+ maData.mnNormalZoom = lclGetXclZoom( rTabSett.mnNormalZoom, EXC_WIN2_NORMALZOOM_DEF );
+ maData.mnPageZoom = lclGetXclZoom( rTabSett.mnPageZoom, EXC_WIN2_PAGEZOOM_DEF );
+ maData.mnCurrentZoom = maData.mbPageMode ? maData.mnPageZoom : maData.mnNormalZoom;
+ }
+
+ // Tab Bg Color
+ if ( GetBiff() == EXC_BIFF8 && !GetDoc().IsDefaultTabBgColor(nScTab) )
+ {
+ XclExpPalette& rPal = GetPalette();
+ maData.maTabBgColor = GetDoc().GetTabBgColor(nScTab);
+ maData.mnTabBgColorId = rPal.InsertColor(maData.maTabBgColor, EXC_COLOR_TABBG, EXC_COLOR_NOTABBG );
+ }
+}
+
+void XclExpTabViewSettings::Save( XclExpStream& rStrm )
+{
+ WriteWindow2( rStrm );
+ WriteScl( rStrm );
+ WritePane( rStrm );
+ WriteSelection( rStrm, EXC_PANE_TOPLEFT );
+ WriteSelection( rStrm, EXC_PANE_TOPRIGHT );
+ WriteSelection( rStrm, EXC_PANE_BOTTOMLEFT );
+ WriteSelection( rStrm, EXC_PANE_BOTTOMRIGHT );
+ WriteTabBgColor( rStrm );
+}
+
+static void lcl_WriteSelection( XclExpXmlStream& rStrm, const XclTabViewData& rData, sal_uInt8 nPane )
+{
+ if( rData.HasPane( nPane ) )
+ XclExpSelection( rData, nPane ).SaveXml( rStrm );
+}
+
+OString lcl_GetZoom( sal_uInt16 nZoom )
+{
+ if( nZoom )
+ return OString::valueOf( (sal_Int32)nZoom );
+ return OString( "100" );
+}
+
+void XclExpTabViewSettings::SaveXml( XclExpXmlStream& rStrm )
+{
+ sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+ rWorksheet->startElement( XML_sheetViews, FSEND );
+ rWorksheet->startElement( XML_sheetView,
+ XML_windowProtection, XclXmlUtils::ToPsz( maData.mbFrozenPanes ),
+ XML_showFormulas, XclXmlUtils::ToPsz( maData.mbShowFormulas ),
+ XML_showGridLines, XclXmlUtils::ToPsz( maData.mbShowGrid ),
+ XML_showRowColHeaders, XclXmlUtils::ToPsz( maData.mbShowHeadings ),
+ XML_showZeros, XclXmlUtils::ToPsz( maData.mbShowZeros ),
+ XML_rightToLeft, XclXmlUtils::ToPsz( maData.mbMirrored ),
+ XML_tabSelected, XclXmlUtils::ToPsz( maData.mbSelected ),
+ // OOXTODO: XML_showRuler,
+ XML_showOutlineSymbols, XclXmlUtils::ToPsz( maData.mbShowOutline ),
+ XML_defaultGridColor, mnGridColorId == XclExpPalette::GetColorIdFromIndex( EXC_COLOR_WINDOWTEXT ) ? "true" : "false",
+ // OOXTODO: XML_showWhiteSpace,
+ XML_view, maData.mbPageMode ? "pageBreakPreview" : "normal", // OOXTODO: pageLayout
+ XML_topLeftCell, XclXmlUtils::ToOString( maData.maFirstXclPos ).getStr(),
+ XML_colorId, OString::valueOf( (sal_Int32) rStrm.GetRoot().GetPalette().GetColorIndex( mnGridColorId ) ).getStr(),
+ XML_zoomScale, lcl_GetZoom( maData.mnCurrentZoom ).getStr(),
+ XML_zoomScaleNormal, lcl_GetZoom( maData.mnNormalZoom ).getStr(),
+ // OOXTODO: XML_zoomScaleSheetLayoutView,
+ XML_zoomScalePageLayoutView, lcl_GetZoom( maData.mnPageZoom ).getStr(),
+ XML_workbookViewId, "0", // OOXTODO? 0-based index of document(xl/workbook.xml)/workbook/bookviews/workbookView
+ // should always be 0, as we only generate 1 such element.
+ FSEND );
+ if( maData.IsSplit() )
+ {
+ XclExpPane aPane( maData );
+ aPane.SaveXml( rStrm );
+ }
+ lcl_WriteSelection( rStrm, maData, EXC_PANE_TOPLEFT );
+ lcl_WriteSelection( rStrm, maData, EXC_PANE_TOPRIGHT );
+ lcl_WriteSelection( rStrm, maData, EXC_PANE_BOTTOMLEFT );
+ lcl_WriteSelection( rStrm, maData, EXC_PANE_BOTTOMRIGHT );
+ rWorksheet->endElement( XML_sheetView );
+ // OOXTODO: XML_extLst
+ rWorksheet->endElement( XML_sheetViews );
+}
+
+// private --------------------------------------------------------------------
+
+void XclExpTabViewSettings::CreateSelectionData( sal_uInt8 nPane,
+ const ScAddress& rCursor, const ScRangeList& rSelection )
+{
+ if( maData.HasPane( nPane ) )
+ {
+ XclSelectionData& rSelData = maData.CreateSelectionData( nPane );
+
+ // first step: use top-left visible cell as cursor
+ rSelData.maXclCursor.mnCol = ((nPane == EXC_PANE_TOPLEFT) || (nPane == EXC_PANE_BOTTOMLEFT)) ?
+ maData.maFirstXclPos.mnCol : maData.maSecondXclPos.mnCol;
+ rSelData.maXclCursor.mnRow = ((nPane == EXC_PANE_TOPLEFT) || (nPane == EXC_PANE_TOPRIGHT)) ?
+ maData.maFirstXclPos.mnRow : maData.maSecondXclPos.mnRow;
+
+ // second step, active pane: create actual selection data with current cursor position
+ if( nPane == maData.mnActivePane )
+ {
+ XclExpAddressConverter& rAddrConv = GetAddressConverter();
+ // cursor position (keep top-left pane position from above, if rCursor is invalid)
+ if( (rCursor.Col() >= 0) && (rCursor.Row() >= 0) )
+ rSelData.maXclCursor = rAddrConv.CreateValidAddress( rCursor, false );
+ // selection
+ rAddrConv.ConvertRangeList( rSelData.maXclSelection, rSelection, false );
+ }
+ }
+}
+
+void XclExpTabViewSettings::WriteWindow2( XclExpStream& rStrm ) const
+{
+// #i43553# GCC 3.3 parse error
+// XclExpWindow2( GetRoot(), maData, mnGridColorId ).Save( rStrm );
+ XclExpWindow2 aWindow2( GetRoot(), maData, mnGridColorId );
+ aWindow2.Save( rStrm );
+}
+
+void XclExpTabViewSettings::WriteScl( XclExpStream& rStrm ) const
+{
+ if( maData.mnCurrentZoom != 0 )
+ XclExpScl( maData.mnCurrentZoom ).Save( rStrm );
+}
+
+void XclExpTabViewSettings::WritePane( XclExpStream& rStrm ) const
+{
+ if( maData.IsSplit() )
+// #i43553# GCC 3.3 parse error
+// XclExpPane( GetRoot(), maData ).Save( rStrm );
+ {
+ XclExpPane aPane( maData );
+ aPane.Save( rStrm );
+ }
+}
+
+void XclExpTabViewSettings::WriteSelection( XclExpStream& rStrm, sal_uInt8 nPane ) const
+{
+ if( maData.HasPane( nPane ) )
+ XclExpSelection( maData, nPane ).Save( rStrm );
+}
+
+void XclExpTabViewSettings::WriteTabBgColor( XclExpStream& rStrm ) const
+{
+ if ( !maData.IsDefaultTabBgColor() )
+ XclExpTabBgColor( maData ).Save( rStrm );
+}
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xichart.cxx b/sc/source/filter/excel/xichart.cxx
new file mode 100644
index 000000000000..0393ad2d45bf
--- /dev/null
+++ b/sc/source/filter/excel/xichart.cxx
@@ -0,0 +1,4332 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "xichart.hxx"
+
+#include <algorithm>
+#include <memory>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/drawing/Direction3D.hpp>
+#include <com/sun/star/drawing/ProjectionMode.hpp>
+#include <com/sun/star/drawing/ShadeMode.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
+#include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
+#include <com/sun/star/chart/ChartAxisMarkPosition.hpp>
+#include <com/sun/star/chart/ChartAxisPosition.hpp>
+#include <com/sun/star/chart/ChartLegendExpansion.hpp>
+#include <com/sun/star/chart/TimeInterval.hpp>
+#include <com/sun/star/chart/TimeUnit.hpp>
+#include <com/sun/star/chart/XChartDocument.hpp>
+#include <com/sun/star/chart/XDiagramPositioning.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart2/XDiagram.hpp>
+#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
+#include <com/sun/star/chart2/XChartTypeContainer.hpp>
+#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
+#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
+#include <com/sun/star/chart2/XTitled.hpp>
+#include <com/sun/star/chart2/data/XDataProvider.hpp>
+#include <com/sun/star/chart2/data/XDataReceiver.hpp>
+#include <com/sun/star/chart2/data/XDataSink.hpp>
+#include <com/sun/star/chart2/AxisType.hpp>
+#include <com/sun/star/chart2/CurveStyle.hpp>
+#include <com/sun/star/chart2/DataPointGeometry3D.hpp>
+#include <com/sun/star/chart2/DataPointLabel.hpp>
+#include <com/sun/star/chart2/LegendPosition.hpp>
+#include <com/sun/star/chart2/StackingDirection.hpp>
+#include <com/sun/star/chart2/TickmarkStyle.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
+#include <com/sun/star/chart2/RelativeSize.hpp>
+#include <com/sun/star/chart/DataLabelPlacement.hpp>
+#include <com/sun/star/chart/ErrorBarStyle.hpp>
+#include <com/sun/star/chart/MissingValueTreatment.hpp>
+
+#include <sfx2/objsh.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unoapi.hxx>
+
+#include "document.hxx"
+#include "drwlayer.hxx"
+#include "rangeutl.hxx"
+#include "tokenarray.hxx"
+#include "token.hxx"
+#include "compiler.hxx"
+#include "reftokenhelper.hxx"
+#include "chartlis.hxx"
+#include "fprogressbar.hxx"
+#include "xltracer.hxx"
+#include "xistream.hxx"
+#include "xiformula.hxx"
+#include "xistyle.hxx"
+#include "xipage.hxx"
+#include "xiview.hxx"
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::UNO_SET_THROW;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::frame::XModel;
+using ::com::sun::star::util::XNumberFormatsSupplier;
+using ::com::sun::star::drawing::XDrawPage;
+using ::com::sun::star::drawing::XDrawPageSupplier;
+using ::com::sun::star::drawing::XShape;
+
+using ::com::sun::star::chart2::IncrementData;
+using ::com::sun::star::chart2::RelativePosition;
+using ::com::sun::star::chart2::RelativeSize;
+using ::com::sun::star::chart2::ScaleData;
+using ::com::sun::star::chart2::SubIncrement;
+using ::com::sun::star::chart2::XAxis;
+using ::com::sun::star::chart2::XChartDocument;
+using ::com::sun::star::chart2::XChartType;
+using ::com::sun::star::chart2::XChartTypeContainer;
+using ::com::sun::star::chart2::XCoordinateSystem;
+using ::com::sun::star::chart2::XCoordinateSystemContainer;
+using ::com::sun::star::chart2::XDataSeries;
+using ::com::sun::star::chart2::XDataSeriesContainer;
+using ::com::sun::star::chart2::XDiagram;
+using ::com::sun::star::chart2::XFormattedString;
+using ::com::sun::star::chart2::XLegend;
+using ::com::sun::star::chart2::XRegressionCurve;
+using ::com::sun::star::chart2::XRegressionCurveContainer;
+using ::com::sun::star::chart2::XScaling;
+using ::com::sun::star::chart2::XTitle;
+using ::com::sun::star::chart2::XTitled;
+
+using ::com::sun::star::chart2::data::XDataProvider;
+using ::com::sun::star::chart2::data::XDataReceiver;
+using ::com::sun::star::chart2::data::XDataSequence;
+using ::com::sun::star::chart2::data::XDataSink;
+using ::com::sun::star::chart2::data::XLabeledDataSequence;
+
+using ::formula::FormulaToken;
+using ::formula::StackVar;
+using ::boost::shared_ptr;
+using ::std::pair;
+using ::std::auto_ptr;
+
+namespace cssc = ::com::sun::star::chart;
+namespace cssc2 = ::com::sun::star::chart2;
+
+// Helpers ====================================================================
+
+namespace {
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclChRectangle& rRect )
+{
+ return rStrm >> rRect.mnX >> rRect.mnY >> rRect.mnWidth >> rRect.mnHeight;
+}
+
+inline void lclSetValueOrClearAny( Any& rAny, double fValue, bool bClear )
+{
+ if( bClear )
+ rAny.clear();
+ else
+ rAny <<= fValue;
+}
+
+void lclSetExpValueOrClearAny( Any& rAny, double fValue, bool bLogScale, bool bClear )
+{
+ if( !bClear && bLogScale )
+ fValue = pow( 10.0, fValue );
+ lclSetValueOrClearAny( rAny, fValue, bClear );
+}
+
+double lclGetSerialDay( const XclImpRoot& rRoot, sal_uInt16 nValue, sal_uInt16 nTimeUnit )
+{
+ switch( nTimeUnit )
+ {
+ case EXC_CHDATERANGE_DAYS:
+ return nValue;
+ case EXC_CHDATERANGE_MONTHS:
+ return rRoot.GetDoubleFromDateTime( Date( 1, static_cast< sal_uInt16 >( 1 + nValue % 12 ), static_cast< sal_uInt16 >( rRoot.GetBaseYear() + nValue / 12 ) ) );
+ case EXC_CHDATERANGE_YEARS:
+ return rRoot.GetDoubleFromDateTime( Date( 1, 1, static_cast< sal_uInt16 >( rRoot.GetBaseYear() + nValue ) ) );
+ default:
+ OSL_ENSURE( false, "lclGetSerialDay - unexpected time unit" );
+ }
+ return nValue;
+}
+
+void lclConvertTimeValue( const XclImpRoot& rRoot, Any& rAny, sal_uInt16 nValue, bool bAuto, sal_uInt16 nTimeUnit )
+{
+ if( bAuto )
+ rAny.clear();
+ else
+ rAny <<= lclGetSerialDay( rRoot, nValue, nTimeUnit );
+}
+
+sal_Int32 lclGetApiTimeUnit( sal_uInt16 nTimeUnit )
+{
+ switch( nTimeUnit )
+ {
+ case EXC_CHDATERANGE_DAYS: return cssc::TimeUnit::DAY;
+ case EXC_CHDATERANGE_MONTHS: return cssc::TimeUnit::MONTH;
+ case EXC_CHDATERANGE_YEARS: return cssc::TimeUnit::YEAR;
+ default: OSL_ENSURE( false, "lclGetApiTimeUnit - unexpected time unit" );
+ }
+ return cssc::TimeUnit::DAY;
+}
+
+void lclConvertTimeInterval( Any& rInterval, sal_uInt16 nValue, bool bAuto, sal_uInt16 nTimeUnit )
+{
+ if( bAuto || (nValue == 0) )
+ rInterval.clear();
+ else
+ rInterval <<= cssc::TimeInterval( nValue, lclGetApiTimeUnit( nTimeUnit ) );
+}
+
+} // namespace
+
+// Common =====================================================================
+
+/** Stores global data needed in various classes of the Chart import filter. */
+struct XclImpChRootData : public XclChRootData
+{
+ XclImpChChart& mrChartData; /// The chart data object.
+
+ inline explicit XclImpChRootData( XclImpChChart& rChartData ) : mrChartData( rChartData ) {}
+};
+
+// ----------------------------------------------------------------------------
+
+XclImpChRoot::XclImpChRoot( const XclImpRoot& rRoot, XclImpChChart& rChartData ) :
+ XclImpRoot( rRoot ),
+ mxChData( new XclImpChRootData( rChartData ) )
+{
+}
+
+XclImpChRoot::~XclImpChRoot()
+{
+}
+
+XclImpChChart& XclImpChRoot::GetChartData() const
+{
+ return mxChData->mrChartData;
+}
+
+const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( XclChTypeId eType ) const
+{
+ return mxChData->mxTypeInfoProv->GetTypeInfo( eType );
+}
+
+const XclChTypeInfo& XclImpChRoot::GetChartTypeInfo( sal_uInt16 nRecId ) const
+{
+ return mxChData->mxTypeInfoProv->GetTypeInfoFromRecId( nRecId );
+}
+
+const XclChFormatInfo& XclImpChRoot::GetFormatInfo( XclChObjectType eObjType ) const
+{
+ return mxChData->mxFmtInfoProv->GetFormatInfo( eObjType );
+}
+
+Color XclImpChRoot::GetFontAutoColor() const
+{
+ return GetPalette().GetColor( EXC_COLOR_CHWINDOWTEXT );
+}
+
+Color XclImpChRoot::GetSeriesLineAutoColor( sal_uInt16 nFormatIdx ) const
+{
+ return GetPalette().GetColor( XclChartHelper::GetSeriesLineAutoColorIdx( nFormatIdx ) );
+}
+
+Color XclImpChRoot::GetSeriesFillAutoColor( sal_uInt16 nFormatIdx ) const
+{
+ const XclImpPalette& rPal = GetPalette();
+ Color aColor = rPal.GetColor( XclChartHelper::GetSeriesFillAutoColorIdx( nFormatIdx ) );
+ sal_uInt8 nTrans = XclChartHelper::GetSeriesFillAutoTransp( nFormatIdx );
+ return ScfTools::GetMixedColor( aColor, rPal.GetColor( EXC_COLOR_CHWINDOWBACK ), nTrans );
+}
+
+void XclImpChRoot::InitConversion( Reference< XChartDocument > xChartDoc, const Rectangle& rChartRect ) const
+{
+ // create formatting object tables
+ mxChData->InitConversion( GetRoot(), xChartDoc, rChartRect );
+
+ // lock the model to suppress any internal updates
+ Reference< XModel > xModel( xChartDoc, UNO_QUERY );
+ if( xModel.is() )
+ xModel->lockControllers();
+
+ SfxObjectShell* pDocShell = GetDocShell();
+ Reference< XDataReceiver > xDataRec( xChartDoc, UNO_QUERY );
+ if( pDocShell && xDataRec.is() )
+ {
+ // create and register a data provider
+ Reference< XDataProvider > xDataProv(
+ ScfApiHelper::CreateInstance( pDocShell, SERVICE_CHART2_DATAPROVIDER ), UNO_QUERY );
+ if( xDataProv.is() )
+ xDataRec->attachDataProvider( xDataProv );
+ // attach the number formatter
+ Reference< XNumberFormatsSupplier > xNumFmtSupp( pDocShell->GetModel(), UNO_QUERY );
+ if( xNumFmtSupp.is() )
+ xDataRec->attachNumberFormatsSupplier( xNumFmtSupp );
+ }
+}
+
+void XclImpChRoot::FinishConversion( XclImpDffConverter& rDffConv ) const
+{
+ rDffConv.Progress( EXC_CHART_PROGRESS_SIZE );
+ // unlock the model
+ Reference< XModel > xModel( mxChData->mxChartDoc, UNO_QUERY );
+ if( xModel.is() )
+ xModel->unlockControllers();
+ rDffConv.Progress( EXC_CHART_PROGRESS_SIZE );
+
+ mxChData->FinishConversion();
+}
+
+Reference< XDataProvider > XclImpChRoot::GetDataProvider() const
+{
+ return mxChData->mxChartDoc->getDataProvider();
+}
+
+Reference< XShape > XclImpChRoot::GetTitleShape( const XclChTextKey& rTitleKey ) const
+{
+ return mxChData->GetTitleShape( rTitleKey );
+}
+
+sal_Int32 XclImpChRoot::CalcHmmFromChartX( sal_Int32 nPosX ) const
+{
+ return static_cast< sal_Int32 >( mxChData->mfUnitSizeX * nPosX + mxChData->mnBorderGapX + 0.5 );
+}
+
+sal_Int32 XclImpChRoot::CalcHmmFromChartY( sal_Int32 nPosY ) const
+{
+ return static_cast< sal_Int32 >( mxChData->mfUnitSizeY * nPosY + mxChData->mnBorderGapY + 0.5 );
+}
+
+::com::sun::star::awt::Rectangle XclImpChRoot::CalcHmmFromChartRect( const XclChRectangle& rRect ) const
+{
+ return ::com::sun::star::awt::Rectangle(
+ CalcHmmFromChartX( rRect.mnX ),
+ CalcHmmFromChartY( rRect.mnY ),
+ CalcHmmFromChartX( rRect.mnWidth ),
+ CalcHmmFromChartY( rRect.mnHeight ) );
+}
+
+double XclImpChRoot::CalcRelativeFromHmmX( sal_Int32 nPosX ) const
+{
+ return static_cast< double >( nPosX ) / mxChData->maChartRect.GetWidth();
+}
+
+double XclImpChRoot::CalcRelativeFromHmmY( sal_Int32 nPosY ) const
+{
+ return static_cast< double >( nPosY ) / mxChData->maChartRect.GetHeight();
+}
+
+double XclImpChRoot::CalcRelativeFromChartX( sal_Int32 nPosX ) const
+{
+ return CalcRelativeFromHmmX( CalcHmmFromChartX( nPosX ) );
+}
+
+double XclImpChRoot::CalcRelativeFromChartY( sal_Int32 nPosY ) const
+{
+ return CalcRelativeFromHmmY( CalcHmmFromChartY( nPosY ) );
+}
+
+void XclImpChRoot::ConvertLineFormat( ScfPropertySet& rPropSet,
+ const XclChLineFormat& rLineFmt, XclChPropertyMode ePropMode ) const
+{
+ GetChartPropSetHelper().WriteLineProperties(
+ rPropSet, *mxChData->mxLineDashTable, rLineFmt, ePropMode );
+}
+
+void XclImpChRoot::ConvertAreaFormat( ScfPropertySet& rPropSet,
+ const XclChAreaFormat& rAreaFmt, XclChPropertyMode ePropMode ) const
+{
+ GetChartPropSetHelper().WriteAreaProperties( rPropSet, rAreaFmt, ePropMode );
+}
+
+void XclImpChRoot::ConvertEscherFormat( ScfPropertySet& rPropSet,
+ const XclChEscherFormat& rEscherFmt, const XclChPicFormat& rPicFmt,
+ XclChPropertyMode ePropMode ) const
+{
+ GetChartPropSetHelper().WriteEscherProperties( rPropSet,
+ *mxChData->mxGradientTable, *mxChData->mxHatchTable, *mxChData->mxBitmapTable,
+ rEscherFmt, rPicFmt, ePropMode );
+}
+
+void XclImpChRoot::ConvertFont( ScfPropertySet& rPropSet,
+ sal_uInt16 nFontIdx, const Color* pFontColor ) const
+{
+ GetFontBuffer().WriteFontProperties( rPropSet, EXC_FONTPROPSET_CHART, nFontIdx, pFontColor );
+}
+
+void XclImpChRoot::ConvertPieRotation( ScfPropertySet& rPropSet, sal_uInt16 nAngle )
+{
+ sal_Int32 nApiRot = (450 - (nAngle % 360)) % 360;
+ rPropSet.SetProperty( EXC_CHPROP_STARTINGANGLE, nApiRot );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChGroupBase::~XclImpChGroupBase()
+{
+}
+
+void XclImpChGroupBase::ReadRecordGroup( XclImpStream& rStrm )
+{
+ // read contents of the header record
+ ReadHeaderRecord( rStrm );
+
+ // only read sub records, if the next record is a CHBEGIN
+ if( rStrm.GetNextRecId() == EXC_ID_CHBEGIN )
+ {
+ // read the CHBEGIN record, may be used for special initial processing
+ rStrm.StartNextRecord();
+ ReadSubRecord( rStrm );
+
+ // read the nested records
+ bool bLoop = true;
+ while( bLoop && rStrm.StartNextRecord() )
+ {
+ sal_uInt16 nRecId = rStrm.GetRecId();
+ bLoop = nRecId != EXC_ID_CHEND;
+ // skip unsupported nested blocks
+ if( nRecId == EXC_ID_CHBEGIN )
+ SkipBlock( rStrm );
+ else
+ ReadSubRecord( rStrm );
+ }
+ }
+ /* Returns with current CHEND record or unchanged stream, if no record
+ group present. In every case another call to StartNextRecord() will go
+ to next record of interest. */
+}
+
+void XclImpChGroupBase::SkipBlock( XclImpStream& rStrm )
+{
+ DBG_ASSERT( rStrm.GetRecId() == EXC_ID_CHBEGIN, "XclImpChGroupBase::SkipBlock - no CHBEGIN record" );
+ // do nothing if current record is not CHBEGIN
+ bool bLoop = rStrm.GetRecId() == EXC_ID_CHBEGIN;
+ while( bLoop && rStrm.StartNextRecord() )
+ {
+ sal_uInt16 nRecId = rStrm.GetRecId();
+ bLoop = nRecId != EXC_ID_CHEND;
+ // skip nested record groups
+ if( nRecId == EXC_ID_CHBEGIN )
+ SkipBlock( rStrm );
+ }
+}
+
+// Frame formatting ===========================================================
+
+void XclImpChFramePos::ReadChFramePos( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnTLMode >> maData.mnBRMode;
+ /* According to the spec, the upper 16 bits of all members in the
+ rectangle are unused and may contain garbage. */
+ maData.maRect.mnX = rStrm.ReadInt16(); rStrm.Ignore( 2 );
+ maData.maRect.mnY = rStrm.ReadInt16(); rStrm.Ignore( 2 );
+ maData.maRect.mnWidth = rStrm.ReadInt16(); rStrm.Ignore( 2 );
+ maData.maRect.mnHeight = rStrm.ReadInt16(); rStrm.Ignore( 2 );
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpChLineFormat::ReadChLineFormat( XclImpStream& rStrm )
+{
+ rStrm >> maData.maColor >> maData.mnPattern >> maData.mnWeight >> maData.mnFlags;
+
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ if( rRoot.GetBiff() == EXC_BIFF8 )
+ // BIFF8: index into palette used instead of RGB data
+ maData.maColor = rRoot.GetPalette().GetColor( rStrm.ReaduInt16() );
+}
+
+void XclImpChLineFormat::Convert( const XclImpChRoot& rRoot,
+ ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
+{
+ const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
+ if( IsAuto() )
+ {
+ XclChLineFormat aLineFmt;
+ aLineFmt.maColor = (eObjType == EXC_CHOBJTYPE_LINEARSERIES) ?
+ rRoot.GetSeriesLineAutoColor( nFormatIdx ) :
+ rRoot.GetPalette().GetColor( rFmtInfo.mnAutoLineColorIdx );
+ aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
+ aLineFmt.mnWeight = rFmtInfo.mnAutoLineWeight;
+ rRoot.ConvertLineFormat( rPropSet, aLineFmt, rFmtInfo.mePropMode );
+ }
+ else
+ {
+ rRoot.ConvertLineFormat( rPropSet, maData, rFmtInfo.mePropMode );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpChAreaFormat::ReadChAreaFormat( XclImpStream& rStrm )
+{
+ rStrm >> maData.maPattColor >> maData.maBackColor >> maData.mnPattern >> maData.mnFlags;
+
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ if( rRoot.GetBiff() == EXC_BIFF8 )
+ {
+ // BIFF8: index into palette used instead of RGB data
+ const XclImpPalette& rPal = rRoot.GetPalette();
+ maData.maPattColor = rPal.GetColor( rStrm.ReaduInt16() );
+ maData.maBackColor = rPal.GetColor( rStrm.ReaduInt16());
+ }
+}
+
+void XclImpChAreaFormat::Convert( const XclImpChRoot& rRoot,
+ ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
+{
+ const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
+ if( IsAuto() )
+ {
+ XclChAreaFormat aAreaFmt;
+ aAreaFmt.maPattColor = (eObjType == EXC_CHOBJTYPE_FILLEDSERIES) ?
+ rRoot.GetSeriesFillAutoColor( nFormatIdx ) :
+ rRoot.GetPalette().GetColor( rFmtInfo.mnAutoPattColorIdx );
+ aAreaFmt.mnPattern = EXC_PATT_SOLID;
+ rRoot.ConvertAreaFormat( rPropSet, aAreaFmt, rFmtInfo.mePropMode );
+ }
+ else
+ {
+ rRoot.ConvertAreaFormat( rPropSet, maData, rFmtInfo.mePropMode );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChEscherFormat::XclImpChEscherFormat( const XclImpRoot& rRoot )
+{
+ maData.mxItemSet.reset(
+ new SfxItemSet( rRoot.GetDoc().GetDrawLayer()->GetItemPool() ) );
+}
+
+void XclImpChEscherFormat::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ // read from stream - CHESCHERFORMAT uses own ID for record continuation
+ XclImpDffPropSet aPropSet( rStrm.GetRoot() );
+ rStrm.ResetRecord( true, rStrm.GetRecId() );
+ rStrm >> aPropSet;
+ // get the data
+ aPropSet.FillToItemSet( *maData.mxItemSet );
+ // get bitmap mode from DFF item set
+ sal_uInt32 nType = aPropSet.GetPropertyValue( DFF_Prop_fillType, mso_fillSolid );
+ maPicFmt.mnBmpMode = (nType == mso_fillPicture) ? EXC_CHPICFORMAT_STRETCH : EXC_CHPICFORMAT_STACK;
+}
+
+void XclImpChEscherFormat::ReadSubRecord( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_CHPICFORMAT:
+ rStrm >> maPicFmt.mnBmpMode >> maPicFmt.mnFormat >> maPicFmt.mnFlags >> maPicFmt.mfScale;
+ break;
+ }
+}
+
+void XclImpChEscherFormat::Convert( const XclImpChRoot& rRoot,
+ ScfPropertySet& rPropSet, XclChObjectType eObjType ) const
+{
+ const XclChFormatInfo& rFmtInfo = rRoot.GetFormatInfo( eObjType );
+ rRoot.ConvertEscherFormat( rPropSet, maData, maPicFmt, rFmtInfo.mePropMode );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChFrameBase::XclImpChFrameBase( const XclChFormatInfo& rFmtInfo )
+{
+ if( rFmtInfo.mbCreateDefFrame ) switch( rFmtInfo.meDefFrameType )
+ {
+ case EXC_CHFRAMETYPE_AUTO:
+ mxLineFmt.reset( new XclImpChLineFormat );
+ if( rFmtInfo.mbIsFrame )
+ mxAreaFmt.reset( new XclImpChAreaFormat );
+ break;
+ case EXC_CHFRAMETYPE_INVISIBLE:
+ {
+ XclChLineFormat aLineFmt;
+ ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, false );
+ aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE;
+ mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) );
+ if( rFmtInfo.mbIsFrame )
+ {
+ XclChAreaFormat aAreaFmt;
+ ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, false );
+ aAreaFmt.mnPattern = EXC_PATT_NONE;
+ mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) );
+ }
+ }
+ break;
+ default:
+ DBG_ERRORFILE( "XclImpChFrameBase::XclImpChFrameBase - unknown frame type" );
+ }
+}
+
+void XclImpChFrameBase::ReadSubRecord( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_CHLINEFORMAT:
+ mxLineFmt.reset( new XclImpChLineFormat );
+ mxLineFmt->ReadChLineFormat( rStrm );
+ break;
+ case EXC_ID_CHAREAFORMAT:
+ mxAreaFmt.reset( new XclImpChAreaFormat );
+ mxAreaFmt->ReadChAreaFormat( rStrm );
+ break;
+ case EXC_ID_CHESCHERFORMAT:
+ mxEscherFmt.reset( new XclImpChEscherFormat( rStrm.GetRoot() ) );
+ mxEscherFmt->ReadRecordGroup( rStrm );
+ break;
+ }
+}
+
+void XclImpChFrameBase::ConvertLineBase( const XclImpChRoot& rRoot,
+ ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
+{
+ if( mxLineFmt )
+ mxLineFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx );
+}
+
+void XclImpChFrameBase::ConvertAreaBase( const XclImpChRoot& rRoot,
+ ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
+{
+ if( rRoot.GetFormatInfo( eObjType ).mbIsFrame )
+ {
+ // CHESCHERFORMAT overrides CHAREAFORMAT (even if it is auto)
+ if( mxEscherFmt )
+ mxEscherFmt->Convert( rRoot, rPropSet, eObjType );
+ else if( mxAreaFmt )
+ mxAreaFmt->Convert( rRoot, rPropSet, eObjType, nFormatIdx );
+ }
+}
+
+void XclImpChFrameBase::ConvertFrameBase( const XclImpChRoot& rRoot,
+ ScfPropertySet& rPropSet, XclChObjectType eObjType, sal_uInt16 nFormatIdx ) const
+{
+ ConvertLineBase( rRoot, rPropSet, eObjType, nFormatIdx );
+ ConvertAreaBase( rRoot, rPropSet, eObjType, nFormatIdx );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChFrame::XclImpChFrame( const XclImpChRoot& rRoot, XclChObjectType eObjType ) :
+ XclImpChFrameBase( rRoot.GetFormatInfo( eObjType ) ),
+ XclImpChRoot( rRoot ),
+ meObjType( eObjType )
+{
+}
+
+void XclImpChFrame::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnFormat >> maData.mnFlags;
+}
+
+void XclImpChFrame::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
+{
+ const XclImpPalette& rPal = GetPalette();
+
+ if( rLineData.IsVisible() && (!mxLineFmt || !mxLineFmt->HasLine()) )
+ {
+ // line formatting
+ XclChLineFormat aLineFmt;
+ aLineFmt.maColor = rPal.GetColor( rLineData.mnColorIdx );
+ switch( rLineData.mnStyle )
+ {
+ case EXC_OBJ_LINE_SOLID: aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID; break;
+ case EXC_OBJ_LINE_DASH: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASH; break;
+ case EXC_OBJ_LINE_DOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DOT; break;
+ case EXC_OBJ_LINE_DASHDOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOT; break;
+ case EXC_OBJ_LINE_DASHDOTDOT: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DASHDOTDOT; break;
+ case EXC_OBJ_LINE_MEDTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_MEDTRANS; break;
+ case EXC_OBJ_LINE_DARKTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_DARKTRANS; break;
+ case EXC_OBJ_LINE_LIGHTTRANS: aLineFmt.mnPattern = EXC_CHLINEFORMAT_LIGHTTRANS; break;
+ case EXC_OBJ_LINE_NONE: aLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE; break;
+ default: aLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
+ }
+ switch( rLineData.mnWidth )
+ {
+ case EXC_OBJ_LINE_HAIR: aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR; break;
+ case EXC_OBJ_LINE_THIN: aLineFmt.mnWeight = EXC_CHLINEFORMAT_SINGLE; break;
+ case EXC_OBJ_LINE_MEDIUM: aLineFmt.mnWeight = EXC_CHLINEFORMAT_DOUBLE; break;
+ case EXC_OBJ_LINE_THICK: aLineFmt.mnWeight = EXC_CHLINEFORMAT_TRIPLE; break;
+ default: aLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR;
+ }
+ ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, rLineData.IsAuto() );
+ mxLineFmt.reset( new XclImpChLineFormat( aLineFmt ) );
+ }
+
+ if( rFillData.IsFilled() && (!mxAreaFmt || !mxAreaFmt->HasArea()) && !mxEscherFmt )
+ {
+ // area formatting
+ XclChAreaFormat aAreaFmt;
+ aAreaFmt.maPattColor = rPal.GetColor( rFillData.mnPattColorIdx );
+ aAreaFmt.maBackColor = rPal.GetColor( rFillData.mnBackColorIdx );
+ aAreaFmt.mnPattern = rFillData.mnPattern;
+ ::set_flag( aAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, rFillData.IsAuto() );
+ mxAreaFmt.reset( new XclImpChAreaFormat( aAreaFmt ) );
+ }
+}
+
+void XclImpChFrame::Convert( ScfPropertySet& rPropSet ) const
+{
+ ConvertFrameBase( GetChRoot(), rPropSet, meObjType );
+}
+
+// Source links ===============================================================
+
+namespace {
+
+/** Creates a labeled data sequence object, adds link for series title if present. */
+Reference< XLabeledDataSequence > lclCreateLabeledDataSequence(
+ XclImpChSourceLinkRef xValueLink, const OUString& rValueRole,
+ const XclImpChSourceLink* pTitleLink = 0 )
+{
+ // create data sequence for values and title
+ Reference< XDataSequence > xValueSeq;
+ if( xValueLink )
+ xValueSeq = xValueLink->CreateDataSequence( rValueRole );
+ Reference< XDataSequence > xTitleSeq;
+ if( pTitleLink )
+ xTitleSeq = pTitleLink->CreateDataSequence( EXC_CHPROP_ROLE_LABEL );
+
+ // create the labeled data sequence, if values or title are present
+ Reference< XLabeledDataSequence > xLabeledSeq;
+ if( xValueSeq.is() || xTitleSeq.is() )
+ xLabeledSeq.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_LABELEDDATASEQ ), UNO_QUERY );
+ if( xLabeledSeq.is() )
+ {
+ if( xValueSeq.is() )
+ xLabeledSeq->setValues( xValueSeq );
+ if( xTitleSeq.is() )
+ xLabeledSeq->setLabel( xTitleSeq );
+ }
+ return xLabeledSeq;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclImpChSourceLink::XclImpChSourceLink( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot )
+{
+}
+
+XclImpChSourceLink::~XclImpChSourceLink()
+{
+}
+
+void XclImpChSourceLink::ReadChSourceLink( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnDestType
+ >> maData.mnLinkType
+ >> maData.mnFlags
+ >> maData.mnNumFmtIdx;
+
+ mxTokenArray.reset();
+ if( GetLinkType() == EXC_CHSRCLINK_WORKSHEET )
+ {
+ // read token array
+ XclTokenArray aXclTokArr;
+ rStrm >> aXclTokArr;
+
+ // convert BIFF formula tokens to Calc token array
+ if( const ScTokenArray* pTokens = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aXclTokArr ) )
+ mxTokenArray.reset( pTokens->Clone() );
+ }
+
+ // try to read a following CHSTRING record
+ if( (rStrm.GetNextRecId() == EXC_ID_CHSTRING) && rStrm.StartNextRecord() )
+ {
+ mxString.reset( new XclImpString );
+ rStrm.Ignore( 2 );
+ mxString->Read( rStrm, EXC_STR_8BITLENGTH | EXC_STR_SEPARATEFORMATS );
+ }
+}
+
+void XclImpChSourceLink::SetString( const String& rString )
+{
+ if( !mxString )
+ mxString.reset( new XclImpString );
+ mxString->SetText( rString );
+}
+
+void XclImpChSourceLink::SetTextFormats( const XclFormatRunVec& rFormats )
+{
+ if( mxString )
+ mxString->SetFormats( rFormats );
+}
+
+sal_uInt16 XclImpChSourceLink::GetCellCount() const
+{
+ sal_uInt32 nCellCount = 0;
+ if( mxTokenArray )
+ {
+ mxTokenArray->Reset();
+ for( const FormulaToken* pToken = mxTokenArray->First(); pToken; pToken = mxTokenArray->Next() )
+ {
+ switch( pToken->GetType() )
+ {
+ case ::formula::svSingleRef:
+ case ::formula::svExternalSingleRef:
+ // single cell
+ ++nCellCount;
+ break;
+ case ::formula::svDoubleRef:
+ case ::formula::svExternalDoubleRef:
+ {
+ // cell range
+ const ScComplexRefData& rComplexRef = static_cast< const ScToken* >( pToken )->GetDoubleRef();
+ const ScSingleRefData& rRef1 = rComplexRef.Ref1;
+ const ScSingleRefData& rRef2 = rComplexRef.Ref2;
+ sal_uInt32 nTabs = static_cast< sal_uInt32 >( rRef2.nTab - rRef1.nTab + 1 );
+ sal_uInt32 nCols = static_cast< sal_uInt32 >( rRef2.nCol - rRef1.nCol + 1 );
+ sal_uInt32 nRows = static_cast< sal_uInt32 >( rRef2.nRow - rRef1.nRow + 1 );
+ nCellCount += nCols * nRows * nTabs;
+ }
+ break;
+ default: ;
+ }
+ }
+ }
+ return limit_cast< sal_uInt16 >( nCellCount );
+}
+
+void XclImpChSourceLink::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
+{
+ bool bLinkToSource = ::get_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT );
+ sal_uInt32 nScNumFmt = bLinkToSource ? GetNumFmtBuffer().GetScFormat( maData.mnNumFmtIdx ) : NUMBERFORMAT_ENTRY_NOT_FOUND;
+ OUString aPropName = bPercent ? EXC_CHPROP_PERCENTAGENUMFMT : EXC_CHPROP_NUMBERFORMAT;
+ if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
+ rPropSet.SetProperty( aPropName, static_cast< sal_Int32 >( nScNumFmt ) );
+ else
+ // restore 'link to source' at data point (series may contain manual number format)
+ rPropSet.SetAnyProperty( aPropName, Any() );
+}
+
+Reference< XDataSequence > XclImpChSourceLink::CreateDataSequence( const OUString& rRole ) const
+{
+ Reference< XDataSequence > xDataSeq;
+ Reference< XDataProvider > xDataProv = GetDataProvider();
+ if( xDataProv.is() && mxTokenArray )
+ {
+ ScCompiler aComp( GetDocPtr(), ScAddress(), *mxTokenArray );
+ aComp.SetGrammar( ::formula::FormulaGrammar::GRAM_ENGLISH );
+ OUStringBuffer aRangeRep;
+ aComp.CreateStringFromTokenArray( aRangeRep );
+ try
+ {
+ xDataSeq = xDataProv->createDataSequenceByRangeRepresentation( aRangeRep.makeStringAndClear() );
+ // set sequence role
+ ScfPropertySet aSeqProp( xDataSeq );
+ aSeqProp.SetProperty( EXC_CHPROP_ROLE, rRole );
+ }
+ catch( Exception& )
+ {
+// DBG_ERRORFILE( "XclImpChSourceLink::CreateDataSequence - cannot create data sequence" );
+ }
+ }
+ return xDataSeq;
+}
+
+Sequence< Reference< XFormattedString > > XclImpChSourceLink::CreateStringSequence(
+ const XclImpChRoot& rRoot, sal_uInt16 nLeadFontIdx, const Color& rLeadFontColor ) const
+{
+ ::std::vector< Reference< XFormattedString > > aStringVec;
+ if( mxString )
+ {
+ for( XclImpStringIterator aIt( *mxString ); aIt.Is(); ++aIt )
+ {
+ Reference< XFormattedString > xFmtStr(
+ ScfApiHelper::CreateInstance( SERVICE_CHART2_FORMATTEDSTRING ), UNO_QUERY );
+ if( xFmtStr.is() )
+ {
+ // set text data
+ xFmtStr->setString( aIt.GetPortionText() );
+
+ // set font formatting and font color
+ ScfPropertySet aStringProp( xFmtStr );
+ sal_uInt16 nFontIdx = aIt.GetPortionFont();
+ if( (nFontIdx == EXC_FONT_NOTFOUND) && (aIt.GetPortionIndex() == 0) )
+ // leading unformatted portion - use passed font settings
+ rRoot.ConvertFont( aStringProp, nLeadFontIdx, &rLeadFontColor );
+ else
+ rRoot.ConvertFont( aStringProp, nFontIdx );
+
+ // add string to vector of strings
+ aStringVec.push_back( xFmtStr );
+ }
+ }
+ }
+ return ScfApiHelper::VectorToSequence( aStringVec );
+}
+
+void XclImpChSourceLink::FillSourceLink( ::std::vector< ScTokenRef >& rTokens ) const
+{
+ if( !mxTokenArray )
+ // no links to fill.
+ return;
+
+ mxTokenArray->Reset();
+ for (FormulaToken* p = mxTokenArray->First(); p; p = mxTokenArray->Next())
+ {
+ ScTokenRef pToken(static_cast<ScToken*>(p->Clone()));
+ if (ScRefTokenHelper::isRef(pToken))
+ // This is a reference token. Store it.
+ ScRefTokenHelper::join(rTokens, pToken);
+ }
+}
+
+// Text =======================================================================
+
+XclImpChFontBase::~XclImpChFontBase()
+{
+}
+
+void XclImpChFontBase::ConvertFontBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const
+{
+ Color aFontColor = GetFontColor();
+ rRoot.ConvertFont( rPropSet, GetFontIndex(), &aFontColor );
+}
+
+void XclImpChFontBase::ConvertRotationBase( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet, bool bSupportsStacked ) const
+{
+ rRoot.GetChartPropSetHelper().WriteRotationProperties( rPropSet, GetRotation(), bSupportsStacked );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChFont::XclImpChFont() :
+ mnFontIdx( EXC_FONT_NOTFOUND )
+{
+}
+
+void XclImpChFont::ReadChFont( XclImpStream& rStrm )
+{
+ rStrm >> mnFontIdx;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChText::XclImpChText( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot )
+{
+}
+
+void XclImpChText::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnHAlign
+ >> maData.mnVAlign
+ >> maData.mnBackMode
+ >> maData.maTextColor
+ >> maData.maRect
+ >> maData.mnFlags;
+
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ // BIFF8: index into palette used instead of RGB data
+ maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() );
+ // placement and rotation
+ rStrm >> maData.mnFlags2 >> maData.mnRotation;
+ }
+ else
+ {
+ // BIFF2-BIFF7: get rotation from text orientation
+ sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 8, 3 );
+ maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient );
+ }
+}
+
+void XclImpChText::ReadSubRecord( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_CHFRAMEPOS:
+ mxFramePos.reset( new XclImpChFramePos );
+ mxFramePos->ReadChFramePos( rStrm );
+ break;
+ case EXC_ID_CHFONT:
+ mxFont.reset( new XclImpChFont );
+ mxFont->ReadChFont( rStrm );
+ break;
+ case EXC_ID_CHFORMATRUNS:
+ if( GetBiff() == EXC_BIFF8 )
+ XclImpString::ReadFormats( rStrm, maFormats );
+ break;
+ case EXC_ID_CHSOURCELINK:
+ mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) );
+ mxSrcLink->ReadChSourceLink( rStrm );
+ break;
+ case EXC_ID_CHFRAME:
+ mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_TEXT ) );
+ mxFrame->ReadRecordGroup( rStrm );
+ break;
+ case EXC_ID_CHOBJECTLINK:
+ rStrm >> maObjLink.mnTarget >> maObjLink.maPointPos.mnSeriesIdx >> maObjLink.maPointPos.mnPointIdx;
+ break;
+ case EXC_ID_CHFRLABELPROPS:
+ ReadChFrLabelProps( rStrm );
+ break;
+ case EXC_ID_CHEND:
+ if( mxSrcLink && !maFormats.empty() )
+ mxSrcLink->SetTextFormats( maFormats );
+ break;
+ }
+}
+
+sal_uInt16 XclImpChText::GetFontIndex() const
+{
+ return mxFont ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND;
+}
+
+Color XclImpChText::GetFontColor() const
+{
+ return ::get_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor;
+}
+
+sal_uInt16 XclImpChText::GetRotation() const
+{
+ return maData.mnRotation;
+}
+
+void XclImpChText::SetString( const String& rString )
+{
+ if( !mxSrcLink )
+ mxSrcLink.reset( new XclImpChSourceLink( GetChRoot() ) );
+ mxSrcLink->SetString( rString );
+}
+
+void XclImpChText::UpdateText( const XclImpChText* pParentText )
+{
+ if( pParentText )
+ {
+ // update missing members
+ if( !mxFrame )
+ mxFrame = pParentText->mxFrame;
+ if( !mxFont )
+ {
+ mxFont = pParentText->mxFont;
+ // text color is taken from CHTEXT record, not from font in CHFONT
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_AUTOCOLOR, ::get_flag( pParentText->maData.mnFlags, EXC_CHTEXT_AUTOCOLOR ) );
+ maData.maTextColor = pParentText->maData.maTextColor;
+ }
+ }
+}
+
+void XclImpChText::UpdateDataLabel( bool bCateg, bool bValue, bool bPercent )
+{
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEG, bCateg );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWVALUE, bValue );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWPERCENT, bPercent );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_SHOWCATEGPERC, bCateg && bPercent );
+ ::set_flag( maData.mnFlags, EXC_CHTEXT_DELETED, !bCateg && !bValue && !bPercent );
+}
+
+void XclImpChText::ConvertFont( ScfPropertySet& rPropSet ) const
+{
+ ConvertFontBase( GetChRoot(), rPropSet );
+}
+
+void XclImpChText::ConvertRotation( ScfPropertySet& rPropSet, bool bSupportsStacked ) const
+{
+ ConvertRotationBase( GetChRoot(), rPropSet, bSupportsStacked );
+}
+
+void XclImpChText::ConvertFrame( ScfPropertySet& rPropSet ) const
+{
+ if( mxFrame )
+ mxFrame->Convert( rPropSet );
+}
+
+void XclImpChText::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
+{
+ if( mxSrcLink )
+ mxSrcLink->ConvertNumFmt( rPropSet, bPercent );
+}
+
+void XclImpChText::ConvertDataLabel( ScfPropertySet& rPropSet, const XclChTypeInfo& rTypeInfo ) const
+{
+ // existing CHFRLABELPROPS record wins over flags from CHTEXT
+ sal_uInt16 nShowFlags = mxLabelProps ? mxLabelProps->mnFlags : maData.mnFlags;
+ sal_uInt16 SHOWANYCATEG = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWCATEG : (EXC_CHTEXT_SHOWCATEGPERC | EXC_CHTEXT_SHOWCATEG);
+ sal_uInt16 SHOWANYVALUE = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWVALUE : EXC_CHTEXT_SHOWVALUE;
+ sal_uInt16 SHOWANYPERCENT = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWPERCENT : (EXC_CHTEXT_SHOWPERCENT | EXC_CHTEXT_SHOWCATEGPERC);
+ sal_uInt16 SHOWANYBUBBLE = mxLabelProps ? EXC_CHFRLABELPROPS_SHOWBUBBLE : EXC_CHTEXT_SHOWBUBBLE;
+
+ // get raw flags for label values
+ bool bShowNone = IsDeleted();
+ bool bShowCateg = !bShowNone && ::get_flag( nShowFlags, SHOWANYCATEG );
+ bool bShowPercent = !bShowNone && ::get_flag( nShowFlags, SHOWANYPERCENT );
+ bool bShowValue = !bShowNone && ::get_flag( nShowFlags, SHOWANYVALUE );
+ bool bShowBubble = !bShowNone && ::get_flag( nShowFlags, SHOWANYBUBBLE );
+
+ // adjust to Chart2 behaviour
+ if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES )
+ bShowValue = bShowBubble; // Chart2 bubble charts show bubble size if 'ShowValue' is set
+
+ // other flags
+ bool bShowAny = bShowValue || bShowPercent || bShowCateg;
+ bool bShowSymbol = bShowAny && ::get_flag( maData.mnFlags, EXC_CHTEXT_SHOWSYMBOL );
+
+ // create API struct for label values, set API label separator
+ cssc2::DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol );
+ rPropSet.SetProperty( EXC_CHPROP_LABEL, aPointLabel );
+ String aSep = mxLabelProps ? mxLabelProps->maSeparator : String( sal_Unicode( '\n' ) );
+ if( aSep.Len() == 0 )
+ aSep = CREATE_STRING( "; " );
+ rPropSet.SetStringProperty( EXC_CHPROP_LABELSEPARATOR, aSep );
+
+ // text properties of attached label
+ if( bShowAny )
+ {
+ ConvertFont( rPropSet );
+ ConvertRotation( rPropSet, false );
+ // label placement
+ using namespace cssc::DataLabelPlacement;
+ sal_Int32 nPlacement = rTypeInfo.mnDefaultLabelPos;
+ switch( ::extract_value< sal_uInt16 >( maData.mnFlags2, 0, 4 ) )
+ {
+ case EXC_CHTEXT_POS_DEFAULT: nPlacement = rTypeInfo.mnDefaultLabelPos; break;
+ case EXC_CHTEXT_POS_OUTSIDE: nPlacement = OUTSIDE; break;
+ case EXC_CHTEXT_POS_INSIDE: nPlacement = INSIDE; break;
+ case EXC_CHTEXT_POS_CENTER: nPlacement = CENTER; break;
+ case EXC_CHTEXT_POS_AXIS: nPlacement = NEAR_ORIGIN; break;
+ case EXC_CHTEXT_POS_ABOVE: nPlacement = TOP; break;
+ case EXC_CHTEXT_POS_BELOW: nPlacement = BOTTOM; break;
+ case EXC_CHTEXT_POS_LEFT: nPlacement = LEFT; break;
+ case EXC_CHTEXT_POS_RIGHT: nPlacement = RIGHT; break;
+ case EXC_CHTEXT_POS_AUTO: nPlacement = AVOID_OVERLAP; break;
+ }
+ rPropSet.SetProperty( EXC_CHPROP_LABELPLACEMENT, nPlacement );
+ // label number format (percentage format wins over value format)
+ if( bShowPercent || bShowValue )
+ ConvertNumFmt( rPropSet, bShowPercent );
+ }
+}
+
+Reference< XTitle > XclImpChText::CreateTitle() const
+{
+ Reference< XTitle > xTitle;
+ if( mxSrcLink && mxSrcLink->HasString() )
+ {
+ // create the formatted strings
+ Sequence< Reference< XFormattedString > > aStringSeq(
+ mxSrcLink->CreateStringSequence( GetChRoot(), GetFontIndex(), GetFontColor() ) );
+ if( aStringSeq.hasElements() )
+ {
+ // create the title object
+ xTitle.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_TITLE ), UNO_QUERY );
+ if( xTitle.is() )
+ {
+ // set the formatted strings
+ xTitle->setText( aStringSeq );
+ // more title formatting properties
+ ScfPropertySet aTitleProp( xTitle );
+ ConvertFrame( aTitleProp );
+ ConvertRotation( aTitleProp, true );
+ }
+ }
+ }
+ return xTitle;
+}
+
+void XclImpChText::ConvertTitlePosition( const XclChTextKey& rTitleKey ) const
+{
+ if( !mxFramePos ) return;
+
+ const XclChFramePos& rPosData = mxFramePos->GetFramePosData();
+ OSL_ENSURE( (rPosData.mnTLMode == EXC_CHFRAMEPOS_PARENT) && (rPosData.mnBRMode == EXC_CHFRAMEPOS_PARENT),
+ "XclImpChText::ConvertTitlePosition - unexpected frame position mode" );
+
+ /* Check if title is moved manually. To get the actual position of the
+ title, we do some kind of hack and use the values from the CHTEXT
+ record, effectively ignoring the contents of the CHFRAMEPOS record
+ which contains the position relative to the default title position
+ (according to the spec, the CHFRAMEPOS supersedes the CHTEXT record).
+ Especially when it comes to axis titles, things would become very
+ complicated here, because the relative title position is stored in a
+ measurement unit that is dependent on the size of the inner plot area,
+ the interpretation of the X and Y coordinate is dependent on the
+ direction of the axis, and in 3D charts, and the title default
+ positions are dependent on the 3D view settings (rotation, elevation,
+ and perspective). Thus, it is easier to assume that the creator has
+ written out the correct absolute position and size of the title in the
+ CHTEXT record. This is assured by checking that the shape size stored
+ in the CHTEXT record is non-zero. */
+ if( (rPosData.mnTLMode == EXC_CHFRAMEPOS_PARENT) &&
+ ((rPosData.maRect.mnX != 0) || (rPosData.maRect.mnY != 0)) &&
+ (maData.maRect.mnWidth > 0) && (maData.maRect.mnHeight > 0) ) try
+ {
+ Reference< XShape > xTitleShape( GetTitleShape( rTitleKey ), UNO_SET_THROW );
+ // the call to XShape.getSize() may recalc the chart view
+ ::com::sun::star::awt::Size aTitleSize = xTitleShape->getSize();
+ // rotated titles need special handling...
+ sal_Int32 nScRot = XclTools::GetScRotation( GetRotation(), 0 );
+ double fRad = nScRot * F_PI18000;
+ double fSin = fabs( sin( fRad ) );
+ double fCos = fabs( cos( fRad ) );
+ ::com::sun::star::awt::Size aBoundSize(
+ static_cast< sal_Int32 >( fCos * aTitleSize.Width + fSin * aTitleSize.Height + 0.5 ),
+ static_cast< sal_Int32 >( fSin * aTitleSize.Width + fCos * aTitleSize.Height + 0.5 ) );
+ // calculate the title position from the values in the CHTEXT record
+ ::com::sun::star::awt::Point aTitlePos(
+ CalcHmmFromChartX( maData.maRect.mnX ),
+ CalcHmmFromChartY( maData.maRect.mnY ) );
+ // add part of height to X direction, if title is rotated down (clockwise)
+ if( nScRot > 18000 )
+ aTitlePos.X += static_cast< sal_Int32 >( fSin * aTitleSize.Height + 0.5 );
+ // add part of width to Y direction, if title is rotated up (counterclockwise)
+ else if( nScRot > 0 )
+ aTitlePos.Y += static_cast< sal_Int32 >( fSin * aTitleSize.Width + 0.5 );
+ // set the resulting position at the title shape
+ xTitleShape->setPosition( aTitlePos );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void XclImpChText::ReadChFrLabelProps( XclImpStream& rStrm )
+{
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ mxLabelProps.reset( new XclChFrLabelProps );
+ sal_uInt16 nSepLen;
+ rStrm.Ignore( 12 );
+ rStrm >> mxLabelProps->mnFlags >> nSepLen;
+ if( nSepLen > 0 )
+ mxLabelProps->maSeparator = rStrm.ReadUniString( nSepLen );
+ }
+}
+
+namespace {
+
+void lclUpdateText( XclImpChTextRef& rxText, const XclImpChText* xDefText )
+{
+ if( rxText )
+ rxText->UpdateText( xDefText );
+ else
+ {
+ XclImpChTextRef xNew(new XclImpChText(*xDefText));
+ rxText = xNew;
+ }
+}
+
+void lclFinalizeTitle( XclImpChTextRef& rxTitle, const XclImpChText* pDefText, const String& rAutoTitle )
+{
+ /* Do not update a title, if it is not visible (if rxTitle is null).
+ Existing reference indicates enabled title. */
+ if( rxTitle )
+ {
+ if( !rxTitle->HasString() )
+ rxTitle->SetString( rAutoTitle );
+ if( rxTitle->HasString() )
+ rxTitle->UpdateText(pDefText);
+ else
+ rxTitle.reset();
+ }
+}
+
+} // namespace
+
+// Data series ================================================================
+
+void XclImpChMarkerFormat::ReadChMarkerFormat( XclImpStream& rStrm )
+{
+ rStrm >> maData.maLineColor >> maData.maFillColor >> maData.mnMarkerType >> maData.mnFlags;
+
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ if( rRoot.GetBiff() == EXC_BIFF8 )
+ {
+ // BIFF8: index into palette used instead of RGB data
+ const XclImpPalette& rPal = rRoot.GetPalette();
+ maData.maLineColor = rPal.GetColor( rStrm.ReaduInt16() );
+ maData.maFillColor = rPal.GetColor( rStrm.ReaduInt16() );
+ // marker size
+ rStrm >> maData.mnMarkerSize;
+ }
+}
+
+void XclImpChMarkerFormat::Convert( const XclImpChRoot& rRoot,
+ ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx, sal_Int16 nLineWeight ) const
+{
+ if( IsAuto() )
+ {
+ XclChMarkerFormat aMarkerFmt;
+ // line and fill color of the symbol are equal to series line color
+ //! TODO: Excel sets no fill color for specific symbols (e.g. cross)
+ aMarkerFmt.maLineColor = aMarkerFmt.maFillColor = rRoot.GetSeriesLineAutoColor( nFormatIdx );
+ switch( nLineWeight )
+ {
+ case EXC_CHLINEFORMAT_HAIR: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_HAIRSIZE; break;
+ case EXC_CHLINEFORMAT_SINGLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE; break;
+ case EXC_CHLINEFORMAT_DOUBLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_DOUBLESIZE; break;
+ case EXC_CHLINEFORMAT_TRIPLE: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_TRIPLESIZE; break;
+ default: aMarkerFmt.mnMarkerSize = EXC_CHMARKERFORMAT_SINGLESIZE;
+ }
+ aMarkerFmt.mnMarkerType = XclChartHelper::GetAutoMarkerType( nFormatIdx );
+ rRoot.GetChartPropSetHelper().WriteMarkerProperties( rPropSet, aMarkerFmt );
+ }
+ else
+ {
+ rRoot.GetChartPropSetHelper().WriteMarkerProperties( rPropSet, maData );
+ }
+}
+
+void XclImpChMarkerFormat::ConvertColor( const XclImpChRoot& rRoot,
+ ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx ) const
+{
+ Color aLineColor = IsAuto() ? rRoot.GetSeriesLineAutoColor( nFormatIdx ) : maData.maFillColor;
+ rPropSet.SetColorProperty( EXC_CHPROP_COLOR, aLineColor );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChPieFormat::XclImpChPieFormat() :
+ mnPieDist( 0 )
+{
+}
+
+void XclImpChPieFormat::ReadChPieFormat( XclImpStream& rStrm )
+{
+ rStrm >> mnPieDist;
+}
+
+void XclImpChPieFormat::Convert( ScfPropertySet& rPropSet ) const
+{
+ double fApiDist = ::std::min< double >( mnPieDist / 100.0, 1.0 );
+ rPropSet.SetProperty( EXC_CHPROP_OFFSET, fApiDist );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChSeriesFormat::XclImpChSeriesFormat() :
+ mnFlags( 0 )
+{
+}
+
+void XclImpChSeriesFormat::ReadChSeriesFormat( XclImpStream& rStrm )
+{
+ rStrm >> mnFlags;
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpCh3dDataFormat::ReadCh3dDataFormat( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnBase >> maData.mnTop;
+}
+
+void XclImpCh3dDataFormat::Convert( ScfPropertySet& rPropSet ) const
+{
+ using namespace ::com::sun::star::chart2::DataPointGeometry3D;
+ sal_Int32 nApiType = (maData.mnBase == EXC_CH3DDATAFORMAT_RECT) ?
+ ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CUBOID : PYRAMID) :
+ ((maData.mnTop == EXC_CH3DDATAFORMAT_STRAIGHT) ? CYLINDER : CONE);
+ rPropSet.SetProperty( EXC_CHPROP_GEOMETRY3D, nApiType );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChAttachedLabel::XclImpChAttachedLabel( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot ),
+ mnFlags( 0 )
+{
+}
+
+void XclImpChAttachedLabel::ReadChAttachedLabel( XclImpStream& rStrm )
+{
+ rStrm >> mnFlags;
+}
+
+XclImpChTextRef XclImpChAttachedLabel::CreateDataLabel( const XclImpChText* pParent ) const
+{
+ const sal_uInt16 EXC_CHATTLABEL_SHOWANYVALUE = EXC_CHATTLABEL_SHOWVALUE;
+ const sal_uInt16 EXC_CHATTLABEL_SHOWANYPERCENT = EXC_CHATTLABEL_SHOWPERCENT | EXC_CHATTLABEL_SHOWCATEGPERC;
+ const sal_uInt16 EXC_CHATTLABEL_SHOWANYCATEG = EXC_CHATTLABEL_SHOWCATEG | EXC_CHATTLABEL_SHOWCATEGPERC;
+
+ XclImpChTextRef xLabel( pParent ? new XclImpChText( *pParent ) : new XclImpChText( GetChRoot() ) );
+ xLabel->UpdateDataLabel(
+ ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYCATEG ),
+ ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYVALUE ),
+ ::get_flag( mnFlags, EXC_CHATTLABEL_SHOWANYPERCENT ) );
+ return xLabel;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChDataFormat::XclImpChDataFormat( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot )
+{
+}
+
+void XclImpChDataFormat::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ rStrm >> maData.maPointPos.mnPointIdx
+ >> maData.maPointPos.mnSeriesIdx
+ >> maData.mnFormatIdx
+ >> maData.mnFlags;
+}
+
+void XclImpChDataFormat::ReadSubRecord( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_CHMARKERFORMAT:
+ mxMarkerFmt.reset( new XclImpChMarkerFormat );
+ mxMarkerFmt->ReadChMarkerFormat( rStrm );
+ break;
+ case EXC_ID_CHPIEFORMAT:
+ mxPieFmt.reset( new XclImpChPieFormat );
+ mxPieFmt->ReadChPieFormat( rStrm );
+ break;
+ case EXC_ID_CHSERIESFORMAT:
+ mxSeriesFmt.reset( new XclImpChSeriesFormat );
+ mxSeriesFmt->ReadChSeriesFormat( rStrm );
+ break;
+ case EXC_ID_CH3DDATAFORMAT:
+ mx3dDataFmt.reset( new XclImpCh3dDataFormat );
+ mx3dDataFmt->ReadCh3dDataFormat( rStrm );
+ break;
+ case EXC_ID_CHATTACHEDLABEL:
+ mxAttLabel.reset( new XclImpChAttachedLabel( GetChRoot() ) );
+ mxAttLabel->ReadChAttachedLabel( rStrm );
+ break;
+ default:
+ XclImpChFrameBase::ReadSubRecord( rStrm );
+ }
+}
+
+void XclImpChDataFormat::SetPointPos( const XclChDataPointPos& rPointPos, sal_uInt16 nFormatIdx )
+{
+ maData.maPointPos = rPointPos;
+ maData.mnFormatIdx = nFormatIdx;
+}
+
+void XclImpChDataFormat::UpdateGroupFormat( const XclChExtTypeInfo& rTypeInfo )
+{
+ // remove formats not used for the current chart type
+ RemoveUnusedFormats( rTypeInfo );
+}
+
+void XclImpChDataFormat::UpdateSeriesFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pGroupFmt )
+{
+ // update missing formats from passed chart type group format
+ if( pGroupFmt )
+ {
+ if( !mxLineFmt )
+ mxLineFmt = pGroupFmt->mxLineFmt;
+ if( !mxAreaFmt && !mxEscherFmt )
+ {
+ mxAreaFmt = pGroupFmt->mxAreaFmt;
+ mxEscherFmt = pGroupFmt->mxEscherFmt;
+ }
+ if( !mxMarkerFmt )
+ mxMarkerFmt = pGroupFmt->mxMarkerFmt;
+ if( !mxPieFmt )
+ mxPieFmt = pGroupFmt->mxPieFmt;
+ if( !mxSeriesFmt )
+ mxSeriesFmt = pGroupFmt->mxSeriesFmt;
+ if( !mx3dDataFmt )
+ mx3dDataFmt = pGroupFmt->mx3dDataFmt;
+ if( !mxAttLabel )
+ mxAttLabel = pGroupFmt->mxAttLabel;
+ }
+
+ /* Create missing but required formats. Existing line, area, and marker
+ format objects are needed to create automatic series formatting. */
+ if( !mxLineFmt )
+ mxLineFmt.reset( new XclImpChLineFormat );
+ if( !mxAreaFmt && !mxEscherFmt )
+ mxAreaFmt.reset( new XclImpChAreaFormat );
+ if( !mxMarkerFmt )
+ mxMarkerFmt.reset( new XclImpChMarkerFormat );
+
+ // remove formats not used for the current chart type
+ RemoveUnusedFormats( rTypeInfo );
+ // update data label
+ UpdateDataLabel( pGroupFmt );
+}
+
+void XclImpChDataFormat::UpdatePointFormat( const XclChExtTypeInfo& rTypeInfo, const XclImpChDataFormat* pSeriesFmt )
+{
+ // remove formats if they are automatic in this and in the passed series format
+ if( pSeriesFmt )
+ {
+ if( IsAutoLine() && pSeriesFmt->IsAutoLine() )
+ mxLineFmt.reset();
+ if( IsAutoArea() && pSeriesFmt->IsAutoArea() )
+ mxAreaFmt.reset();
+ if( IsAutoMarker() && pSeriesFmt->IsAutoMarker() )
+ mxMarkerFmt.reset();
+ mxSeriesFmt.reset();
+ }
+
+ // Excel ignores 3D bar format for single data points
+ mx3dDataFmt.reset();
+ // remove point line formats for linear chart types, TODO: implement in OOChart
+ if( !rTypeInfo.IsSeriesFrameFormat() )
+ mxLineFmt.reset();
+
+ // remove formats not used for the current chart type
+ RemoveUnusedFormats( rTypeInfo );
+ // update data label
+ UpdateDataLabel( pSeriesFmt );
+}
+
+void XclImpChDataFormat::UpdateTrendLineFormat()
+{
+ if( !mxLineFmt )
+ mxLineFmt.reset( new XclImpChLineFormat );
+ mxAreaFmt.reset();
+ mxEscherFmt.reset();
+ mxMarkerFmt.reset();
+ mxPieFmt.reset();
+ mxSeriesFmt.reset();
+ mx3dDataFmt.reset();
+ mxAttLabel.reset();
+ // update data label
+ UpdateDataLabel( 0 );
+}
+
+void XclImpChDataFormat::Convert( ScfPropertySet& rPropSet, const XclChExtTypeInfo& rTypeInfo ) const
+{
+ // line and area format
+ ConvertFrameBase( GetChRoot(), rPropSet, rTypeInfo.GetSeriesObjectType(), maData.mnFormatIdx );
+#if EXC_CHART2_3DBAR_HAIRLINES_ONLY
+ // #i83151# only hair lines in 3D charts with filled data points
+ if( rTypeInfo.mb3dChart && rTypeInfo.IsSeriesFrameFormat() && mxLineFmt && mxLineFmt->HasLine() )
+ rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "BorderWidth" ), 0 );
+#endif
+
+ // other formatting
+ if( mxMarkerFmt )
+ mxMarkerFmt->Convert( GetChRoot(), rPropSet, maData.mnFormatIdx, GetLineWeight() );
+ if( mxPieFmt )
+ mxPieFmt->Convert( rPropSet );
+ if( mx3dDataFmt )
+ mx3dDataFmt->Convert( rPropSet );
+ if( mxLabel )
+ mxLabel->ConvertDataLabel( rPropSet, rTypeInfo );
+
+ // 3D settings
+ rPropSet.SetProperty< sal_Int16 >( EXC_CHPROP_PERCENTDIAGONAL, 0 );
+
+ /* Special case: set marker color as line color, if series line is not
+ visible. This makes the color visible in the marker area.
+ TODO: remove this if OOChart supports own colors in markers. */
+ if( !rTypeInfo.IsSeriesFrameFormat() && !HasLine() && mxMarkerFmt )
+ mxMarkerFmt->ConvertColor( GetChRoot(), rPropSet, maData.mnFormatIdx );
+}
+
+void XclImpChDataFormat::ConvertLine( ScfPropertySet& rPropSet, XclChObjectType eObjType ) const
+{
+ ConvertLineBase( GetChRoot(), rPropSet, eObjType );
+}
+
+void XclImpChDataFormat::ConvertArea( ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx ) const
+{
+ ConvertAreaBase( GetChRoot(), rPropSet, EXC_CHOBJTYPE_FILLEDSERIES, nFormatIdx );
+}
+
+void XclImpChDataFormat::RemoveUnusedFormats( const XclChExtTypeInfo& rTypeInfo )
+{
+ // data point marker only in linear 2D charts
+ if( rTypeInfo.IsSeriesFrameFormat() )
+ mxMarkerFmt.reset();
+ // pie format only in pie/donut charts
+ if( rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_PIE )
+ mxPieFmt.reset();
+ // 3D format only in 3D bar charts
+ if( !rTypeInfo.mb3dChart || (rTypeInfo.meTypeCateg != EXC_CHTYPECATEG_BAR) )
+ mx3dDataFmt.reset();
+}
+
+void XclImpChDataFormat::UpdateDataLabel( const XclImpChDataFormat* pParentFmt )
+{
+ /* CHTEXT groups linked to data labels override existing CHATTACHEDLABEL
+ records. Only if there is a CHATTACHEDLABEL record without a CHTEXT
+ group, the contents of the CHATTACHEDLABEL record are used. In this
+ case a new CHTEXT group is created and filled with the settings from
+ the CHATTACHEDLABEL record. */
+ const XclImpChText* pDefText = NULL;
+ if (pParentFmt)
+ pDefText = pParentFmt->GetDataLabel();
+ if (!pDefText)
+ pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_DATALABEL );
+ if (mxLabel)
+ mxLabel->UpdateText(pDefText);
+ else if (mxAttLabel)
+ mxLabel = mxAttLabel->CreateDataLabel( pDefText );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChSerTrendLine::XclImpChSerTrendLine( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot )
+{
+}
+
+void XclImpChSerTrendLine::ReadChSerTrendLine( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnLineType
+ >> maData.mnOrder
+ >> maData.mfIntercept
+ >> maData.mnShowEquation
+ >> maData.mnShowRSquared
+ >> maData.mfForecastFor
+ >> maData.mfForecastBack;
+}
+
+Reference< XRegressionCurve > XclImpChSerTrendLine::CreateRegressionCurve() const
+{
+ // trend line type
+ OUString aService;
+ switch( maData.mnLineType )
+ {
+ case EXC_CHSERTREND_POLYNOMIAL:
+ // TODO: only linear trend lines are supported by OOChart (#i20819#)
+ if( maData.mnOrder == 1 )
+ aService = SERVICE_CHART2_LINEARREGCURVE;
+ break;
+ case EXC_CHSERTREND_EXPONENTIAL:
+ aService = SERVICE_CHART2_EXPREGCURVE;
+ break;
+ case EXC_CHSERTREND_LOGARITHMIC:
+ aService = SERVICE_CHART2_LOGREGCURVE;
+ break;
+ case EXC_CHSERTREND_POWER:
+ aService = SERVICE_CHART2_POTREGCURVE;
+ break;
+ }
+ Reference< XRegressionCurve > xRegCurve;
+ if( aService.getLength() > 0 )
+ xRegCurve.set( ScfApiHelper::CreateInstance( aService ), UNO_QUERY );
+
+ // trend line formatting
+ if( xRegCurve.is() && mxDataFmt )
+ {
+ ScfPropertySet aPropSet( xRegCurve );
+ mxDataFmt->ConvertLine( aPropSet, EXC_CHOBJTYPE_TRENDLINE );
+
+ // #i83100# show equation and correlation coefficient
+ ScfPropertySet aLabelProp( xRegCurve->getEquationProperties() );
+ aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWEQUATION, maData.mnShowEquation != 0 );
+ aLabelProp.SetBoolProperty( EXC_CHPROP_SHOWCORRELATION, maData.mnShowRSquared != 0 );
+
+ // #i83100# formatting of the equation text box
+ if (const XclImpChText* pLabel = mxDataFmt->GetDataLabel())
+ {
+ pLabel->ConvertFont( aLabelProp );
+ pLabel->ConvertFrame( aLabelProp );
+ pLabel->ConvertNumFmt( aLabelProp, false );
+ }
+ }
+
+ // missing features
+ // #i20819# polynomial trend lines
+ // #i66819# moving average trend lines
+ // #i5085# manual trend line size
+ // #i34093# manual crossing point
+
+ return xRegCurve;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChSerErrorBar::XclImpChSerErrorBar( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot )
+{
+}
+
+void XclImpChSerErrorBar::ReadChSerErrorBar( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnBarType >> maData.mnSourceType >> maData.mnLineEnd;
+ rStrm.Ignore( 1 );
+ rStrm >> maData.mfValue >> maData.mnValueCount;
+}
+
+void XclImpChSerErrorBar::SetSeriesData( XclImpChSourceLinkRef xValueLink, XclImpChDataFormatRef xDataFmt )
+{
+ mxValueLink = xValueLink;
+ mxDataFmt = xDataFmt;
+}
+
+Reference< XLabeledDataSequence > XclImpChSerErrorBar::CreateValueSequence() const
+{
+ return lclCreateLabeledDataSequence( mxValueLink, XclChartHelper::GetErrorBarValuesRole( maData.mnBarType ) );
+}
+
+Reference< XPropertySet > XclImpChSerErrorBar::CreateErrorBar( const XclImpChSerErrorBar* pPosBar, const XclImpChSerErrorBar* pNegBar )
+{
+ Reference< XPropertySet > xErrorBar;
+
+ if( const XclImpChSerErrorBar* pPrimaryBar = pPosBar ? pPosBar : pNegBar )
+ {
+ xErrorBar.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_ERRORBAR ), UNO_QUERY );
+ ScfPropertySet aBarProp( xErrorBar );
+
+ // plus/minus bars visible?
+ aBarProp.SetBoolProperty( EXC_CHPROP_SHOWPOSITIVEERROR, pPosBar != 0 );
+ aBarProp.SetBoolProperty( EXC_CHPROP_SHOWNEGATIVEERROR, pNegBar != 0 );
+
+ // type of displayed error
+ switch( pPrimaryBar->maData.mnSourceType )
+ {
+ case EXC_CHSERERR_PERCENT:
+ aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::RELATIVE );
+ aBarProp.SetProperty( EXC_CHPROP_POSITIVEERROR, pPrimaryBar->maData.mfValue );
+ aBarProp.SetProperty( EXC_CHPROP_NEGATIVEERROR, pPrimaryBar->maData.mfValue );
+ break;
+ case EXC_CHSERERR_FIXED:
+ aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::ABSOLUTE );
+ aBarProp.SetProperty( EXC_CHPROP_POSITIVEERROR, pPrimaryBar->maData.mfValue );
+ aBarProp.SetProperty( EXC_CHPROP_NEGATIVEERROR, pPrimaryBar->maData.mfValue );
+ break;
+ case EXC_CHSERERR_STDDEV:
+ aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::STANDARD_DEVIATION );
+ aBarProp.SetProperty( EXC_CHPROP_WEIGHT, pPrimaryBar->maData.mfValue );
+ break;
+ case EXC_CHSERERR_STDERR:
+ aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::STANDARD_ERROR );
+ break;
+ case EXC_CHSERERR_CUSTOM:
+ {
+ aBarProp.SetProperty( EXC_CHPROP_ERRORBARSTYLE, cssc::ErrorBarStyle::FROM_DATA );
+ // attach data sequences to erorr bar
+ Reference< XDataSink > xDataSink( xErrorBar, UNO_QUERY );
+ if( xDataSink.is() )
+ {
+ // create vector of all value sequences
+ ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
+ // add positive values
+ if( pPosBar )
+ {
+ Reference< XLabeledDataSequence > xValueSeq = pPosBar->CreateValueSequence();
+ if( xValueSeq.is() )
+ aLabeledSeqVec.push_back( xValueSeq );
+ }
+ // add negative values
+ if( pNegBar )
+ {
+ Reference< XLabeledDataSequence > xValueSeq = pNegBar->CreateValueSequence();
+ if( xValueSeq.is() )
+ aLabeledSeqVec.push_back( xValueSeq );
+ }
+ // attach labeled data sequences to series
+ if( aLabeledSeqVec.empty() )
+ xErrorBar.clear();
+ else
+ xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
+ }
+ }
+ break;
+ default:
+ xErrorBar.clear();
+ }
+
+ // error bar formatting
+ if( pPrimaryBar->mxDataFmt && xErrorBar.is() )
+ pPrimaryBar->mxDataFmt->ConvertLine( aBarProp, EXC_CHOBJTYPE_ERRORBAR );
+ }
+
+ return xErrorBar;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChSeries::XclImpChSeries( const XclImpChRoot& rRoot, sal_uInt16 nSeriesIdx ) :
+ XclImpChRoot( rRoot ),
+ mnGroupIdx( EXC_CHSERGROUP_NONE ),
+ mnSeriesIdx( nSeriesIdx ),
+ mnParentIdx( EXC_CHSERIES_INVALID )
+{
+}
+
+void XclImpChSeries::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnCategType >> maData.mnValueType >> maData.mnCategCount >> maData.mnValueCount;
+ if( GetBiff() == EXC_BIFF8 )
+ rStrm >> maData.mnBubbleType >> maData.mnBubbleCount;
+}
+
+void XclImpChSeries::ReadSubRecord( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_CHSOURCELINK:
+ ReadChSourceLink( rStrm );
+ break;
+ case EXC_ID_CHDATAFORMAT:
+ ReadChDataFormat( rStrm );
+ break;
+ case EXC_ID_CHSERGROUP:
+ rStrm >> mnGroupIdx;
+ break;
+ case EXC_ID_CHSERPARENT:
+ ReadChSerParent( rStrm );
+ break;
+ case EXC_ID_CHSERTRENDLINE:
+ ReadChSerTrendLine( rStrm );
+ break;
+ case EXC_ID_CHSERERRORBAR:
+ ReadChSerErrorBar( rStrm );
+ break;
+ }
+}
+
+void XclImpChSeries::SetDataFormat( XclImpChDataFormatRef xDataFmt )
+{
+ if( xDataFmt )
+ {
+ XclImpChDataFormatRef* pxDataFmt = GetDataFormatRef( xDataFmt->GetPointPos().mnPointIdx );
+ // do not overwrite existing data format
+ if( pxDataFmt && !*pxDataFmt )
+ {
+ *pxDataFmt = xDataFmt;
+ // #i51639# register series format index at chart type group
+ if( (pxDataFmt == &mxSeriesFmt) && !HasParentSeries() )
+ if( XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
+ pTypeGroup->SetUsedFormatIndex( xDataFmt->GetFormatIdx() );
+ }
+ }
+}
+
+void XclImpChSeries::SetDataLabel( XclImpChTextRef xLabel )
+{
+ if( xLabel )
+ {
+ XclImpChTextRef* pxLabel = GetDataLabelRef( xLabel->GetPointPos().mnPointIdx );
+ if( pxLabel && !*pxLabel )
+ *pxLabel = xLabel;
+ }
+}
+
+void XclImpChSeries::AddChildSeries( const XclImpChSeries& rSeries )
+{
+ DBG_ASSERT( !HasParentSeries(), "XclImpChSeries::AddChildSeries - not allowed for child series" );
+
+ /* In Excel, trend lines and error bars are stored as own series. In Calc,
+ these are properties of the parent series. This function adds the
+ settings of the passed series to this series. */
+ maTrendLines.insert( maTrendLines.end(), rSeries.maTrendLines.begin(), rSeries.maTrendLines.end() );
+ maErrorBars.insert( rSeries.maErrorBars.begin(), rSeries.maErrorBars.end() );
+}
+
+void XclImpChSeries::FinalizeDataFormats()
+{
+ if( HasParentSeries() )
+ {
+ // *** series is a child series, e.g. trend line or error bar ***
+
+ // create missing series format
+ if( !mxSeriesFmt )
+ mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, 0 );
+
+ if( mxSeriesFmt )
+ {
+ // #i83100# set text label format, e.g. for trend line equations
+ XclImpChTextRef xLabel;
+ XclImpChTextMap::iterator itr = maLabels.find(EXC_CHDATAFORMAT_ALLPOINTS);
+ if (itr != maLabels.end())
+ xLabel = itr->second;
+ mxSeriesFmt->SetDataLabel(xLabel);
+ // create missing automatic formats
+ mxSeriesFmt->UpdateTrendLineFormat();
+ }
+
+ // copy series formatting to child objects
+ for( XclImpChSerTrendLineList::iterator aLIt = maTrendLines.begin(), aLEnd = maTrendLines.end(); aLIt != aLEnd; ++aLIt )
+ (*aLIt)->SetDataFormat( mxSeriesFmt );
+ for( XclImpChSerErrorBarMap::iterator aMIt = maErrorBars.begin(), aMEnd = maErrorBars.end(); aMIt != aMEnd; ++aMIt )
+ aMIt->second->SetSeriesData( mxValueLink, mxSeriesFmt );
+ }
+ else if( XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
+ {
+ // *** series is a regular data series ***
+
+ // create missing series format
+ if( !mxSeriesFmt )
+ {
+ // #i51639# use a new unused format index to create series default format
+ sal_uInt16 nFormatIdx = pTypeGroup->PopUnusedFormatIndex();
+ mxSeriesFmt = CreateDataFormat( EXC_CHDATAFORMAT_ALLPOINTS, nFormatIdx );
+ }
+
+ // set text labels to data formats
+ for( XclImpChTextMap::iterator aTIt = maLabels.begin(), aTEnd = maLabels.end(); aTIt != aTEnd; ++aTIt )
+ {
+ if( XclImpChDataFormatRef* pxDataFmt = GetDataFormatRef( aTIt->first ) )
+ {
+ if( !*pxDataFmt )
+ *pxDataFmt = CreateDataFormat( aTIt->first, EXC_CHDATAFORMAT_DEFAULT );
+ (*pxDataFmt)->SetDataLabel( aTIt->second );
+ }
+ }
+
+ // update series format (copy missing formatting from group default format)
+ if( mxSeriesFmt )
+ mxSeriesFmt->UpdateSeriesFormat( pTypeGroup->GetTypeInfo(), pTypeGroup->GetGroupFormat().get() );
+
+ // update data point formats (removes unchanged automatic formatting)
+ for( XclImpChDataFormatMap::iterator aFIt = maPointFmts.begin(), aFEnd = maPointFmts.end(); aFIt != aFEnd; ++aFIt )
+ aFIt->second->UpdatePointFormat( pTypeGroup->GetTypeInfo(), mxSeriesFmt.get() );
+ }
+}
+
+namespace {
+
+/** Returns the property set of the specified data point. */
+ScfPropertySet lclGetPointPropSet( Reference< XDataSeries > xDataSeries, sal_uInt16 nPointIdx )
+{
+ ScfPropertySet aPropSet;
+ try
+ {
+ aPropSet.Set( xDataSeries->getDataPointByIndex( static_cast< sal_Int32 >( nPointIdx ) ) );
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "lclGetPointPropSet - no data point property set" );
+ }
+ return aPropSet;
+}
+
+} // namespace
+
+Reference< XLabeledDataSequence > XclImpChSeries::CreateValueSequence( const OUString& rValueRole ) const
+{
+ return lclCreateLabeledDataSequence( mxValueLink, rValueRole, mxTitleLink.get() );
+}
+
+Reference< XLabeledDataSequence > XclImpChSeries::CreateCategSequence( const OUString& rCategRole ) const
+{
+ return lclCreateLabeledDataSequence( mxCategLink, rCategRole );
+}
+
+Reference< XDataSeries > XclImpChSeries::CreateDataSeries() const
+{
+ Reference< XDataSeries > xDataSeries;
+ if( const XclImpChTypeGroup* pTypeGroup = GetChartData().GetTypeGroup( mnGroupIdx ).get() )
+ {
+ const XclChExtTypeInfo& rTypeInfo = pTypeGroup->GetTypeInfo();
+
+ // create the data series object
+ xDataSeries.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY );
+
+ // attach data and title sequences to series
+ Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
+ if( xDataSink.is() )
+ {
+ // create vector of all value sequences
+ ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
+ // add Y values
+ Reference< XLabeledDataSequence > xYValueSeq =
+ CreateValueSequence( EXC_CHPROP_ROLE_YVALUES );
+ if( xYValueSeq.is() )
+ aLabeledSeqVec.push_back( xYValueSeq );
+ // add X values
+ if( !rTypeInfo.mbCategoryAxis )
+ {
+ Reference< XLabeledDataSequence > xXValueSeq =
+ CreateCategSequence( EXC_CHPROP_ROLE_XVALUES );
+ if( xXValueSeq.is() )
+ aLabeledSeqVec.push_back( xXValueSeq );
+ // add size values of bubble charts
+ if( rTypeInfo.meTypeId == EXC_CHTYPEID_BUBBLES )
+ {
+ Reference< XLabeledDataSequence > xSizeValueSeq =
+ lclCreateLabeledDataSequence( mxBubbleLink, EXC_CHPROP_ROLE_SIZEVALUES, mxTitleLink.get() );
+ if( xSizeValueSeq.is() )
+ aLabeledSeqVec.push_back( xSizeValueSeq );
+ }
+ }
+ // attach labeled data sequences to series
+ if( !aLabeledSeqVec.empty() )
+ xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
+ }
+
+ // series formatting
+ ScfPropertySet aSeriesProp( xDataSeries );
+ if( mxSeriesFmt )
+ mxSeriesFmt->Convert( aSeriesProp, rTypeInfo );
+
+ // trend lines
+ ConvertTrendLines( xDataSeries );
+
+ // error bars
+ Reference< XPropertySet > xErrorBarX = CreateErrorBar( EXC_CHSERERR_XPLUS, EXC_CHSERERR_XMINUS );
+ if( xErrorBarX.is() )
+ aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARX, xErrorBarX );
+ Reference< XPropertySet > xErrorBarY = CreateErrorBar( EXC_CHSERERR_YPLUS, EXC_CHSERERR_YMINUS );
+ if( xErrorBarY.is() )
+ aSeriesProp.SetProperty( EXC_CHPROP_ERRORBARY, xErrorBarY );
+
+ // own area formatting for every data point (TODO: varying line color not supported)
+ bool bVarPointFmt = pTypeGroup->HasVarPointFormat() && rTypeInfo.IsSeriesFrameFormat();
+#if EXC_CHART2_VARYCOLORSBY_PROP
+ aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, bVarPointFmt );
+#else
+ aSeriesProp.SetBoolProperty( EXC_CHPROP_VARYCOLORSBY, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE );
+#endif
+ // #i91271# always set area formatting for every point in pie/doughnut charts
+ if( mxSeriesFmt && ((bVarPointFmt && mxSeriesFmt->IsAutoArea()) || (rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE)) )
+ {
+ for( sal_uInt16 nPointIdx = 0, nPointCount = mxValueLink->GetCellCount(); nPointIdx < nPointCount; ++nPointIdx )
+ {
+ ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, nPointIdx );
+ mxSeriesFmt->ConvertArea( aPointProp, bVarPointFmt ? nPointIdx : mnSeriesIdx );
+ }
+ }
+
+ // data point formatting
+ for( XclImpChDataFormatMap::const_iterator aIt = maPointFmts.begin(), aEnd = maPointFmts.end(); aIt != aEnd; ++aIt )
+ {
+ ScfPropertySet aPointProp = lclGetPointPropSet( xDataSeries, aIt->first );
+ aIt->second->Convert( aPointProp, rTypeInfo );
+ }
+ }
+ return xDataSeries;
+}
+
+void XclImpChSeries::FillAllSourceLinks( ::std::vector< ScTokenRef >& rTokens ) const
+{
+ if( mxValueLink )
+ mxValueLink->FillSourceLink( rTokens );
+ if( mxCategLink )
+ mxCategLink->FillSourceLink( rTokens );
+ if( mxTitleLink )
+ mxTitleLink->FillSourceLink( rTokens );
+ if( mxBubbleLink )
+ mxBubbleLink->FillSourceLink( rTokens );
+}
+
+void XclImpChSeries::ReadChSourceLink( XclImpStream& rStrm )
+{
+ XclImpChSourceLinkRef xSrcLink( new XclImpChSourceLink( GetChRoot() ) );
+ xSrcLink->ReadChSourceLink( rStrm );
+ switch( xSrcLink->GetDestType() )
+ {
+ case EXC_CHSRCLINK_TITLE: mxTitleLink = xSrcLink; break;
+ case EXC_CHSRCLINK_VALUES: mxValueLink = xSrcLink; break;
+ case EXC_CHSRCLINK_CATEGORY: mxCategLink = xSrcLink; break;
+ case EXC_CHSRCLINK_BUBBLES: mxBubbleLink = xSrcLink; break;
+ }
+}
+
+void XclImpChSeries::ReadChDataFormat( XclImpStream& rStrm )
+{
+ // #i51639# chart stores all data formats and assigns them later to the series
+ GetChartData().ReadChDataFormat( rStrm );
+}
+
+void XclImpChSeries::ReadChSerParent( XclImpStream& rStrm )
+{
+ rStrm >> mnParentIdx;
+ // index to parent series is 1-based, convert it to 0-based
+ if( mnParentIdx > 0 )
+ --mnParentIdx;
+ else
+ mnParentIdx = EXC_CHSERIES_INVALID;
+}
+
+void XclImpChSeries::ReadChSerTrendLine( XclImpStream& rStrm )
+{
+ XclImpChSerTrendLineRef xTrendLine( new XclImpChSerTrendLine( GetChRoot() ) );
+ xTrendLine->ReadChSerTrendLine( rStrm );
+ maTrendLines.push_back( xTrendLine );
+}
+
+void XclImpChSeries::ReadChSerErrorBar( XclImpStream& rStrm )
+{
+ auto_ptr<XclImpChSerErrorBar> pErrorBar(new XclImpChSerErrorBar(GetChRoot()));
+ pErrorBar->ReadChSerErrorBar(rStrm);
+ sal_uInt8 nBarType = pErrorBar->GetBarType();
+ maErrorBars.insert(nBarType, pErrorBar);
+}
+
+XclImpChDataFormatRef XclImpChSeries::CreateDataFormat( sal_uInt16 nPointIdx, sal_uInt16 nFormatIdx )
+{
+ XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
+ xDataFmt->SetPointPos( XclChDataPointPos( mnSeriesIdx, nPointIdx ), nFormatIdx );
+ return xDataFmt;
+}
+
+XclImpChDataFormatRef* XclImpChSeries::GetDataFormatRef( sal_uInt16 nPointIdx )
+{
+ if( nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS )
+ return &mxSeriesFmt;
+
+ if (nPointIdx < EXC_CHDATAFORMAT_MAXPOINTCOUNT)
+ {
+ XclImpChDataFormatMap::iterator itr = maPointFmts.lower_bound(nPointIdx);
+ if (itr == maPointFmts.end() || maPointFmts.key_comp()(nPointIdx, itr->first))
+ {
+ // No object exists at this point index position. Insert a new one.
+ XclImpChDataFormatRef p(new XclImpChDataFormat(GetChRoot()));
+ itr = maPointFmts.insert(itr, XclImpChDataFormatMap::value_type(nPointIdx, p));
+ }
+ return &itr->second;
+ }
+ return 0;
+}
+
+XclImpChTextRef* XclImpChSeries::GetDataLabelRef( sal_uInt16 nPointIdx )
+{
+ if ((nPointIdx == EXC_CHDATAFORMAT_ALLPOINTS) || (nPointIdx < EXC_CHDATAFORMAT_MAXPOINTCOUNT))
+ {
+ XclImpChTextMap::iterator itr = maLabels.lower_bound(nPointIdx);
+ if (itr == maLabels.end() || maLabels.key_comp()(nPointIdx, itr->first))
+ {
+ // No object exists at this point index position. Insert a new one.
+ XclImpChTextRef p(new XclImpChText(GetChRoot()));
+ itr = maLabels.insert(itr, XclImpChTextMap::value_type(nPointIdx, p));
+ }
+ return &itr->second;
+ }
+ return 0;
+}
+
+void XclImpChSeries::ConvertTrendLines( Reference< XDataSeries > xDataSeries ) const
+{
+ Reference< XRegressionCurveContainer > xRegCurveCont( xDataSeries, UNO_QUERY );
+ if( xRegCurveCont.is() )
+ {
+ for( XclImpChSerTrendLineList::const_iterator aIt = maTrendLines.begin(), aEnd = maTrendLines.end(); aIt != aEnd; ++aIt )
+ {
+ try
+ {
+ Reference< XRegressionCurve > xRegCurve = (*aIt)->CreateRegressionCurve();
+ if( xRegCurve.is() )
+ xRegCurveCont->addRegressionCurve( xRegCurve );
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "XclImpChSeries::ConvertTrendLines - cannot add regression curve" );
+ }
+ }
+ }
+}
+
+Reference< XPropertySet > XclImpChSeries::CreateErrorBar( sal_uInt8 nPosBarId, sal_uInt8 nNegBarId ) const
+{
+ XclImpChSerErrorBarMap::const_iterator itrPosBar = maErrorBars.find(nPosBarId);
+ XclImpChSerErrorBarMap::const_iterator itrNegBar = maErrorBars.find(nNegBarId);
+ XclImpChSerErrorBarMap::const_iterator itrEnd = maErrorBars.end();
+ if (itrPosBar == itrEnd || itrNegBar == itrEnd)
+ return Reference<XPropertySet>();
+
+ return XclImpChSerErrorBar::CreateErrorBar(itrPosBar->second, itrNegBar->second);
+}
+
+// Chart type groups ==========================================================
+
+XclImpChType::XclImpChType( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot ),
+ mnRecId( EXC_ID_CHUNKNOWN ),
+ maTypeInfo( rRoot.GetChartTypeInfo( EXC_CHTYPEID_UNKNOWN ) )
+{
+}
+
+void XclImpChType::ReadChType( XclImpStream& rStrm )
+{
+ sal_uInt16 nRecId = rStrm.GetRecId();
+ bool bKnownType = true;
+
+ switch( nRecId )
+ {
+ case EXC_ID_CHBAR:
+ rStrm >> maData.mnOverlap >> maData.mnGap >> maData.mnFlags;
+ break;
+
+ case EXC_ID_CHLINE:
+ case EXC_ID_CHAREA:
+ case EXC_ID_CHRADARLINE:
+ case EXC_ID_CHRADARAREA:
+ rStrm >> maData.mnFlags;
+ break;
+
+ case EXC_ID_CHPIE:
+ rStrm >> maData.mnRotation >> maData.mnPieHole;
+ if( GetBiff() == EXC_BIFF8 )
+ rStrm >> maData.mnFlags;
+ else
+ maData.mnFlags = 0;
+ break;
+
+ case EXC_ID_CHPIEEXT:
+ maData.mnRotation = 0;
+ maData.mnPieHole = 0;
+ maData.mnFlags = 0;
+ break;
+
+ case EXC_ID_CHSCATTER:
+ if( GetBiff() == EXC_BIFF8 )
+ rStrm >> maData.mnBubbleSize >> maData.mnBubbleType >> maData.mnFlags;
+ else
+ maData.mnFlags = 0;
+ break;
+
+ case EXC_ID_CHSURFACE:
+ rStrm >> maData.mnFlags;
+ break;
+
+ default:
+ bKnownType = false;
+ }
+
+ if( bKnownType )
+ mnRecId = nRecId;
+}
+
+void XclImpChType::Finalize( bool bStockChart )
+{
+ switch( mnRecId )
+ {
+ case EXC_ID_CHLINE:
+ maTypeInfo = GetChartTypeInfo( bStockChart ?
+ EXC_CHTYPEID_STOCK : EXC_CHTYPEID_LINE );
+ break;
+ case EXC_ID_CHBAR:
+ maTypeInfo = GetChartTypeInfo( ::get_flagvalue(
+ maData.mnFlags, EXC_CHBAR_HORIZONTAL,
+ EXC_CHTYPEID_HORBAR, EXC_CHTYPEID_BAR ) );
+ break;
+ case EXC_ID_CHPIE:
+ maTypeInfo = GetChartTypeInfo( (maData.mnPieHole > 0) ?
+ EXC_CHTYPEID_DONUT : EXC_CHTYPEID_PIE );
+ break;
+ case EXC_ID_CHSCATTER:
+ maTypeInfo = GetChartTypeInfo( ::get_flagvalue(
+ maData.mnFlags, EXC_CHSCATTER_BUBBLES,
+ EXC_CHTYPEID_BUBBLES, EXC_CHTYPEID_SCATTER ) );
+ break;
+ default:
+ maTypeInfo = GetChartTypeInfo( mnRecId );
+ }
+
+ switch( maTypeInfo.meTypeId )
+ {
+ case EXC_CHTYPEID_PIEEXT:
+ case EXC_CHTYPEID_BUBBLES:
+ case EXC_CHTYPEID_SURFACE:
+ case EXC_CHTYPEID_UNKNOWN:
+ GetTracer().TraceChartUnKnownType();
+ break;
+ default:;
+ }
+}
+
+bool XclImpChType::IsStacked() const
+{
+ bool bStacked = false;
+ if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg )
+ {
+ case EXC_CHTYPECATEG_LINE:
+ bStacked =
+ ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) &&
+ !::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT );
+ break;
+ case EXC_CHTYPECATEG_BAR:
+ bStacked =
+ ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) &&
+ !::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT );
+ break;
+ default:;
+ }
+ return bStacked;
+}
+
+bool XclImpChType::IsPercent() const
+{
+ bool bPercent = false;
+ if( maTypeInfo.mbSupportsStacking ) switch( maTypeInfo.meTypeCateg )
+ {
+ case EXC_CHTYPECATEG_LINE:
+ bPercent =
+ ::get_flag( maData.mnFlags, EXC_CHLINE_STACKED ) &&
+ ::get_flag( maData.mnFlags, EXC_CHLINE_PERCENT );
+ break;
+ case EXC_CHTYPECATEG_BAR:
+ bPercent =
+ ::get_flag( maData.mnFlags, EXC_CHBAR_STACKED ) &&
+ ::get_flag( maData.mnFlags, EXC_CHBAR_PERCENT );
+ break;
+ default:;
+ }
+ return bPercent;
+}
+
+bool XclImpChType::HasCategoryLabels() const
+{
+ // radar charts disable category labels in chart type, not in CHTICK of X axis
+ return (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) || ::get_flag( maData.mnFlags, EXC_CHRADAR_AXISLABELS );
+}
+
+Reference< XCoordinateSystem > XclImpChType::CreateCoordSystem( bool b3dChart ) const
+{
+ // service name
+ OUString aCoordSysService;
+ if( maTypeInfo.mbPolarCoordSystem )
+ {
+ if( b3dChart )
+ aCoordSysService = SERVICE_CHART2_POLARCOORDSYS3D;
+ else
+ aCoordSysService = SERVICE_CHART2_POLARCOORDSYS2D;
+ }
+ else
+ {
+ if( b3dChart )
+ aCoordSysService = SERVICE_CHART2_CARTESIANCOORDSYS3D;
+ else
+ aCoordSysService = SERVICE_CHART2_CARTESIANCOORDSYS2D;
+ }
+
+ // create the coordinate system object
+ Reference< XCoordinateSystem > xCoordSystem( ScfApiHelper::CreateInstance( aCoordSysService ), UNO_QUERY );
+
+ // swap X and Y axis
+ if( maTypeInfo.mbSwappedAxesSet )
+ {
+ ScfPropertySet aCoordSysProp( xCoordSystem );
+ aCoordSysProp.SetBoolProperty( EXC_CHPROP_SWAPXANDYAXIS, true );
+ }
+
+ return xCoordSystem;
+}
+
+Reference< XChartType > XclImpChType::CreateChartType( Reference< XDiagram > xDiagram, bool b3dChart ) const
+{
+ OUString aService = OUString::createFromAscii( maTypeInfo.mpcServiceName );
+ Reference< XChartType > xChartType( ScfApiHelper::CreateInstance( aService ), UNO_QUERY );
+
+ // additional properties
+ switch( maTypeInfo.meTypeCateg )
+ {
+ case EXC_CHTYPECATEG_BAR:
+ {
+ ScfPropertySet aTypeProp( xChartType );
+ Sequence< sal_Int32 > aInt32Seq( 2 );
+ aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = -maData.mnOverlap;
+ aTypeProp.SetProperty( EXC_CHPROP_OVERLAPSEQ, aInt32Seq );
+ aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = maData.mnGap;
+ aTypeProp.SetProperty( EXC_CHPROP_GAPWIDTHSEQ, aInt32Seq );
+ }
+ break;
+ case EXC_CHTYPECATEG_PIE:
+ {
+ ScfPropertySet aTypeProp( xChartType );
+ aTypeProp.SetBoolProperty( EXC_CHPROP_USERINGS, maTypeInfo.meTypeId == EXC_CHTYPEID_DONUT );
+ /* #i85166# starting angle of first pie slice. 3D pie charts use Y
+ rotation setting in view3D element. Of-pie charts do not
+ support pie rotation. */
+ if( !b3dChart && (maTypeInfo.meTypeId != EXC_CHTYPEID_PIEEXT) )
+ {
+ ScfPropertySet aDiaProp( xDiagram );
+ XclImpChRoot::ConvertPieRotation( aDiaProp, maData.mnRotation );
+ }
+ }
+ break;
+ default:;
+ }
+
+ return xChartType;
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpChChart3d::ReadChChart3d( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnRotation
+ >> maData.mnElevation
+ >> maData.mnEyeDist
+ >> maData.mnRelHeight
+ >> maData.mnRelDepth
+ >> maData.mnDepthGap
+ >> maData.mnFlags;
+}
+
+void XclImpChChart3d::Convert( ScfPropertySet& rPropSet, bool b3dWallChart ) const
+{
+ namespace cssd = ::com::sun::star::drawing;
+
+// #i104057# do not assert this, written by broken external generators
+// DBG_ASSERT( ::get_flag( maData.mnFlags, EXC_CHCHART3D_HASWALLS ) == b3dWallChart, "XclImpChChart3d::Convert - wrong wall flag" );
+
+ sal_Int32 nRotationY = 0;
+ sal_Int32 nRotationX = 0;
+ sal_Int32 nPerspective = 15;
+ bool bRightAngled = false;
+ cssd::ProjectionMode eProjMode = cssd::ProjectionMode_PERSPECTIVE;
+ Color aAmbientColor, aLightColor;
+
+ if( b3dWallChart )
+ {
+ // Y rotation (Excel [0..359], Chart2 [-179,180])
+ nRotationY = maData.mnRotation % 360;
+ if( nRotationY > 180 ) nRotationY -= 360;
+ // X rotation a.k.a. elevation (Excel [-90..90], Chart2 [-179,180])
+ nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, -90, 90 );
+ // perspective (Excel and Chart2 [0,100])
+ nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 );
+ // right-angled axes
+ bRightAngled = !::get_flag( maData.mnFlags, EXC_CHCHART3D_REAL3D );
+ // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%)
+ bool bParallel = bRightAngled || (nPerspective == 0);
+ eProjMode = bParallel ? cssd::ProjectionMode_PARALLEL : cssd::ProjectionMode_PERSPECTIVE;
+ // ambient color (Gray 20%)
+ aAmbientColor.SetColor( RGB_COLORDATA( 204, 204, 204 ) );
+ // light color (Gray 60%)
+ aLightColor.SetColor( RGB_COLORDATA( 102, 102, 102 ) );
+ }
+ else
+ {
+ // Y rotation not used in pie charts, but 'first pie slice angle'
+ nRotationY = 0;
+ XclImpChRoot::ConvertPieRotation( rPropSet, maData.mnRotation );
+ // X rotation a.k.a. elevation (map Excel [10..80] to Chart2 [-80,-10])
+ nRotationX = limit_cast< sal_Int32, sal_Int32 >( maData.mnElevation, 10, 80 ) - 90;
+ // perspective (Excel and Chart2 [0,100])
+ nPerspective = limit_cast< sal_Int32, sal_Int32 >( maData.mnEyeDist, 0, 100 );
+ // no right-angled axes in pie charts, but parallel projection
+ bRightAngled = false;
+ eProjMode = cssd::ProjectionMode_PARALLEL;
+ // ambient color (Gray 30%)
+ aAmbientColor.SetColor( RGB_COLORDATA( 179, 179, 179 ) );
+ // light color (Gray 70%)
+ aLightColor.SetColor( RGB_COLORDATA( 76, 76, 76 ) );
+ }
+
+ // properties
+ rPropSet.SetProperty( EXC_CHPROP_ROTATIONVERTICAL, nRotationY );
+ rPropSet.SetProperty( EXC_CHPROP_ROTATIONHORIZONTAL, nRotationX );
+ rPropSet.SetProperty( EXC_CHPROP_PERSPECTIVE, nPerspective );
+ rPropSet.SetBoolProperty( EXC_CHPROP_RIGHTANGLEDAXES, bRightAngled );
+ rPropSet.SetProperty( EXC_CHPROP_D3DSCENEPERSPECTIVE, eProjMode );
+
+ // light settings
+ rPropSet.SetProperty( EXC_CHPROP_D3DSCENESHADEMODE, cssd::ShadeMode_FLAT );
+ rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENEAMBIENTCOLOR, aAmbientColor );
+ rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON1, false );
+ rPropSet.SetBoolProperty( EXC_CHPROP_D3DSCENELIGHTON2, true );
+ rPropSet.SetColorProperty( EXC_CHPROP_D3DSCENELIGHTCOLOR2, aLightColor );
+ rPropSet.SetProperty( EXC_CHPROP_D3DSCENELIGHTDIR2, cssd::Direction3D( 0.2, 0.4, 1.0 ) );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChLegend::XclImpChLegend( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot )
+{
+}
+
+void XclImpChLegend::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ rStrm >> maData.maRect >> maData.mnDockMode >> maData.mnSpacing >> maData.mnFlags;
+
+ // trace unsupported features
+ if( GetTracer().IsEnabled() )
+ {
+ if( maData.mnDockMode == EXC_CHLEGEND_NOTDOCKED )
+ GetTracer().TraceChartLegendPosition();
+ if( ::get_flag( maData.mnFlags, EXC_CHLEGEND_DATATABLE ) )
+ GetTracer().TraceChartDataTable();
+ }
+}
+
+void XclImpChLegend::ReadSubRecord( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_CHFRAMEPOS:
+ mxFramePos.reset( new XclImpChFramePos );
+ mxFramePos->ReadChFramePos( rStrm );
+ break;
+ case EXC_ID_CHTEXT:
+ mxText.reset( new XclImpChText( GetChRoot() ) );
+ mxText->ReadRecordGroup( rStrm );
+ break;
+ case EXC_ID_CHFRAME:
+ mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
+ mxFrame->ReadRecordGroup( rStrm );
+ break;
+ }
+}
+
+void XclImpChLegend::Finalize()
+{
+ // legend default formatting differs in OOChart and Excel, missing frame means automatic
+ if( !mxFrame )
+ mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_LEGEND ) );
+ // Update text formatting. If mxText is empty, the passed default text is used.
+ lclUpdateText( mxText, GetChartData().GetDefaultText( EXC_CHTEXTTYPE_LEGEND ) );
+}
+
+Reference< XLegend > XclImpChLegend::CreateLegend() const
+{
+ Reference< XLegend > xLegend( ScfApiHelper::CreateInstance( SERVICE_CHART2_LEGEND ), UNO_QUERY );
+ if( xLegend.is() )
+ {
+ ScfPropertySet aLegendProp( xLegend );
+ aLegendProp.SetBoolProperty( EXC_CHPROP_SHOW, true );
+
+ // frame properties
+ if( mxFrame )
+ mxFrame->Convert( aLegendProp );
+ // text properties
+ if( mxText )
+ mxText->ConvertFont( aLegendProp );
+
+ /* Legend position and size. Default positions are used only if the
+ plot area is positioned automatically (Excel sets the plot area to
+ manual mode, if the legend is moved or resized). With manual plot
+ areas, Excel ignores the value in maData.mnDockMode completely. */
+ cssc2::LegendPosition eApiPos = cssc2::LegendPosition_CUSTOM;
+ cssc::ChartLegendExpansion eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
+ if( !GetChartData().IsManualPlotArea() ) switch( maData.mnDockMode )
+ {
+ case EXC_CHLEGEND_LEFT:
+ eApiPos = cssc2::LegendPosition_LINE_START;
+ eApiExpand = cssc::ChartLegendExpansion_HIGH;
+ break;
+ case EXC_CHLEGEND_RIGHT:
+ // top-right not supported
+ case EXC_CHLEGEND_CORNER:
+ eApiPos = cssc2::LegendPosition_LINE_END;
+ eApiExpand = cssc::ChartLegendExpansion_HIGH;
+ break;
+ case EXC_CHLEGEND_TOP:
+ eApiPos = cssc2::LegendPosition_PAGE_START;
+ eApiExpand = cssc::ChartLegendExpansion_WIDE;
+ break;
+ case EXC_CHLEGEND_BOTTOM:
+ eApiPos = cssc2::LegendPosition_PAGE_END;
+ eApiExpand = cssc::ChartLegendExpansion_WIDE;
+ break;
+ }
+
+ // no automatic position/size: try to find the correct position and size
+ if( eApiPos == cssc2::LegendPosition_CUSTOM )
+ {
+ const XclChFramePos* pFramePos = mxFramePos ? &mxFramePos->GetFramePosData() : 0;
+
+ /* Legend position. Only the settings from the CHFRAMEPOS record
+ are used by Excel, the position in the CHLEGEND record will be
+ ignored. */
+ if( pFramePos )
+ {
+ RelativePosition aRelPos(
+ CalcRelativeFromChartX( pFramePos->maRect.mnX ),
+ CalcRelativeFromChartY( pFramePos->maRect.mnY ),
+ ::com::sun::star::drawing::Alignment_TOP_LEFT );
+ aLegendProp.SetProperty( EXC_CHPROP_RELATIVEPOSITION, aRelPos );
+ }
+ else
+ {
+ // no manual position/size found, just go for the default
+ eApiPos = cssc2::LegendPosition_LINE_END;
+ }
+
+ /* Legend size. The member mnBRMode specifies whether size is
+ automatic or changes manually. Manual size is given in points,
+ not in chart units. */
+ if( pFramePos && (pFramePos->mnBRMode == EXC_CHFRAMEPOS_ABSSIZE_POINTS) &&
+ (pFramePos->maRect.mnWidth > 0) && (pFramePos->maRect.mnHeight > 0) )
+ {
+ eApiExpand = cssc::ChartLegendExpansion_CUSTOM;
+ sal_Int32 nWidthHmm = static_cast< sal_Int32 >( pFramePos->maRect.mnWidth / EXC_POINTS_PER_HMM );
+ sal_Int32 nHeightHmm = static_cast< sal_Int32 >( pFramePos->maRect.mnHeight / EXC_POINTS_PER_HMM );
+ RelativeSize aRelSize( CalcRelativeFromHmmX( nWidthHmm ), CalcRelativeFromHmmY( nHeightHmm ) );
+ aLegendProp.SetProperty( EXC_CHPROP_RELATIVESIZE, aRelSize );
+ }
+ else
+ {
+ // automatic size: determine entry direction from flags
+ eApiExpand = ::get_flagvalue( maData.mnFlags, EXC_CHLEGEND_STACKED,
+ cssc::ChartLegendExpansion_HIGH, cssc::ChartLegendExpansion_WIDE );
+ }
+ }
+ aLegendProp.SetProperty( EXC_CHPROP_ANCHORPOSITION, eApiPos );
+ aLegendProp.SetProperty( EXC_CHPROP_EXPANSION, eApiExpand );
+ }
+ return xLegend;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChDropBar::XclImpChDropBar( sal_uInt16 nDropBar ) :
+ mnDropBar( nDropBar ),
+ mnBarDist( 0 )
+{
+}
+
+void XclImpChDropBar::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ rStrm >> mnBarDist;
+}
+
+void XclImpChDropBar::Convert( const XclImpChRoot& rRoot, ScfPropertySet& rPropSet ) const
+{
+ XclChObjectType eObjType = EXC_CHOBJTYPE_BACKGROUND;
+ switch( mnDropBar )
+ {
+ case EXC_CHDROPBAR_UP: eObjType = EXC_CHOBJTYPE_WHITEDROPBAR; break;
+ case EXC_CHDROPBAR_DOWN: eObjType = EXC_CHOBJTYPE_BLACKDROPBAR; break;
+ }
+ ConvertFrameBase( rRoot, rPropSet, eObjType );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChTypeGroup::XclImpChTypeGroup( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot ),
+ maType( rRoot ),
+ maTypeInfo( maType.GetTypeInfo() )
+{
+ // Initialize unused format indexes set. At this time, all formats are unused.
+ for( sal_uInt16 nFormatIdx = 0; nFormatIdx <= EXC_CHSERIES_MAXSERIES; ++nFormatIdx )
+ maUnusedFormats.insert( maUnusedFormats.end(), nFormatIdx );
+}
+
+void XclImpChTypeGroup::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ rStrm.Ignore( 16 );
+ rStrm >> maData.mnFlags >> maData.mnGroupIdx;
+}
+
+void XclImpChTypeGroup::ReadSubRecord( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_CHCHART3D:
+ mxChart3d.reset( new XclImpChChart3d );
+ mxChart3d->ReadChChart3d( rStrm );
+ break;
+ case EXC_ID_CHLEGEND:
+ mxLegend.reset( new XclImpChLegend( GetChRoot() ) );
+ mxLegend->ReadRecordGroup( rStrm );
+ break;
+ case EXC_ID_CHDEFAULTTEXT:
+ GetChartData().ReadChDefaultText( rStrm );
+ break;
+ case EXC_ID_CHDROPBAR:
+ ReadChDropBar( rStrm );
+ break;
+ case EXC_ID_CHCHARTLINE:
+ ReadChChartLine( rStrm );
+ break;
+ case EXC_ID_CHDATAFORMAT:
+ ReadChDataFormat( rStrm );
+ break;
+ default:
+ maType.ReadChType( rStrm );
+ }
+}
+
+void XclImpChTypeGroup::Finalize()
+{
+ // check and set valid chart type
+ bool bStockChart =
+ (maType.GetRecId() == EXC_ID_CHLINE) && // must be a line chart
+ !mxChart3d && // must be a 2d chart
+ HasHiLoLine() && // must contain hi-lo lines
+ (maSeries.size() == static_cast<XclImpChSeriesVec::size_type>(HasDropBars() ? 4 : 3)); // correct series count
+ maType.Finalize( bStockChart );
+
+ // extended type info
+ maTypeInfo.Set( maType.GetTypeInfo(), mxChart3d, false );
+
+ // reverse series order for some unstacked 2D chart types
+ if( maTypeInfo.mbReverseSeries && !Is3dChart() && !maType.IsStacked() && !maType.IsPercent() )
+ ::std::reverse( maSeries.begin(), maSeries.end() );
+
+ // update chart type group format, may depend on chart type finalized above
+ if( mxGroupFmt )
+ mxGroupFmt->UpdateGroupFormat( maTypeInfo );
+}
+
+void XclImpChTypeGroup::AddSeries( XclImpChSeriesRef xSeries )
+{
+ if( xSeries )
+ maSeries.push_back( xSeries );
+ // store first inserted series separately, series order may be reversed later
+ if( !mxFirstSeries )
+ mxFirstSeries = xSeries;
+}
+
+void XclImpChTypeGroup::SetUsedFormatIndex( sal_uInt16 nFormatIdx )
+{
+ maUnusedFormats.erase( nFormatIdx );
+}
+
+sal_uInt16 XclImpChTypeGroup::PopUnusedFormatIndex()
+{
+ DBG_ASSERT( !maUnusedFormats.empty(), "XclImpChTypeGroup::PopUnusedFormatIndex - no more format indexes available" );
+ sal_uInt16 nFormatIdx = maUnusedFormats.empty() ? 0 : *maUnusedFormats.begin();
+ SetUsedFormatIndex( nFormatIdx );
+ return nFormatIdx;
+}
+
+bool XclImpChTypeGroup::HasVarPointFormat() const
+{
+ return ::get_flag( maData.mnFlags, EXC_CHTYPEGROUP_VARIEDCOLORS ) &&
+ ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_MULTI) || // multiple series allowed
+ ((maTypeInfo.meVarPointMode == EXC_CHVARPOINT_SINGLE) && // or exactly 1 series?
+ (maSeries.size() == 1)));
+}
+
+bool XclImpChTypeGroup::HasConnectorLines() const
+{
+ // existence of connector lines (only in stacked bar charts)
+ if ( !(maType.IsStacked() || maType.IsPercent()) || (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_BAR) )
+ return false;
+ XclImpChLineFormatMap::const_iterator xConLine = maChartLines.find( EXC_CHCHARTLINE_CONNECT );
+ return ( xConLine != maChartLines.end() && xConLine->second->HasLine() );
+}
+
+const String& XclImpChTypeGroup::GetSingleSeriesTitle() const
+{
+ // no automatic title for series with trendlines or error bars
+ // pie charts always show an automatic title, even if more series exist
+ return (mxFirstSeries && !mxFirstSeries->HasChildSeries() && (maTypeInfo.mbSingleSeriesVis || (maSeries.size() == 1))) ?
+ mxFirstSeries->GetTitle() : String::EmptyString();
+}
+
+void XclImpChTypeGroup::ConvertChart3d( ScfPropertySet& rPropSet ) const
+{
+ if( mxChart3d )
+ mxChart3d->Convert( rPropSet, Is3dWallChart() );
+}
+
+Reference< XCoordinateSystem > XclImpChTypeGroup::CreateCoordSystem() const
+{
+ return maType.CreateCoordSystem( Is3dChart() );
+}
+
+Reference< XChartType > XclImpChTypeGroup::CreateChartType( Reference< XDiagram > xDiagram, sal_Int32 nApiAxesSetIdx ) const
+{
+ DBG_ASSERT( IsValidGroup(), "XclImpChTypeGroup::CreateChartType - type group without series" );
+
+ // create the chart type object
+ Reference< XChartType > xChartType = maType.CreateChartType( xDiagram, Is3dChart() );
+
+ // bar chart connector lines
+ if( HasConnectorLines() )
+ {
+ ScfPropertySet aDiaProp( xDiagram );
+ aDiaProp.SetBoolProperty( EXC_CHPROP_CONNECTBARS, true );
+ }
+
+ /* Stock chart needs special processing. Create one 'big' series with
+ data sequences of different roles. */
+ if( maTypeInfo.meTypeId == EXC_CHTYPEID_STOCK )
+ CreateStockSeries( xChartType, nApiAxesSetIdx );
+ else
+ CreateDataSeries( xChartType, nApiAxesSetIdx );
+
+ return xChartType;
+}
+
+Reference< XLabeledDataSequence > XclImpChTypeGroup::CreateCategSequence() const
+{
+ Reference< XLabeledDataSequence > xLabeledSeq;
+ // create category sequence from first visible series
+ if( mxFirstSeries )
+ xLabeledSeq = mxFirstSeries->CreateCategSequence( EXC_CHPROP_ROLE_CATEG );
+ return xLabeledSeq;
+}
+
+void XclImpChTypeGroup::ReadChDropBar( XclImpStream& rStrm )
+{
+ if (maDropBars.find(EXC_CHDROPBAR_UP) == maDropBars.end())
+ {
+ auto_ptr<XclImpChDropBar> p(new XclImpChDropBar(EXC_CHDROPBAR_UP));
+ p->ReadRecordGroup(rStrm);
+ maDropBars.insert(EXC_CHDROPBAR_UP, p);
+ }
+ else if(maDropBars.find(EXC_CHDROPBAR_DOWN) == maDropBars.end())
+ {
+ auto_ptr<XclImpChDropBar> p(new XclImpChDropBar(EXC_CHDROPBAR_DOWN));
+ p->ReadRecordGroup(rStrm);
+ maDropBars.insert(EXC_CHDROPBAR_DOWN, p);
+ }
+}
+
+void XclImpChTypeGroup::ReadChChartLine( XclImpStream& rStrm )
+{
+ sal_uInt16 nLineId = rStrm.ReaduInt16();
+ if( (rStrm.GetNextRecId() == EXC_ID_CHLINEFORMAT) && rStrm.StartNextRecord() )
+ {
+ XclImpChLineFormat xLineFmt;
+ xLineFmt.ReadChLineFormat( rStrm );
+ maChartLines[ nLineId ] = xLineFmt;
+ }
+}
+
+void XclImpChTypeGroup::ReadChDataFormat( XclImpStream& rStrm )
+{
+ // global series and data point format
+ XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
+ xDataFmt->ReadRecordGroup( rStrm );
+ const XclChDataPointPos& rPos = xDataFmt->GetPointPos();
+ if( (rPos.mnSeriesIdx == 0) && (rPos.mnPointIdx == 0) &&
+ (xDataFmt->GetFormatIdx() == EXC_CHDATAFORMAT_DEFAULT) )
+ mxGroupFmt = xDataFmt;
+}
+
+
+void XclImpChTypeGroup::InsertDataSeries( Reference< XChartType > xChartType,
+ Reference< XDataSeries > xSeries, sal_Int32 nApiAxesSetIdx ) const
+{
+ Reference< XDataSeriesContainer > xSeriesCont( xChartType, UNO_QUERY );
+ if( xSeriesCont.is() && xSeries.is() )
+ {
+ // series stacking mode
+ cssc2::StackingDirection eStacking = cssc2::StackingDirection_NO_STACKING;
+ // stacked overrides deep-3d
+ if( maType.IsStacked() || maType.IsPercent() )
+ eStacking = cssc2::StackingDirection_Y_STACKING;
+ else if( Is3dDeepChart() )
+ eStacking = cssc2::StackingDirection_Z_STACKING;
+
+ // additional series properties
+ ScfPropertySet aSeriesProp( xSeries );
+ aSeriesProp.SetProperty( EXC_CHPROP_STACKINGDIR, eStacking );
+ aSeriesProp.SetProperty( EXC_CHPROP_ATTAXISINDEX, nApiAxesSetIdx );
+
+ // insert series into container
+ try
+ {
+ xSeriesCont->addDataSeries( xSeries );
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "XclImpChTypeGroup::InsertDataSeries - cannot add data series" );
+ }
+ }
+}
+
+void XclImpChTypeGroup::CreateDataSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const
+{
+ bool bSpline = false;
+ for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt )
+ {
+ Reference< XDataSeries > xDataSeries = (*aIt)->CreateDataSeries();
+ InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx );
+ bSpline |= (*aIt)->HasSpline();
+ }
+ // spline - TODO: set at single series (#i66858#)
+ if( bSpline && !maTypeInfo.IsSeriesFrameFormat() && (maTypeInfo.meTypeCateg != EXC_CHTYPECATEG_RADAR) )
+ {
+ ScfPropertySet aTypeProp( xChartType );
+ aTypeProp.SetProperty( EXC_CHPROP_CURVESTYLE, ::com::sun::star::chart2::CurveStyle_CUBIC_SPLINES );
+ }
+}
+
+void XclImpChTypeGroup::CreateStockSeries( Reference< XChartType > xChartType, sal_Int32 nApiAxesSetIdx ) const
+{
+ // create the data series object
+ Reference< XDataSeries > xDataSeries( ScfApiHelper::CreateInstance( SERVICE_CHART2_DATASERIES ), UNO_QUERY );
+ Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
+ if( xDataSink.is() )
+ {
+ // create a list of data sequences from all series
+ ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
+ DBG_ASSERT( maSeries.size() >= 3, "XclImpChTypeGroup::CreateChartType - missing stock series" );
+ int nRoleIdx = (maSeries.size() == 3) ? 1 : 0;
+ for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end();
+ (nRoleIdx < 4) && (aIt != aEnd); ++nRoleIdx, ++aIt )
+ {
+ // create a data sequence with a specific role
+ OUString aRole;
+ switch( nRoleIdx )
+ {
+ case 0: aRole = EXC_CHPROP_ROLE_OPENVALUES; break;
+ case 1: aRole = EXC_CHPROP_ROLE_HIGHVALUES; break;
+ case 2: aRole = EXC_CHPROP_ROLE_LOWVALUES; break;
+ case 3: aRole = EXC_CHPROP_ROLE_CLOSEVALUES; break;
+ }
+ Reference< XLabeledDataSequence > xDataSeq = (*aIt)->CreateValueSequence( aRole );
+ if( xDataSeq.is() )
+ aLabeledSeqVec.push_back( xDataSeq );
+ }
+
+ // attach labeled data sequences to series and insert series into chart type
+ xDataSink->setData( ScfApiHelper::VectorToSequence( aLabeledSeqVec ) );
+
+ // formatting of special stock chart elements
+ ScfPropertySet aTypeProp( xChartType );
+ aTypeProp.SetBoolProperty( EXC_CHPROP_JAPANESE, HasDropBars() );
+ aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWFIRST, HasDropBars() );
+ aTypeProp.SetBoolProperty( EXC_CHPROP_SHOWHIGHLOW, true );
+ // hi-lo line format
+ XclImpChLineFormatMap::const_iterator xHiLoLine = maChartLines.find( EXC_CHCHARTLINE_HILO );
+ if ( xHiLoLine != maChartLines.end() )
+ {
+ ScfPropertySet aSeriesProp( xDataSeries );
+ xHiLoLine->second->Convert( GetChRoot(), aSeriesProp, EXC_CHOBJTYPE_HILOLINE );
+ }
+ // white dropbar format
+ XclImpChDropBarMap::const_iterator itr = maDropBars.find(EXC_CHDROPBAR_UP);
+ Reference<XPropertySet> xWhitePropSet;
+ if (itr != maDropBars.end() && aTypeProp.GetProperty(xWhitePropSet, EXC_CHPROP_WHITEDAY))
+ {
+ ScfPropertySet aBarProp( xWhitePropSet );
+ itr->second->Convert(GetChRoot(), aBarProp);
+ }
+ // black dropbar format
+ itr = maDropBars.find(EXC_CHDROPBAR_DOWN);
+ Reference<XPropertySet> xBlackPropSet;
+ if (itr != maDropBars.end() && aTypeProp.GetProperty(xBlackPropSet, EXC_CHPROP_BLACKDAY))
+ {
+ ScfPropertySet aBarProp( xBlackPropSet );
+ itr->second->Convert(GetChRoot(), aBarProp);
+ }
+
+ // insert the series into the chart type object
+ InsertDataSeries( xChartType, xDataSeries, nApiAxesSetIdx );
+ }
+}
+
+// Axes =======================================================================
+
+XclImpChLabelRange::XclImpChLabelRange( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot )
+{
+}
+
+void XclImpChLabelRange::ReadChLabelRange( XclImpStream& rStrm )
+{
+ rStrm >> maLabelData.mnCross >> maLabelData.mnLabelFreq >> maLabelData.mnTickFreq >> maLabelData.mnFlags;
+}
+
+void XclImpChLabelRange::ReadChDateRange( XclImpStream& rStrm )
+{
+ rStrm >> maDateData.mnMinDate
+ >> maDateData.mnMaxDate
+ >> maDateData.mnMajorStep
+ >> maDateData.mnMajorUnit
+ >> maDateData.mnMinorStep
+ >> maDateData.mnMinorUnit
+ >> maDateData.mnBaseUnit
+ >> maDateData.mnCross
+ >> maDateData.mnFlags;
+}
+
+void XclImpChLabelRange::Convert( ScfPropertySet& rPropSet, ScaleData& rScaleData, bool bMirrorOrient ) const
+{
+ // automatic axis type detection
+ rScaleData.AutoDateAxis = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTODATE );
+
+ // the flag EXC_CHDATERANGE_DATEAXIS specifies whether this is a date axis
+ if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ) )
+ {
+ /* Chart2 requires axis type CATEGORY for automatic category/date axis
+ (even if it is a date axis currently). */
+ rScaleData.AxisType = rScaleData.AutoDateAxis ? cssc2::AxisType::CATEGORY : cssc2::AxisType::DATE;
+ rScaleData.Scaling.set( ScfApiHelper::CreateInstance( SERVICE_CHART2_LINEARSCALING ), UNO_QUERY );
+ /* Min/max values depend on base time unit, they specify the number of
+ days, months, or years starting from null date. */
+ lclConvertTimeValue( GetRoot(), rScaleData.Minimum, maDateData.mnMinDate, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMIN ), maDateData.mnBaseUnit );
+ lclConvertTimeValue( GetRoot(), rScaleData.Maximum, maDateData.mnMaxDate, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAX ), maDateData.mnBaseUnit );
+ // increment
+ cssc::TimeIncrement& rTimeIncrement = rScaleData.TimeIncrement;
+ lclConvertTimeInterval( rTimeIncrement.MajorTimeInterval, maDateData.mnMajorStep, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMAJOR ), maDateData.mnMajorUnit );
+ lclConvertTimeInterval( rTimeIncrement.MinorTimeInterval, maDateData.mnMinorStep, ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOMINOR ), maDateData.mnMinorUnit );
+ // base unit
+ if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOBASE ) )
+ rTimeIncrement.TimeResolution.clear();
+ else
+ rTimeIncrement.TimeResolution <<= lclGetApiTimeUnit( maDateData.mnBaseUnit );
+ }
+ else
+ {
+ // do not overlap text unless all labels are visible
+ rPropSet.SetBoolProperty( EXC_CHPROP_TEXTOVERLAP, maLabelData.mnLabelFreq == 1 );
+ // do not break text into several lines unless all labels are visible
+ rPropSet.SetBoolProperty( EXC_CHPROP_TEXTBREAK, maLabelData.mnLabelFreq == 1 );
+ // do not stagger labels in two lines
+ rPropSet.SetProperty( EXC_CHPROP_ARRANGEORDER, cssc::ChartAxisArrangeOrderType_SIDE_BY_SIDE );
+ }
+
+ // reverse order
+ bool bReverse = ::get_flag( maLabelData.mnFlags, EXC_CHLABELRANGE_REVERSE ) != bMirrorOrient;
+ rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL;
+
+ //! TODO #i58731# show n-th category
+}
+
+void XclImpChLabelRange::ConvertAxisPosition( ScfPropertySet& rPropSet, bool b3dChart ) const
+{
+ /* Crossing mode (max-cross flag overrides other crossing settings). Excel
+ does not move the Y axis in 3D charts, regardless of actual settings.
+ But: the Y axis has to be moved to "end", if the X axis is mirrored,
+ to keep it at the left end of the chart. */
+ bool bMaxCross = ::get_flag( maLabelData.mnFlags, b3dChart ? EXC_CHLABELRANGE_REVERSE : EXC_CHLABELRANGE_MAXCROSS );
+ cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE;
+ rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos );
+
+ // crossing position (depending on axis type text/date)
+ if( ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_DATEAXIS ) )
+ {
+ bool bAutoCross = ::get_flag( maDateData.mnFlags, EXC_CHDATERANGE_AUTOCROSS );
+ /* Crossing position value depends on base time unit, it specifies the
+ number of days, months, or years from null date. Note that Excel
+ 2007/2010 write broken BIFF8 files, they always stores the number
+ of days cregardless of the base time unit (and they are reading it
+ the same way, thus wrongly displaying files written by Excel
+ 97-2003). This filter sticks to the correct behaviour of Excel
+ 97-2003. */
+ double fCrossingPos = bAutoCross ? 1.0 : lclGetSerialDay( GetRoot(), maDateData.mnCross, maDateData.mnBaseUnit );
+ rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
+ }
+ else
+ {
+ double fCrossingPos = b3dChart ? 1.0 : maLabelData.mnCross;
+ rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChValueRange::XclImpChValueRange( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot )
+{
+}
+
+void XclImpChValueRange::ReadChValueRange( XclImpStream& rStrm )
+{
+ rStrm >> maData.mfMin
+ >> maData.mfMax
+ >> maData.mfMajorStep
+ >> maData.mfMinorStep
+ >> maData.mfCross
+ >> maData.mnFlags;
+}
+
+void XclImpChValueRange::Convert( ScaleData& rScaleData, bool bMirrorOrient ) const
+{
+ // scaling algorithm
+ bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE );
+ OUString aScalingService = bLogScale ? SERVICE_CHART2_LOGSCALING : SERVICE_CHART2_LINEARSCALING;
+ rScaleData.Scaling.set( ScfApiHelper::CreateInstance( aScalingService ), UNO_QUERY );
+
+ // min/max
+ lclSetExpValueOrClearAny( rScaleData.Minimum, maData.mfMin, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMIN ) );
+ lclSetExpValueOrClearAny( rScaleData.Maximum, maData.mfMax, bLogScale, ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAX ) );
+
+ // increment
+ bool bAutoMajor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMAJOR );
+ bool bAutoMinor = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOMINOR );
+ // major increment
+ IncrementData& rIncrementData = rScaleData.IncrementData;
+ lclSetValueOrClearAny( rIncrementData.Distance, maData.mfMajorStep, bAutoMajor );
+ // minor increment
+ Sequence< SubIncrement >& rSubIncrementSeq = rIncrementData.SubIncrements;
+ rSubIncrementSeq.realloc( 1 );
+ Any& rIntervalCount = rSubIncrementSeq[ 0 ].IntervalCount;
+ rIntervalCount.clear();
+ if( bLogScale )
+ {
+ if( !bAutoMinor )
+ rIntervalCount <<= sal_Int32( 9 );
+ }
+ else
+ {
+ if( !bAutoMajor && !bAutoMinor && (0.0 < maData.mfMinorStep) && (maData.mfMinorStep <= maData.mfMajorStep) )
+ {
+ double fCount = maData.mfMajorStep / maData.mfMinorStep + 0.5;
+ if( (1.0 <= fCount) && (fCount < 1001.0) )
+ rIntervalCount <<= static_cast< sal_Int32 >( fCount );
+ }
+ }
+
+ // reverse order
+ bool bReverse = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_REVERSE ) != bMirrorOrient;
+ rScaleData.Orientation = bReverse ? cssc2::AxisOrientation_REVERSE : cssc2::AxisOrientation_MATHEMATICAL;
+}
+
+void XclImpChValueRange::ConvertAxisPosition( ScfPropertySet& rPropSet ) const
+{
+ bool bMaxCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_MAXCROSS );
+ bool bAutoCross = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_AUTOCROSS );
+ bool bLogScale = ::get_flag( maData.mnFlags, EXC_CHVALUERANGE_LOGSCALE );
+
+ // crossing mode (max-cross flag overrides other crossing settings)
+ cssc::ChartAxisPosition eAxisPos = bMaxCross ? cssc::ChartAxisPosition_END : cssc::ChartAxisPosition_VALUE;
+ rPropSet.SetProperty( EXC_CHPROP_CROSSOVERPOSITION, eAxisPos );
+
+ // crossing position
+ double fCrossingPos = bAutoCross ? 0.0 : maData.mfCross;
+ if( bLogScale ) fCrossingPos = pow( 10.0, fCrossingPos );
+ rPropSet.SetProperty( EXC_CHPROP_CROSSOVERVALUE, fCrossingPos );
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+sal_Int32 lclGetApiTickmarks( sal_uInt8 nXclTickPos )
+{
+ using namespace ::com::sun::star::chart2::TickmarkStyle;
+ sal_Int32 nApiTickmarks = NONE;
+ ::set_flag( nApiTickmarks, INNER, ::get_flag( nXclTickPos, EXC_CHTICK_INSIDE ) );
+ ::set_flag( nApiTickmarks, OUTER, ::get_flag( nXclTickPos, EXC_CHTICK_OUTSIDE ) );
+ return nApiTickmarks;
+}
+
+cssc::ChartAxisLabelPosition lclGetApiLabelPosition( sal_Int8 nXclLabelPos )
+{
+ using namespace ::com::sun::star::chart;
+ switch( nXclLabelPos )
+ {
+ case EXC_CHTICK_LOW: return ChartAxisLabelPosition_OUTSIDE_START;
+ case EXC_CHTICK_HIGH: return ChartAxisLabelPosition_OUTSIDE_END;
+ case EXC_CHTICK_NEXT: return ChartAxisLabelPosition_NEAR_AXIS;
+ }
+ return ChartAxisLabelPosition_NEAR_AXIS;
+}
+
+} // namespace
+
+XclImpChTick::XclImpChTick( const XclImpChRoot& rRoot ) :
+ XclImpChRoot( rRoot )
+{
+}
+
+void XclImpChTick::ReadChTick( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnMajor
+ >> maData.mnMinor
+ >> maData.mnLabelPos
+ >> maData.mnBackMode;
+ rStrm.Ignore( 16 );
+ rStrm >> maData.maTextColor
+ >> maData.mnFlags;
+
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ // BIFF8: index into palette used instead of RGB data
+ maData.maTextColor = GetPalette().GetColor( rStrm.ReaduInt16() );
+ // rotation
+ rStrm >> maData.mnRotation;
+ }
+ else
+ {
+ // BIFF2-BIFF7: get rotation from text orientation
+ sal_uInt8 nOrient = ::extract_value< sal_uInt8 >( maData.mnFlags, 2, 3 );
+ maData.mnRotation = XclTools::GetXclRotFromOrient( nOrient );
+ }
+}
+
+Color XclImpChTick::GetFontColor() const
+{
+ return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOCOLOR ) ? GetFontAutoColor() : maData.maTextColor;
+}
+
+sal_uInt16 XclImpChTick::GetRotation() const
+{
+ return ::get_flag( maData.mnFlags, EXC_CHTICK_AUTOROT ) ? EXC_CHART_AUTOROTATION : maData.mnRotation;
+}
+
+void XclImpChTick::Convert( ScfPropertySet& rPropSet ) const
+{
+ rPropSet.SetProperty( EXC_CHPROP_MAJORTICKS, lclGetApiTickmarks( maData.mnMajor ) );
+ rPropSet.SetProperty( EXC_CHPROP_MINORTICKS, lclGetApiTickmarks( maData.mnMinor ) );
+ rPropSet.SetProperty( EXC_CHPROP_LABELPOSITION, lclGetApiLabelPosition( maData.mnLabelPos ) );
+ rPropSet.SetProperty( EXC_CHPROP_MARKPOSITION, cssc::ChartAxisMarkPosition_AT_AXIS );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChAxis::XclImpChAxis( const XclImpChRoot& rRoot, sal_uInt16 nAxisType ) :
+ XclImpChRoot( rRoot ),
+ mnNumFmtIdx( EXC_FORMAT_NOTFOUND )
+{
+ maData.mnType = nAxisType;
+}
+
+void XclImpChAxis::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnType;
+}
+
+void XclImpChAxis::ReadSubRecord( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_CHLABELRANGE:
+ mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
+ mxLabelRange->ReadChLabelRange( rStrm );
+ break;
+ case EXC_ID_CHDATERANGE:
+ if( !mxLabelRange )
+ mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
+ mxLabelRange->ReadChDateRange( rStrm );
+ break;
+ case EXC_ID_CHVALUERANGE:
+ mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) );
+ mxValueRange->ReadChValueRange( rStrm );
+ break;
+ case EXC_ID_CHFORMAT:
+ rStrm >> mnNumFmtIdx;
+ break;
+ case EXC_ID_CHTICK:
+ mxTick.reset( new XclImpChTick( GetChRoot() ) );
+ mxTick->ReadChTick( rStrm );
+ break;
+ case EXC_ID_CHFONT:
+ mxFont.reset( new XclImpChFont );
+ mxFont->ReadChFont( rStrm );
+ break;
+ case EXC_ID_CHAXISLINE:
+ ReadChAxisLine( rStrm );
+ break;
+ }
+}
+
+void XclImpChAxis::Finalize()
+{
+ // add default scaling, needed e.g. to adjust rotation direction of pie and radar charts
+ if( !mxLabelRange )
+ mxLabelRange.reset( new XclImpChLabelRange( GetChRoot() ) );
+ if( !mxValueRange )
+ mxValueRange.reset( new XclImpChValueRange( GetChRoot() ) );
+ // remove invisible grid lines completely
+ if( mxMajorGrid && !mxMajorGrid->HasLine() )
+ mxMajorGrid.reset();
+ if( mxMinorGrid && !mxMinorGrid->HasLine() )
+ mxMinorGrid.reset();
+ // default tick settings different in OOChart and Excel
+ if( !mxTick )
+ mxTick.reset( new XclImpChTick( GetChRoot() ) );
+ // #i4140# different default axis line color
+ if( !mxAxisLine )
+ {
+ XclChLineFormat aLineFmt;
+ // set "show axis" flag, default if line format record is missing
+ ::set_flag( aLineFmt.mnFlags, EXC_CHLINEFORMAT_SHOWAXIS );
+ mxAxisLine.reset( new XclImpChLineFormat( aLineFmt ) );
+ }
+ // add wall/floor frame for 3d charts
+ if( !mxWallFrame )
+ CreateWallFrame();
+}
+
+sal_uInt16 XclImpChAxis::GetFontIndex() const
+{
+ return mxFont ? mxFont->GetFontIndex() : EXC_FONT_NOTFOUND;
+}
+
+Color XclImpChAxis::GetFontColor() const
+{
+ return mxTick ? mxTick->GetFontColor() : GetFontAutoColor();
+}
+
+sal_uInt16 XclImpChAxis::GetRotation() const
+{
+ return mxTick ? mxTick->GetRotation() : EXC_CHART_AUTOROTATION;
+}
+
+Reference< XAxis > XclImpChAxis::CreateAxis( const XclImpChTypeGroup& rTypeGroup, const XclImpChAxis* pCrossingAxis ) const
+{
+ // create the axis object (always)
+ Reference< XAxis > xAxis( ScfApiHelper::CreateInstance( SERVICE_CHART2_AXIS ), UNO_QUERY );
+ if( xAxis.is() )
+ {
+ ScfPropertySet aAxisProp( xAxis );
+ // #i58688# axis enabled
+ aAxisProp.SetBoolProperty( EXC_CHPROP_SHOW, IsActivated() );
+
+ // axis line properties
+ if( mxAxisLine )
+ mxAxisLine->Convert( GetChRoot(), aAxisProp, EXC_CHOBJTYPE_AXISLINE );
+ // axis ticks properties
+ if( mxTick )
+ mxTick->Convert( aAxisProp );
+
+ // axis caption text --------------------------------------------------
+
+ // radar charts disable their category labels via chart type, not via axis
+ bool bHasLabels = HasLabels() &&
+ ((GetAxisType() != EXC_CHAXIS_X) || rTypeGroup.HasCategoryLabels());
+ aAxisProp.SetBoolProperty( EXC_CHPROP_DISPLAYLABELS, bHasLabels );
+ if( bHasLabels )
+ {
+ // font settings from CHFONT record or from default text
+ if( mxFont )
+ ConvertFontBase( GetChRoot(), aAxisProp );
+ else if( const XclImpChText* pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISLABEL ) )
+ pDefText->ConvertFont( aAxisProp );
+ // label text rotation
+ ConvertRotationBase( GetChRoot(), aAxisProp, true );
+ // number format
+ sal_uInt32 nScNumFmt = GetNumFmtBuffer().GetScFormat( mnNumFmtIdx );
+ if( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND )
+ aAxisProp.SetProperty( EXC_CHPROP_NUMBERFORMAT, static_cast< sal_Int32 >( nScNumFmt ) );
+ }
+
+ // axis scaling and increment -----------------------------------------
+
+ const XclChExtTypeInfo& rTypeInfo = rTypeGroup.GetTypeInfo();
+ ScaleData aScaleData = xAxis->getScaleData();
+ // set axis type
+ switch( GetAxisType() )
+ {
+ case EXC_CHAXIS_X:
+ if( rTypeInfo.mbCategoryAxis )
+ {
+ aScaleData.AxisType = cssc2::AxisType::CATEGORY;
+ aScaleData.Categories = rTypeGroup.CreateCategSequence();
+ }
+ else
+ aScaleData.AxisType = cssc2::AxisType::REALNUMBER;
+ break;
+ case EXC_CHAXIS_Y:
+ aScaleData.AxisType = rTypeGroup.IsPercent() ?
+ cssc2::AxisType::PERCENT : cssc2::AxisType::REALNUMBER;
+ break;
+ case EXC_CHAXIS_Z:
+ aScaleData.AxisType = cssc2::AxisType::SERIES;
+ break;
+ }
+ // axis scaling settings, dependent on axis type
+ switch( aScaleData.AxisType )
+ {
+ case cssc2::AxisType::CATEGORY:
+ case cssc2::AxisType::SERIES:
+ // #i71684# radar charts have reversed rotation direction
+ mxLabelRange->Convert( aAxisProp, aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_RADAR );
+ break;
+ case cssc2::AxisType::REALNUMBER:
+ case cssc2::AxisType::PERCENT:
+ // #i85167# pie/donut charts have reversed rotation direction (at Y axis!)
+ mxValueRange->Convert( aScaleData, rTypeInfo.meTypeCateg == EXC_CHTYPECATEG_PIE );
+ break;
+ default:
+ DBG_ERRORFILE( "XclImpChAxis::CreateAxis - unknown axis type" );
+ }
+
+ /* Do not set a value to the Origin member anymore (will be done via
+ new axis properties 'CrossoverPosition' and 'CrossoverValue'). */
+ aScaleData.Origin.clear();
+
+ // write back
+ xAxis->setScaleData( aScaleData );
+
+ // grid ---------------------------------------------------------------
+
+ // main grid
+ ScfPropertySet aGridProp( xAxis->getGridProperties() );
+ aGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMajorGrid() );
+ if( mxMajorGrid )
+ mxMajorGrid->Convert( GetChRoot(), aGridProp, EXC_CHOBJTYPE_GRIDLINE );
+ // sub grid
+ Sequence< Reference< XPropertySet > > aSubGridPropSeq = xAxis->getSubGridProperties();
+ if( aSubGridPropSeq.hasElements() )
+ {
+ ScfPropertySet aSubGridProp( aSubGridPropSeq[ 0 ] );
+ aSubGridProp.SetBoolProperty( EXC_CHPROP_SHOW, HasMinorGrid() );
+ if( mxMinorGrid )
+ mxMinorGrid->Convert( GetChRoot(), aSubGridProp, EXC_CHOBJTYPE_GRIDLINE );
+ }
+
+ // position of crossing axis ------------------------------------------
+
+ if( pCrossingAxis )
+ pCrossingAxis->ConvertAxisPosition( aAxisProp, rTypeGroup );
+ }
+ return xAxis;
+}
+
+void XclImpChAxis::ConvertWall( ScfPropertySet& rPropSet ) const
+{
+ if( mxWallFrame )
+ mxWallFrame->Convert( rPropSet );
+}
+
+void XclImpChAxis::ConvertAxisPosition( ScfPropertySet& rPropSet, const XclImpChTypeGroup& rTypeGroup ) const
+{
+ if( ((GetAxisType() == EXC_CHAXIS_X) && rTypeGroup.GetTypeInfo().mbCategoryAxis) || (GetAxisType() == EXC_CHAXIS_Z) )
+ mxLabelRange->ConvertAxisPosition( rPropSet, rTypeGroup.Is3dChart() );
+ else
+ mxValueRange->ConvertAxisPosition( rPropSet );
+}
+
+void XclImpChAxis::ReadChAxisLine( XclImpStream& rStrm )
+{
+ XclImpChLineFormatRef* pxLineFmt = 0;
+ bool bWallFrame = false;
+ switch( rStrm.ReaduInt16() )
+ {
+ case EXC_CHAXISLINE_AXISLINE: pxLineFmt = &mxAxisLine; break;
+ case EXC_CHAXISLINE_MAJORGRID: pxLineFmt = &mxMajorGrid; break;
+ case EXC_CHAXISLINE_MINORGRID: pxLineFmt = &mxMinorGrid; break;
+ case EXC_CHAXISLINE_WALLS: bWallFrame = true; break;
+ }
+ if( bWallFrame )
+ CreateWallFrame();
+
+ bool bLoop = pxLineFmt || bWallFrame;
+ while( bLoop )
+ {
+ sal_uInt16 nRecId = rStrm.GetNextRecId();
+ bLoop = ((nRecId == EXC_ID_CHLINEFORMAT) ||
+ (nRecId == EXC_ID_CHAREAFORMAT) ||
+ (nRecId == EXC_ID_CHESCHERFORMAT))
+ && rStrm.StartNextRecord();
+ if( bLoop )
+ {
+ if( pxLineFmt && (nRecId == EXC_ID_CHLINEFORMAT) )
+ {
+ pxLineFmt->reset( new XclImpChLineFormat );
+ (*pxLineFmt)->ReadChLineFormat( rStrm );
+ }
+ else if( bWallFrame && mxWallFrame )
+ {
+ mxWallFrame->ReadSubRecord( rStrm );
+ }
+ }
+ }
+}
+
+void XclImpChAxis::CreateWallFrame()
+{
+ switch( GetAxisType() )
+ {
+ case EXC_CHAXIS_X:
+ mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_WALL3D ) );
+ break;
+ case EXC_CHAXIS_Y:
+ mxWallFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_FLOOR3D ) );
+ break;
+ default:
+ mxWallFrame.reset();
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChAxesSet::XclImpChAxesSet( const XclImpChRoot& rRoot, sal_uInt16 nAxesSetId ) :
+ XclImpChRoot( rRoot )
+{
+ maData.mnAxesSetId = nAxesSetId;
+}
+
+void XclImpChAxesSet::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnAxesSetId >> maData.maRect;
+}
+
+void XclImpChAxesSet::ReadSubRecord( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_CHFRAMEPOS:
+ mxFramePos.reset( new XclImpChFramePos );
+ mxFramePos->ReadChFramePos( rStrm );
+ break;
+ case EXC_ID_CHAXIS:
+ ReadChAxis( rStrm );
+ break;
+ case EXC_ID_CHTEXT:
+ ReadChText( rStrm );
+ break;
+ case EXC_ID_CHPLOTFRAME:
+ ReadChPlotFrame( rStrm );
+ break;
+ case EXC_ID_CHTYPEGROUP:
+ ReadChTypeGroup( rStrm );
+ break;
+ }
+}
+
+void XclImpChAxesSet::Finalize()
+{
+ if( IsValidAxesSet() )
+ {
+ // finalize chart type groups, erase empty groups without series
+ XclImpChTypeGroupMap aValidGroups;
+ for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt )
+ {
+ XclImpChTypeGroupRef xTypeGroup = aIt->second;
+ xTypeGroup->Finalize();
+ if( xTypeGroup->IsValidGroup() )
+ aValidGroups.insert(
+ XclImpChTypeGroupMap::value_type(aIt->first, xTypeGroup));
+ }
+ maTypeGroups.swap( aValidGroups );
+ }
+
+ // invalid chart type groups are deleted now, check again with IsValidAxesSet()
+ if( IsValidAxesSet() )
+ {
+ // always create missing axis objects
+ if( !mxXAxis )
+ mxXAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_X ) );
+ if( !mxYAxis )
+ mxYAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Y ) );
+ if( !mxZAxis && GetFirstTypeGroup()->Is3dDeepChart() )
+ mxZAxis.reset( new XclImpChAxis( GetChRoot(), EXC_CHAXIS_Z ) );
+
+ // finalize axes
+ if( mxXAxis ) mxXAxis->Finalize();
+ if( mxYAxis ) mxYAxis->Finalize();
+ if( mxZAxis ) mxZAxis->Finalize();
+
+ // finalize axis titles
+ const XclImpChText* pDefText = GetChartData().GetDefaultText( EXC_CHTEXTTYPE_AXISTITLE );
+ String aAutoTitle = CREATE_STRING( "Axis Title" );
+ lclFinalizeTitle( mxXAxisTitle, pDefText, aAutoTitle );
+ lclFinalizeTitle( mxYAxisTitle, pDefText, aAutoTitle );
+ lclFinalizeTitle( mxZAxisTitle, pDefText, aAutoTitle );
+
+ // #i47745# missing plot frame -> invisible border and area
+ if( !mxPlotFrame )
+ mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) );
+ }
+}
+
+XclImpChTypeGroupRef XclImpChAxesSet::GetTypeGroup( sal_uInt16 nGroupIdx ) const
+{
+ XclImpChTypeGroupMap::const_iterator itr = maTypeGroups.find(nGroupIdx);
+ return itr == maTypeGroups.end() ? XclImpChTypeGroupRef() : itr->second;
+}
+
+XclImpChTypeGroupRef XclImpChAxesSet::GetFirstTypeGroup() const
+{
+ XclImpChTypeGroupRef xTypeGroup;
+ if( !maTypeGroups.empty() )
+ xTypeGroup = maTypeGroups.begin()->second;
+ return xTypeGroup;
+}
+
+XclImpChLegendRef XclImpChAxesSet::GetLegend() const
+{
+ XclImpChLegendRef xLegend;
+ for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); !xLegend && (aIt != aEnd); ++aIt )
+ xLegend = aIt->second->GetLegend();
+ return xLegend;
+}
+
+const String& XclImpChAxesSet::GetSingleSeriesTitle() const
+{
+ return (maTypeGroups.size() == 1) ? maTypeGroups.begin()->second->GetSingleSeriesTitle() : String::EmptyString();
+}
+
+void XclImpChAxesSet::Convert( Reference< XDiagram > xDiagram ) const
+{
+ if( IsValidAxesSet() && xDiagram.is() )
+ {
+ // diagram background formatting
+ if( GetAxesSetId() == EXC_CHAXESSET_PRIMARY )
+ ConvertBackground( xDiagram );
+
+ // create the coordinate system, this inserts all chart types and series
+ Reference< XCoordinateSystem > xCoordSystem = CreateCoordSystem( xDiagram );
+ if( xCoordSystem.is() )
+ {
+ // insert coordinate system, if not already done
+ try
+ {
+ Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY_THROW );
+ Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
+ if( aCoordSystems.getLength() == 0 )
+ xCoordSystemCont->addCoordinateSystem( xCoordSystem );
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "XclImpChAxesSet::Convert - cannot insert coordinate system" );
+ }
+
+ // create the axes with grids and axis titles and insert them into the diagram
+ ConvertAxis( mxXAxis, mxXAxisTitle, xCoordSystem, mxYAxis.get() );
+ ConvertAxis( mxYAxis, mxYAxisTitle, xCoordSystem, mxXAxis.get() );
+ ConvertAxis( mxZAxis, mxZAxisTitle, xCoordSystem, 0 );
+ }
+ }
+}
+
+void XclImpChAxesSet::ConvertTitlePositions() const
+{
+ if( mxXAxisTitle )
+ mxXAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_X ) );
+ if( mxYAxisTitle )
+ mxYAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_Y ) );
+ if( mxZAxisTitle )
+ mxZAxisTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, maData.mnAxesSetId, EXC_CHAXIS_Z ) );
+}
+
+void XclImpChAxesSet::ReadChAxis( XclImpStream& rStrm )
+{
+ XclImpChAxisRef xAxis( new XclImpChAxis( GetChRoot() ) );
+ xAxis->ReadRecordGroup( rStrm );
+
+ switch( xAxis->GetAxisType() )
+ {
+ case EXC_CHAXIS_X: mxXAxis = xAxis; break;
+ case EXC_CHAXIS_Y: mxYAxis = xAxis; break;
+ case EXC_CHAXIS_Z: mxZAxis = xAxis; break;
+ }
+}
+
+void XclImpChAxesSet::ReadChText( XclImpStream& rStrm )
+{
+ XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
+ xText->ReadRecordGroup( rStrm );
+
+ switch( xText->GetLinkTarget() )
+ {
+ case EXC_CHOBJLINK_XAXIS: mxXAxisTitle = xText; break;
+ case EXC_CHOBJLINK_YAXIS: mxYAxisTitle = xText; break;
+ case EXC_CHOBJLINK_ZAXIS: mxZAxisTitle = xText; break;
+ }
+}
+
+void XclImpChAxesSet::ReadChPlotFrame( XclImpStream& rStrm )
+{
+ if( (rStrm.GetNextRecId() == EXC_ID_CHFRAME) && rStrm.StartNextRecord() )
+ {
+ mxPlotFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_PLOTFRAME ) );
+ mxPlotFrame->ReadRecordGroup( rStrm );
+ }
+}
+
+void XclImpChAxesSet::ReadChTypeGroup( XclImpStream& rStrm )
+{
+ XclImpChTypeGroupRef xTypeGroup( new XclImpChTypeGroup( GetChRoot() ) );
+ xTypeGroup->ReadRecordGroup( rStrm );
+ sal_uInt16 nGroupIdx = xTypeGroup->GetGroupIdx();
+ XclImpChTypeGroupMap::iterator itr = maTypeGroups.lower_bound(nGroupIdx);
+ if (itr != maTypeGroups.end() && !maTypeGroups.key_comp()(nGroupIdx, itr->first))
+ // Overwrite the existing element.
+ itr->second = xTypeGroup;
+ else
+ maTypeGroups.insert(
+ itr, XclImpChTypeGroupMap::value_type(nGroupIdx, xTypeGroup));
+}
+
+Reference< XCoordinateSystem > XclImpChAxesSet::CreateCoordSystem( Reference< XDiagram > xDiagram ) const
+{
+ Reference< XCoordinateSystem > xCoordSystem;
+
+ /* Try to get existing ccordinate system. For now, all series from primary
+ and secondary axes sets are inserted into one coordinate system. Later,
+ this should be changed to use one coordinate system for each axes set. */
+ Reference< XCoordinateSystemContainer > xCoordSystemCont( xDiagram, UNO_QUERY );
+ if( xCoordSystemCont.is() )
+ {
+ Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
+ DBG_ASSERT( aCoordSystems.getLength() <= 1, "XclImpChAxesSet::CreateCoordSystem - too many existing coordinate systems" );
+ if( aCoordSystems.getLength() > 0 )
+ xCoordSystem = aCoordSystems[ 0 ];
+ }
+
+ // create the coordinate system according to the first chart type
+ if( !xCoordSystem.is() )
+ {
+ XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
+ if( xTypeGroup )
+ {
+ xCoordSystem = xTypeGroup->CreateCoordSystem();
+ // convert 3d chart settings
+ ScfPropertySet aDiaProp( xDiagram );
+ xTypeGroup->ConvertChart3d( aDiaProp );
+ }
+ }
+
+ /* Create XChartType objects for all chart type groups. Each group will
+ add its series to the data provider attached to the chart document. */
+ Reference< XChartTypeContainer > xChartTypeCont( xCoordSystem, UNO_QUERY );
+ if( xChartTypeCont.is() )
+ {
+ sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
+ for( XclImpChTypeGroupMap::const_iterator aIt = maTypeGroups.begin(), aEnd = maTypeGroups.end(); aIt != aEnd; ++aIt )
+ {
+ try
+ {
+ Reference< XChartType > xChartType = aIt->second->CreateChartType( xDiagram, nApiAxesSetIdx );
+ if( xChartType.is() )
+ xChartTypeCont->addChartType( xChartType );
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "XclImpChAxesSet::CreateCoordSystem - cannot add chart type" );
+ }
+ }
+ }
+
+ return xCoordSystem;
+}
+
+void XclImpChAxesSet::ConvertAxis(
+ XclImpChAxisRef xChAxis, XclImpChTextRef xChAxisTitle,
+ Reference< XCoordinateSystem > xCoordSystem, const XclImpChAxis* pCrossingAxis ) const
+{
+ if( xChAxis )
+ {
+ // create and attach the axis object
+ Reference< XAxis > xAxis = CreateAxis( *xChAxis, pCrossingAxis );
+ if( xAxis.is() )
+ {
+ // create and attach the axis title
+ if( xChAxisTitle ) try
+ {
+ Reference< XTitled > xTitled( xAxis, UNO_QUERY_THROW );
+ Reference< XTitle > xTitle( xChAxisTitle->CreateTitle(), UNO_SET_THROW );
+ xTitled->setTitleObject( xTitle );
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "XclImpChAxesSet::ConvertAxis - cannot set axis title" );
+ }
+
+ // insert axis into coordinate system
+ try
+ {
+ sal_Int32 nApiAxisDim = xChAxis->GetApiAxisDimension();
+ sal_Int32 nApiAxesSetIdx = GetApiAxesSetIndex();
+ xCoordSystem->setAxisByDimension( nApiAxisDim, xAxis, nApiAxesSetIdx );
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "XclImpChAxesSet::ConvertAxis - cannot set axis" );
+ }
+ }
+ }
+}
+
+Reference< XAxis > XclImpChAxesSet::CreateAxis( const XclImpChAxis& rChAxis, const XclImpChAxis* pCrossingAxis ) const
+{
+ Reference< XAxis > xAxis;
+ if( const XclImpChTypeGroup* pTypeGroup = GetFirstTypeGroup().get() )
+ xAxis = rChAxis.CreateAxis( *pTypeGroup, pCrossingAxis );
+ return xAxis;
+}
+
+void XclImpChAxesSet::ConvertBackground( Reference< XDiagram > xDiagram ) const
+{
+ XclImpChTypeGroupRef xTypeGroup = GetFirstTypeGroup();
+ if( xTypeGroup && xTypeGroup->Is3dWallChart() )
+ {
+ // wall/floor formatting (3D charts)
+ if( mxXAxis )
+ {
+ ScfPropertySet aWallProp( xDiagram->getWall() );
+ mxXAxis->ConvertWall( aWallProp );
+ }
+ if( mxYAxis )
+ {
+ ScfPropertySet aFloorProp( xDiagram->getFloor() );
+ mxYAxis->ConvertWall( aFloorProp );
+ }
+ }
+ else if( mxPlotFrame )
+ {
+ // diagram background formatting
+ ScfPropertySet aWallProp( xDiagram->getWall() );
+ mxPlotFrame->Convert( aWallProp );
+ }
+}
+
+// The chart object ===========================================================
+
+XclImpChChart::XclImpChChart( const XclImpRoot& rRoot ) :
+ XclImpChRoot( rRoot, *this )
+{
+ mxPrimAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_PRIMARY ) );
+ mxSecnAxesSet.reset( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_SECONDARY ) );
+}
+
+XclImpChChart::~XclImpChChart()
+{
+}
+
+void XclImpChChart::ReadHeaderRecord( XclImpStream& rStrm )
+{
+ // coordinates are stored as 16.16 fixed point
+ rStrm >> maRect;
+}
+
+void XclImpChChart::ReadSubRecord( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_CHFRAME:
+ mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
+ mxFrame->ReadRecordGroup( rStrm );
+ break;
+ case EXC_ID_CHSERIES:
+ ReadChSeries( rStrm );
+ break;
+ case EXC_ID_CHPROPERTIES:
+ ReadChProperties( rStrm );
+ break;
+ case EXC_ID_CHDEFAULTTEXT:
+ ReadChDefaultText( rStrm );
+ break;
+ case EXC_ID_CHAXESSET:
+ ReadChAxesSet( rStrm );
+ break;
+ case EXC_ID_CHTEXT:
+ ReadChText( rStrm );
+ break;
+ case EXC_ID_CHEND:
+ Finalize(); // finalize the entire chart object
+ break;
+ }
+}
+
+void XclImpChChart::ReadChDefaultText( XclImpStream& rStrm )
+{
+ sal_uInt16 nTextId = rStrm.ReaduInt16();
+ if( (rStrm.GetNextRecId() == EXC_ID_CHTEXT) && rStrm.StartNextRecord() )
+ {
+ auto_ptr<XclImpChText> pText(new XclImpChText(GetChRoot()));
+ pText->ReadRecordGroup(rStrm);
+ maDefTexts.insert(nTextId, pText);
+ }
+}
+
+void XclImpChChart::ReadChDataFormat( XclImpStream& rStrm )
+{
+ XclImpChDataFormatRef xDataFmt( new XclImpChDataFormat( GetChRoot() ) );
+ xDataFmt->ReadRecordGroup( rStrm );
+ if( xDataFmt->GetPointPos().mnSeriesIdx <= EXC_CHSERIES_MAXSERIES )
+ {
+ const XclChDataPointPos& rPos = xDataFmt->GetPointPos();
+ XclImpChDataFormatMap::iterator itr = maDataFmts.lower_bound(rPos);
+ if (itr == maDataFmts.end() || maDataFmts.key_comp()(rPos, itr->first))
+ // No element exists for this data point. Insert it.
+ maDataFmts.insert(
+ itr, XclImpChDataFormatMap::value_type(rPos, xDataFmt));
+
+ /* Do not overwrite existing data format group, Excel always uses the
+ first data format group occuring in any CHSERIES group. */
+ }
+}
+
+void XclImpChChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
+{
+ if( !mxFrame )
+ mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
+ mxFrame->UpdateObjFrame( rLineData, rFillData );
+}
+
+XclImpChTypeGroupRef XclImpChChart::GetTypeGroup( sal_uInt16 nGroupIdx ) const
+{
+ XclImpChTypeGroupRef xTypeGroup = mxPrimAxesSet->GetTypeGroup( nGroupIdx );
+ if( !xTypeGroup ) xTypeGroup = mxSecnAxesSet->GetTypeGroup( nGroupIdx );
+ if( !xTypeGroup ) xTypeGroup = mxPrimAxesSet->GetFirstTypeGroup();
+ return xTypeGroup;
+}
+
+const XclImpChText* XclImpChChart::GetDefaultText( XclChTextType eTextType ) const
+{
+ sal_uInt16 nDefTextId = EXC_CHDEFTEXT_GLOBAL;
+ bool bBiff8 = GetBiff() == EXC_BIFF8;
+ switch( eTextType )
+ {
+ case EXC_CHTEXTTYPE_TITLE: nDefTextId = EXC_CHDEFTEXT_GLOBAL; break;
+ case EXC_CHTEXTTYPE_LEGEND: nDefTextId = EXC_CHDEFTEXT_GLOBAL; break;
+ case EXC_CHTEXTTYPE_AXISTITLE: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
+ case EXC_CHTEXTTYPE_AXISLABEL: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
+ case EXC_CHTEXTTYPE_DATALABEL: nDefTextId = bBiff8 ? EXC_CHDEFTEXT_AXESSET : EXC_CHDEFTEXT_GLOBAL; break;
+ }
+
+ XclImpChTextMap::const_iterator itr = maDefTexts.find(nDefTextId);
+ return itr == maDefTexts.end() ? NULL : itr->second;
+}
+
+bool XclImpChChart::IsManualPlotArea() const
+{
+ // there is no real automatic mode in BIFF5 charts
+ return (GetBiff() <= EXC_BIFF5) || ::get_flag( maProps.mnFlags, EXC_CHPROPS_USEMANPLOTAREA );
+}
+
+void XclImpChChart::Convert( Reference< XChartDocument > xChartDoc,
+ XclImpDffConverter& rDffConv, const OUString& rObjName, const Rectangle& rChartRect ) const
+{
+ // initialize conversion (locks the model to suppress any internal updates)
+ InitConversion( xChartDoc, rChartRect );
+
+ // chart frame formatting
+ if( mxFrame )
+ {
+ ScfPropertySet aFrameProp( xChartDoc->getPageBackground() );
+ mxFrame->Convert( aFrameProp );
+ }
+
+ // chart title
+ if( mxTitle ) try
+ {
+ Reference< XTitled > xTitled( xChartDoc, UNO_QUERY_THROW );
+ Reference< XTitle > xTitle( mxTitle->CreateTitle(), UNO_SET_THROW );
+ xTitled->setTitleObject( xTitle );
+ }
+ catch( Exception& )
+ {
+ }
+
+ /* Create the diagram object and attach it to the chart document. Currently,
+ one diagram is used to carry all coordinate systems and data series. */
+ Reference< XDiagram > xDiagram = CreateDiagram();
+ xChartDoc->setFirstDiagram( xDiagram );
+
+ // coordinate systems and chart types, convert axis settings
+ mxPrimAxesSet->Convert( xDiagram );
+ mxSecnAxesSet->Convert( xDiagram );
+
+ // legend
+ if( xDiagram.is() && mxLegend )
+ xDiagram->setLegend( mxLegend->CreateLegend() );
+
+ /* Following all conversions needing the old Chart1 API that involves full
+ initialization of the chart view. */
+ Reference< cssc::XChartDocument > xChart1Doc( xChartDoc, UNO_QUERY );
+ if( xChart1Doc.is() )
+ {
+ Reference< cssc::XDiagram > xDiagram1 = xChart1Doc->getDiagram();
+
+ /* Set the 'IncludeHiddenCells' property via the old API as only this
+ ensures that the data provider and all created sequences get this
+ flag correctly. */
+ ScfPropertySet aDiaProp( xDiagram1 );
+ bool bShowVisCells = ::get_flag( maProps.mnFlags, EXC_CHPROPS_SHOWVISIBLEONLY );
+ aDiaProp.SetBoolProperty( EXC_CHPROP_INCLUDEHIDDENCELLS, !bShowVisCells );
+
+ // plot area position and size (there is no real automatic mode in BIFF5 charts)
+ XclImpChFramePosRef xPlotAreaPos = mxPrimAxesSet->GetPlotAreaFramePos();
+ if( IsManualPlotArea() && xPlotAreaPos ) try
+ {
+ const XclChFramePos& rFramePos = xPlotAreaPos->GetFramePosData();
+ if( (rFramePos.mnTLMode == EXC_CHFRAMEPOS_PARENT) && (rFramePos.mnBRMode == EXC_CHFRAMEPOS_PARENT) )
+ {
+ Reference< cssc::XDiagramPositioning > xPositioning( xDiagram1, UNO_QUERY_THROW );
+ ::com::sun::star::awt::Rectangle aDiagramRect = CalcHmmFromChartRect( rFramePos.maRect );
+ // for pie charts, always set inner plot area size to exclude the data labels as Excel does
+ const XclImpChTypeGroup* pFirstTypeGroup = mxPrimAxesSet->GetFirstTypeGroup().get();
+ if( pFirstTypeGroup && (pFirstTypeGroup->GetTypeInfo().meTypeCateg == EXC_CHTYPECATEG_PIE) )
+ xPositioning->setDiagramPositionExcludingAxes( aDiagramRect );
+ else if( pFirstTypeGroup && pFirstTypeGroup->Is3dChart() )
+ xPositioning->setDiagramPositionIncludingAxesAndAxisTitles( aDiagramRect );
+ else
+ xPositioning->setDiagramPositionIncludingAxes( aDiagramRect );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+
+ // positions of all title objects
+ if( mxTitle )
+ mxTitle->ConvertTitlePosition( XclChTextKey( EXC_CHTEXTTYPE_TITLE ) );
+ mxPrimAxesSet->ConvertTitlePositions();
+ mxSecnAxesSet->ConvertTitlePositions();
+ }
+
+ // unlock the model
+ FinishConversion( rDffConv );
+
+ // start listening to this chart
+ ScDocument& rDoc = GetRoot().GetDoc();
+ if( ScChartListenerCollection* pChartCollection = rDoc.GetChartListenerCollection() )
+ {
+ ::std::auto_ptr< ::std::vector< ScTokenRef > > xRefTokens( new ::std::vector< ScTokenRef > );
+ for( XclImpChSeriesVec::const_iterator aIt = maSeries.begin(), aEnd = maSeries.end(); aIt != aEnd; ++aIt )
+ (*aIt)->FillAllSourceLinks( *xRefTokens );
+ if( !xRefTokens->empty() )
+ {
+ ::std::auto_ptr< ScChartListener > xListener( new ScChartListener( rObjName, &rDoc, xRefTokens.release() ) );
+ xListener->SetUsed( true );
+ xListener->StartListeningTo();
+ pChartCollection->Insert( xListener.release() );
+ }
+ }
+}
+
+void XclImpChChart::ReadChSeries( XclImpStream& rStrm )
+{
+ sal_uInt16 nNewSeriesIdx = static_cast< sal_uInt16 >( maSeries.size() );
+ XclImpChSeriesRef xSeries( new XclImpChSeries( GetChRoot(), nNewSeriesIdx ) );
+ xSeries->ReadRecordGroup( rStrm );
+ maSeries.push_back( xSeries );
+}
+
+void XclImpChChart::ReadChProperties( XclImpStream& rStrm )
+{
+ rStrm >> maProps.mnFlags >> maProps.mnEmptyMode;
+}
+
+void XclImpChChart::ReadChAxesSet( XclImpStream& rStrm )
+{
+ XclImpChAxesSetRef xAxesSet( new XclImpChAxesSet( GetChRoot(), EXC_CHAXESSET_NONE ) );
+ xAxesSet->ReadRecordGroup( rStrm );
+ switch( xAxesSet->GetAxesSetId() )
+ {
+ case EXC_CHAXESSET_PRIMARY: mxPrimAxesSet = xAxesSet; break;
+ case EXC_CHAXESSET_SECONDARY: mxSecnAxesSet = xAxesSet; break;
+ }
+}
+
+void XclImpChChart::ReadChText( XclImpStream& rStrm )
+{
+ XclImpChTextRef xText( new XclImpChText( GetChRoot() ) );
+ xText->ReadRecordGroup( rStrm );
+ switch( xText->GetLinkTarget() )
+ {
+ case EXC_CHOBJLINK_TITLE:
+ mxTitle = xText;
+ break;
+ case EXC_CHOBJLINK_DATA:
+ {
+ sal_uInt16 nSeriesIdx = xText->GetPointPos().mnSeriesIdx;
+ if( nSeriesIdx < maSeries.size() )
+ maSeries[ nSeriesIdx ]->SetDataLabel( xText );
+ }
+ break;
+ }
+}
+
+void XclImpChChart::Finalize()
+{
+ // finalize series (must be done first)
+ FinalizeSeries();
+ // #i49218# legend may be attached to primary or secondary axes set
+ mxLegend = mxPrimAxesSet->GetLegend();
+ if( !mxLegend )
+ mxLegend = mxSecnAxesSet->GetLegend();
+ if( mxLegend )
+ mxLegend->Finalize();
+ // axes sets, updates chart type group default formats -> must be called before FinalizeDataFormats()
+ mxPrimAxesSet->Finalize();
+ mxSecnAxesSet->Finalize();
+ // formatting of all series
+ FinalizeDataFormats();
+ // #i47745# missing frame -> invisible border and area
+ if( !mxFrame )
+ mxFrame.reset( new XclImpChFrame( GetChRoot(), EXC_CHOBJTYPE_BACKGROUND ) );
+ // chart title
+ FinalizeTitle();
+}
+
+void XclImpChChart::FinalizeSeries()
+{
+ for( XclImpChSeriesVec::iterator aSIt = maSeries.begin(), aSEnd = maSeries.end(); aSIt != aSEnd; ++aSIt )
+ {
+ XclImpChSeriesRef xSeries = *aSIt;
+ if( xSeries->HasParentSeries() )
+ {
+ /* Process child series (trend lines and error bars). Data of
+ child series will be set at the connected parent series. */
+ if( xSeries->GetParentIdx() < maSeries.size() )
+ maSeries[ xSeries->GetParentIdx() ]->AddChildSeries( *xSeries );
+ }
+ else
+ {
+ // insert the series into the related chart type group
+ if( XclImpChTypeGroup* pTypeGroup = GetTypeGroup( xSeries->GetGroupIdx() ).get() )
+ pTypeGroup->AddSeries( xSeries );
+ }
+ }
+}
+
+void XclImpChChart::FinalizeDataFormats()
+{
+ /* #i51639# (part 1): CHDATAFORMAT groups are part of CHSERIES groups.
+ Each CHDATAFORMAT group specifies the series and data point it is
+ assigned to. This makes it possible to have a data format that is
+ related to another series, e.g. a CHDATAFORMAT group for series 2 is
+ part of a CHSERIES group that describes series 1. Therefore the chart
+ itself has collected all CHDATAFORMAT groups to be able to store data
+ format groups for series that have not been imported at that time. This
+ loop finally assigns these groups to the related series. */
+ for( XclImpChDataFormatMap::const_iterator aMIt = maDataFmts.begin(), aMEnd = maDataFmts.end(); aMIt != aMEnd; ++aMIt )
+ {
+ sal_uInt16 nSeriesIdx = aMIt->first.mnSeriesIdx;
+ if( nSeriesIdx < maSeries.size() )
+ maSeries[ nSeriesIdx ]->SetDataFormat( aMIt->second );
+ }
+
+ /* #i51639# (part 2): Finalize data formats of all series. This adds for
+ example missing CHDATAFORMAT groups for entire series that are needed
+ for automatic colors of lines and areas. */
+ for( XclImpChSeriesVec::iterator aVIt = maSeries.begin(), aVEnd = maSeries.end(); aVIt != aVEnd; ++aVIt )
+ (*aVIt)->FinalizeDataFormats();
+}
+
+void XclImpChChart::FinalizeTitle()
+{
+ // special handling for auto-generated title
+ String aAutoTitle;
+ if( !mxTitle || (!mxTitle->IsDeleted() && !mxTitle->HasString()) )
+ {
+ // automatic title from first series name (if there are no series on secondary axes set)
+ if( !mxSecnAxesSet->IsValidAxesSet() )
+ aAutoTitle = mxPrimAxesSet->GetSingleSeriesTitle();
+ if( mxTitle || (aAutoTitle.Len() > 0) )
+ {
+ if( !mxTitle )
+ mxTitle.reset( new XclImpChText( GetChRoot() ) );
+ if( aAutoTitle.Len() == 0 )
+ aAutoTitle = CREATE_STRING( "Chart Title" );
+ }
+ }
+
+ // will reset mxTitle, if it does not contain a string and no auto title exists
+ lclFinalizeTitle( mxTitle, GetDefaultText( EXC_CHTEXTTYPE_TITLE ), aAutoTitle );
+}
+
+Reference< XDiagram > XclImpChChart::CreateDiagram() const
+{
+ // create a diagram object
+ Reference< XDiagram > xDiagram( ScfApiHelper::CreateInstance( SERVICE_CHART2_DIAGRAM ), UNO_QUERY );
+
+ // convert global chart settings
+ ScfPropertySet aDiaProp( xDiagram );
+
+ // treatment of missing values
+ using namespace cssc::MissingValueTreatment;
+ sal_Int32 nMissingValues = LEAVE_GAP;
+ switch( maProps.mnEmptyMode )
+ {
+ case EXC_CHPROPS_EMPTY_SKIP: nMissingValues = LEAVE_GAP; break;
+ case EXC_CHPROPS_EMPTY_ZERO: nMissingValues = USE_ZERO; break;
+ case EXC_CHPROPS_EMPTY_INTERPOLATE: nMissingValues = CONTINUE; break;
+ }
+ aDiaProp.SetProperty( EXC_CHPROP_MISSINGVALUETREATMENT, nMissingValues );
+
+ return xDiagram;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChartDrawing::XclImpChartDrawing( const XclImpRoot& rRoot, bool bOwnTab ) :
+ XclImpDrawing( rRoot, bOwnTab ), // sheet charts may contain OLE objects
+ mnScTab( rRoot.GetCurrScTab() ),
+ mbOwnTab( bOwnTab )
+{
+}
+
+void XclImpChartDrawing::ConvertObjects( XclImpDffConverter& rDffConv,
+ const Reference< XModel >& rxModel, const Rectangle& rChartRect )
+{
+ maChartRect = rChartRect; // needed in CalcAnchorRect() callback
+
+ SdrModel* pSdrModel = 0;
+ SdrPage* pSdrPage = 0;
+ if( mbOwnTab )
+ {
+ // chart sheet: insert all shapes into the sheet, not into the chart object
+ pSdrModel = GetDoc().GetDrawLayer();
+ pSdrPage = GetSdrPage( mnScTab );
+ }
+ else
+ {
+ // embedded chart object: insert all shapes into the chart
+ try
+ {
+ Reference< XDrawPageSupplier > xDrawPageSupp( rxModel, UNO_QUERY_THROW );
+ Reference< XDrawPage > xDrawPage( xDrawPageSupp->getDrawPage(), UNO_SET_THROW );
+ pSdrPage = ::GetSdrPageFromXDrawPage( xDrawPage );
+ pSdrModel = pSdrPage ? pSdrPage->GetModel() : 0;
+ }
+ catch( Exception& )
+ {
+ }
+ }
+
+ if( pSdrModel && pSdrPage )
+ ImplConvertObjects( rDffConv, *pSdrModel, *pSdrPage );
+}
+
+Rectangle XclImpChartDrawing::CalcAnchorRect( const XclObjAnchor& rAnchor, bool bDffAnchor ) const
+{
+ /* In objects with DFF client anchor, the position of the shape is stored
+ in the cell address components of the client anchor. In old BIFF3-BIFF5
+ objects, the position is stored in the offset components of the anchor. */
+ Rectangle aRect(
+ static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maFirst.mnCol : rAnchor.mnLX ) / EXC_CHART_TOTALUNITS * maChartRect.GetWidth() + 0.5 ),
+ static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maFirst.mnRow : rAnchor.mnTY ) / EXC_CHART_TOTALUNITS * maChartRect.GetHeight() + 0.5 ),
+ static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maLast.mnCol : rAnchor.mnRX ) / EXC_CHART_TOTALUNITS * maChartRect.GetWidth() + 0.5 ),
+ static_cast< long >( static_cast< double >( bDffAnchor ? rAnchor.maLast.mnRow : rAnchor.mnBY ) / EXC_CHART_TOTALUNITS * maChartRect.GetHeight() + 0.5 ) );
+ aRect.Justify();
+ // move shapes into chart area for sheet charts
+ if( mbOwnTab )
+ aRect.Move( maChartRect.Left(), maChartRect.Top() );
+ return aRect;
+}
+
+void XclImpChartDrawing::OnObjectInserted( const XclImpDrawObjBase& )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChart::XclImpChart( const XclImpRoot& rRoot, bool bOwnTab ) :
+ XclImpRoot( rRoot ),
+ mbOwnTab( bOwnTab ),
+ mbIsPivotChart( false )
+{
+}
+
+XclImpChart::~XclImpChart()
+{
+}
+
+void XclImpChart::ReadChartSubStream( XclImpStream& rStrm )
+{
+ XclImpPageSettings& rPageSett = GetPageSettings();
+ XclImpTabViewSettings& rTabViewSett = GetTabViewSettings();
+
+ bool bLoop = true;
+ while( bLoop && rStrm.StartNextRecord() )
+ {
+ // page settings - only for charts in entire sheet
+ if( mbOwnTab ) switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_HORPAGEBREAKS:
+ case EXC_ID_VERPAGEBREAKS: rPageSett.ReadPageBreaks( rStrm ); break;
+ case EXC_ID_HEADER:
+ case EXC_ID_FOOTER: rPageSett.ReadHeaderFooter( rStrm ); break;
+ case EXC_ID_LEFTMARGIN:
+ case EXC_ID_RIGHTMARGIN:
+ case EXC_ID_TOPMARGIN:
+ case EXC_ID_BOTTOMMARGIN: rPageSett.ReadMargin( rStrm ); break;
+ case EXC_ID_PRINTHEADERS: rPageSett.ReadPrintHeaders( rStrm ); break;
+ case EXC_ID_PRINTGRIDLINES: rPageSett.ReadPrintGridLines( rStrm ); break;
+ case EXC_ID_HCENTER:
+ case EXC_ID_VCENTER: rPageSett.ReadCenter( rStrm ); break;
+ case EXC_ID_SETUP: rPageSett.ReadSetup( rStrm ); break;
+ case EXC_ID8_IMGDATA: rPageSett.ReadImgData( rStrm ); break;
+
+ case EXC_ID_WINDOW2: rTabViewSett.ReadWindow2( rStrm, true );break;
+ case EXC_ID_SCL: rTabViewSett.ReadScl( rStrm ); break;
+
+ case EXC_ID_SHEETEXT: //0x0862
+ {
+ // FIXME: do not need to pass palette, XclImpTabVieSettings is derived from root
+ XclImpPalette& rPal = GetPalette();
+ rTabViewSett.ReadTabBgColor( rStrm, rPal);
+ }
+ break;
+
+ case EXC_ID_CODENAME: ReadCodeName( rStrm, false ); break;
+ }
+
+ // common records
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_EOF: bLoop = false; break;
+
+ // #i31882# ignore embedded chart objects
+ case EXC_ID2_BOF:
+ case EXC_ID3_BOF:
+ case EXC_ID4_BOF:
+ case EXC_ID5_BOF: XclTools::SkipSubStream( rStrm ); break;
+
+ case EXC_ID_CHCHART: ReadChChart( rStrm ); break;
+
+ case EXC_ID8_CHPIVOTREF:
+ GetTracer().TracePivotChartExists();
+ mbIsPivotChart = true;
+ break;
+
+ // BIFF specific records
+ default: switch( GetBiff() )
+ {
+ case EXC_BIFF5: switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_OBJ: GetChartDrawing().ReadObj( rStrm ); break;
+ }
+ break;
+ case EXC_BIFF8: switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_MSODRAWING: GetChartDrawing().ReadMsoDrawing( rStrm ); break;
+ // #i61786# weird documents: OBJ without MSODRAWING -> read in BIFF5 format
+ case EXC_ID_OBJ: GetChartDrawing().ReadObj( rStrm ); break;
+ }
+ break;
+ default:;
+ }
+ }
+ }
+}
+
+void XclImpChart::UpdateObjFrame( const XclObjLineData& rLineData, const XclObjFillData& rFillData )
+{
+ if( !mxChartData )
+ mxChartData.reset( new XclImpChChart( GetRoot() ) );
+ mxChartData->UpdateObjFrame( rLineData, rFillData );
+}
+
+sal_Size XclImpChart::GetProgressSize() const
+{
+ return
+ (mxChartData ? mxChartData->GetProgressSize() : 0) +
+ (mxChartDrawing ? mxChartDrawing->GetProgressSize() : 0);
+}
+
+void XclImpChart::Convert( Reference< XModel > xModel, XclImpDffConverter& rDffConv, const OUString& rObjName, const Rectangle& rChartRect ) const
+{
+ Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY );
+ if( xChartDoc.is() )
+ {
+ if( mxChartData )
+ mxChartData->Convert( xChartDoc, rDffConv, rObjName, rChartRect );
+ if( mxChartDrawing )
+ mxChartDrawing->ConvertObjects( rDffConv, xModel, rChartRect );
+ }
+}
+
+XclImpChartDrawing& XclImpChart::GetChartDrawing()
+{
+ if( !mxChartDrawing )
+ mxChartDrawing.reset( new XclImpChartDrawing( GetRoot(), mbOwnTab ) );
+ return *mxChartDrawing;
+}
+
+void XclImpChart::ReadChChart( XclImpStream& rStrm )
+{
+ mxChartData.reset( new XclImpChChart( GetRoot() ) );
+ mxChartData->ReadRecordGroup( rStrm );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx
new file mode 100644
index 000000000000..07bfb4e239fa
--- /dev/null
+++ b/sc/source/filter/excel/xicontent.cxx
@@ -0,0 +1,1329 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xicontent.hxx"
+#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <tools/urlobj.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <svl/itemset.hxx>
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crsditem.hxx>
+#include "document.hxx"
+#include "editutil.hxx"
+#include "cell.hxx"
+#include "validat.hxx"
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "rangenam.hxx"
+#include "arealink.hxx"
+#include "stlsheet.hxx"
+#include "scextopt.hxx"
+#include "xlformula.hxx"
+#include "xltracer.hxx"
+#include "xistream.hxx"
+#include "xihelper.hxx"
+#include "xistyle.hxx"
+#include "xiescher.hxx"
+#include "xiname.hxx"
+
+#include "excform.hxx"
+#include "tabprotection.hxx"
+
+#include <memory>
+
+using ::com::sun::star::uno::Sequence;
+using ::std::auto_ptr;
+
+// Shared string table ========================================================
+
+XclImpSst::XclImpSst( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpSst::ReadSst( XclImpStream& rStrm )
+{
+ sal_uInt32 nStrCount;
+ rStrm.Ignore( 4 );
+ rStrm >> nStrCount;
+ maStrings.clear();
+ maStrings.reserve( static_cast< size_t >( nStrCount ) );
+ while( (nStrCount > 0) && rStrm.IsValid() )
+ {
+ XclImpString aString;
+ aString.Read( rStrm );
+ maStrings.push_back( aString );
+ --nStrCount;
+ }
+}
+
+const XclImpString* XclImpSst::GetString( sal_uInt32 nSstIndex ) const
+{
+ return (nSstIndex < maStrings.size()) ? &maStrings[ nSstIndex ] : 0;
+}
+
+ScBaseCell* XclImpSst::CreateCell( sal_uInt32 nSstIndex, sal_uInt16 nXFIndex ) const
+{
+ ScBaseCell* pCell = 0;
+ if( const XclImpString* pString = GetString( nSstIndex ) )
+ pCell = XclImpStringHelper::CreateCell( *this, *pString, nXFIndex );
+ return pCell;
+}
+
+// Hyperlinks =================================================================
+
+namespace {
+
+/** Reads character array and stores it into rString.
+ @param nChars Number of following characters (not byte count!).
+ @param b16Bit true = 16-bit characters, false = 8-bit characters. */
+void lclAppendString32( String& rString, XclImpStream& rStrm, sal_uInt32 nChars, bool b16Bit )
+{
+ sal_uInt16 nReadChars = ulimit_cast< sal_uInt16 >( nChars );
+ rString.Append( rStrm.ReadRawUniString( nReadChars, b16Bit ) );
+ // ignore remaining chars
+ sal_Size nIgnore = nChars - nReadChars;
+ if( b16Bit )
+ nIgnore *= 2;
+ rStrm.Ignore( nIgnore );
+}
+
+/** Reads 32-bit string length and the character array and stores it into rString.
+ @param b16Bit true = 16-bit characters, false = 8-bit characters. */
+void lclAppendString32( String& rString, XclImpStream& rStrm, bool b16Bit )
+{
+ lclAppendString32( rString, rStrm, rStrm.ReaduInt32(), b16Bit );
+}
+
+/** Reads 32-bit string length and ignores following character array.
+ @param b16Bit true = 16-bit characters, false = 8-bit characters. */
+void lclIgnoreString32( XclImpStream& rStrm, bool b16Bit )
+{
+ sal_uInt32 nChars;
+ rStrm >> nChars;
+ if( b16Bit )
+ nChars *= 2;
+ rStrm.Ignore( nChars );
+}
+
+/** Converts a path to an absolute path.
+ @param rPath The source path. The resulting path is returned here.
+ @param nLevel Number of parent directories to add in front of the path. */
+void lclGetAbsPath( String& rPath, sal_uInt16 nLevel, SfxObjectShell* pDocShell )
+{
+ String aTmpStr;
+ while( nLevel )
+ {
+ aTmpStr.AppendAscii( "../" );
+ --nLevel;
+ }
+ aTmpStr += rPath;
+
+ if( pDocShell )
+ {
+ bool bWasAbs = false;
+ rPath = pDocShell->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr, bWasAbs ).GetMainURL( INetURLObject::NO_DECODE );
+ // full path as stored in SvxURLField must be encoded
+ }
+ else
+ rPath = aTmpStr;
+}
+
+/** Inserts the URL into a text cell. Does not modify value or formula cells. */
+void lclInsertUrl( const XclImpRoot& rRoot, const String& rUrl, SCCOL nScCol, SCROW nScRow, SCTAB nScTab )
+{
+ ScDocument& rDoc = rRoot.GetDoc();
+ ScAddress aScPos( nScCol, nScRow, nScTab );
+ CellType eCellType = rDoc.GetCellType( aScPos );
+ switch( eCellType )
+ {
+ // #i54261# hyperlinks in string cells
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ {
+ String aDisplText;
+ rDoc.GetString( nScCol, nScRow, nScTab, aDisplText );
+ if( !aDisplText.Len() )
+ aDisplText = rUrl;
+
+ ScEditEngineDefaulter& rEE = rRoot.GetEditEngine();
+ SvxURLField aUrlField( rUrl, aDisplText, SVXURLFORMAT_APPDEFAULT );
+
+ const ScEditCell* pEditCell = (eCellType == CELLTYPE_EDIT) ? static_cast< const ScEditCell* >( rDoc.GetCell( aScPos ) ) : 0;
+ const EditTextObject* pEditObj = pEditCell ? pEditCell->GetData() : 0;
+ if( pEditObj )
+ {
+ rEE.SetText( *pEditObj );
+ rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0, 0, 0xFFFF, 0 ) );
+ }
+ else
+ {
+ rEE.SetText( EMPTY_STRING );
+ rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection() );
+ if( const ScPatternAttr* pPattern = rDoc.GetPattern( aScPos.Col(), aScPos.Row(), nScTab ) )
+ {
+ SfxItemSet aItemSet( rEE.GetEmptyItemSet() );
+ pPattern->FillEditItemSet( &aItemSet );
+ rEE.QuickSetAttribs( aItemSet, ESelection( 0, 0, 0xFFFF, 0 ) );
+ }
+ }
+ ::std::auto_ptr< EditTextObject > xTextObj( rEE.CreateTextObject() );
+
+ ScEditCell* pCell = new ScEditCell( xTextObj.get(), &rDoc, rEE.GetEditTextObjectPool() );
+ rDoc.PutCell( aScPos, pCell );
+ }
+ break;
+
+ default:;
+ }
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+void XclImpHyperlink::ReadHlink( XclImpStream& rStrm )
+{
+ XclRange aXclRange( ScAddress::UNINITIALIZED );
+ rStrm >> aXclRange;
+ // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
+ aXclRange.maFirst.mnCol &= 0xFF;
+ aXclRange.maLast.mnCol &= 0xFF;
+ String aString = ReadEmbeddedData( rStrm );
+ if ( aString.Len() > 0 )
+ rStrm.GetRoot().GetXFRangeBuffer().SetHyperlink( aXclRange, aString );
+}
+
+String XclImpHyperlink::ReadEmbeddedData( XclImpStream& rStrm )
+{
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ SfxObjectShell* pDocShell = rRoot.GetDocShell();
+
+ DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
+
+ sal_uInt32 nFlags;
+ XclGuid aGuid;
+ rStrm >> aGuid;
+ rStrm.Ignore( 4 );
+ rStrm >> nFlags;
+
+ DBG_ASSERT( aGuid == XclTools::maGuidStdLink, "XclImpHyperlink::ReadEmbeddedData - unknown header GUID" );
+
+ ::std::auto_ptr< String > xLongName; // link / file name
+ ::std::auto_ptr< String > xShortName; // 8.3-representation of file name
+ ::std::auto_ptr< String > xTextMark; // text mark
+
+ // description (ignore)
+ if( ::get_flag( nFlags, EXC_HLINK_DESCR ) )
+ lclIgnoreString32( rStrm, true );
+ // target frame (ignore) !! DESCR/FRAME - is this the right order? (never seen them together)
+ if( ::get_flag( nFlags, EXC_HLINK_FRAME ) )
+ lclIgnoreString32( rStrm, true );
+
+ // URL fields are zero-terminated - do not let the stream replace them
+ // in the lclAppendString32() with the '?' character.
+ rStrm.SetNulSubstChar( '\0' );
+
+ // UNC path
+ if( ::get_flag( nFlags, EXC_HLINK_UNC ) )
+ {
+ xLongName.reset( new String );
+ lclAppendString32( *xLongName, rStrm, true );
+ lclGetAbsPath( *xLongName, 0, pDocShell );
+ }
+ // file link or URL
+ else if( ::get_flag( nFlags, EXC_HLINK_BODY ) )
+ {
+ rStrm >> aGuid;
+
+ if( aGuid == XclTools::maGuidFileMoniker )
+ {
+ sal_uInt16 nLevel = 0; // counter for level to climb down in path
+ rStrm >> nLevel;
+ xShortName.reset( new String );
+ lclAppendString32( *xShortName, rStrm, false );
+ rStrm.Ignore( 24 );
+
+ sal_uInt32 nStrLen;
+ rStrm >> nStrLen;
+ if( nStrLen )
+ {
+ rStrm >> nStrLen;
+ nStrLen /= 2; // it's byte count here...
+ rStrm.Ignore( 2 );
+ xLongName.reset( new String );
+ lclAppendString32( *xLongName, rStrm, nStrLen, true );
+ lclGetAbsPath( *xLongName, nLevel, pDocShell );
+ }
+ else
+ lclGetAbsPath( *xShortName, nLevel, pDocShell );
+ }
+ else if( aGuid == XclTools::maGuidUrlMoniker )
+ {
+ sal_uInt32 nStrLen;
+ rStrm >> nStrLen;
+ nStrLen /= 2; // it's byte count here...
+ xLongName.reset( new String );
+ lclAppendString32( *xLongName, rStrm, nStrLen, true );
+ if( !::get_flag( nFlags, EXC_HLINK_ABS ) )
+ lclGetAbsPath( *xLongName, 0, pDocShell );
+ }
+ else
+ {
+ DBG_ERRORFILE( "XclImpHyperlink::ReadEmbeddedData - unknown content GUID" );
+ }
+ }
+
+ // text mark
+ if( ::get_flag( nFlags, EXC_HLINK_MARK ) )
+ {
+ xTextMark.reset( new String );
+ lclAppendString32( *xTextMark, rStrm, true );
+ }
+
+ rStrm.SetNulSubstChar(); // back to default
+
+ DBG_ASSERT( rStrm.GetRecLeft() == 0, "XclImpHyperlink::ReadEmbeddedData - record size mismatch" );
+
+ if( !xLongName.get() && xShortName.get() )
+ xLongName = xShortName;
+ else if( !xLongName.get() && xTextMark.get() )
+ xLongName.reset( new String );
+
+ if( xLongName.get() )
+ {
+ if( xTextMark.get() )
+ {
+ if( xLongName->Len() == 0 )
+ xTextMark->SearchAndReplaceAll( '!', '.' );
+ xLongName->Append( '#' );
+ xLongName->Append( *xTextMark );
+ }
+ return *xLongName;
+ }
+ return String::EmptyString();
+}
+
+void XclImpHyperlink::ConvertToValidTabName(String& rUrl)
+{
+ xub_StrLen n = rUrl.Len();
+ if (n < 4)
+ // Needs at least 4 characters.
+ return;
+
+ sal_Unicode c = rUrl.GetChar(0);
+ if (c != sal_Unicode('#'))
+ // the 1st character must be '#'.
+ return;
+
+ String aNewUrl(sal_Unicode('#')), aTabName;
+
+ bool bInQuote = false;
+ bool bQuoteTabName = false;
+ for (xub_StrLen i = 1; i < n; ++i)
+ {
+ c = rUrl.GetChar(i);
+ if (c == sal_Unicode('\''))
+ {
+ if (bInQuote && i+1 < n && rUrl.GetChar(i+1) == sal_Unicode('\''))
+ {
+ // Two consecutive single quotes ('') signify a single literal
+ // quite. When this occurs, the whole table name needs to be
+ // quoted.
+ bQuoteTabName = true;
+ aTabName.Append(c);
+ aTabName.Append(c);
+ ++i;
+ continue;
+ }
+
+ bInQuote = !bInQuote;
+ if (!bInQuote && aTabName.Len() > 0)
+ {
+ if (bQuoteTabName)
+ aNewUrl.Append(sal_Unicode('\''));
+ aNewUrl.Append(aTabName);
+ if (bQuoteTabName)
+ aNewUrl.Append(sal_Unicode('\''));
+ }
+ }
+ else if (bInQuote)
+ aTabName.Append(c);
+ else
+ aNewUrl.Append(c);
+ }
+
+ if (bInQuote)
+ // It should be outside the quotes!
+ return;
+
+ // All is good. Pass the new URL.
+ rUrl = aNewUrl;
+}
+
+void XclImpHyperlink::InsertUrl( const XclImpRoot& rRoot, const XclRange& rXclRange, const String& rUrl )
+{
+ String aUrl(rUrl);
+ ConvertToValidTabName(aUrl);
+
+ SCTAB nScTab = rRoot.GetCurrScTab();
+ ScRange aScRange( ScAddress::UNINITIALIZED );
+ if( rRoot.GetAddressConverter().ConvertRange( aScRange, rXclRange, nScTab, nScTab, true ) )
+ {
+ SCCOL nScCol1, nScCol2;
+ SCROW nScRow1, nScRow2;
+ aScRange.GetVars( nScCol1, nScRow1, nScTab, nScCol2, nScRow2, nScTab );
+ for( SCCOL nScCol = nScCol1; nScCol <= nScCol2; ++nScCol )
+ for( SCROW nScRow = nScRow1; nScRow <= nScRow2; ++nScRow )
+ lclInsertUrl( rRoot, aUrl, nScCol, nScRow, nScTab );
+ }
+}
+
+// Label ranges ===============================================================
+
+void XclImpLabelranges::ReadLabelranges( XclImpStream& rStrm )
+{
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
+
+ ScDocument& rDoc = rRoot.GetDoc();
+ SCTAB nScTab = rRoot.GetCurrScTab();
+ XclImpAddressConverter& rAddrConv = rRoot.GetAddressConverter();
+ ScRangePairListRef xLabelRangesRef;
+ const ScRange* pScRange = 0;
+
+ XclRangeList aRowXclRanges, aColXclRanges;
+ rStrm >> aRowXclRanges >> aColXclRanges;
+
+ // row label ranges
+ ScRangeList aRowScRanges;
+ rAddrConv.ConvertRangeList( aRowScRanges, aRowXclRanges, nScTab, false );
+ xLabelRangesRef = rDoc.GetRowNameRangesRef();
+ for ( size_t i = 0, nRanges = aRowScRanges.size(); i < nRanges; ++i )
+ {
+ pScRange = aRowScRanges[ i ];
+ ScRange aDataRange( *pScRange );
+ if( aDataRange.aEnd.Col() < MAXCOL )
+ {
+ aDataRange.aStart.SetCol( aDataRange.aEnd.Col() + 1 );
+ aDataRange.aEnd.SetCol( MAXCOL );
+ }
+ else if( aDataRange.aStart.Col() > 0 )
+ {
+ aDataRange.aEnd.SetCol( aDataRange.aStart.Col() - 1 );
+ aDataRange.aStart.SetCol( 0 );
+ }
+ xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
+ }
+
+ // column label ranges
+ ScRangeList aColScRanges;
+ rAddrConv.ConvertRangeList( aColScRanges, aColXclRanges, nScTab, false );
+ xLabelRangesRef = rDoc.GetColNameRangesRef();
+
+ for ( size_t i = 0, nRanges = aColScRanges.size(); i < nRanges; ++i )
+ {
+ pScRange = aColScRanges[ i ];
+ ScRange aDataRange( *pScRange );
+ if( aDataRange.aEnd.Row() < MAXROW )
+ {
+ aDataRange.aStart.SetRow( aDataRange.aEnd.Row() + 1 );
+ aDataRange.aEnd.SetRow( MAXROW );
+ }
+ else if( aDataRange.aStart.Row() > 0 )
+ {
+ aDataRange.aEnd.SetRow( aDataRange.aStart.Row() - 1 );
+ aDataRange.aStart.SetRow( 0 );
+ }
+ xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
+ }
+}
+
+// Conditional formatting =====================================================
+
+XclImpCondFormat::XclImpCondFormat( const XclImpRoot& rRoot, sal_uInt32 nFormatIndex ) :
+ XclImpRoot( rRoot ),
+ mnFormatIndex( nFormatIndex ),
+ mnCondCount( 0 ),
+ mnCondIndex( 0 )
+{
+}
+
+XclImpCondFormat::~XclImpCondFormat()
+{
+}
+
+void XclImpCondFormat::ReadCondfmt( XclImpStream& rStrm )
+{
+ DBG_ASSERT( !mnCondCount, "XclImpCondFormat::ReadCondfmt - already initialized" );
+ XclRangeList aXclRanges;
+ rStrm >> mnCondCount;
+ rStrm.Ignore( 10 );
+ rStrm >> aXclRanges;
+ GetAddressConverter().ConvertRangeList( maRanges, aXclRanges, GetCurrScTab(), true );
+}
+
+void XclImpCondFormat::ReadCF( XclImpStream& rStrm )
+{
+ if( mnCondIndex >= mnCondCount )
+ {
+ DBG_ERRORFILE( "XclImpCondFormat::ReadCF - CF without leading CONDFMT" );
+ return;
+ }
+
+ // entire conditional format outside of valid range?
+ if( maRanges.empty() )
+ return;
+
+ sal_uInt8 nType, nOperator;
+ sal_uInt16 nFmlaSize1, nFmlaSize2;
+ sal_uInt32 nFlags;
+
+ rStrm >> nType >> nOperator >> nFmlaSize1 >> nFmlaSize2 >> nFlags;
+ rStrm.Ignore( 2 );
+
+ // *** mode and comparison operator ***
+
+ ScConditionMode eMode = SC_COND_NONE;
+ switch( nType )
+ {
+ case EXC_CF_TYPE_CELL:
+ {
+ switch( nOperator )
+ {
+ case EXC_CF_CMP_BETWEEN: eMode = SC_COND_BETWEEN; break;
+ case EXC_CF_CMP_NOT_BETWEEN: eMode = SC_COND_NOTBETWEEN; break;
+ case EXC_CF_CMP_EQUAL: eMode = SC_COND_EQUAL; break;
+ case EXC_CF_CMP_NOT_EQUAL: eMode = SC_COND_NOTEQUAL; break;
+ case EXC_CF_CMP_GREATER: eMode = SC_COND_GREATER; break;
+ case EXC_CF_CMP_LESS: eMode = SC_COND_LESS; break;
+ case EXC_CF_CMP_GREATER_EQUAL: eMode = SC_COND_EQGREATER; break;
+ case EXC_CF_CMP_LESS_EQUAL: eMode = SC_COND_EQLESS; break;
+ default:
+ OSL_TRACE( "XclImpCondFormat::ReadCF - unknown CF comparison 0x%02hX", nOperator );
+ }
+ }
+ break;
+
+ case EXC_CF_TYPE_FMLA:
+ eMode = SC_COND_DIRECT;
+ break;
+
+ default:
+ OSL_TRACE( "XclImpCondFormat::ReadCF - unknown CF mode 0x%02hX", nType );
+ return;
+ }
+
+ // *** create style sheet ***
+
+ String aStyleName( XclTools::GetCondFormatStyleName( GetCurrScTab(), mnFormatIndex, mnCondIndex ) );
+ SfxItemSet& rStyleItemSet = ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), aStyleName, true ).GetItemSet();
+
+ const XclImpPalette& rPalette = GetPalette();
+
+ // *** font block ***
+
+ if( ::get_flag( nFlags, EXC_CF_BLOCK_FONT ) )
+ {
+ XclImpFont aFont( GetRoot() );
+ aFont.ReadCFFontBlock( rStrm );
+ aFont.FillToItemSet( rStyleItemSet, EXC_FONTITEM_CELL );
+ }
+
+ // *** border block ***
+
+ if( ::get_flag( nFlags, EXC_CF_BLOCK_BORDER ) )
+ {
+ sal_uInt16 nLineStyle;
+ sal_uInt32 nLineColor;
+ rStrm >> nLineStyle >> nLineColor;
+ rStrm.Ignore( 2 );
+
+ XclImpCellBorder aBorder;
+ aBorder.FillFromCF8( nLineStyle, nLineColor, nFlags );
+ aBorder.FillToItemSet( rStyleItemSet, rPalette );
+ }
+
+ // *** pattern block ***
+
+ if( ::get_flag( nFlags, EXC_CF_BLOCK_AREA ) )
+ {
+ sal_uInt16 nPattern, nColor;
+ rStrm >> nPattern >> nColor;
+
+ XclImpCellArea aArea;
+ aArea.FillFromCF8( nPattern, nColor, nFlags );
+ aArea.FillToItemSet( rStyleItemSet, rPalette );
+ }
+
+ // *** formulas ***
+
+ const ScAddress& rPos = maRanges.front()->aStart; // assured above that maRanges is not empty
+ ExcelToSc& rFmlaConv = GetOldFmlaConverter();
+
+ ::std::auto_ptr< ScTokenArray > xTokArr1;
+ if( nFmlaSize1 > 0 )
+ {
+ const ScTokenArray* pTokArr = 0;
+ rFmlaConv.Reset( rPos );
+ rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize1, false, FT_RangeName );
+ // formula converter owns pTokArr -> create a copy of the token array
+ if( pTokArr )
+ xTokArr1.reset( pTokArr->Clone() );
+ }
+
+ ::std::auto_ptr< ScTokenArray > pTokArr2;
+ if( nFmlaSize2 > 0 )
+ {
+ const ScTokenArray* pTokArr = 0;
+ rFmlaConv.Reset( rPos );
+ rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize2, false, FT_RangeName );
+ // formula converter owns pTokArr -> create a copy of the token array
+ if( pTokArr )
+ pTokArr2.reset( pTokArr->Clone() );
+ }
+
+ // *** create the Calc conditional formatting ***
+
+ if( !mxScCondFmt.get() )
+ {
+ sal_uLong nKey = 0;
+ mxScCondFmt.reset( new ScConditionalFormat( nKey, GetDocPtr() ) );
+ }
+
+ ScCondFormatEntry aEntry( eMode, xTokArr1.get(), pTokArr2.get(), GetDocPtr(), rPos, aStyleName );
+ mxScCondFmt->AddEntry( aEntry );
+ ++mnCondIndex;
+}
+
+void XclImpCondFormat::Apply()
+{
+ if( mxScCondFmt.get() )
+ {
+ ScDocument& rDoc = GetDoc();
+
+ sal_uLong nKey = rDoc.AddCondFormat( *mxScCondFmt );
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_CONDITIONAL, nKey ) );
+
+ // maRanges contains only valid cell ranges
+ for ( size_t i = 0, nRanges = maRanges.size(); i < nRanges; ++i )
+ {
+ const ScRange* pScRange = maRanges[ i ];
+ rDoc.ApplyPatternAreaTab(
+ pScRange->aStart.Col(), pScRange->aStart.Row(),
+ pScRange->aEnd.Col(), pScRange->aEnd.Row(),
+ pScRange->aStart.Tab(), aPattern );
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpCondFormatManager::XclImpCondFormatManager( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpCondFormatManager::ReadCondfmt( XclImpStream& rStrm )
+{
+ XclImpCondFormat* pFmt = new XclImpCondFormat( GetRoot(), maCondFmtList.size() );
+ pFmt->ReadCondfmt( rStrm );
+ maCondFmtList.push_back( pFmt );
+}
+
+void XclImpCondFormatManager::ReadCF( XclImpStream& rStrm )
+{
+ DBG_ASSERT( !maCondFmtList.empty(), "XclImpCondFormatManager::ReadCF - CF without leading CONDFMT" );
+ if( !maCondFmtList.empty() )
+ maCondFmtList.back().ReadCF( rStrm );
+}
+
+void XclImpCondFormatManager::Apply()
+{
+ for( XclImpCondFmtList::iterator itFmt = maCondFmtList.begin(); itFmt != maCondFmtList.end(); ++itFmt )
+ itFmt->Apply();
+ maCondFmtList.clear();
+}
+
+// Data Validation ============================================================
+
+XclImpValidationManager::DVItem::DVItem( const ScRangeList& rRanges, const ScValidationData& rValidData ) :
+ maRanges(rRanges), maValidData(rValidData) {}
+
+XclImpValidationManager::XclImpValidationManager( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpValidationManager::ReadDval( XclImpStream& rStrm )
+{
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
+
+ sal_uInt32 nObjId;
+ rStrm.Ignore( 10 );
+ rStrm >> nObjId;
+ if( nObjId != EXC_DVAL_NOOBJ )
+ {
+ DBG_ASSERT( nObjId <= 0xFFFF, "XclImpValidation::ReadDval - invalid object ID" );
+ rRoot.GetCurrSheetDrawing().SetSkipObj( static_cast< sal_uInt16 >( nObjId ) );
+ }
+}
+
+void XclImpValidationManager::ReadDV( XclImpStream& rStrm )
+{
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
+
+ ScDocument& rDoc = rRoot.GetDoc();
+ SCTAB nScTab = rRoot.GetCurrScTab();
+ ExcelToSc& rFmlaConv = rRoot.GetOldFmlaConverter();
+
+ // flags
+ sal_uInt32 nFlags;
+ rStrm >> nFlags;
+
+ // message strings
+ /* Empty strings are single NUL characters in Excel (string length is 1).
+ -> Do not let the stream replace them with '?' characters. */
+ rStrm.SetNulSubstChar( '\0' );
+ String aPromptTitle( rStrm.ReadUniString() );
+ String aErrorTitle( rStrm.ReadUniString() );
+ String aPromptMessage( rStrm.ReadUniString() );
+ String aErrorMessage( rStrm.ReadUniString() );
+ rStrm.SetNulSubstChar(); // back to default
+
+ // formula(s)
+ if ( rStrm.GetRecLeft() <= 8 )
+ // Not enough bytes left in the record. Bail out.
+ return;
+
+ sal_uInt16 nLen;
+
+ // first formula
+ // string list is single tStr token with NUL separators -> replace them with LF
+ rStrm.SetNulSubstChar( '\n' );
+ ::std::auto_ptr< ScTokenArray > xTokArr1;
+ rStrm >> nLen;
+ rStrm.Ignore( 2 );
+ if( nLen > 0 )
+ {
+ const ScTokenArray* pTokArr = 0;
+ rFmlaConv.Reset();
+ rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_RangeName );
+ // formula converter owns pTokArr -> create a copy of the token array
+ if( pTokArr )
+ xTokArr1.reset( pTokArr->Clone() );
+ }
+ rStrm.SetNulSubstChar(); // back to default
+
+ // second formula
+ ::std::auto_ptr< ScTokenArray > xTokArr2;
+ rStrm >> nLen;
+ rStrm.Ignore( 2 );
+ if( nLen > 0 )
+ {
+ const ScTokenArray* pTokArr = 0;
+ rFmlaConv.Reset();
+ rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_RangeName );
+ // formula converter owns pTokArr -> create a copy of the token array
+ if( pTokArr )
+ xTokArr2.reset( pTokArr->Clone() );
+ }
+
+ // read all cell ranges
+ XclRangeList aXclRanges;
+ rStrm >> aXclRanges;
+
+ // convert to Calc range list
+ ScRangeList aScRanges;
+ rRoot.GetAddressConverter().ConvertRangeList( aScRanges, aXclRanges, nScTab, true );
+
+ // only continue if there are valid ranges
+ if ( aScRanges.empty() )
+ return;
+
+ bool bIsValid = true; // valid settings in flags field
+
+ ScValidationMode eValMode = SC_VALID_ANY;
+ switch( nFlags & EXC_DV_MODE_MASK )
+ {
+ case EXC_DV_MODE_ANY: eValMode = SC_VALID_ANY; break;
+ case EXC_DV_MODE_WHOLE: eValMode = SC_VALID_WHOLE; break;
+ case EXC_DV_MODE_DECIMAL: eValMode = SC_VALID_DECIMAL; break;
+ case EXC_DV_MODE_LIST: eValMode = SC_VALID_LIST; break;
+ case EXC_DV_MODE_DATE: eValMode = SC_VALID_DATE; break;
+ case EXC_DV_MODE_TIME: eValMode = SC_VALID_TIME; break;
+ case EXC_DV_MODE_TEXTLEN: eValMode = SC_VALID_TEXTLEN; break;
+ case EXC_DV_MODE_CUSTOM: eValMode = SC_VALID_CUSTOM; break;
+ default: bIsValid = false;
+ }
+ rRoot.GetTracer().TraceDVType(eValMode == SC_VALID_CUSTOM);
+
+ ScConditionMode eCondMode = SC_COND_BETWEEN;
+ switch( nFlags & EXC_DV_COND_MASK )
+ {
+ case EXC_DV_COND_BETWEEN: eCondMode = SC_COND_BETWEEN; break;
+ case EXC_DV_COND_NOTBETWEEN:eCondMode = SC_COND_NOTBETWEEN; break;
+ case EXC_DV_COND_EQUAL: eCondMode = SC_COND_EQUAL; break;
+ case EXC_DV_COND_NOTEQUAL: eCondMode = SC_COND_NOTEQUAL; break;
+ case EXC_DV_COND_GREATER: eCondMode = SC_COND_GREATER; break;
+ case EXC_DV_COND_LESS: eCondMode = SC_COND_LESS; break;
+ case EXC_DV_COND_EQGREATER: eCondMode = SC_COND_EQGREATER; break;
+ case EXC_DV_COND_EQLESS: eCondMode = SC_COND_EQLESS; break;
+ default: bIsValid = false;
+ }
+
+ if ( !bIsValid )
+ // No valid validation found. Bail out.
+ return;
+
+
+ // first range for base address for relative references
+ const ScRange& rScRange = *aScRanges.front(); // aScRanges is not empty
+
+ // process string list of a list validity (convert to list of string tokens)
+ if( xTokArr1.get() && (eValMode == SC_VALID_LIST) && ::get_flag( nFlags, EXC_DV_STRINGLIST ) )
+ XclTokenArrayHelper::ConvertStringToList( *xTokArr1, '\n', true );
+
+ maDVItems.push_back(
+ new DVItem(aScRanges, ScValidationData(eValMode, eCondMode, xTokArr1.get(), xTokArr2.get(), &rDoc, rScRange.aStart)));
+ DVItem& rItem = maDVItems.back();
+
+ rItem.maValidData.SetIgnoreBlank( ::get_flag( nFlags, EXC_DV_IGNOREBLANK ) );
+ rItem.maValidData.SetListType( ::get_flagvalue( nFlags, EXC_DV_SUPPRESSDROPDOWN, ValidListType::INVISIBLE, ValidListType::UNSORTED ) );
+
+ // *** prompt box ***
+ if( aPromptTitle.Len() || aPromptMessage.Len() )
+ {
+ // set any text stored in the record
+ rItem.maValidData.SetInput( aPromptTitle, aPromptMessage );
+ if( !::get_flag( nFlags, EXC_DV_SHOWPROMPT ) )
+ rItem.maValidData.ResetInput();
+ }
+
+ // *** error box ***
+ ScValidErrorStyle eErrStyle = SC_VALERR_STOP;
+ switch( nFlags & EXC_DV_ERROR_MASK )
+ {
+ case EXC_DV_ERROR_WARNING: eErrStyle = SC_VALERR_WARNING; break;
+ case EXC_DV_ERROR_INFO: eErrStyle = SC_VALERR_INFO; break;
+ }
+ // set texts and error style
+ rItem.maValidData.SetError( aErrorTitle, aErrorMessage, eErrStyle );
+ if( !::get_flag( nFlags, EXC_DV_SHOWERROR ) )
+ rItem.maValidData.ResetError();
+}
+
+void XclImpValidationManager::Apply()
+{
+ ScDocument& rDoc = GetRoot().GetDoc();
+ DVItemList::iterator itr = maDVItems.begin(), itrEnd = maDVItems.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ DVItem& rItem = *itr;
+ // set the handle ID
+ sal_uLong nHandle = rDoc.AddValidationEntry( rItem.maValidData );
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nHandle ) );
+
+ // apply all ranges
+ for ( size_t i = 0, nRanges = rItem.maRanges.size(); i < nRanges; ++i )
+ {
+ const ScRange* pScRange = rItem.maRanges[ i ];
+ rDoc.ApplyPatternAreaTab( pScRange->aStart.Col(), pScRange->aStart.Row(),
+ pScRange->aEnd.Col(), pScRange->aEnd.Row(), pScRange->aStart.Tab(), aPattern );
+ }
+ }
+ maDVItems.clear();
+}
+
+// Web queries ================================================================
+
+XclImpWebQuery::XclImpWebQuery( const ScRange& rDestRange ) :
+ maDestRange( rDestRange ),
+ meMode( xlWQUnknown ),
+ mnRefresh( 0 )
+{
+}
+
+void XclImpWebQuery::ReadParamqry( XclImpStream& rStrm )
+{
+ sal_uInt16 nFlags = rStrm.ReaduInt16();
+ sal_uInt16 nType = ::extract_value< sal_uInt16 >( nFlags, 0, 3 );
+ if( (nType == EXC_PQRYTYPE_WEBQUERY) && ::get_flag( nFlags, EXC_PQRY_WEBQUERY ) )
+ {
+ if( ::get_flag( nFlags, EXC_PQRY_TABLES ) )
+ {
+ meMode = xlWQAllTables;
+ maTables = ScfTools::GetHTMLTablesName();
+ }
+ else
+ {
+ meMode = xlWQDocument;
+ maTables = ScfTools::GetHTMLDocName();
+ }
+ }
+}
+
+void XclImpWebQuery::ReadWqstring( XclImpStream& rStrm )
+{
+ maURL = rStrm.ReadUniString();
+}
+
+void XclImpWebQuery::ReadWqsettings( XclImpStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm.Ignore( 10 );
+ rStrm >> nFlags;
+ rStrm.Ignore( 10 );
+ rStrm >> mnRefresh;
+
+ if( ::get_flag( nFlags, EXC_WQSETT_SPECTABLES ) && (meMode == xlWQAllTables) )
+ meMode = xlWQSpecTables;
+}
+
+void XclImpWebQuery::ReadWqtables( XclImpStream& rStrm )
+{
+ if( meMode == xlWQSpecTables )
+ {
+ rStrm.Ignore( 4 );
+ String aTables( rStrm.ReadUniString() );
+
+ const sal_Unicode cSep = ';';
+ String aQuotedPairs( RTL_CONSTASCII_USTRINGPARAM( "\"\"" ) );
+ xub_StrLen nTokenCnt = aTables.GetQuotedTokenCount( aQuotedPairs, ',' );
+ maTables.Erase();
+ xub_StrLen nStringIx = 0;
+ for( xub_StrLen nToken = 0; nToken < nTokenCnt; ++nToken )
+ {
+ String aToken( aTables.GetQuotedToken( 0, aQuotedPairs, ',', nStringIx ) );
+ sal_Int32 nTabNum = CharClass::isAsciiNumeric( aToken ) ? aToken.ToInt32() : 0;
+ if( nTabNum > 0 )
+ ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32 >( nTabNum ) ), cSep );
+ else
+ {
+ ScGlobal::EraseQuotes( aToken, '"', false );
+ if( aToken.Len() )
+ ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLName( aToken ), cSep );
+ }
+ }
+ }
+}
+
+void XclImpWebQuery::Apply( ScDocument& rDoc, const String& rFilterName )
+{
+ if( maURL.Len() && (meMode != xlWQUnknown) && rDoc.GetDocumentShell() )
+ {
+ ScAreaLink* pLink = new ScAreaLink( rDoc.GetDocumentShell(),
+ maURL, rFilterName, EMPTY_STRING, maTables, maDestRange, mnRefresh * 60UL );
+ rDoc.GetLinkManager()->InsertFileLink( *pLink, OBJECT_CLIENT_FILE,
+ maURL, &rFilterName, &maTables );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpWebQueryBuffer::XclImpWebQueryBuffer( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpWebQueryBuffer::ReadQsi( XclImpStream& rStrm )
+{
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ rStrm.Ignore( 10 );
+ String aXclName( rStrm.ReadUniString() );
+
+ // #i64794# Excel replaces spaces with underscores
+ aXclName.SearchAndReplaceAll( ' ', '_' );
+
+ // find the defined name used in Calc
+ if( const XclImpName* pName = GetNameManager().FindName( aXclName, GetCurrScTab() ) )
+ {
+ if( const ScRangeData* pRangeData = pName->GetScRangeData() )
+ {
+ ScRange aRange;
+ if( pRangeData->IsReference( aRange ) )
+ maWQList.push_back( new XclImpWebQuery( aRange ) );
+ }
+ }
+ }
+ else
+ {
+ DBG_ERROR_BIFF();
+ }
+}
+
+void XclImpWebQueryBuffer::ReadParamqry( XclImpStream& rStrm )
+{
+ if (!maWQList.empty())
+ maWQList.back().ReadParamqry( rStrm );
+}
+
+void XclImpWebQueryBuffer::ReadWqstring( XclImpStream& rStrm )
+{
+ if (!maWQList.empty())
+ maWQList.back().ReadWqstring( rStrm );
+}
+
+void XclImpWebQueryBuffer::ReadWqsettings( XclImpStream& rStrm )
+{
+ if (!maWQList.empty())
+ maWQList.back().ReadWqsettings( rStrm );
+}
+
+void XclImpWebQueryBuffer::ReadWqtables( XclImpStream& rStrm )
+{
+ if (!maWQList.empty())
+ maWQList.back().ReadWqtables( rStrm );
+}
+
+void XclImpWebQueryBuffer::Apply()
+{
+ ScDocument& rDoc = GetDoc();
+ String aFilterName( RTL_CONSTASCII_USTRINGPARAM( EXC_WEBQRY_FILTER ) );
+ for( XclImpWebQueryList::iterator itQuery = maWQList.begin(); itQuery != maWQList.end(); ++itQuery )
+ itQuery->Apply( rDoc, aFilterName );
+}
+
+// Decryption =================================================================
+
+namespace {
+
+XclImpDecrypterRef lclReadFilepass5( XclImpStream& rStrm )
+{
+ XclImpDecrypterRef xDecr;
+ DBG_ASSERT( rStrm.GetRecLeft() == 4, "lclReadFilepass5 - wrong record size" );
+ if( rStrm.GetRecLeft() == 4 )
+ {
+ sal_uInt16 nKey, nHash;
+ rStrm >> nKey >> nHash;
+ xDecr.reset( new XclImpBiff5Decrypter( nKey, nHash ) );
+ }
+ return xDecr;
+}
+
+XclImpDecrypterRef lclReadFilepass8_Standard( XclImpStream& rStrm )
+{
+ XclImpDecrypterRef xDecr;
+ DBG_ASSERT( rStrm.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
+ if( rStrm.GetRecLeft() == 48 )
+ {
+ sal_uInt8 pnSalt[ 16 ];
+ sal_uInt8 pnVerifier[ 16 ];
+ sal_uInt8 pnVerifierHash[ 16 ];
+ rStrm.Read( pnSalt, 16 );
+ rStrm.Read( pnVerifier, 16 );
+ rStrm.Read( pnVerifierHash, 16 );
+ xDecr.reset( new XclImpBiff8Decrypter( pnSalt, pnVerifier, pnVerifierHash ) );
+ }
+ return xDecr;
+}
+
+XclImpDecrypterRef lclReadFilepass8_Strong( XclImpStream& /*rStrm*/ )
+{
+ // not supported
+ return XclImpDecrypterRef();
+}
+
+XclImpDecrypterRef lclReadFilepass8( XclImpStream& rStrm )
+{
+ XclImpDecrypterRef xDecr;
+
+ sal_uInt16 nMode;
+ rStrm >> nMode;
+ switch( nMode )
+ {
+ case EXC_FILEPASS_BIFF5:
+ xDecr = lclReadFilepass5( rStrm );
+ break;
+
+ case EXC_FILEPASS_BIFF8:
+ {
+ rStrm.Ignore( 2 );
+ sal_uInt16 nSubMode;
+ rStrm >> nSubMode;
+ switch( nSubMode )
+ {
+ case EXC_FILEPASS_BIFF8_STD:
+ xDecr = lclReadFilepass8_Standard( rStrm );
+ break;
+ case EXC_FILEPASS_BIFF8_STRONG:
+ xDecr = lclReadFilepass8_Strong( rStrm );
+ break;
+ default:
+ DBG_ERRORFILE( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
+ }
+ }
+ break;
+
+ default:
+ DBG_ERRORFILE( "lclReadFilepass8 - unknown encryption mode" );
+ }
+
+ return xDecr;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+ErrCode XclImpDecryptHelper::ReadFilepass( XclImpStream& rStrm )
+{
+ XclImpDecrypterRef xDecr;
+ rStrm.DisableDecryption();
+
+ // read the FILEPASS record and create a new decrypter object
+ switch( rStrm.GetRoot().GetBiff() )
+ {
+ case EXC_BIFF2:
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ case EXC_BIFF5: xDecr = lclReadFilepass5( rStrm ); break;
+ case EXC_BIFF8: xDecr = lclReadFilepass8( rStrm ); break;
+ default: DBG_ERROR_BIFF();
+ };
+
+ // set decrypter at import stream
+ rStrm.SetDecrypter( xDecr );
+
+ // request and verify a password (decrypter implements IDocPasswordVerifier)
+ if( xDecr )
+ rStrm.GetRoot().RequestEncryptionData( *xDecr );
+
+ // return error code (success, wrong password, etc.)
+ return xDecr ? xDecr->GetError() : EXC_ENCR_ERROR_UNSUPP_CRYPT;
+}
+
+// Document protection ========================================================
+
+XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ mnPassHash(0x0000),
+ mbDocProtect(false),
+ mbWinProtect(false)
+{
+}
+
+void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream& rStrm )
+{
+ mbDocProtect = rStrm.ReaduInt16() ? true : false;
+}
+
+void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream& rStrm )
+{
+ mbWinProtect = rStrm.ReaduInt16() ? true : false;
+}
+
+void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream& rStrm )
+{
+ rStrm.EnableDecryption();
+ mnPassHash = rStrm.ReaduInt16();
+}
+
+void XclImpDocProtectBuffer::Apply() const
+{
+ if (!mbDocProtect && !mbWinProtect)
+ // Excel requires either the structure or windows protection is set.
+ // If neither is set then the document is not protected at all.
+ return;
+
+ auto_ptr<ScDocProtection> pProtect(new ScDocProtection);
+ pProtect->setProtected(true);
+
+ if (mnPassHash)
+ {
+ // 16-bit password pash.
+ Sequence<sal_Int8> aPass(2);
+ aPass[0] = (mnPassHash >> 8) & 0xFF;
+ aPass[1] = mnPassHash & 0xFF;
+ pProtect->setPasswordHash(aPass, PASSHASH_XL);
+ }
+
+ // document protection options
+ pProtect->setOption(ScDocProtection::STRUCTURE, mbDocProtect);
+ pProtect->setOption(ScDocProtection::WINDOWS, mbWinProtect);
+
+ GetDoc().SetDocProtection(pProtect.get());
+}
+
+// Sheet Protection ===========================================================
+
+XclImpSheetProtectBuffer::Sheet::Sheet() :
+ mbProtected(false),
+ mnPasswordHash(0x0000),
+ mnOptions(0x4400)
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet& r) :
+ mbProtected(r.mbProtected),
+ mnPasswordHash(r.mnPasswordHash),
+ mnOptions(r.mnOptions)
+{
+}
+
+XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpSheetProtectBuffer::ReadProtect( XclImpStream& rStrm, SCTAB nTab )
+{
+ if ( rStrm.ReaduInt16() )
+ {
+ Sheet* pSheet = GetSheetItem(nTab);
+ if (pSheet)
+ pSheet->mbProtected = true;
+ }
+}
+
+void XclImpSheetProtectBuffer::ReadOptions( XclImpStream& rStrm, SCTAB nTab )
+{
+ rStrm.Ignore(12);
+
+ // feature type can be either 2 or 4. If 2, this record stores flag for
+ // enhanced protection, whereas if 4 it stores flag for smart tag.
+ sal_uInt16 nFeatureType;
+ rStrm >> nFeatureType;
+ if (nFeatureType != 2)
+ // We currently only support import of enhanced protection data.
+ return;
+
+ rStrm.Ignore(1); // always 1
+
+ // The flag size specifies the size of bytes that follows that stores
+ // feature data. If -1 it depends on the feature type imported earlier.
+ // For enhanced protection data, the size is always 4. For the most xls
+ // documents out there this value is almost always -1.
+ sal_Int32 nFlagSize;
+ rStrm >> nFlagSize;
+ if (nFlagSize != -1)
+ return;
+
+ // There are actually 4 bytes to read, but the upper 2 bytes currently
+ // don't store any bits.
+ sal_uInt16 nOptions;
+ rStrm >> nOptions;
+
+ Sheet* pSheet = GetSheetItem(nTab);
+ if (pSheet)
+ pSheet->mnOptions = nOptions;
+}
+
+void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream& rStrm, SCTAB nTab )
+{
+ sal_uInt16 nHash;
+ rStrm >> nHash;
+ Sheet* pSheet = GetSheetItem(nTab);
+ if (pSheet)
+ pSheet->mnPasswordHash = nHash;
+}
+
+void XclImpSheetProtectBuffer::Apply() const
+{
+ for (ProtectedSheetMap::const_iterator itr = maProtectedSheets.begin(), itrEnd = maProtectedSheets.end();
+ itr != itrEnd; ++itr)
+ {
+ if (!itr->second.mbProtected)
+ // This sheet is (for whatever reason) not protected.
+ continue;
+
+ auto_ptr<ScTableProtection> pProtect(new ScTableProtection);
+ pProtect->setProtected(true);
+
+ // 16-bit hash password
+ const sal_uInt16 nHash = itr->second.mnPasswordHash;
+ if (nHash)
+ {
+ Sequence<sal_Int8> aPass(2);
+ aPass[0] = (nHash >> 8) & 0xFF;
+ aPass[1] = nHash & 0xFF;
+ pProtect->setPasswordHash(aPass, PASSHASH_XL);
+ }
+
+ // sheet protection options
+ const sal_uInt16 nOptions = itr->second.mnOptions;
+ pProtect->setOption( ScTableProtection::OBJECTS, (nOptions & 0x0001) );
+ pProtect->setOption( ScTableProtection::SCENARIOS, (nOptions & 0x0002) );
+ pProtect->setOption( ScTableProtection::FORMAT_CELLS, (nOptions & 0x0004) );
+ pProtect->setOption( ScTableProtection::FORMAT_COLUMNS, (nOptions & 0x0008) );
+ pProtect->setOption( ScTableProtection::FORMAT_ROWS, (nOptions & 0x0010) );
+ pProtect->setOption( ScTableProtection::INSERT_COLUMNS, (nOptions & 0x0020) );
+ pProtect->setOption( ScTableProtection::INSERT_ROWS, (nOptions & 0x0040) );
+ pProtect->setOption( ScTableProtection::INSERT_HYPERLINKS, (nOptions & 0x0080) );
+ pProtect->setOption( ScTableProtection::DELETE_COLUMNS, (nOptions & 0x0100) );
+ pProtect->setOption( ScTableProtection::DELETE_ROWS, (nOptions & 0x0200) );
+ pProtect->setOption( ScTableProtection::SELECT_LOCKED_CELLS, (nOptions & 0x0400) );
+ pProtect->setOption( ScTableProtection::SORT, (nOptions & 0x0800) );
+ pProtect->setOption( ScTableProtection::AUTOFILTER, (nOptions & 0x1000) );
+ pProtect->setOption( ScTableProtection::PIVOT_TABLES, (nOptions & 0x2000) );
+ pProtect->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS, (nOptions & 0x4000) );
+
+ // all done. now commit.
+ GetDoc().SetTabProtection(itr->first, pProtect.get());
+ }
+}
+
+XclImpSheetProtectBuffer::Sheet* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab )
+{
+ ProtectedSheetMap::iterator itr = maProtectedSheets.find(nTab);
+ if (itr == maProtectedSheets.end())
+ {
+ // new sheet
+ if ( !maProtectedSheets.insert( ProtectedSheetMap::value_type(nTab, Sheet()) ).second )
+ return NULL;
+
+ itr = maProtectedSheets.find(nTab);
+ }
+
+ return &itr->second;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xiescher.cxx b/sc/source/filter/excel/xiescher.cxx
new file mode 100644
index 000000000000..8d360b6f9259
--- /dev/null
+++ b/sc/source/filter/excel/xiescher.cxx
@@ -0,0 +1,4206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "xiescher.hxx"
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/awt/PushButtonType.hpp>
+#include <com/sun/star/awt/ScrollBarOrientation.hpp>
+#include <com/sun/star/awt/VisualEffect.hpp>
+#include <com/sun/star/style/HorizontalAlignment.hpp>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <com/sun/star/form/binding/XBindableValue.hpp>
+#include <com/sun/star/form/binding/XValueBinding.hpp>
+#include <com/sun/star/form/binding/XListEntrySink.hpp>
+#include <com/sun/star/form/binding/XListEntrySource.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+
+#include <rtl/logfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <unotools/fltrcfg.hxx>
+#include <svtools/wmf.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/classids.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+#include <svx/svdopath.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdpage.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svditer.hxx>
+#include <editeng/writingmodeitem.hxx>
+
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+#include <editeng/colritem.hxx>
+#include <svx/xflclit.hxx>
+#include <sal/macros.h>
+#include <editeng/adjitem.hxx>
+#include <svx/xlineit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xbtmpit.hxx>
+
+#include "document.hxx"
+#include "drwlayer.hxx"
+#include "userdat.hxx"
+#include "chartarr.hxx"
+#include "detfunc.hxx"
+#include "unonames.hxx"
+#include "convuno.hxx"
+#include "postit.hxx"
+#include "globstr.hrc"
+
+#include "fprogressbar.hxx"
+#include "xltracer.hxx"
+#include "xistream.hxx"
+#include "xihelper.hxx"
+#include "xiformula.hxx"
+#include "xilink.hxx"
+#include "xistyle.hxx"
+#include "xipage.hxx"
+#include "xichart.hxx"
+#include "xicontent.hxx"
+#include "scextopt.hxx"
+
+#include "namebuff.hxx"
+#include <boost/shared_ptr.hpp>
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::UNO_SET_THROW;
+using ::com::sun::star::beans::NamedValue;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::container::XIndexContainer;
+using ::com::sun::star::container::XNameContainer;
+using ::com::sun::star::frame::XModel;
+using ::com::sun::star::awt::XControlModel;
+using ::com::sun::star::embed::XEmbeddedObject;
+using ::com::sun::star::embed::XEmbedPersist;
+using ::com::sun::star::drawing::XControlShape;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::form::XForm;
+using ::com::sun::star::form::XFormComponent;
+using ::com::sun::star::form::XFormsSupplier;
+using ::com::sun::star::form::binding::XBindableValue;
+using ::com::sun::star::form::binding::XValueBinding;
+using ::com::sun::star::form::binding::XListEntrySink;
+using ::com::sun::star::form::binding::XListEntrySource;
+using ::com::sun::star::script::ScriptEventDescriptor;
+using ::com::sun::star::script::XEventAttacherManager;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+
+// ============================================================================
+
+namespace {
+
+/** Helper class which mimics the auto_ptr< SdrObject > semantics, but calls
+ SdrObject::Free instead of deleting the SdrObject directly. */
+template< typename SdrObjType >
+class TSdrObjectPtr
+{
+public:
+ inline explicit TSdrObjectPtr( SdrObjType* pObj = 0 ) : mpObj( pObj ) {}
+ inline ~TSdrObjectPtr() { free(); }
+
+ inline const SdrObjType* operator->() const { return mpObj; }
+ inline SdrObjType* operator->() { return mpObj; }
+
+ inline const SdrObjType* get() const { return mpObj; }
+ inline SdrObjType* get() { return mpObj; }
+
+ inline const SdrObjType& operator*() const { return *mpObj; }
+ inline SdrObjType& operator*() { return *mpObj; }
+
+ inline bool is() const { return mpObj != 0; }
+ inline bool operator!() const { return mpObj == 0; }
+
+ inline void reset( SdrObjType* pObj = 0 ) { free(); mpObj = pObj; }
+ inline SdrObjType* release() { SdrObjType* pObj = mpObj; mpObj = 0; return pObj; }
+
+private:
+ TSdrObjectPtr( const TSdrObjectPtr& ); // not implemented
+ TSdrObjectPtr& operator=( TSdrObjectPtr& rxObj ); // not implemented
+
+ inline void free() { SdrObject* pObj = mpObj; mpObj = 0; SdrObject::Free( pObj ); }
+
+private:
+ SdrObjType* mpObj;
+};
+
+typedef TSdrObjectPtr< SdrObject > SdrObjectPtr;
+
+} // namespace
+
+// Drawing objects ============================================================
+
+XclImpDrawObjBase::XclImpDrawObjBase( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ mnObjId( EXC_OBJ_INVALID_ID ),
+ mnObjType( EXC_OBJTYPE_UNKNOWN ),
+ mnDffShapeId( 0 ),
+ mnDffFlags( 0 ),
+ mbHasAnchor( false ),
+ mbHidden( false ),
+ mbVisible( true ),
+ mbPrintable( true ),
+ mbAreaObj( false ),
+ mbAutoMargin( true ),
+ mbSimpleMacro( true ),
+ mbProcessSdr( true ),
+ mbInsertSdr( true ),
+ mbCustomDff( false )
+{
+}
+
+XclImpDrawObjBase::~XclImpDrawObjBase()
+{
+}
+
+XclImpDrawObjRef XclImpDrawObjBase::ReadObj3( const XclImpRoot& rRoot, XclImpStream& rStrm )
+{
+ XclImpDrawObjRef xDrawObj;
+
+ if( rStrm.GetRecLeft() >= 30 )
+ {
+ sal_uInt16 nObjType;
+ rStrm.Ignore( 4 );
+ rStrm >> nObjType;
+ switch( nObjType )
+ {
+ case EXC_OBJTYPE_GROUP: xDrawObj.reset( new XclImpGroupObj( rRoot ) ); break;
+ case EXC_OBJTYPE_LINE: xDrawObj.reset( new XclImpLineObj( rRoot ) ); break;
+ case EXC_OBJTYPE_RECTANGLE: xDrawObj.reset( new XclImpRectObj( rRoot ) ); break;
+ case EXC_OBJTYPE_OVAL: xDrawObj.reset( new XclImpOvalObj( rRoot ) ); break;
+ case EXC_OBJTYPE_ARC: xDrawObj.reset( new XclImpArcObj( rRoot ) ); break;
+ case EXC_OBJTYPE_CHART: xDrawObj.reset( new XclImpChartObj( rRoot ) ); break;
+ case EXC_OBJTYPE_TEXT: xDrawObj.reset( new XclImpTextObj( rRoot ) ); break;
+ case EXC_OBJTYPE_BUTTON: xDrawObj.reset( new XclImpButtonObj( rRoot ) ); break;
+ case EXC_OBJTYPE_PICTURE: xDrawObj.reset( new XclImpPictureObj( rRoot ) ); break;
+ default:
+ OSL_TRACE( "XclImpDrawObjBase::ReadObj3 - unknown object type 0x%04hX", nObjType );
+ rRoot.GetTracer().TraceUnsupportedObjects();
+ xDrawObj.reset( new XclImpPhObj( rRoot ) );
+ }
+ }
+
+ xDrawObj->mnTab = rRoot.GetCurrScTab();
+ xDrawObj->ImplReadObj3( rStrm );
+ return xDrawObj;
+}
+
+XclImpDrawObjRef XclImpDrawObjBase::ReadObj4( const XclImpRoot& rRoot, XclImpStream& rStrm )
+{
+ XclImpDrawObjRef xDrawObj;
+
+ if( rStrm.GetRecLeft() >= 30 )
+ {
+ sal_uInt16 nObjType;
+ rStrm.Ignore( 4 );
+ rStrm >> nObjType;
+ switch( nObjType )
+ {
+ case EXC_OBJTYPE_GROUP: xDrawObj.reset( new XclImpGroupObj( rRoot ) ); break;
+ case EXC_OBJTYPE_LINE: xDrawObj.reset( new XclImpLineObj( rRoot ) ); break;
+ case EXC_OBJTYPE_RECTANGLE: xDrawObj.reset( new XclImpRectObj( rRoot ) ); break;
+ case EXC_OBJTYPE_OVAL: xDrawObj.reset( new XclImpOvalObj( rRoot ) ); break;
+ case EXC_OBJTYPE_ARC: xDrawObj.reset( new XclImpArcObj( rRoot ) ); break;
+ case EXC_OBJTYPE_CHART: xDrawObj.reset( new XclImpChartObj( rRoot ) ); break;
+ case EXC_OBJTYPE_TEXT: xDrawObj.reset( new XclImpTextObj( rRoot ) ); break;
+ case EXC_OBJTYPE_BUTTON: xDrawObj.reset( new XclImpButtonObj( rRoot ) ); break;
+ case EXC_OBJTYPE_PICTURE: xDrawObj.reset( new XclImpPictureObj( rRoot ) ); break;
+ case EXC_OBJTYPE_POLYGON: xDrawObj.reset( new XclImpPolygonObj( rRoot ) ); break;
+ default:
+ OSL_TRACE( "XclImpDrawObjBase::ReadObj4 - unknown object type 0x%04hX", nObjType );
+ rRoot.GetTracer().TraceUnsupportedObjects();
+ xDrawObj.reset( new XclImpPhObj( rRoot ) );
+ }
+ }
+
+ xDrawObj->mnTab = rRoot.GetCurrScTab();
+ xDrawObj->ImplReadObj4( rStrm );
+ return xDrawObj;
+}
+
+XclImpDrawObjRef XclImpDrawObjBase::ReadObj5( const XclImpRoot& rRoot, XclImpStream& rStrm )
+{
+ XclImpDrawObjRef xDrawObj;
+
+ if( rStrm.GetRecLeft() >= 34 )
+ {
+ sal_uInt16 nObjType;
+ rStrm.Ignore( 4 );
+ rStrm >> nObjType;
+ switch( nObjType )
+ {
+ case EXC_OBJTYPE_GROUP: xDrawObj.reset( new XclImpGroupObj( rRoot ) ); break;
+ case EXC_OBJTYPE_LINE: xDrawObj.reset( new XclImpLineObj( rRoot ) ); break;
+ case EXC_OBJTYPE_RECTANGLE: xDrawObj.reset( new XclImpRectObj( rRoot ) ); break;
+ case EXC_OBJTYPE_OVAL: xDrawObj.reset( new XclImpOvalObj( rRoot ) ); break;
+ case EXC_OBJTYPE_ARC: xDrawObj.reset( new XclImpArcObj( rRoot ) ); break;
+ case EXC_OBJTYPE_CHART: xDrawObj.reset( new XclImpChartObj( rRoot ) ); break;
+ case EXC_OBJTYPE_TEXT: xDrawObj.reset( new XclImpTextObj( rRoot ) ); break;
+ case EXC_OBJTYPE_BUTTON: xDrawObj.reset( new XclImpButtonObj( rRoot ) ); break;
+ case EXC_OBJTYPE_PICTURE: xDrawObj.reset( new XclImpPictureObj( rRoot ) ); break;
+ case EXC_OBJTYPE_POLYGON: xDrawObj.reset( new XclImpPolygonObj( rRoot ) ); break;
+ case EXC_OBJTYPE_CHECKBOX: xDrawObj.reset( new XclImpCheckBoxObj( rRoot ) ); break;
+ case EXC_OBJTYPE_OPTIONBUTTON: xDrawObj.reset( new XclImpOptionButtonObj( rRoot ) ); break;
+ case EXC_OBJTYPE_EDIT: xDrawObj.reset( new XclImpEditObj( rRoot ) ); break;
+ case EXC_OBJTYPE_LABEL: xDrawObj.reset( new XclImpLabelObj( rRoot ) ); break;
+ case EXC_OBJTYPE_DIALOG: xDrawObj.reset( new XclImpDialogObj( rRoot ) ); break;
+ case EXC_OBJTYPE_SPIN: xDrawObj.reset( new XclImpSpinButtonObj( rRoot ) ); break;
+ case EXC_OBJTYPE_SCROLLBAR: xDrawObj.reset( new XclImpScrollBarObj( rRoot ) ); break;
+ case EXC_OBJTYPE_LISTBOX: xDrawObj.reset( new XclImpListBoxObj( rRoot ) ); break;
+ case EXC_OBJTYPE_GROUPBOX: xDrawObj.reset( new XclImpGroupBoxObj( rRoot ) ); break;
+ case EXC_OBJTYPE_DROPDOWN: xDrawObj.reset( new XclImpDropDownObj( rRoot ) ); break;
+ default:
+ OSL_TRACE( "XclImpDrawObjBase::ReadObj5 - unknown object type 0x%04hX", nObjType );
+ rRoot.GetTracer().TraceUnsupportedObjects();
+ xDrawObj.reset( new XclImpPhObj( rRoot ) );
+ }
+ }
+
+ xDrawObj->mnTab = rRoot.GetCurrScTab();
+ xDrawObj->ImplReadObj5( rStrm );
+ return xDrawObj;
+}
+
+XclImpDrawObjRef XclImpDrawObjBase::ReadObj8( const XclImpRoot& rRoot, XclImpStream& rStrm )
+{
+ XclImpDrawObjRef xDrawObj;
+
+ if( rStrm.GetRecLeft() >= 10 )
+ {
+ sal_uInt16 nSubRecId, nSubRecSize, nObjType;
+ rStrm >> nSubRecId >> nSubRecSize >> nObjType;
+ DBG_ASSERT( nSubRecId == EXC_ID_OBJCMO, "XclImpDrawObjBase::ReadObj8 - OBJCMO subrecord expected" );
+ if( (nSubRecId == EXC_ID_OBJCMO) && (nSubRecSize >= 6) )
+ {
+ switch( nObjType )
+ {
+ // in BIFF8, all simple objects support text
+ case EXC_OBJTYPE_LINE:
+ case EXC_OBJTYPE_ARC:
+ xDrawObj.reset( new XclImpTextObj( rRoot ) );
+ // lines and arcs may be 2-dimensional
+ xDrawObj->SetAreaObj( false );
+ break;
+
+ // in BIFF8, all simple objects support text
+ case EXC_OBJTYPE_RECTANGLE:
+ case EXC_OBJTYPE_OVAL:
+ case EXC_OBJTYPE_POLYGON:
+ case EXC_OBJTYPE_DRAWING:
+ case EXC_OBJTYPE_TEXT:
+ xDrawObj.reset( new XclImpTextObj( rRoot ) );
+ break;
+
+ case EXC_OBJTYPE_GROUP: xDrawObj.reset( new XclImpGroupObj( rRoot ) ); break;
+ case EXC_OBJTYPE_CHART: xDrawObj.reset( new XclImpChartObj( rRoot ) ); break;
+ case EXC_OBJTYPE_BUTTON: xDrawObj.reset( new XclImpButtonObj( rRoot ) ); break;
+ case EXC_OBJTYPE_PICTURE: xDrawObj.reset( new XclImpPictureObj( rRoot ) ); break;
+ case EXC_OBJTYPE_CHECKBOX: xDrawObj.reset( new XclImpCheckBoxObj( rRoot ) ); break;
+ case EXC_OBJTYPE_OPTIONBUTTON: xDrawObj.reset( new XclImpOptionButtonObj( rRoot ) ); break;
+ case EXC_OBJTYPE_EDIT: xDrawObj.reset( new XclImpEditObj( rRoot ) ); break;
+ case EXC_OBJTYPE_LABEL: xDrawObj.reset( new XclImpLabelObj( rRoot ) ); break;
+ case EXC_OBJTYPE_DIALOG: xDrawObj.reset( new XclImpDialogObj( rRoot ) ); break;
+ case EXC_OBJTYPE_SPIN: xDrawObj.reset( new XclImpSpinButtonObj( rRoot ) ); break;
+ case EXC_OBJTYPE_SCROLLBAR: xDrawObj.reset( new XclImpScrollBarObj( rRoot ) ); break;
+ case EXC_OBJTYPE_LISTBOX: xDrawObj.reset( new XclImpListBoxObj( rRoot ) ); break;
+ case EXC_OBJTYPE_GROUPBOX: xDrawObj.reset( new XclImpGroupBoxObj( rRoot ) ); break;
+ case EXC_OBJTYPE_DROPDOWN: xDrawObj.reset( new XclImpDropDownObj( rRoot ) ); break;
+ case EXC_OBJTYPE_NOTE: xDrawObj.reset( new XclImpNoteObj( rRoot ) ); break;
+
+ default:
+ OSL_TRACE( "XclImpDrawObjBase::ReadObj8 - unknown object type 0x%04hX", nObjType );
+ rRoot.GetTracer().TraceUnsupportedObjects();
+ xDrawObj.reset( new XclImpPhObj( rRoot ) );
+ }
+ }
+ }
+
+ xDrawObj->mnTab = rRoot.GetCurrScTab();
+ xDrawObj->ImplReadObj8( rStrm );
+ return xDrawObj;
+}
+
+void XclImpDrawObjBase::SetAnchor( const XclObjAnchor& rAnchor )
+{
+ maAnchor = rAnchor;
+ mbHasAnchor = true;
+}
+
+void XclImpDrawObjBase::SetDffData( const DffObjData& rDffObjData, const String& rObjName, const String& rHyperlink, bool bVisible, bool bAutoMargin )
+{
+ mnDffShapeId = rDffObjData.nShapeId;
+ mnDffFlags = rDffObjData.nSpFlags;
+ maObjName = rObjName;
+ maHyperlink = rHyperlink;
+ mbVisible = bVisible;
+ mbAutoMargin = bAutoMargin;
+}
+
+String XclImpDrawObjBase::GetObjName() const
+{
+ /* #i51348# Always return a non-empty name. Create English
+ default names depending on the object type. This is not implemented as
+ virtual functions in derived classes, as class type and object type may
+ not match. */
+ return (maObjName.Len() > 0) ? maObjName : GetObjectManager().GetDefaultObjName( *this );
+}
+
+const XclObjAnchor* XclImpDrawObjBase::GetAnchor() const
+{
+ return mbHasAnchor ? &maAnchor : 0;
+}
+
+bool XclImpDrawObjBase::IsValidSize( const Rectangle& rAnchorRect ) const
+{
+ // XclObjAnchor rounds up the width, width of 3 is the result of an Excel width of 0
+ return mbAreaObj ?
+ ((rAnchorRect.GetWidth() > 3) && (rAnchorRect.GetHeight() > 1)) :
+ ((rAnchorRect.GetWidth() > 3) || (rAnchorRect.GetHeight() > 1));
+}
+
+ScRange XclImpDrawObjBase::GetUsedArea( SCTAB nScTab ) const
+{
+ ScRange aScUsedArea( ScAddress::INITIALIZE_INVALID );
+ // #i44077# object inserted -> update used area for OLE object import
+ if( mbHasAnchor && GetAddressConverter().ConvertRange( aScUsedArea, maAnchor, nScTab, nScTab, false ) )
+ {
+ // reduce range, if object ends directly on borders between two columns or rows
+ if( (maAnchor.mnRX == 0) && (aScUsedArea.aStart.Col() < aScUsedArea.aEnd.Col()) )
+ aScUsedArea.aEnd.IncCol( -1 );
+ if( (maAnchor.mnBY == 0) && (aScUsedArea.aStart.Row() < aScUsedArea.aEnd.Row()) )
+ aScUsedArea.aEnd.IncRow( -1 );
+ }
+ return aScUsedArea;
+}
+
+sal_Size XclImpDrawObjBase::GetProgressSize() const
+{
+ return DoGetProgressSize();
+}
+
+SdrObject* XclImpDrawObjBase::CreateSdrObject( XclImpDffConverter& rDffConv, const Rectangle& rAnchorRect, bool bIsDff ) const
+{
+ SdrObjectPtr xSdrObj;
+ if( bIsDff && !mbCustomDff )
+ {
+ rDffConv.Progress( GetProgressSize() );
+ }
+ else
+ {
+ xSdrObj.reset( DoCreateSdrObj( rDffConv, rAnchorRect ) );
+ if( xSdrObj.is() )
+ xSdrObj->SetModel( rDffConv.GetModel() );
+ }
+ return xSdrObj.release();
+}
+
+void XclImpDrawObjBase::PreProcessSdrObject( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
+{
+ // default: front layer, derived classes may have to set other layer in DoPreProcessSdrObj()
+ rSdrObj.NbcSetLayer( SC_LAYER_FRONT );
+
+ // set object name (GetObjName() will always return a non-empty name)
+ rSdrObj.SetName( GetObjName() );
+
+ // #i39167# full width for all objects regardless of horizontal alignment
+ rSdrObj.SetMergedItem( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_BLOCK ) );
+
+ // automatic text margin
+ if( mbAutoMargin )
+ {
+ sal_Int32 nMargin = rDffConv.GetDefaultTextMargin();
+ rSdrObj.SetMergedItem( SdrTextLeftDistItem( nMargin ) );
+ rSdrObj.SetMergedItem( SdrTextRightDistItem( nMargin ) );
+ rSdrObj.SetMergedItem( SdrTextUpperDistItem( nMargin ) );
+ rSdrObj.SetMergedItem( SdrTextLowerDistItem( nMargin ) );
+ }
+
+ // macro and hyperlink
+ // removed oracle/sun check for mbSimpleMacro ( no idea what its for )
+ if( (maMacroName.Len() > 0 ) ||
+ (maHyperlink.Len() > 0) )
+ {
+ if( ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( &rSdrObj, sal_True ) )
+ {
+ pInfo->SetMacro( XclTools::GetSbMacroUrl( maMacroName, GetDocShell() ) );
+ pInfo->SetHlink( maHyperlink );
+ }
+ }
+
+ // call virtual function for object type specific processing
+ DoPreProcessSdrObj( rDffConv, rSdrObj );
+}
+
+void XclImpDrawObjBase::PostProcessSdrObject( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
+{
+ // call virtual function for object type specific processing
+ DoPostProcessSdrObj( rDffConv, rSdrObj );
+}
+
+// protected ------------------------------------------------------------------
+
+void XclImpDrawObjBase::ReadName5( XclImpStream& rStrm, sal_uInt16 nNameLen )
+{
+ maObjName.Erase();
+ if( nNameLen > 0 )
+ {
+ // name length field is repeated before the name
+ maObjName = rStrm.ReadByteString( false );
+ // skip padding byte for word boundaries
+ if( rStrm.GetRecPos() & 1 ) rStrm.Ignore( 1 );
+ }
+}
+
+void XclImpDrawObjBase::ReadMacro3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ maMacroName.Erase();
+ rStrm.Ignore( nMacroSize );
+ // skip padding byte for word boundaries, not contained in nMacroSize
+ if( rStrm.GetRecPos() & 1 ) rStrm.Ignore( 1 );
+}
+
+void XclImpDrawObjBase::ReadMacro4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ maMacroName.Erase();
+ rStrm.Ignore( nMacroSize );
+}
+
+void XclImpDrawObjBase::ReadMacro5( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ maMacroName.Erase();
+ rStrm.Ignore( nMacroSize );
+}
+
+void XclImpDrawObjBase::ReadMacro8( XclImpStream& rStrm )
+{
+ maMacroName.Erase();
+ if( rStrm.GetRecLeft() > 6 )
+ {
+ // macro is stored in a tNameXR token containing a link to a defined name
+ sal_uInt16 nFmlaSize;
+ rStrm >> nFmlaSize;
+ rStrm.Ignore( 4 );
+ DBG_ASSERT( nFmlaSize == 7, "XclImpDrawObjBase::ReadMacro - unexpected formula size" );
+ if( nFmlaSize == 7 )
+ {
+ sal_uInt8 nTokenId;
+ sal_uInt16 nExtSheet, nExtName;
+ rStrm >> nTokenId >> nExtSheet >> nExtName;
+ DBG_ASSERT( nTokenId == XclTokenArrayHelper::GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ),
+ "XclImpDrawObjBase::ReadMacro - tNameXR token expected" );
+ if( nTokenId == XclTokenArrayHelper::GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ) )
+ maMacroName = GetLinkManager().GetMacroName( nExtSheet, nExtName );
+ }
+ }
+}
+
+void XclImpDrawObjBase::ConvertLineStyle( SdrObject& rSdrObj, const XclObjLineData& rLineData ) const
+{
+ if( rLineData.IsAuto() )
+ {
+ XclObjLineData aAutoData;
+ aAutoData.mnAuto = 0;
+ ConvertLineStyle( rSdrObj, aAutoData );
+ }
+ else
+ {
+ long nLineWidth = 35 * ::std::min( rLineData.mnWidth, EXC_OBJ_LINE_THICK );
+ rSdrObj.SetMergedItem( XLineWidthItem( nLineWidth ) );
+ rSdrObj.SetMergedItem( XLineColorItem( EMPTY_STRING, GetPalette().GetColor( rLineData.mnColorIdx ) ) );
+ rSdrObj.SetMergedItem( XLineJointItem( XLINEJOINT_MITER ) );
+
+ sal_uLong nDotLen = ::std::max< sal_uLong >( 70 * rLineData.mnWidth, 35 );
+ sal_uLong nDashLen = 3 * nDotLen;
+ sal_uLong nDist = 2 * nDotLen;
+
+ switch( rLineData.mnStyle )
+ {
+ default:
+ case EXC_OBJ_LINE_SOLID:
+ rSdrObj.SetMergedItem( XLineStyleItem( XLINE_SOLID ) );
+ break;
+ case EXC_OBJ_LINE_DASH:
+ rSdrObj.SetMergedItem( XLineStyleItem( XLINE_DASH ) );
+ rSdrObj.SetMergedItem( XLineDashItem( EMPTY_STRING, XDash( XDASH_RECT, 0, nDotLen, 1, nDashLen, nDist ) ) );
+ break;
+ case EXC_OBJ_LINE_DOT:
+ rSdrObj.SetMergedItem( XLineStyleItem( XLINE_DASH ) );
+ rSdrObj.SetMergedItem( XLineDashItem( EMPTY_STRING, XDash( XDASH_RECT, 1, nDotLen, 0, nDashLen, nDist ) ) );
+ break;
+ case EXC_OBJ_LINE_DASHDOT:
+ rSdrObj.SetMergedItem( XLineStyleItem( XLINE_DASH ) );
+ rSdrObj.SetMergedItem( XLineDashItem( EMPTY_STRING, XDash( XDASH_RECT, 1, nDotLen, 1, nDashLen, nDist ) ) );
+ break;
+ case EXC_OBJ_LINE_DASHDOTDOT:
+ rSdrObj.SetMergedItem( XLineStyleItem( XLINE_DASH ) );
+ rSdrObj.SetMergedItem( XLineDashItem( EMPTY_STRING, XDash( XDASH_RECT, 2, nDotLen, 1, nDashLen, nDist ) ) );
+ break;
+ case EXC_OBJ_LINE_MEDTRANS:
+ rSdrObj.SetMergedItem( XLineStyleItem( XLINE_SOLID ) );
+ rSdrObj.SetMergedItem( XLineTransparenceItem( 50 ) );
+ break;
+ case EXC_OBJ_LINE_DARKTRANS:
+ rSdrObj.SetMergedItem( XLineStyleItem( XLINE_SOLID ) );
+ rSdrObj.SetMergedItem( XLineTransparenceItem( 25 ) );
+ break;
+ case EXC_OBJ_LINE_LIGHTTRANS:
+ rSdrObj.SetMergedItem( XLineStyleItem( XLINE_SOLID ) );
+ rSdrObj.SetMergedItem( XLineTransparenceItem( 75 ) );
+ break;
+ case EXC_OBJ_LINE_NONE:
+ rSdrObj.SetMergedItem( XLineStyleItem( XLINE_NONE ) );
+ break;
+ }
+ }
+}
+
+void XclImpDrawObjBase::ConvertFillStyle( SdrObject& rSdrObj, const XclObjFillData& rFillData ) const
+{
+ if( rFillData.IsAuto() )
+ {
+ XclObjFillData aAutoData;
+ aAutoData.mnAuto = 0;
+ ConvertFillStyle( rSdrObj, aAutoData );
+ }
+ else if( rFillData.mnPattern == EXC_PATT_NONE )
+ {
+ rSdrObj.SetMergedItem( XFillStyleItem( XFILL_NONE ) );
+ }
+ else
+ {
+ Color aPattColor = GetPalette().GetColor( rFillData.mnPattColorIdx );
+ Color aBackColor = GetPalette().GetColor( rFillData.mnBackColorIdx );
+ if( (rFillData.mnPattern == EXC_PATT_SOLID) || (aPattColor == aBackColor) )
+ {
+ rSdrObj.SetMergedItem( XFillStyleItem( XFILL_SOLID ) );
+ rSdrObj.SetMergedItem( XFillColorItem( EMPTY_STRING, aPattColor ) );
+ }
+ else
+ {
+ static const sal_uInt8 sppnPatterns[][ 8 ] =
+ {
+ { 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 },
+ { 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD },
+ { 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22 },
+ { 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00 },
+ { 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC },
+ { 0x33, 0x66, 0xCC, 0x99, 0x33, 0x66, 0xCC, 0x99 },
+ { 0xCC, 0x66, 0x33, 0x99, 0xCC, 0x66, 0x33, 0x99 },
+ { 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33 },
+ { 0xCC, 0xFF, 0x33, 0xFF, 0xCC, 0xFF, 0x33, 0xFF },
+ { 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 },
+ { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 },
+ { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 },
+ { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 },
+ { 0xFF, 0x11, 0x11, 0x11, 0xFF, 0x11, 0x11, 0x11 },
+ { 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11 },
+ { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 },
+ { 0x80, 0x00, 0x08, 0x00, 0x80, 0x00, 0x08, 0x00 }
+ };
+ const sal_uInt8* const pnPattern = sppnPatterns[ ::std::min< size_t >( rFillData.mnPattern - 2, SAL_N_ELEMENTS( sppnPatterns ) ) ];
+ // create 2-colored 8x8 DIB
+ SvMemoryStream aMemStrm;
+ aMemStrm << sal_uInt32( 12 ) << sal_Int16( 8 ) << sal_Int16( 8 ) << sal_uInt16( 1 ) << sal_uInt16( 1 );
+ aMemStrm << sal_uInt8( 0xFF ) << sal_uInt8( 0xFF ) << sal_uInt8( 0xFF );
+ aMemStrm << sal_uInt8( 0x00 ) << sal_uInt8( 0x00 ) << sal_uInt8( 0x00 );
+ for( size_t nIdx = 0; nIdx < 8; ++nIdx )
+ aMemStrm << sal_uInt32( pnPattern[ nIdx ] ); // 32-bit little-endian
+ aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
+ Bitmap aBitmap;
+ aBitmap.Read( aMemStrm, false );
+ XOBitmap aXOBitmap( aBitmap );
+ aXOBitmap.Bitmap2Array();
+ aXOBitmap.SetBitmapType( XBITMAP_8X8 );
+ if( aXOBitmap.GetBackgroundColor().GetColor() == COL_BLACK )
+ ::std::swap( aPattColor, aBackColor );
+ aXOBitmap.SetPixelColor( aPattColor );
+ aXOBitmap.SetBackgroundColor( aBackColor );
+ rSdrObj.SetMergedItem( XFillStyleItem( XFILL_BITMAP ) );
+ rSdrObj.SetMergedItem( XFillBitmapItem( EMPTY_STRING, aXOBitmap ) );
+ }
+ }
+}
+
+void XclImpDrawObjBase::ConvertFrameStyle( SdrObject& rSdrObj, sal_uInt16 nFrameFlags ) const
+{
+ if( ::get_flag( nFrameFlags, EXC_OBJ_FRAME_SHADOW ) )
+ {
+ rSdrObj.SetMergedItem( SdrShadowItem( sal_True ) );
+ rSdrObj.SetMergedItem( SdrShadowXDistItem( 35 ) );
+ rSdrObj.SetMergedItem( SdrShadowYDistItem( 35 ) );
+ rSdrObj.SetMergedItem( SdrShadowColorItem( EMPTY_STRING, GetPalette().GetColor( EXC_COLOR_WINDOWTEXT ) ) );
+ }
+}
+
+Color XclImpDrawObjBase::GetSolidLineColor( const XclObjLineData& rLineData ) const
+{
+ Color aColor( COL_TRANSPARENT );
+ if( rLineData.IsAuto() )
+ {
+ XclObjLineData aAutoData;
+ aAutoData.mnAuto = 0;
+ aColor = GetSolidLineColor( aAutoData );
+ }
+ else if( rLineData.mnStyle != EXC_OBJ_LINE_NONE )
+ {
+ aColor = GetPalette().GetColor( rLineData.mnColorIdx );
+ }
+ return aColor;
+}
+
+Color XclImpDrawObjBase::GetSolidFillColor( const XclObjFillData& rFillData ) const
+{
+ Color aColor( COL_TRANSPARENT );
+ if( rFillData.IsAuto() )
+ {
+ XclObjFillData aAutoData;
+ aAutoData.mnAuto = 0;
+ aColor = GetSolidFillColor( aAutoData );
+ }
+ else if( rFillData.mnPattern != EXC_PATT_NONE )
+ {
+ Color aPattColor = GetPalette().GetColor( rFillData.mnPattColorIdx );
+ Color aBackColor = GetPalette().GetColor( rFillData.mnBackColorIdx );
+ aColor = XclTools::GetPatternColor( aPattColor, aBackColor, rFillData.mnPattern );
+ }
+ return aColor;
+}
+
+void XclImpDrawObjBase::DoReadObj3( XclImpStream&, sal_uInt16 )
+{
+}
+
+void XclImpDrawObjBase::DoReadObj4( XclImpStream&, sal_uInt16 )
+{
+}
+
+void XclImpDrawObjBase::DoReadObj5( XclImpStream&, sal_uInt16, sal_uInt16 )
+{
+}
+
+void XclImpDrawObjBase::DoReadObj8SubRec( XclImpStream&, sal_uInt16, sal_uInt16 )
+{
+}
+
+sal_Size XclImpDrawObjBase::DoGetProgressSize() const
+{
+ return 1;
+}
+
+SdrObject* XclImpDrawObjBase::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& ) const
+{
+ rDffConv.Progress( GetProgressSize() );
+ return 0;
+}
+
+void XclImpDrawObjBase::DoPreProcessSdrObj( XclImpDffConverter&, SdrObject& ) const
+{
+ // trace if object is not printable
+ if( !IsPrintable() )
+ GetTracer().TraceObjectNotPrintable();
+}
+
+void XclImpDrawObjBase::DoPostProcessSdrObj( XclImpDffConverter&, SdrObject& ) const
+{
+}
+
+void XclImpDrawObjBase::ImplReadObj3( XclImpStream& rStrm )
+{
+ // back to offset 4 (ignore object count field)
+ rStrm.Seek( 4 );
+
+ sal_uInt16 nObjFlags, nMacroSize;
+ rStrm >> mnObjType >> mnObjId >> nObjFlags >> maAnchor >> nMacroSize;
+ rStrm.Ignore( 2 );
+
+ mbHasAnchor = true;
+ mbHidden = ::get_flag( nObjFlags, EXC_OBJ_HIDDEN );
+ mbVisible = ::get_flag( nObjFlags, EXC_OBJ_VISIBLE );
+ DoReadObj3( rStrm, nMacroSize );
+}
+
+void XclImpDrawObjBase::ImplReadObj4( XclImpStream& rStrm )
+{
+ // back to offset 4 (ignore object count field)
+ rStrm.Seek( 4 );
+
+ sal_uInt16 nObjFlags, nMacroSize;
+ rStrm >> mnObjType >> mnObjId >> nObjFlags >> maAnchor >> nMacroSize;
+ rStrm.Ignore( 2 );
+
+ mbHasAnchor = true;
+ mbHidden = ::get_flag( nObjFlags, EXC_OBJ_HIDDEN );
+ mbVisible = ::get_flag( nObjFlags, EXC_OBJ_VISIBLE );
+ mbPrintable = ::get_flag( nObjFlags, EXC_OBJ_PRINTABLE );
+ DoReadObj4( rStrm, nMacroSize );
+}
+
+void XclImpDrawObjBase::ImplReadObj5( XclImpStream& rStrm )
+{
+ // back to offset 4 (ignore object count field)
+ rStrm.Seek( 4 );
+
+ sal_uInt16 nObjFlags, nMacroSize, nNameLen;
+ rStrm >> mnObjType >> mnObjId >> nObjFlags >> maAnchor >> nMacroSize;
+ rStrm.Ignore( 2 );
+ rStrm >> nNameLen;
+ rStrm.Ignore( 2 );
+
+ mbHasAnchor = true;
+ mbHidden = ::get_flag( nObjFlags, EXC_OBJ_HIDDEN );
+ mbVisible = ::get_flag( nObjFlags, EXC_OBJ_VISIBLE );
+ mbPrintable = ::get_flag( nObjFlags, EXC_OBJ_PRINTABLE );
+ DoReadObj5( rStrm, nNameLen, nMacroSize );
+}
+
+void XclImpDrawObjBase::ImplReadObj8( XclImpStream& rStrm )
+{
+ // back to beginning
+ rStrm.Seek( EXC_REC_SEEK_TO_BEGIN );
+
+ bool bLoop = true;
+ while( bLoop && (rStrm.GetRecLeft() >= 4) )
+ {
+ sal_uInt16 nSubRecId, nSubRecSize;
+ rStrm >> nSubRecId >> nSubRecSize;
+ rStrm.PushPosition();
+ // sometimes the last subrecord has an invalid length (OBJLBSDATA) -> min()
+ nSubRecSize = static_cast< sal_uInt16 >( ::std::min< sal_Size >( nSubRecSize, rStrm.GetRecLeft() ) );
+
+ switch( nSubRecId )
+ {
+ case EXC_ID_OBJCMO:
+ DBG_ASSERT( rStrm.GetRecPos() == 4, "XclImpDrawObjBase::ImplReadObj8 - unexpected OBJCMO subrecord" );
+ if( (rStrm.GetRecPos() == 4) && (nSubRecSize >= 6) )
+ {
+ sal_uInt16 nObjFlags;
+ rStrm >> mnObjType >> mnObjId >> nObjFlags;
+ mbPrintable = ::get_flag( nObjFlags, EXC_OBJCMO_PRINTABLE );
+ }
+ break;
+ case EXC_ID_OBJMACRO:
+ ReadMacro8( rStrm );
+ break;
+ case EXC_ID_OBJEND:
+ bLoop = false;
+ break;
+ default:
+ DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
+ }
+
+ rStrm.PopPosition();
+ rStrm.Ignore( nSubRecSize );
+ }
+
+ /* Call DoReadObj8SubRec() with EXC_ID_OBJEND for further stream
+ processing (e.g. charts), even if the OBJEND subrecord is missing. */
+ DoReadObj8SubRec( rStrm, EXC_ID_OBJEND, 0 );
+
+ /* Pictures that Excel reads from BIFF5 and writes to BIFF8 still have the
+ IMGDATA record following the OBJ record (but they use the image data
+ stored in DFF). The IMGDATA record may be continued by several CONTINUE
+ records. But the last CONTINUE record may be in fact an MSODRAWING
+ record that contains the DFF data of the next drawing object! So we
+ have to skip just enough CONTINUE records to look at the next
+ MSODRAWING/CONTINUE record. */
+ if( (rStrm.GetNextRecId() == EXC_ID3_IMGDATA) && rStrm.StartNextRecord() )
+ {
+ sal_uInt32 nDataSize;
+ rStrm.Ignore( 4 );
+ rStrm >> nDataSize;
+ nDataSize -= rStrm.GetRecLeft();
+ // skip following CONTINUE records until IMGDATA ends
+ while( (nDataSize > 0) && (rStrm.GetNextRecId() == EXC_ID_CONT) && rStrm.StartNextRecord() )
+ {
+ DBG_ASSERT( nDataSize >= rStrm.GetRecLeft(), "XclImpDrawObjBase::ImplReadObj8 - CONTINUE too long" );
+ nDataSize -= ::std::min< sal_uInt32 >( rStrm.GetRecLeft(), nDataSize );
+ }
+ DBG_ASSERT( nDataSize == 0, "XclImpDrawObjBase::ImplReadObj8 - missing CONTINUE records" );
+ // next record may be MSODRAWING or CONTINUE or anything else
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpDrawObjVector::InsertGrouped( XclImpDrawObjRef xDrawObj )
+{
+ if( !empty() )
+ if( XclImpGroupObj* pGroupObj = dynamic_cast< XclImpGroupObj* >( back().get() ) )
+ if( pGroupObj->TryInsert( xDrawObj ) )
+ return;
+ push_back( xDrawObj );
+}
+
+sal_Size XclImpDrawObjVector::GetProgressSize() const
+{
+ sal_Size nProgressSize = 0;
+ for( const_iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
+ nProgressSize += (*aIt)->GetProgressSize();
+ return nProgressSize;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpPhObj::XclImpPhObj( const XclImpRoot& rRoot ) :
+ XclImpDrawObjBase( rRoot )
+{
+ SetProcessSdrObj( false );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpGroupObj::XclImpGroupObj( const XclImpRoot& rRoot ) :
+ XclImpDrawObjBase( rRoot ),
+ mnFirstUngrouped( 0 )
+{
+}
+
+bool XclImpGroupObj::TryInsert( XclImpDrawObjRef xDrawObj )
+{
+ if( xDrawObj->GetObjId() == mnFirstUngrouped )
+ return false;
+ // insert into own list or into nested group
+ maChildren.InsertGrouped( xDrawObj );
+ return true;
+}
+
+void XclImpGroupObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ rStrm.Ignore( 4 );
+ rStrm >> mnFirstUngrouped;
+ rStrm.Ignore( 16 );
+ ReadMacro3( rStrm, nMacroSize );
+}
+
+void XclImpGroupObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ rStrm.Ignore( 4 );
+ rStrm >> mnFirstUngrouped;
+ rStrm.Ignore( 16 );
+ ReadMacro4( rStrm, nMacroSize );
+}
+
+void XclImpGroupObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+ rStrm.Ignore( 4 );
+ rStrm >> mnFirstUngrouped;
+ rStrm.Ignore( 16 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, nMacroSize );
+}
+
+sal_Size XclImpGroupObj::DoGetProgressSize() const
+{
+ return XclImpDrawObjBase::DoGetProgressSize() + maChildren.GetProgressSize();
+}
+
+SdrObject* XclImpGroupObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& /*rAnchorRect*/ ) const
+{
+ TSdrObjectPtr< SdrObjGroup > xSdrObj( new SdrObjGroup );
+ // child objects in BIFF2-BIFF5 have absolute size, not needed to pass own anchor rectangle
+ SdrObjList& rObjList = *xSdrObj->GetSubList(); // SdrObjGroup always returns existing sublist
+ for( XclImpDrawObjVector::const_iterator aIt = maChildren.begin(), aEnd = maChildren.end(); aIt != aEnd; ++aIt )
+ rDffConv.ProcessObject( rObjList, **aIt );
+ rDffConv.Progress();
+ return xSdrObj.release();
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpLineObj::XclImpLineObj( const XclImpRoot& rRoot ) :
+ XclImpDrawObjBase( rRoot ),
+ mnArrows( 0 ),
+ mnStartPoint( EXC_OBJ_LINE_TL )
+{
+ SetAreaObj( false );
+}
+
+void XclImpLineObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ rStrm >> maLineData >> mnArrows >> mnStartPoint;
+ rStrm.Ignore( 1 );
+ ReadMacro3( rStrm, nMacroSize );
+}
+
+void XclImpLineObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ rStrm >> maLineData >> mnArrows >> mnStartPoint;
+ rStrm.Ignore( 1 );
+ ReadMacro4( rStrm, nMacroSize );
+}
+
+void XclImpLineObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+ rStrm >> maLineData >> mnArrows >> mnStartPoint;
+ rStrm.Ignore( 1 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, nMacroSize );
+}
+
+SdrObject* XclImpLineObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& rAnchorRect ) const
+{
+ ::basegfx::B2DPolygon aB2DPolygon;
+ switch( mnStartPoint )
+ {
+ default:
+ case EXC_OBJ_LINE_TL:
+ aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Left(), rAnchorRect.Top() ) );
+ aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Right(), rAnchorRect.Bottom() ) );
+ break;
+ case EXC_OBJ_LINE_TR:
+ aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Right(), rAnchorRect.Top() ) );
+ aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Left(), rAnchorRect.Bottom() ) );
+ break;
+ case EXC_OBJ_LINE_BR:
+ aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Right(), rAnchorRect.Bottom() ) );
+ aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Left(), rAnchorRect.Top() ) );
+ break;
+ case EXC_OBJ_LINE_BL:
+ aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Left(), rAnchorRect.Bottom() ) );
+ aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Right(), rAnchorRect.Top() ) );
+ break;
+ }
+ SdrObjectPtr xSdrObj( new SdrPathObj( OBJ_LINE, ::basegfx::B2DPolyPolygon( aB2DPolygon ) ) );
+ ConvertLineStyle( *xSdrObj, maLineData );
+
+ // line ends
+ sal_uInt8 nArrowType = ::extract_value< sal_uInt8 >( mnArrows, 0, 4 );
+ bool bLineStart = false;
+ bool bLineEnd = false;
+ bool bFilled = false;
+ switch( nArrowType )
+ {
+ case EXC_OBJ_ARROW_OPEN: bLineStart = false; bLineEnd = true; bFilled = false; break;
+ case EXC_OBJ_ARROW_OPENBOTH: bLineStart = true; bLineEnd = true; bFilled = false; break;
+ case EXC_OBJ_ARROW_FILLED: bLineStart = false; bLineEnd = true; bFilled = true; break;
+ case EXC_OBJ_ARROW_FILLEDBOTH: bLineStart = true; bLineEnd = true; bFilled = true; break;
+ }
+ if( bLineStart || bLineEnd )
+ {
+ sal_uInt8 nArrowWidth = ::extract_value< sal_uInt8 >( mnArrows, 4, 4 );
+ double fArrowWidth = 3.0;
+ switch( nArrowWidth )
+ {
+ case EXC_OBJ_ARROW_NARROW: fArrowWidth = 2.0; break;
+ case EXC_OBJ_ARROW_MEDIUM: fArrowWidth = 3.0; break;
+ case EXC_OBJ_ARROW_WIDE: fArrowWidth = 5.0; break;
+ }
+
+ sal_uInt8 nArrowLength = ::extract_value< sal_uInt8 >( mnArrows, 8, 4 );
+ double fArrowLength = 3.0;
+ switch( nArrowLength )
+ {
+ case EXC_OBJ_ARROW_NARROW: fArrowLength = 2.5; break;
+ case EXC_OBJ_ARROW_MEDIUM: fArrowLength = 3.5; break;
+ case EXC_OBJ_ARROW_WIDE: fArrowLength = 6.0; break;
+ }
+
+ ::basegfx::B2DPolygon aArrowPoly;
+#define EXC_ARROW_POINT( x, y ) ::basegfx::B2DPoint( fArrowWidth * (x), fArrowLength * (y) )
+ if( bFilled )
+ {
+ aArrowPoly.append( EXC_ARROW_POINT( 0, 100 ) );
+ aArrowPoly.append( EXC_ARROW_POINT( 50, 0 ) );
+ aArrowPoly.append( EXC_ARROW_POINT( 100, 100 ) );
+ }
+ else
+ {
+ sal_uInt8 nLineWidth = ::limit_cast< sal_uInt8 >( maLineData.mnWidth, EXC_OBJ_LINE_THIN, EXC_OBJ_LINE_THICK );
+ aArrowPoly.append( EXC_ARROW_POINT( 50, 0 ) );
+ aArrowPoly.append( EXC_ARROW_POINT( 100, 100 - 3 * nLineWidth ) );
+ aArrowPoly.append( EXC_ARROW_POINT( 100 - 5 * nLineWidth, 100 ) );
+ aArrowPoly.append( EXC_ARROW_POINT( 50, 12 * nLineWidth ) );
+ aArrowPoly.append( EXC_ARROW_POINT( 5 * nLineWidth, 100 ) );
+ aArrowPoly.append( EXC_ARROW_POINT( 0, 100 - 3 * nLineWidth ) );
+ }
+#undef EXC_ARROW_POINT
+
+ ::basegfx::B2DPolyPolygon aArrowPolyPoly( aArrowPoly );
+ long nWidth = static_cast< long >( 125 * fArrowWidth );
+ if( bLineStart )
+ {
+ xSdrObj->SetMergedItem( XLineStartItem( EMPTY_STRING, aArrowPolyPoly ) );
+ xSdrObj->SetMergedItem( XLineStartWidthItem( nWidth ) );
+ xSdrObj->SetMergedItem( XLineStartCenterItem( false ) );
+ }
+ if( bLineEnd )
+ {
+ xSdrObj->SetMergedItem( XLineEndItem( EMPTY_STRING, aArrowPolyPoly ) );
+ xSdrObj->SetMergedItem( XLineEndWidthItem( nWidth ) );
+ xSdrObj->SetMergedItem( XLineEndCenterItem( false ) );
+ }
+ }
+ rDffConv.Progress();
+ return xSdrObj.release();
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpRectObj::XclImpRectObj( const XclImpRoot& rRoot ) :
+ XclImpDrawObjBase( rRoot ),
+ mnFrameFlags( 0 )
+{
+ SetAreaObj( true );
+}
+
+void XclImpRectObj::ReadFrameData( XclImpStream& rStrm )
+{
+ rStrm >> maFillData >> maLineData >> mnFrameFlags;
+}
+
+void XclImpRectObj::ConvertRectStyle( SdrObject& rSdrObj ) const
+{
+ ConvertLineStyle( rSdrObj, maLineData );
+ ConvertFillStyle( rSdrObj, maFillData );
+ ConvertFrameStyle( rSdrObj, mnFrameFlags );
+}
+
+void XclImpRectObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ ReadFrameData( rStrm );
+ ReadMacro3( rStrm, nMacroSize );
+}
+
+void XclImpRectObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ ReadFrameData( rStrm );
+ ReadMacro4( rStrm, nMacroSize );
+}
+
+void XclImpRectObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+ ReadFrameData( rStrm );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, nMacroSize );
+}
+
+SdrObject* XclImpRectObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& rAnchorRect ) const
+{
+ SdrObjectPtr xSdrObj( new SdrRectObj( rAnchorRect ) );
+ ConvertRectStyle( *xSdrObj );
+ rDffConv.Progress();
+ return xSdrObj.release();
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpOvalObj::XclImpOvalObj( const XclImpRoot& rRoot ) :
+ XclImpRectObj( rRoot )
+{
+}
+
+SdrObject* XclImpOvalObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& rAnchorRect ) const
+{
+ SdrObjectPtr xSdrObj( new SdrCircObj( OBJ_CIRC, rAnchorRect ) );
+ ConvertRectStyle( *xSdrObj );
+ rDffConv.Progress();
+ return xSdrObj.release();
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpArcObj::XclImpArcObj( const XclImpRoot& rRoot ) :
+ XclImpDrawObjBase( rRoot ),
+ mnQuadrant( EXC_OBJ_ARC_TR )
+{
+ SetAreaObj( false ); // arc may be 2-dimensional
+}
+
+void XclImpArcObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ rStrm >> maFillData >> maLineData >> mnQuadrant;
+ rStrm.Ignore( 1 );
+ ReadMacro3( rStrm, nMacroSize );
+}
+
+void XclImpArcObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ rStrm >> maFillData >> maLineData >> mnQuadrant;
+ rStrm.Ignore( 1 );
+ ReadMacro4( rStrm, nMacroSize );
+}
+
+void XclImpArcObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+ rStrm >> maFillData >> maLineData >> mnQuadrant;
+ rStrm.Ignore( 1 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, nMacroSize );
+}
+
+SdrObject* XclImpArcObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& rAnchorRect ) const
+{
+ Rectangle aNewRect = rAnchorRect;
+ long nStartAngle = 0;
+ long nEndAngle = 0;
+ switch( mnQuadrant )
+ {
+ default:
+ case EXC_OBJ_ARC_TR:
+ nStartAngle = 0;
+ nEndAngle = 9000;
+ aNewRect.Left() -= rAnchorRect.GetWidth();
+ aNewRect.Bottom() += rAnchorRect.GetHeight();
+ break;
+ case EXC_OBJ_ARC_TL:
+ nStartAngle = 9000;
+ nEndAngle = 18000;
+ aNewRect.Right() += rAnchorRect.GetWidth();
+ aNewRect.Bottom() += rAnchorRect.GetHeight();
+ break;
+ case EXC_OBJ_ARC_BL:
+ nStartAngle = 18000;
+ nEndAngle = 27000;
+ aNewRect.Right() += rAnchorRect.GetWidth();
+ aNewRect.Top() -= rAnchorRect.GetHeight();
+ break;
+ case EXC_OBJ_ARC_BR:
+ nStartAngle = 27000;
+ nEndAngle = 0;
+ aNewRect.Left() -= rAnchorRect.GetWidth();
+ aNewRect.Top() -= rAnchorRect.GetHeight();
+ break;
+ }
+ SdrObjKind eObjKind = maFillData.IsFilled() ? OBJ_SECT : OBJ_CARC;
+ SdrObjectPtr xSdrObj( new SdrCircObj( eObjKind, aNewRect, nStartAngle, nEndAngle ) );
+ ConvertFillStyle( *xSdrObj, maFillData );
+ ConvertLineStyle( *xSdrObj, maLineData );
+ rDffConv.Progress();
+ return xSdrObj.release();
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpPolygonObj::XclImpPolygonObj( const XclImpRoot& rRoot ) :
+ XclImpRectObj( rRoot ),
+ mnPolyFlags( 0 ),
+ mnPointCount( 0 )
+{
+ SetAreaObj( false ); // polygon may be 2-dimensional
+}
+
+void XclImpPolygonObj::ReadCoordList( XclImpStream& rStrm )
+{
+ if( (rStrm.GetNextRecId() == EXC_ID_COORDLIST) && rStrm.StartNextRecord() )
+ {
+ DBG_ASSERT( rStrm.GetRecLeft() / 4 == mnPointCount, "XclImpPolygonObj::ReadCoordList - wrong polygon point count" );
+ while( rStrm.GetRecLeft() >= 4 )
+ {
+ sal_uInt16 nX, nY;
+ rStrm >> nX >> nY;
+ maCoords.push_back( Point( nX, nY ) );
+ }
+ }
+}
+
+void XclImpPolygonObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ ReadFrameData( rStrm );
+ rStrm >> mnPolyFlags;
+ rStrm.Ignore( 10 );
+ rStrm >> mnPointCount;
+ rStrm.Ignore( 8 );
+ ReadMacro4( rStrm, nMacroSize );
+ ReadCoordList( rStrm );
+}
+
+void XclImpPolygonObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+ ReadFrameData( rStrm );
+ rStrm >> mnPolyFlags;
+ rStrm.Ignore( 10 );
+ rStrm >> mnPointCount;
+ rStrm.Ignore( 8 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, nMacroSize );
+ ReadCoordList( rStrm );
+}
+
+namespace {
+
+::basegfx::B2DPoint lclGetPolyPoint( const Rectangle& rAnchorRect, const Point& rPoint )
+{
+ return ::basegfx::B2DPoint(
+ rAnchorRect.Left() + static_cast< sal_Int32 >( ::std::min< double >( rPoint.X(), 16384.0 ) / 16384.0 * rAnchorRect.GetWidth() + 0.5 ),
+ rAnchorRect.Top() + static_cast< sal_Int32 >( ::std::min< double >( rPoint.Y(), 16384.0 ) / 16384.0 * rAnchorRect.GetHeight() + 0.5 ) );
+}
+
+} // namespace
+
+SdrObject* XclImpPolygonObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& rAnchorRect ) const
+{
+ SdrObjectPtr xSdrObj;
+ if( maCoords.size() >= 2 )
+ {
+ // create the polygon
+ ::basegfx::B2DPolygon aB2DPolygon;
+ for( PointVector::const_iterator aIt = maCoords.begin(), aEnd = maCoords.end(); aIt != aEnd; ++aIt )
+ aB2DPolygon.append( lclGetPolyPoint( rAnchorRect, *aIt ) );
+ // close polygon if specified
+ if( ::get_flag( mnPolyFlags, EXC_OBJ_POLY_CLOSED ) && (maCoords.front() != maCoords.back()) )
+ aB2DPolygon.append( lclGetPolyPoint( rAnchorRect, maCoords.front() ) );
+ // create the SdrObject
+ SdrObjKind eObjKind = maFillData.IsFilled() ? OBJ_PATHPOLY : OBJ_PATHPLIN;
+ xSdrObj.reset( new SdrPathObj( eObjKind, ::basegfx::B2DPolyPolygon( aB2DPolygon ) ) );
+ ConvertRectStyle( *xSdrObj );
+ }
+ rDffConv.Progress();
+ return xSdrObj.release();
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpObjTextData::ReadByteString( XclImpStream& rStrm )
+{
+ mxString.reset();
+ if( maData.mnTextLen > 0 )
+ {
+ mxString.reset( new XclImpString( rStrm.ReadRawByteString( maData.mnTextLen ) ) );
+ // skip padding byte for word boundaries
+ if( rStrm.GetRecPos() & 1 ) rStrm.Ignore( 1 );
+ }
+}
+
+void XclImpObjTextData::ReadFormats( XclImpStream& rStrm )
+{
+ if( mxString )
+ mxString->ReadObjFormats( rStrm, maData.mnFormatSize );
+ else
+ rStrm.Ignore( maData.mnFormatSize );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpTextObj::XclImpTextObj( const XclImpRoot& rRoot ) :
+ XclImpRectObj( rRoot )
+{
+}
+
+void XclImpTextObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ ReadFrameData( rStrm );
+ maTextData.maData.ReadObj3( rStrm );
+ ReadMacro3( rStrm, nMacroSize );
+ maTextData.ReadByteString( rStrm );
+ maTextData.ReadFormats( rStrm );
+}
+
+void XclImpTextObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ ReadFrameData( rStrm );
+ maTextData.maData.ReadObj3( rStrm );
+ ReadMacro4( rStrm, nMacroSize );
+ maTextData.ReadByteString( rStrm );
+ maTextData.ReadFormats( rStrm );
+}
+
+void XclImpTextObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+ ReadFrameData( rStrm );
+ maTextData.maData.ReadObj5( rStrm );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, nMacroSize );
+ maTextData.ReadByteString( rStrm );
+ rStrm.Ignore( maTextData.maData.mnLinkSize ); // ignore text link formula
+ maTextData.ReadFormats( rStrm );
+}
+
+SdrObject* XclImpTextObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& rAnchorRect ) const
+{
+ TSdrObjectPtr< SdrObjCustomShape > xSdrObj( new SdrObjCustomShape );
+ xSdrObj->NbcSetSnapRect( rAnchorRect );
+ OUString aRectType = CREATE_OUSTRING( "rectangle" );
+ xSdrObj->MergeDefaultAttributes( &aRectType );
+ ConvertRectStyle( *xSdrObj );
+ sal_Bool bAutoSize = ::get_flag( maTextData.maData.mnFlags, EXC_OBJ_TEXT_AUTOSIZE );
+ xSdrObj->SetMergedItem( SdrTextAutoGrowWidthItem( bAutoSize ) );
+ xSdrObj->SetMergedItem( SdrTextAutoGrowHeightItem( bAutoSize ) );
+ xSdrObj->SetMergedItem( SdrTextWordWrapItem( sal_True ) );
+ rDffConv.Progress();
+ return xSdrObj.release();
+}
+
+void XclImpTextObj::DoPreProcessSdrObj( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
+{
+ // set text data
+ if( SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( &rSdrObj ) )
+ {
+ if( maTextData.mxString )
+ {
+ if( maTextData.mxString->IsRich() )
+ {
+ // rich text
+ ::std::auto_ptr< EditTextObject > xEditObj(
+ XclImpStringHelper::CreateTextObject( GetRoot(), *maTextData.mxString ) );
+ OutlinerParaObject* pOutlineObj = new OutlinerParaObject( *xEditObj );
+ pOutlineObj->SetOutlinerMode( OUTLINERMODE_TEXTOBJECT );
+ // text object takes ownership of the outliner object
+ pTextObj->NbcSetOutlinerParaObject( pOutlineObj );
+ }
+ else
+ {
+ // plain text
+ pTextObj->NbcSetText( maTextData.mxString->GetText() );
+ }
+
+ /* #i96858# Do not apply any formatting if there is no text.
+ SdrObjCustomShape::SetVerticalWriting (initiated from
+ SetMergedItem) calls SdrTextObj::ForceOutlinerParaObject which
+ ensures that we can erroneously write a ClientTextbox record
+ (with no content) while exporting to XLS, which can cause a
+ corrupted exported document. */
+
+ SvxAdjust eHorAlign = SVX_ADJUST_LEFT;
+ SdrTextVertAdjust eVerAlign = SDRTEXTVERTADJUST_TOP;
+
+ // orientation (this is only a fake, drawing does not support real text orientation)
+ namespace csst = ::com::sun::star::text;
+ csst::WritingMode eWriteMode = csst::WritingMode_LR_TB;
+ switch( maTextData.maData.mnOrient )
+ {
+ default:
+ case EXC_OBJ_ORIENT_NONE:
+ {
+ eWriteMode = csst::WritingMode_LR_TB;
+ switch( maTextData.maData.GetHorAlign() )
+ {
+ case EXC_OBJ_HOR_LEFT: eHorAlign = SVX_ADJUST_LEFT; break;
+ case EXC_OBJ_HOR_CENTER: eHorAlign = SVX_ADJUST_CENTER; break;
+ case EXC_OBJ_HOR_RIGHT: eHorAlign = SVX_ADJUST_RIGHT; break;
+ case EXC_OBJ_HOR_JUSTIFY: eHorAlign = SVX_ADJUST_BLOCK; break;
+ }
+ switch( maTextData.maData.GetVerAlign() )
+ {
+ case EXC_OBJ_VER_TOP: eVerAlign = SDRTEXTVERTADJUST_TOP; break;
+ case EXC_OBJ_VER_CENTER: eVerAlign = SDRTEXTVERTADJUST_CENTER; break;
+ case EXC_OBJ_VER_BOTTOM: eVerAlign = SDRTEXTVERTADJUST_BOTTOM; break;
+ case EXC_OBJ_VER_JUSTIFY: eVerAlign = SDRTEXTVERTADJUST_BLOCK; break;
+ }
+ }
+ break;
+
+ case EXC_OBJ_ORIENT_90CCW:
+ {
+ if( SdrObjCustomShape* pObjCustomShape = dynamic_cast< SdrObjCustomShape* >( &rSdrObj ) )
+ {
+ double fAngle = 180.0;
+ com::sun::star::beans::PropertyValue aTextRotateAngle;
+ aTextRotateAngle.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "TextRotateAngle" ) );
+ aTextRotateAngle.Value <<= fAngle;
+ SdrCustomShapeGeometryItem aGeometryItem((SdrCustomShapeGeometryItem&)pObjCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
+ aGeometryItem.SetPropertyValue( aTextRotateAngle );
+ pObjCustomShape->SetMergedItem( aGeometryItem );
+ }
+ eWriteMode = csst::WritingMode_TB_RL;
+ switch( maTextData.maData.GetHorAlign() )
+ {
+ case EXC_OBJ_HOR_LEFT: eVerAlign = SDRTEXTVERTADJUST_TOP; break;
+ case EXC_OBJ_HOR_CENTER: eVerAlign = SDRTEXTVERTADJUST_CENTER; break;
+ case EXC_OBJ_HOR_RIGHT: eVerAlign = SDRTEXTVERTADJUST_BOTTOM; break;
+ case EXC_OBJ_HOR_JUSTIFY: eVerAlign = SDRTEXTVERTADJUST_BLOCK; break;
+ }
+ MSO_Anchor eTextAnchor = (MSO_Anchor)rDffConv.GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
+ switch( eTextAnchor )
+ {
+ case mso_anchorTopCentered :
+ case mso_anchorMiddleCentered :
+ case mso_anchorBottomCentered :
+ {
+ eHorAlign = SVX_ADJUST_CENTER;
+ }
+ break;
+
+ default:
+ {
+ switch( maTextData.maData.GetVerAlign() )
+ {
+ case EXC_OBJ_VER_TOP: eHorAlign = SVX_ADJUST_RIGHT; break;
+ case EXC_OBJ_VER_CENTER: eHorAlign = SVX_ADJUST_CENTER; break;
+ case EXC_OBJ_VER_BOTTOM: eHorAlign = SVX_ADJUST_LEFT; break;
+ case EXC_OBJ_VER_JUSTIFY: eHorAlign = SVX_ADJUST_BLOCK; break;
+ }
+ }
+ }
+ }
+ break;
+
+ case EXC_OBJ_ORIENT_STACKED: // PASSTHROUGH INTENDED
+ {
+ // sj: STACKED is not supported, maybe it can be optimized here a bit
+ }
+ case EXC_OBJ_ORIENT_90CW:
+ {
+ eWriteMode = csst::WritingMode_TB_RL;
+ switch( maTextData.maData.GetHorAlign() )
+ {
+ case EXC_OBJ_HOR_LEFT: eVerAlign = SDRTEXTVERTADJUST_BOTTOM; break;
+ case EXC_OBJ_HOR_CENTER: eVerAlign = SDRTEXTVERTADJUST_CENTER; break;
+ case EXC_OBJ_HOR_RIGHT: eVerAlign = SDRTEXTVERTADJUST_TOP; break;
+ case EXC_OBJ_HOR_JUSTIFY: eVerAlign = SDRTEXTVERTADJUST_BLOCK; break;
+ }
+ MSO_Anchor eTextAnchor = (MSO_Anchor)rDffConv.GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
+ switch ( eTextAnchor )
+ {
+ case mso_anchorTopCentered :
+ case mso_anchorMiddleCentered :
+ case mso_anchorBottomCentered :
+ {
+ eHorAlign = SVX_ADJUST_CENTER;
+ }
+ break;
+
+ default:
+ {
+ switch( maTextData.maData.GetVerAlign() )
+ {
+ case EXC_OBJ_VER_TOP: eHorAlign = SVX_ADJUST_LEFT; break;
+ case EXC_OBJ_VER_CENTER: eHorAlign = SVX_ADJUST_CENTER; break;
+ case EXC_OBJ_VER_BOTTOM: eHorAlign = SVX_ADJUST_RIGHT; break;
+ case EXC_OBJ_VER_JUSTIFY: eHorAlign = SVX_ADJUST_BLOCK; break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ rSdrObj.SetMergedItem( SvxAdjustItem( eHorAlign, EE_PARA_JUST ) );
+ rSdrObj.SetMergedItem( SdrTextVertAdjustItem( eVerAlign ) );
+ rSdrObj.SetMergedItem( SvxWritingModeItem( eWriteMode, SDRATTR_TEXTDIRECTION ) );
+ }
+ }
+ // base class processing
+ XclImpRectObj::DoPreProcessSdrObj( rDffConv, rSdrObj );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpChartObj::XclImpChartObj( const XclImpRoot& rRoot, bool bOwnTab ) :
+ XclImpRectObj( rRoot ),
+ mbOwnTab( bOwnTab )
+{
+ SetSimpleMacro( false );
+ SetCustomDffObj( true );
+}
+
+void XclImpChartObj::ReadChartSubStream( XclImpStream& rStrm )
+{
+ if( mbOwnTab ? (rStrm.GetRecId() == EXC_ID5_BOF) : ((rStrm.GetNextRecId() == EXC_ID5_BOF) && rStrm.StartNextRecord()) )
+ {
+ sal_uInt16 nBofType;
+ rStrm.Seek( 2 );
+ rStrm >> nBofType;
+ DBG_ASSERT( nBofType == EXC_BOF_CHART, "XclImpChartObj::ReadChartSubStream - no chart BOF record" );
+
+ // read chart, even if BOF record contains wrong substream identifier
+ mxChart.reset( new XclImpChart( GetRoot(), mbOwnTab ) );
+ mxChart->ReadChartSubStream( rStrm );
+ if( mbOwnTab )
+ FinalizeTabChart();
+ }
+ else
+ {
+ DBG_ERRORFILE( "XclImpChartObj::ReadChartSubStream - missing chart substream" );
+ }
+}
+
+void XclImpChartObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ // read OBJ record and the following chart substream
+ ReadFrameData( rStrm );
+ rStrm.Ignore( 18 );
+ ReadMacro3( rStrm, nMacroSize );
+ // set frame format from OBJ record, it is used if chart itself is transparent
+ if( mxChart )
+ mxChart->UpdateObjFrame( maLineData, maFillData );
+}
+
+void XclImpChartObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ // read OBJ record and the following chart substream
+ ReadFrameData( rStrm );
+ rStrm.Ignore( 18 );
+ ReadMacro4( rStrm, nMacroSize );
+ // set frame format from OBJ record, it is used if chart itself is transparent
+ if( mxChart )
+ mxChart->UpdateObjFrame( maLineData, maFillData );
+}
+
+void XclImpChartObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+ // read OBJ record and the following chart substream
+ ReadFrameData( rStrm );
+ rStrm.Ignore( 18 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, nMacroSize );
+ ReadChartSubStream( rStrm );
+ // set frame format from OBJ record, it is used if chart itself is transparent
+ if( mxChart )
+ mxChart->UpdateObjFrame( maLineData, maFillData );
+}
+
+void XclImpChartObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 /*nSubRecSize*/ )
+{
+ // read the following chart substream
+ if( nSubRecId == EXC_ID_OBJEND )
+ {
+ // enable CONTINUE handling for the entire chart substream
+ rStrm.ResetRecord( true );
+ ReadChartSubStream( rStrm );
+ /* disable CONTINUE handling again to be able to read
+ following CONTINUE records as MSODRAWING records. */
+ rStrm.ResetRecord( false );
+ }
+}
+
+sal_Size XclImpChartObj::DoGetProgressSize() const
+{
+ return mxChart ? mxChart->GetProgressSize() : 1;
+}
+
+SdrObject* XclImpChartObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& rAnchorRect ) const
+{
+ SdrObjectPtr xSdrObj;
+ SfxObjectShell* pDocShell = GetDocShell();
+ if( rDffConv.SupportsOleObjects() && SvtModuleOptions().IsChart() && pDocShell && mxChart && !mxChart->IsPivotChart() )
+ {
+ // create embedded chart object
+ OUString aEmbObjName;
+ Reference< XEmbeddedObject > xEmbObj = pDocShell->GetEmbeddedObjectContainer().
+ CreateEmbeddedObject( SvGlobalName( SO3_SCH_CLASSID ).GetByteSequence(), aEmbObjName );
+
+ /* Set the size to the embedded object, this prevents that font sizes
+ of text objects are changed in the chart when the object is
+ inserted into the draw page. */
+ sal_Int64 nAspect = ::com::sun::star::embed::Aspects::MSOLE_CONTENT;
+ MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xEmbObj->getMapUnit( nAspect ) );
+ Size aSize( Window::LogicToLogic( rAnchorRect.GetSize(), MapMode( MAP_100TH_MM ), MapMode( aUnit ) ) );
+ ::com::sun::star::awt::Size aAwtSize( aSize.Width(), aSize.Height() );
+ xEmbObj->setVisualAreaSize( nAspect, aAwtSize );
+
+ // create the container OLE object
+ xSdrObj.reset( new SdrOle2Obj( svt::EmbeddedObjectRef( xEmbObj, nAspect ), aEmbObjName, rAnchorRect ) );
+ }
+
+ return xSdrObj.release();
+}
+
+void XclImpChartObj::DoPostProcessSdrObj( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
+{
+ const SdrOle2Obj* pSdrOleObj = dynamic_cast< const SdrOle2Obj* >( &rSdrObj );
+ if( mxChart && pSdrOleObj )
+ {
+ Reference< XEmbeddedObject > xEmbObj = pSdrOleObj->GetObjRef();
+ if( xEmbObj.is() && ::svt::EmbeddedObjectRef::TryRunningState( xEmbObj ) ) try
+ {
+ Reference< XEmbedPersist > xPersist( xEmbObj, UNO_QUERY_THROW );
+ Reference< XModel > xModel( xEmbObj->getComponent(), UNO_QUERY_THROW );
+ mxChart->Convert( xModel, rDffConv, xPersist->getEntryName(), rSdrObj.GetLogicRect() );
+ xPersist->storeOwn();
+ }
+ catch( Exception& )
+ {
+ }
+ }
+}
+
+void XclImpChartObj::FinalizeTabChart()
+{
+ /* #i44077# Calculate and store DFF anchor for sheet charts.
+ Needed to get used area if this chart is inserted as OLE object. */
+ DBG_ASSERT( mbOwnTab, "XclImpChartObj::FinalizeTabChart - not allowed for embedded chart objects" );
+
+ // set uninitialized page to landscape
+ if( !GetPageSettings().GetPageData().mbValid )
+ GetPageSettings().SetPaperSize( EXC_PAPERSIZE_DEFAULT, false );
+
+ // calculate size of the chart object
+ const XclPageData& rPageData = GetPageSettings().GetPageData();
+ Size aPaperSize = rPageData.GetScPaperSize();
+
+ long nWidth = XclTools::GetHmmFromTwips( aPaperSize.Width() );
+ long nHeight = XclTools::GetHmmFromTwips( aPaperSize.Height() );
+
+ // subtract page margins, give some more extra space
+ nWidth -= (XclTools::GetHmmFromInch( rPageData.mfLeftMargin + rPageData.mfRightMargin ) + 2000);
+ nHeight -= (XclTools::GetHmmFromInch( rPageData.mfTopMargin + rPageData.mfBottomMargin ) + 1000);
+
+ // print column/row headers?
+ if( rPageData.mbPrintHeadings )
+ {
+ nWidth -= 2000;
+ nHeight -= 1000;
+ }
+
+ // create the object anchor
+ XclObjAnchor aAnchor;
+ aAnchor.SetRect( GetRoot(), GetCurrScTab(), Rectangle( 1000, 500, nWidth, nHeight ), MAP_100TH_MM );
+ SetAnchor( aAnchor );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpNoteObj::XclImpNoteObj( const XclImpRoot& rRoot ) :
+ XclImpTextObj( rRoot ),
+ maScPos( ScAddress::INITIALIZE_INVALID ),
+ mnNoteFlags( 0 )
+{
+ SetSimpleMacro( false );
+ // caption object will be created manually
+ SetInsertSdrObj( false );
+}
+
+void XclImpNoteObj::SetNoteData( const ScAddress& rScPos, sal_uInt16 nNoteFlags )
+{
+ maScPos = rScPos;
+ mnNoteFlags = nNoteFlags;
+}
+
+void XclImpNoteObj::DoPreProcessSdrObj( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
+{
+ // create formatted text
+ XclImpTextObj::DoPreProcessSdrObj( rDffConv, rSdrObj );
+ OutlinerParaObject* pOutlinerObj = rSdrObj.GetOutlinerParaObject();
+ if( maScPos.IsValid() && pOutlinerObj )
+ {
+ // create cell note with all data from drawing object
+ ScNoteUtil::CreateNoteFromObjectData(
+ GetDoc(), maScPos,
+ rSdrObj.GetMergedItemSet().Clone(), // new object on heap expected
+ new OutlinerParaObject( *pOutlinerObj ), // new object on heap expected
+ rSdrObj.GetLogicRect(),
+ ::get_flag( mnNoteFlags, EXC_NOTE_VISIBLE ),
+ false );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpControlHelper::XclImpControlHelper( const XclImpRoot& rRoot, XclCtrlBindMode eBindMode ) :
+ mrRoot( rRoot ),
+ meBindMode( eBindMode )
+{
+}
+
+XclImpControlHelper::~XclImpControlHelper()
+{
+}
+
+SdrObject* XclImpControlHelper::CreateSdrObjectFromShape(
+ const Reference< XShape >& rxShape, const Rectangle& rAnchorRect ) const
+{
+ mxShape = rxShape;
+ SdrObjectPtr xSdrObj( SdrObject::getSdrObjectFromXShape( rxShape ) );
+ if( xSdrObj.is() )
+ {
+ xSdrObj->NbcSetSnapRect( rAnchorRect );
+ // #i30543# insert into control layer
+ xSdrObj->NbcSetLayer( SC_LAYER_CONTROLS );
+ }
+ return xSdrObj.release();
+}
+
+void XclImpControlHelper::ApplySheetLinkProps() const
+{
+
+ Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( mxShape );
+ if( !xCtrlModel.is() )
+ return;
+ ScfPropertySet aPropSet( xCtrlModel );
+
+ // sheet links
+ if( SfxObjectShell* pDocShell = mrRoot.GetDocShell() )
+ {
+ Reference< XMultiServiceFactory > xFactory( pDocShell->GetModel(), UNO_QUERY );
+ if( xFactory.is() )
+ {
+ // cell link
+ if( mxCellLink ) try
+ {
+ Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY_THROW );
+
+ // create argument sequence for createInstanceWithArguments()
+ CellAddress aApiAddress;
+ ScUnoConversion::FillApiAddress( aApiAddress, *mxCellLink );
+
+ NamedValue aValue;
+ aValue.Name = CREATE_OUSTRING( SC_UNONAME_BOUNDCELL );
+ aValue.Value <<= aApiAddress;
+
+ Sequence< Any > aArgs( 1 );
+ aArgs[ 0 ] <<= aValue;
+
+ // create the CellValueBinding instance and set at the control model
+ OUString aServiceName;
+ switch( meBindMode )
+ {
+ case EXC_CTRL_BINDCONTENT: aServiceName = CREATE_OUSTRING( SC_SERVICENAME_VALBIND ); break;
+ case EXC_CTRL_BINDPOSITION: aServiceName = CREATE_OUSTRING( SC_SERVICENAME_LISTCELLBIND ); break;
+ }
+ Reference< XValueBinding > xBinding(
+ xFactory->createInstanceWithArguments( aServiceName, aArgs ), UNO_QUERY_THROW );
+ xBindable->setValueBinding( xBinding );
+ }
+ catch( const Exception& )
+ {
+ }
+
+ // source range
+ if( mxSrcRange ) try
+ {
+ Reference< XListEntrySink > xEntrySink( xCtrlModel, UNO_QUERY_THROW );
+
+ // create argument sequence for createInstanceWithArguments()
+ CellRangeAddress aApiRange;
+ ScUnoConversion::FillApiRange( aApiRange, *mxSrcRange );
+
+ NamedValue aValue;
+ aValue.Name = CREATE_OUSTRING( SC_UNONAME_CELLRANGE );
+ aValue.Value <<= aApiRange;
+
+ Sequence< Any > aArgs( 1 );
+ aArgs[ 0 ] <<= aValue;
+
+ // create the EntrySource instance and set at the control model
+ Reference< XListEntrySource > xEntrySource( xFactory->createInstanceWithArguments(
+ CREATE_OUSTRING( SC_SERVICENAME_LISTSOURCE ), aArgs ), UNO_QUERY_THROW );
+ xEntrySink->setListEntrySource( xEntrySource );
+ }
+ catch( const Exception& )
+ {
+ }
+ }
+ }
+}
+
+void XclImpControlHelper::ProcessControl( const XclImpDrawObjBase& rDrawObj ) const
+{
+ Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( mxShape );
+ if( !xCtrlModel.is() )
+ return;
+
+ ApplySheetLinkProps();
+
+ ScfPropertySet aPropSet( xCtrlModel );
+
+ // #i51348# set object name at control model
+ aPropSet.SetStringProperty( CREATE_OUSTRING( "Name" ), rDrawObj.GetObjName() );
+
+ // control visible and printable?
+ aPropSet.SetBoolProperty( CREATE_OUSTRING( "EnableVisible" ), rDrawObj.IsVisible() );
+ aPropSet.SetBoolProperty( CREATE_OUSTRING( "Printable" ), rDrawObj.IsPrintable() );
+
+
+ // virtual call for type specific processing
+ DoProcessControl( aPropSet );
+}
+
+void XclImpControlHelper::ReadCellLinkFormula( XclImpStream& rStrm, bool bWithBoundSize )
+{
+ ScRangeList aScRanges;
+ ReadRangeList( aScRanges, rStrm, bWithBoundSize );
+ // Use first cell of first range
+ if ( !aScRanges.empty() )
+ {
+ const ScRange* pScRange = aScRanges.front();
+ mxCellLink.reset( new ScAddress( pScRange->aStart ) );
+ }
+}
+
+void XclImpControlHelper::ReadSourceRangeFormula( XclImpStream& rStrm, bool bWithBoundSize )
+{
+ ScRangeList aScRanges;
+ ReadRangeList( aScRanges, rStrm, bWithBoundSize );
+ // Use first range
+ if ( !aScRanges.empty() )
+ {
+ const ScRange* pScRange = aScRanges.front();
+ mxSrcRange.reset( new ScRange( *pScRange ) );
+ }
+}
+
+void XclImpControlHelper::DoProcessControl( ScfPropertySet& ) const
+{
+}
+
+void XclImpControlHelper::ReadRangeList( ScRangeList& rScRanges, XclImpStream& rStrm )
+{
+ XclTokenArray aXclTokArr;
+ aXclTokArr.ReadSize( rStrm );
+ rStrm.Ignore( 4 );
+ aXclTokArr.ReadArray( rStrm );
+ mrRoot.GetFormulaCompiler().CreateRangeList( rScRanges, EXC_FMLATYPE_CONTROL, aXclTokArr, rStrm );
+}
+
+void XclImpControlHelper::ReadRangeList( ScRangeList& rScRanges, XclImpStream& rStrm, bool bWithBoundSize )
+{
+ if( bWithBoundSize )
+ {
+ sal_uInt16 nSize;
+ rStrm >> nSize;
+ if( nSize > 0 )
+ {
+ rStrm.PushPosition();
+ ReadRangeList( rScRanges, rStrm );
+ rStrm.PopPosition();
+ rStrm.Ignore( nSize );
+ }
+ }
+ else
+ {
+ ReadRangeList( rScRanges, rStrm );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpTbxObjBase::XclImpTbxObjBase( const XclImpRoot& rRoot ) :
+ XclImpTextObj( rRoot ),
+ XclImpControlHelper( rRoot, EXC_CTRL_BINDPOSITION )
+{
+ SetSimpleMacro( false );
+ SetCustomDffObj( true );
+}
+
+namespace {
+
+void lclExtractColor( sal_uInt8& rnColorIdx, const DffPropSet& rDffPropSet, sal_uInt32 nPropId )
+{
+ if( rDffPropSet.IsProperty( nPropId ) )
+ {
+ sal_uInt32 nColor = rDffPropSet.GetPropertyValue( nPropId );
+ if( (nColor & 0xFF000000) == 0x08000000 )
+ rnColorIdx = ::extract_value< sal_uInt8 >( nColor, 0, 8 );
+ }
+}
+
+} // namespace
+
+void XclImpTbxObjBase::SetDffProperties( const DffPropSet& rDffPropSet )
+{
+ maFillData.mnPattern = rDffPropSet.GetPropertyBool( DFF_Prop_fFilled ) ? EXC_PATT_SOLID : EXC_PATT_NONE;
+ lclExtractColor( maFillData.mnBackColorIdx, rDffPropSet, DFF_Prop_fillBackColor );
+ lclExtractColor( maFillData.mnPattColorIdx, rDffPropSet, DFF_Prop_fillColor );
+ ::set_flag( maFillData.mnAuto, EXC_OBJ_LINE_AUTO, false );
+
+ maLineData.mnStyle = rDffPropSet.GetPropertyBool( DFF_Prop_fLine ) ? EXC_OBJ_LINE_SOLID : EXC_OBJ_LINE_NONE;
+ lclExtractColor( maLineData.mnColorIdx, rDffPropSet, DFF_Prop_lineColor );
+ ::set_flag( maLineData.mnAuto, EXC_OBJ_FILL_AUTO, false );
+}
+
+bool XclImpTbxObjBase::FillMacroDescriptor( ScriptEventDescriptor& rDescriptor ) const
+{
+ return XclControlHelper::FillMacroDescriptor( rDescriptor, DoGetEventType(), GetMacroName(), GetDocShell() );
+}
+
+void XclImpTbxObjBase::ConvertFont( ScfPropertySet& rPropSet ) const
+{
+ if( maTextData.mxString )
+ {
+ const XclFormatRunVec& rFormatRuns = maTextData.mxString->GetFormats();
+ if( rFormatRuns.empty() )
+ GetFontBuffer().WriteDefaultCtrlFontProperties( rPropSet );
+ else
+ GetFontBuffer().WriteFontProperties( rPropSet, EXC_FONTPROPSET_CONTROL, rFormatRuns.front().mnFontIdx );
+ }
+}
+
+void XclImpTbxObjBase::ConvertLabel( ScfPropertySet& rPropSet ) const
+{
+ if( maTextData.mxString )
+ {
+ String aLabel = maTextData.mxString->GetText();
+ if( maTextData.maData.mnShortcut > 0 )
+ {
+ xub_StrLen nPos = aLabel.Search( static_cast< sal_Unicode >( maTextData.maData.mnShortcut ) );
+ if( nPos != STRING_NOTFOUND )
+ aLabel.Insert( '~', nPos );
+ }
+ rPropSet.SetStringProperty( CREATE_OUSTRING( "Label" ), aLabel );
+ }
+ ConvertFont( rPropSet );
+}
+
+SdrObject* XclImpTbxObjBase::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& rAnchorRect ) const
+{
+ SdrObjectPtr xSdrObj( rDffConv.CreateSdrObject( *this, rAnchorRect ) );
+ rDffConv.Progress();
+ return xSdrObj.release();
+}
+
+void XclImpTbxObjBase::DoPreProcessSdrObj( XclImpDffConverter& /*rDffConv*/, SdrObject& /*rSdrObj*/ ) const
+{
+ // do not call DoPreProcessSdrObj() from base class (to skip text processing)
+ ProcessControl( *this );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpButtonObj::XclImpButtonObj( const XclImpRoot& rRoot ) :
+ XclImpTbxObjBase( rRoot )
+{
+}
+
+void XclImpButtonObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ // label and text formatting
+ ConvertLabel( rPropSet );
+
+ /* Horizontal text alignment. For unknown reason, the property type is a
+ simple sal_Int16 and not a com.sun.star.style.HorizontalAlignment. */
+ sal_Int16 nHorAlign = 1;
+ switch( maTextData.maData.GetHorAlign() )
+ {
+ case EXC_OBJ_HOR_LEFT: nHorAlign = 0; break;
+ case EXC_OBJ_HOR_CENTER: nHorAlign = 1; break;
+ case EXC_OBJ_HOR_RIGHT: nHorAlign = 2; break;
+ }
+ rPropSet.SetProperty( CREATE_OUSTRING( "Align" ), nHorAlign );
+
+ // vertical text alignment
+ namespace csss = ::com::sun::star::style;
+ csss::VerticalAlignment eVerAlign = csss::VerticalAlignment_MIDDLE;
+ switch( maTextData.maData.GetVerAlign() )
+ {
+ case EXC_OBJ_VER_TOP: eVerAlign = csss::VerticalAlignment_TOP; break;
+ case EXC_OBJ_VER_CENTER: eVerAlign = csss::VerticalAlignment_MIDDLE; break;
+ case EXC_OBJ_VER_BOTTOM: eVerAlign = csss::VerticalAlignment_BOTTOM; break;
+ }
+ rPropSet.SetProperty( CREATE_OUSTRING( "VerticalAlign" ), eVerAlign );
+
+ // always wrap text automatically
+ rPropSet.SetBoolProperty( CREATE_OUSTRING( "MultiLine" ), true );
+
+ // default button
+ bool bDefButton = ::get_flag( maTextData.maData.mnButtonFlags, EXC_OBJ_BUTTON_DEFAULT );
+ rPropSet.SetBoolProperty( CREATE_OUSTRING( "DefaultButton" ), bDefButton );
+
+ // button type (flags cannot be combined in OOo)
+ namespace cssa = ::com::sun::star::awt;
+ cssa::PushButtonType eButtonType = cssa::PushButtonType_STANDARD;
+ if( ::get_flag( maTextData.maData.mnButtonFlags, EXC_OBJ_BUTTON_CLOSE ) )
+ eButtonType = cssa::PushButtonType_OK;
+ else if( ::get_flag( maTextData.maData.mnButtonFlags, EXC_OBJ_BUTTON_CANCEL ) )
+ eButtonType = cssa::PushButtonType_CANCEL;
+ else if( ::get_flag( maTextData.maData.mnButtonFlags, EXC_OBJ_BUTTON_HELP ) )
+ eButtonType = cssa::PushButtonType_HELP;
+ // property type is short, not enum
+ rPropSet.SetProperty( CREATE_OUSTRING( "PushButtonType" ), sal_Int16( eButtonType ) );
+}
+
+OUString XclImpButtonObj::DoGetServiceName() const
+{
+ return CREATE_OUSTRING( "com.sun.star.form.component.CommandButton" );
+}
+
+XclTbxEventType XclImpButtonObj::DoGetEventType() const
+{
+ return EXC_TBX_EVENT_ACTION;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpCheckBoxObj::XclImpCheckBoxObj( const XclImpRoot& rRoot ) :
+ XclImpTbxObjBase( rRoot ),
+ mnState( EXC_OBJ_CHECKBOX_UNCHECKED ),
+ mnCheckBoxFlags( 0 )
+{
+}
+
+void XclImpCheckBoxObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
+{
+ ReadFrameData( rStrm );
+ rStrm.Ignore( 10 );
+ rStrm >> maTextData.maData.mnFlags;
+ rStrm.Ignore( 20 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, rStrm.ReaduInt16() ); // fist macro size invalid and unused
+ ReadCellLinkFormula( rStrm, true );
+ rStrm >> maTextData.maData.mnTextLen;
+ maTextData.ReadByteString( rStrm );
+ rStrm >> mnState >> maTextData.maData.mnShortcut >> maTextData.maData.mnShortcutEA >> mnCheckBoxFlags;
+}
+
+void XclImpCheckBoxObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
+{
+ switch( nSubRecId )
+ {
+ case EXC_ID_OBJCBLS:
+ // do not read EXC_ID_OBJCBLSDATA, not written by OOo Excel export
+ rStrm >> mnState;
+ rStrm.Ignore( 4 );
+ rStrm >> maTextData.maData.mnShortcut >> maTextData.maData.mnShortcutEA >> mnCheckBoxFlags;
+ break;
+ case EXC_ID_OBJCBLSFMLA:
+ ReadCellLinkFormula( rStrm, false );
+ break;
+ default:
+ XclImpTbxObjBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
+ }
+}
+
+void XclImpCheckBoxObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ // label and text formatting
+ ConvertLabel( rPropSet );
+
+ // state
+ bool bSupportsTristate = GetObjType() == EXC_OBJTYPE_CHECKBOX;
+ sal_Int16 nApiState = 0;
+ switch( mnState )
+ {
+ case EXC_OBJ_CHECKBOX_UNCHECKED: nApiState = 0; break;
+ case EXC_OBJ_CHECKBOX_CHECKED: nApiState = 1; break;
+ case EXC_OBJ_CHECKBOX_TRISTATE: nApiState = bSupportsTristate ? 2 : 1; break;
+ }
+ if( bSupportsTristate )
+ rPropSet.SetBoolProperty( CREATE_OUSTRING( "TriState" ), nApiState == 2 );
+ rPropSet.SetProperty( CREATE_OUSTRING( "DefaultState" ), nApiState );
+
+ // box style
+ namespace AwtVisualEffect = ::com::sun::star::awt::VisualEffect;
+ sal_Int16 nEffect = ::get_flagvalue( mnCheckBoxFlags, EXC_OBJ_CHECKBOX_FLAT, AwtVisualEffect::FLAT, AwtVisualEffect::LOOK3D );
+ rPropSet.SetProperty( CREATE_OUSTRING( "VisualEffect" ), nEffect );
+
+ // do not wrap text automatically
+ rPropSet.SetBoolProperty( CREATE_OUSTRING( "MultiLine" ), false );
+
+ // #i40279# always centered vertically
+ namespace csss = ::com::sun::star::style;
+ rPropSet.SetProperty( CREATE_OUSTRING( "VerticalAlign" ), csss::VerticalAlignment_MIDDLE );
+
+ // background color
+ if( maFillData.IsFilled() )
+ {
+ sal_Int32 nColor = static_cast< sal_Int32 >( GetSolidFillColor( maFillData ).GetColor() );
+ rPropSet.SetProperty( CREATE_OUSTRING( "BackgroundColor" ), nColor );
+ }
+}
+
+OUString XclImpCheckBoxObj::DoGetServiceName() const
+{
+ return CREATE_OUSTRING( "com.sun.star.form.component.CheckBox" );
+}
+
+XclTbxEventType XclImpCheckBoxObj::DoGetEventType() const
+{
+ return EXC_TBX_EVENT_ACTION;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpOptionButtonObj::XclImpOptionButtonObj( const XclImpRoot& rRoot ) :
+ XclImpCheckBoxObj( rRoot ),
+ mnNextInGroup( 0 ),
+ mnFirstInGroup( 1 )
+{
+}
+
+void XclImpOptionButtonObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
+{
+ ReadFrameData( rStrm );
+ rStrm.Ignore( 10 );
+ rStrm >> maTextData.maData.mnFlags;
+ rStrm.Ignore( 32 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, rStrm.ReaduInt16() ); // fist macro size invalid and unused
+ ReadCellLinkFormula( rStrm, true );
+ rStrm >> maTextData.maData.mnTextLen;
+ maTextData.ReadByteString( rStrm );
+ rStrm >> mnState >> maTextData.maData.mnShortcut >> maTextData.maData.mnShortcutEA;
+ rStrm >> mnCheckBoxFlags >> mnNextInGroup >> mnFirstInGroup;
+}
+
+void XclImpOptionButtonObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
+{
+ switch( nSubRecId )
+ {
+ case EXC_ID_OBJRBODATA:
+ rStrm >> mnNextInGroup >> mnFirstInGroup;
+ break;
+ default:
+ XclImpCheckBoxObj::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
+ }
+}
+
+void XclImpOptionButtonObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ XclImpCheckBoxObj::DoProcessControl( rPropSet );
+ // TODO: grouping
+ XclImpOptionButtonObj* pTbxObj = dynamic_cast< XclImpOptionButtonObj* >( GetObjectManager().GetSheetDrawing( GetTab() ).FindDrawObj( mnNextInGroup ).get() );
+ if ( ( pTbxObj && pTbxObj->mnFirstInGroup ) )
+ {
+ // Group has terminated
+ // traverse each RadioButton in group and
+ // a) apply the groupname
+ // b) propagate the linked cell from the lead radiobutton
+ // c) apply the correct Ref value
+ XclImpOptionButtonObj* pLeader = pTbxObj;
+ ;
+ sal_Int32 nRefVal = 1;
+ OSL_TRACE( "0x%x start group ", pLeader->GetObjId()/*.mnObjId */);
+ do
+ {
+
+ Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( pTbxObj->mxShape );
+ if ( xCtrlModel.is() )
+ {
+ ScfPropertySet aProps( xCtrlModel );
+ rtl::OUString sGroupName = rtl::OUString::valueOf( static_cast< sal_Int32 >( pLeader->GetDffShapeId() ) );
+
+ aProps.SetStringProperty( CREATE_OUSTRING( "GroupName" ), sGroupName );
+ aProps.SetStringProperty( CREATE_OUSTRING( "RefValue" ), rtl::OUString::valueOf( nRefVal++ ) );
+ if ( pLeader->HasCellLink() && !pTbxObj->HasCellLink() )
+ {
+ // propagate cell link info
+ pTbxObj->mxCellLink.reset( new ScAddress( *pLeader->mxCellLink.get() ) );
+ pTbxObj->ApplySheetLinkProps();
+ }
+ pTbxObj = dynamic_cast< XclImpOptionButtonObj* >( GetObjectManager().GetSheetDrawing( GetTab() ).FindDrawObj( pTbxObj->mnNextInGroup ).get() );
+ }
+ else
+ pTbxObj = NULL;
+ } while ( pTbxObj && !( pTbxObj->mnFirstInGroup == 1 ) );
+ }
+ else
+ {
+ // not the leader? try and find it
+ }
+}
+
+OUString XclImpOptionButtonObj::DoGetServiceName() const
+{
+ return CREATE_OUSTRING( "com.sun.star.form.component.RadioButton" );
+}
+
+XclTbxEventType XclImpOptionButtonObj::DoGetEventType() const
+{
+ return EXC_TBX_EVENT_ACTION;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpLabelObj::XclImpLabelObj( const XclImpRoot& rRoot ) :
+ XclImpTbxObjBase( rRoot )
+{
+}
+
+void XclImpLabelObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ // label and text formatting
+ ConvertLabel( rPropSet );
+
+ // text alignment (always top/left aligned)
+ rPropSet.SetProperty( CREATE_OUSTRING( "Align" ), sal_Int16( 0 ) );
+ namespace csss = ::com::sun::star::style;
+ rPropSet.SetProperty( CREATE_OUSTRING( "VerticalAlign" ), csss::VerticalAlignment_TOP );
+
+ // always wrap text automatically
+ rPropSet.SetBoolProperty( CREATE_OUSTRING( "MultiLine" ), true );
+}
+
+OUString XclImpLabelObj::DoGetServiceName() const
+{
+ return CREATE_OUSTRING( "com.sun.star.form.component.FixedText" );
+}
+
+XclTbxEventType XclImpLabelObj::DoGetEventType() const
+{
+ return EXC_TBX_EVENT_MOUSE;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpGroupBoxObj::XclImpGroupBoxObj( const XclImpRoot& rRoot ) :
+ XclImpTbxObjBase( rRoot ),
+ mnGroupBoxFlags( 0 )
+{
+}
+
+void XclImpGroupBoxObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
+{
+ ReadFrameData( rStrm );
+ rStrm.Ignore( 10 );
+ rStrm >> maTextData.maData.mnFlags;
+ rStrm.Ignore( 26 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, rStrm.ReaduInt16() ); // fist macro size invalid and unused
+ rStrm >> maTextData.maData.mnTextLen;
+ maTextData.ReadByteString( rStrm );
+ rStrm >> maTextData.maData.mnShortcut >> maTextData.maData.mnShortcutEA >> mnGroupBoxFlags;
+}
+
+void XclImpGroupBoxObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
+{
+ switch( nSubRecId )
+ {
+ case EXC_ID_OBJGBODATA:
+ rStrm >> maTextData.maData.mnShortcut >> maTextData.maData.mnShortcutEA >> mnGroupBoxFlags;
+ break;
+ default:
+ XclImpTbxObjBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
+ }
+}
+
+void XclImpGroupBoxObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ // label and text formatting
+ ConvertLabel( rPropSet );
+}
+
+OUString XclImpGroupBoxObj::DoGetServiceName() const
+{
+ return CREATE_OUSTRING( "com.sun.star.form.component.GroupBox" );
+}
+
+XclTbxEventType XclImpGroupBoxObj::DoGetEventType() const
+{
+ return EXC_TBX_EVENT_MOUSE;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpDialogObj::XclImpDialogObj( const XclImpRoot& rRoot ) :
+ XclImpTbxObjBase( rRoot )
+{
+}
+
+void XclImpDialogObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ // label and text formatting
+ ConvertLabel( rPropSet );
+}
+
+OUString XclImpDialogObj::DoGetServiceName() const
+{
+ // dialog frame faked by a groupbox
+ return CREATE_OUSTRING( "com.sun.star.form.component.GroupBox" );
+}
+
+XclTbxEventType XclImpDialogObj::DoGetEventType() const
+{
+ return EXC_TBX_EVENT_MOUSE;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpEditObj::XclImpEditObj( const XclImpRoot& rRoot ) :
+ XclImpTbxObjBase( rRoot ),
+ mnContentType( EXC_OBJ_EDIT_TEXT ),
+ mnMultiLine( 0 ),
+ mnScrollBar( 0 ),
+ mnListBoxObjId( 0 )
+{
+}
+
+bool XclImpEditObj::IsNumeric() const
+{
+ return (mnContentType == EXC_OBJ_EDIT_INTEGER) || (mnContentType == EXC_OBJ_EDIT_DOUBLE);
+}
+
+void XclImpEditObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
+{
+ ReadFrameData( rStrm );
+ rStrm.Ignore( 10 );
+ rStrm >> maTextData.maData.mnFlags;
+ rStrm.Ignore( 14 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, rStrm.ReaduInt16() ); // fist macro size invalid and unused
+ rStrm >> maTextData.maData.mnTextLen;
+ maTextData.ReadByteString( rStrm );
+ rStrm >> mnContentType >> mnMultiLine >> mnScrollBar >> mnListBoxObjId;
+}
+
+void XclImpEditObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
+{
+ switch( nSubRecId )
+ {
+ case EXC_ID_OBJEDODATA:
+ rStrm >> mnContentType >> mnMultiLine >> mnScrollBar >> mnListBoxObjId;
+ break;
+ default:
+ XclImpTbxObjBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
+ }
+}
+
+void XclImpEditObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ if( maTextData.mxString )
+ {
+ OUString aText = maTextData.mxString->GetText();
+ if( IsNumeric() )
+ {
+ // TODO: OUString::toDouble() does not handle local decimal separator
+ rPropSet.SetProperty( CREATE_OUSTRING( "DefaultValue" ), aText.toDouble() );
+ rPropSet.SetBoolProperty( CREATE_OUSTRING( "Spin" ), mnScrollBar != 0 );
+ }
+ else
+ {
+ rPropSet.SetProperty( CREATE_OUSTRING( "DefaultText" ), aText );
+ rPropSet.SetBoolProperty( CREATE_OUSTRING( "MultiLine" ), mnMultiLine != 0 );
+ rPropSet.SetBoolProperty( CREATE_OUSTRING( "VScroll" ), mnScrollBar != 0 );
+ }
+ }
+ ConvertFont( rPropSet );
+}
+
+OUString XclImpEditObj::DoGetServiceName() const
+{
+ return IsNumeric() ?
+ CREATE_OUSTRING( "com.sun.star.form.component.NumericField" ) :
+ CREATE_OUSTRING( "com.sun.star.form.component.TextField" );
+}
+
+XclTbxEventType XclImpEditObj::DoGetEventType() const
+{
+ return EXC_TBX_EVENT_TEXT;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpTbxObjScrollableBase::XclImpTbxObjScrollableBase( const XclImpRoot& rRoot ) :
+ XclImpTbxObjBase( rRoot ),
+ mnValue( 0 ),
+ mnMin( 0 ),
+ mnMax( 100 ),
+ mnStep( 1 ),
+ mnPageStep( 10 ),
+ mnOrient( 0 ),
+ mnThumbWidth( 1 ),
+ mnScrollFlags( 0 )
+{
+}
+
+void XclImpTbxObjScrollableBase::ReadSbs( XclImpStream& rStrm )
+{
+ rStrm.Ignore( 4 );
+ rStrm >> mnValue >> mnMin >> mnMax >> mnStep >> mnPageStep >> mnOrient >> mnThumbWidth >> mnScrollFlags;
+}
+
+void XclImpTbxObjScrollableBase::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
+{
+ switch( nSubRecId )
+ {
+ case EXC_ID_OBJSBS:
+ ReadSbs( rStrm );
+ break;
+ case EXC_ID_OBJSBSFMLA:
+ ReadCellLinkFormula( rStrm, false );
+ break;
+ default:
+ XclImpTbxObjBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpSpinButtonObj::XclImpSpinButtonObj( const XclImpRoot& rRoot ) :
+ XclImpTbxObjScrollableBase( rRoot )
+{
+}
+
+void XclImpSpinButtonObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
+{
+ ReadFrameData( rStrm );
+ ReadSbs( rStrm );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, rStrm.ReaduInt16() ); // fist macro size invalid and unused
+ ReadCellLinkFormula( rStrm, true );
+}
+
+void XclImpSpinButtonObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ // Calc's "Border" property is not the 3D/flat style effect in Excel (#i34712#)
+ rPropSet.SetProperty( CREATE_OUSTRING( "Border" ), ::com::sun::star::awt::VisualEffect::NONE );
+ rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "DefaultSpinValue" ), mnValue );
+ rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "SpinValueMin" ), mnMin );
+ rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "SpinValueMax" ), mnMax );
+ rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "SpinIncrement" ), mnStep );
+
+ // Excel spin buttons always vertical
+ rPropSet.SetProperty( CREATE_OUSTRING( "Orientation" ), ::com::sun::star::awt::ScrollBarOrientation::VERTICAL );
+}
+
+OUString XclImpSpinButtonObj::DoGetServiceName() const
+{
+ return CREATE_OUSTRING( "com.sun.star.form.component.SpinButton" );
+}
+
+XclTbxEventType XclImpSpinButtonObj::DoGetEventType() const
+{
+ return EXC_TBX_EVENT_VALUE;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpScrollBarObj::XclImpScrollBarObj( const XclImpRoot& rRoot ) :
+ XclImpTbxObjScrollableBase( rRoot )
+{
+}
+
+void XclImpScrollBarObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
+{
+ ReadFrameData( rStrm );
+ ReadSbs( rStrm );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, rStrm.ReaduInt16() ); // fist macro size invalid and unused
+ ReadCellLinkFormula( rStrm, true );
+}
+
+void XclImpScrollBarObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ // Calc's "Border" property is not the 3D/flat style effect in Excel (#i34712#)
+ rPropSet.SetProperty( CREATE_OUSTRING( "Border" ), ::com::sun::star::awt::VisualEffect::NONE );
+ rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "DefaultScrollValue" ), mnValue );
+ rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "ScrollValueMin" ), mnMin );
+ rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "ScrollValueMax" ), mnMax );
+ rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "LineIncrement" ), mnStep );
+ rPropSet.SetProperty< sal_Int32 >( CREATE_OUSTRING( "BlockIncrement" ), mnPageStep );
+ rPropSet.SetProperty( CREATE_OUSTRING( "VisibleSize" ), ::std::min< sal_Int32 >( mnPageStep, 1 ) );
+
+ namespace AwtScrollOrient = ::com::sun::star::awt::ScrollBarOrientation;
+ sal_Int32 nApiOrient = ::get_flagvalue( mnOrient, EXC_OBJ_SCROLLBAR_HOR, AwtScrollOrient::HORIZONTAL, AwtScrollOrient::VERTICAL );
+ rPropSet.SetProperty( CREATE_OUSTRING( "Orientation" ), nApiOrient );
+}
+
+OUString XclImpScrollBarObj::DoGetServiceName() const
+{
+ return CREATE_OUSTRING( "com.sun.star.form.component.ScrollBar" );
+}
+
+XclTbxEventType XclImpScrollBarObj::DoGetEventType() const
+{
+ return EXC_TBX_EVENT_VALUE;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpTbxObjListBase::XclImpTbxObjListBase( const XclImpRoot& rRoot ) :
+ XclImpTbxObjScrollableBase( rRoot ),
+ mnEntryCount( 0 ),
+ mnSelEntry( 0 ),
+ mnListFlags( 0 ),
+ mnEditObjId( 0 ),
+ mbHasDefFontIdx( false )
+{
+}
+
+void XclImpTbxObjListBase::ReadLbsData( XclImpStream& rStrm )
+{
+ ReadSourceRangeFormula( rStrm, true );
+ rStrm >> mnEntryCount >> mnSelEntry >> mnListFlags >> mnEditObjId;
+}
+
+void XclImpTbxObjListBase::SetBoxFormatting( ScfPropertySet& rPropSet ) const
+{
+ // border style
+ namespace AwtVisualEffect = ::com::sun::star::awt::VisualEffect;
+ sal_Int16 nApiBorder = ::get_flagvalue( mnListFlags, EXC_OBJ_LISTBOX_FLAT, AwtVisualEffect::FLAT, AwtVisualEffect::LOOK3D );
+ rPropSet.SetProperty( CREATE_OUSTRING( "Border" ), nApiBorder );
+
+ // font formatting
+ if( mbHasDefFontIdx )
+ GetFontBuffer().WriteFontProperties( rPropSet, EXC_FONTPROPSET_CONTROL, maTextData.maData.mnDefFontIdx );
+ else
+ GetFontBuffer().WriteDefaultCtrlFontProperties( rPropSet );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpListBoxObj::XclImpListBoxObj( const XclImpRoot& rRoot ) :
+ XclImpTbxObjListBase( rRoot )
+{
+}
+
+void XclImpListBoxObj::ReadFullLbsData( XclImpStream& rStrm, sal_Size nRecLeft )
+{
+ sal_Size nRecEnd = rStrm.GetRecPos() + nRecLeft;
+ ReadLbsData( rStrm );
+ DBG_ASSERT( (rStrm.GetRecPos() == nRecEnd) || (rStrm.GetRecPos() + mnEntryCount == nRecEnd),
+ "XclImpListBoxObj::ReadFullLbsData - invalid size of OBJLBSDATA record" );
+ while( rStrm.IsValid() && (rStrm.GetRecPos() < nRecEnd) )
+ maSelection.push_back( rStrm.ReaduInt8() );
+}
+
+void XclImpListBoxObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
+{
+ ReadFrameData( rStrm );
+ ReadSbs( rStrm );
+ rStrm.Ignore( 18 );
+ rStrm >> maTextData.maData.mnDefFontIdx;
+ rStrm.Ignore( 4 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, rStrm.ReaduInt16() ); // fist macro size invalid and unused
+ ReadCellLinkFormula( rStrm, true );
+ ReadFullLbsData( rStrm, rStrm.GetRecLeft() );
+ mbHasDefFontIdx = true;
+}
+
+void XclImpListBoxObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
+{
+ switch( nSubRecId )
+ {
+ case EXC_ID_OBJLBSDATA:
+ ReadFullLbsData( rStrm, nSubRecSize );
+ break;
+ default:
+ XclImpTbxObjListBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
+ }
+}
+
+void XclImpListBoxObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ // listbox formatting
+ SetBoxFormatting( rPropSet );
+
+ // selection type
+ sal_uInt8 nSelType = ::extract_value< sal_uInt8 >( mnListFlags, 4, 2 );
+ bool bMultiSel = nSelType != EXC_OBJ_LISTBOX_SINGLE;
+ rPropSet.SetBoolProperty( CREATE_OUSTRING( "MultiSelection" ), bMultiSel );
+
+ // selection (do not set, if listbox is linked to a cell)
+ if( !HasCellLink() )
+ {
+ ScfInt16Vec aSelVec;
+
+ // multi selection: API expects sequence of list entry indexes
+ if( bMultiSel )
+ for( ScfUInt8Vec::const_iterator aBeg = maSelection.begin(), aIt = aBeg, aEnd = maSelection.end(); aIt != aEnd; ++aIt )
+ if( *aIt != 0 )
+ aSelVec.push_back( static_cast< sal_Int16 >( aIt - aBeg ) );
+ // single selection: mnSelEntry is one-based, API expects zero-based
+ else if( mnSelEntry > 0 )
+ aSelVec.push_back( static_cast< sal_Int16 >( mnSelEntry - 1 ) );
+
+ if( !aSelVec.empty() )
+ {
+ Sequence< sal_Int16 > aSelSeq( &aSelVec.front(), static_cast< sal_Int32 >( aSelVec.size() ) );
+ rPropSet.SetProperty( CREATE_OUSTRING( "DefaultSelection" ), aSelSeq );
+ }
+ }
+}
+
+OUString XclImpListBoxObj::DoGetServiceName() const
+{
+ return CREATE_OUSTRING( "com.sun.star.form.component.ListBox" );
+}
+
+XclTbxEventType XclImpListBoxObj::DoGetEventType() const
+{
+ return EXC_TBX_EVENT_CHANGE;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpDropDownObj::XclImpDropDownObj( const XclImpRoot& rRoot ) :
+ XclImpTbxObjListBase( rRoot ),
+ mnLeft( 0 ),
+ mnTop( 0 ),
+ mnRight( 0 ),
+ mnBottom( 0 ),
+ mnDropDownFlags( 0 ),
+ mnLineCount( 0 ),
+ mnMinWidth( 0 )
+{
+}
+
+sal_uInt16 XclImpDropDownObj::GetDropDownType() const
+{
+ return ::extract_value< sal_uInt8 >( mnDropDownFlags, 0, 2 );
+}
+
+void XclImpDropDownObj::ReadFullLbsData( XclImpStream& rStrm )
+{
+ ReadLbsData( rStrm );
+ rStrm >> mnDropDownFlags >> mnLineCount >> mnMinWidth >> maTextData.maData.mnTextLen;
+ maTextData.ReadByteString( rStrm );
+ // dropdowns of auto-filters have 'simple' style, they don't have a text area
+ if( GetDropDownType() == EXC_OBJ_DROPDOWN_SIMPLE )
+ SetProcessSdrObj( false );
+}
+
+void XclImpDropDownObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
+{
+ ReadFrameData( rStrm );
+ ReadSbs( rStrm );
+ rStrm.Ignore( 18 );
+ rStrm >> maTextData.maData.mnDefFontIdx;
+ rStrm.Ignore( 14 );
+ rStrm >> mnLeft >> mnTop >> mnRight >> mnBottom;
+ rStrm.Ignore( 4 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, rStrm.ReaduInt16() ); // fist macro size invalid and unused
+ ReadCellLinkFormula( rStrm, true );
+ ReadFullLbsData( rStrm );
+ mbHasDefFontIdx = true;
+}
+
+void XclImpDropDownObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
+{
+ switch( nSubRecId )
+ {
+ case EXC_ID_OBJLBSDATA:
+ ReadFullLbsData( rStrm );
+ break;
+ default:
+ XclImpTbxObjListBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
+ }
+}
+
+void XclImpDropDownObj::DoProcessControl( ScfPropertySet& rPropSet ) const
+{
+ // dropdown listbox formatting
+ SetBoxFormatting( rPropSet );
+ // enable dropdown button
+ rPropSet.SetBoolProperty( CREATE_OUSTRING( "Dropdown" ), true );
+ // dropdown line count
+ rPropSet.SetProperty( CREATE_OUSTRING( "LineCount" ), mnLineCount );
+
+ if( GetDropDownType() == EXC_OBJ_DROPDOWN_COMBOBOX )
+ {
+ // text of editable combobox
+ if( maTextData.mxString )
+ rPropSet.SetStringProperty( CREATE_OUSTRING( "DefaultText" ), maTextData.mxString->GetText() );
+ }
+ else
+ {
+ // selection (do not set, if dropdown is linked to a cell)
+ if( !HasCellLink() && (mnSelEntry > 0) )
+ {
+ Sequence< sal_Int16 > aSelSeq( 1 );
+ aSelSeq[ 0 ] = mnSelEntry - 1;
+ rPropSet.SetProperty( CREATE_OUSTRING( "DefaultSelection" ), aSelSeq );
+ }
+ }
+}
+
+OUString XclImpDropDownObj::DoGetServiceName() const
+{
+ return (GetDropDownType() == EXC_OBJ_DROPDOWN_COMBOBOX) ?
+ CREATE_OUSTRING( "com.sun.star.form.component.ComboBox" ) :
+ CREATE_OUSTRING( "com.sun.star.form.component.ListBox" );
+}
+
+XclTbxEventType XclImpDropDownObj::DoGetEventType() const
+{
+ return (GetDropDownType() == EXC_OBJ_DROPDOWN_COMBOBOX) ? EXC_TBX_EVENT_TEXT : EXC_TBX_EVENT_CHANGE;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpPictureObj::XclImpPictureObj( const XclImpRoot& rRoot ) :
+ XclImpRectObj( rRoot ),
+ XclImpControlHelper( rRoot, EXC_CTRL_BINDCONTENT ),
+ mnStorageId( 0 ),
+ mnCtlsStrmPos( 0 ),
+ mnCtlsStrmSize( 0 ),
+ mbEmbedded( false ),
+ mbLinked( false ),
+ mbSymbol( false ),
+ mbControl( false ),
+ mbUseCtlsStrm( false )
+{
+ SetAreaObj( true );
+ SetSimpleMacro( false );
+ SetCustomDffObj( true );
+}
+
+String XclImpPictureObj::GetOleStorageName() const
+{
+ String aStrgName;
+ if( (mbEmbedded || mbLinked) && !mbControl && (mnStorageId > 0) )
+ {
+ aStrgName = mbEmbedded ? EXC_STORAGE_OLE_EMBEDDED : EXC_STORAGE_OLE_LINKED;
+ static const sal_Char spcHexChars[] = "0123456789ABCDEF";
+ for( sal_uInt8 nIndex = 32; nIndex > 0; nIndex -= 4 )
+ aStrgName.Append( sal_Unicode( spcHexChars[ ::extract_value< sal_uInt8 >( mnStorageId, nIndex - 4, 4 ) ] ) );
+ }
+ return aStrgName;
+}
+
+void XclImpPictureObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ sal_uInt16 nLinkSize;
+ ReadFrameData( rStrm );
+ rStrm.Ignore( 6 );
+ rStrm >> nLinkSize;
+ rStrm.Ignore( 2 );
+ ReadFlags3( rStrm );
+ ReadMacro3( rStrm, nMacroSize );
+ ReadPictFmla( rStrm, nLinkSize );
+
+ if( (rStrm.GetNextRecId() == EXC_ID3_IMGDATA) && rStrm.StartNextRecord() )
+ maGraphic = XclImpDrawing::ReadImgData( GetRoot(), rStrm );
+}
+
+void XclImpPictureObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
+{
+ sal_uInt16 nLinkSize;
+ ReadFrameData( rStrm );
+ rStrm.Ignore( 6 );
+ rStrm >> nLinkSize;
+ rStrm.Ignore( 2 );
+ ReadFlags3( rStrm );
+ ReadMacro4( rStrm, nMacroSize );
+ ReadPictFmla( rStrm, nLinkSize );
+
+ if( (rStrm.GetNextRecId() == EXC_ID3_IMGDATA) && rStrm.StartNextRecord() )
+ maGraphic = XclImpDrawing::ReadImgData( GetRoot(), rStrm );
+}
+
+void XclImpPictureObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
+{
+ sal_uInt16 nLinkSize;
+ ReadFrameData( rStrm );
+ rStrm.Ignore( 6 );
+ rStrm >> nLinkSize;
+ rStrm.Ignore( 2 );
+ ReadFlags3( rStrm );
+ rStrm.Ignore( 4 );
+ ReadName5( rStrm, nNameLen );
+ ReadMacro5( rStrm, nMacroSize );
+ ReadPictFmla( rStrm, nLinkSize );
+
+ if( (rStrm.GetNextRecId() == EXC_ID3_IMGDATA) && rStrm.StartNextRecord() )
+ {
+ // page background is stored as hidden picture with name "__BkgndObj"
+ if( IsHidden() && (GetObjName() == CREATE_STRING( "__BkgndObj" )) )
+ GetPageSettings().ReadImgData( rStrm );
+ else
+ maGraphic = XclImpDrawing::ReadImgData( GetRoot(), rStrm );
+ }
+}
+
+void XclImpPictureObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
+{
+ switch( nSubRecId )
+ {
+ case EXC_ID_OBJFLAGS:
+ ReadFlags8( rStrm );
+ break;
+ case EXC_ID_OBJPICTFMLA:
+ ReadPictFmla( rStrm, rStrm.ReaduInt16() );
+ break;
+ default:
+ XclImpDrawObjBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
+ }
+}
+
+SdrObject* XclImpPictureObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const Rectangle& rAnchorRect ) const
+{
+ // try to create an OLE object or form control
+ SdrObjectPtr xSdrObj( rDffConv.CreateSdrObject( *this, rAnchorRect ) );
+
+ // no OLE - create a plain picture from IMGDATA record data
+ if( !xSdrObj && (maGraphic.GetType() != GRAPHIC_NONE) )
+ {
+ xSdrObj.reset( new SdrGrafObj( maGraphic, rAnchorRect ) );
+ ConvertRectStyle( *xSdrObj );
+ }
+
+ rDffConv.Progress();
+ return xSdrObj.release();
+}
+
+String XclImpPictureObj::GetObjName() const
+{
+ if( IsOcxControl() )
+ {
+ String sName( GetObjectManager().GetOleNameOverride( GetTab(), GetObjId() ) );
+ if ( sName.Len() > 0 )
+ return sName;
+ }
+ return XclImpDrawObjBase::GetObjName();
+}
+
+void XclImpPictureObj::DoPreProcessSdrObj( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
+{
+ if( IsOcxControl() )
+ {
+ // do not call XclImpRectObj::DoPreProcessSdrObj(), it would trace missing "printable" feature
+ ProcessControl( *this );
+ }
+ else if( mbEmbedded || mbLinked )
+ {
+ // trace missing "printable" feature
+ XclImpRectObj::DoPreProcessSdrObj( rDffConv, rSdrObj );
+
+ SfxObjectShell* pDocShell = GetDocShell();
+ SdrOle2Obj* pOleSdrObj = dynamic_cast< SdrOle2Obj* >( &rSdrObj );
+ if( pOleSdrObj && pDocShell )
+ {
+ comphelper::EmbeddedObjectContainer& rEmbObjCont = pDocShell->GetEmbeddedObjectContainer();
+ Reference< XEmbeddedObject > xEmbObj = pOleSdrObj->GetObjRef();
+ OUString aOldName( pOleSdrObj->GetPersistName() );
+
+ /* The object persistence should be already in the storage, but
+ the object still might not be inserted into the container. */
+ if( rEmbObjCont.HasEmbeddedObject( aOldName ) )
+ {
+ if( !rEmbObjCont.HasEmbeddedObject( xEmbObj ) )
+ // filter code is allowed to call the following method
+ rEmbObjCont.AddEmbeddedObject( xEmbObj, aOldName );
+ }
+ else
+ {
+ /* If the object is still not in container it must be inserted
+ there, the name must be generated in this case. */
+ OUString aNewName;
+ rEmbObjCont.InsertEmbeddedObject( xEmbObj, aNewName );
+ if( aOldName != aNewName )
+ // SetPersistName, not SetName
+ pOleSdrObj->SetPersistName( aNewName );
+ }
+ }
+ }
+}
+
+void XclImpPictureObj::ReadFlags3( XclImpStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags;
+ mbSymbol = ::get_flag( nFlags, EXC_OBJ_PIC_SYMBOL );
+}
+
+void XclImpPictureObj::ReadFlags8( XclImpStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> nFlags;
+ mbSymbol = ::get_flag( nFlags, EXC_OBJ_PIC_SYMBOL );
+ mbControl = ::get_flag( nFlags, EXC_OBJ_PIC_CONTROL );
+ mbUseCtlsStrm = ::get_flag( nFlags, EXC_OBJ_PIC_CTLSSTREAM );
+ DBG_ASSERT( mbControl || !mbUseCtlsStrm, "XclImpPictureObj::ReadFlags8 - CTLS stream for controls only" );
+ SetProcessSdrObj( mbControl || !mbUseCtlsStrm );
+}
+
+void XclImpPictureObj::ReadPictFmla( XclImpStream& rStrm, sal_uInt16 nLinkSize )
+{
+ sal_Size nLinkEnd = rStrm.GetRecPos() + nLinkSize;
+ if( nLinkSize >= 6 )
+ {
+ sal_uInt16 nFmlaSize;
+ rStrm >> nFmlaSize;
+ DBG_ASSERT( nFmlaSize > 0, "XclImpPictureObj::ReadPictFmla - missing link formula" );
+ // BIFF3/BIFF4 do not support storages, nothing to do here
+ if( (nFmlaSize > 0) && (GetBiff() >= EXC_BIFF5) )
+ {
+ rStrm.Ignore( 4 );
+ sal_uInt8 nToken;
+ rStrm >> nToken;
+
+ // different processing for linked vs. embedded OLE objects
+ if( nToken == XclTokenArrayHelper::GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ) )
+ {
+ mbLinked = true;
+ switch( GetBiff() )
+ {
+ case EXC_BIFF5:
+ {
+ sal_Int16 nRefIdx;
+ sal_uInt16 nNameIdx;
+ rStrm >> nRefIdx;
+ rStrm.Ignore( 8 );
+ rStrm >> nNameIdx;
+ rStrm.Ignore( 12 );
+ const ExtName* pExtName = GetOldRoot().pExtNameBuff->GetNameByIndex( nRefIdx, nNameIdx );
+ if( pExtName && pExtName->IsOLE() )
+ mnStorageId = pExtName->nStorageId;
+ }
+ break;
+ case EXC_BIFF8:
+ {
+ sal_uInt16 nXti, nExtName;
+ rStrm >> nXti >> nExtName;
+ const XclImpExtName* pExtName = GetLinkManager().GetExternName( nXti, nExtName );
+ if( pExtName && (pExtName->GetType() == xlExtOLE) )
+ mnStorageId = pExtName->GetStorageId();
+ }
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+ }
+ else if( nToken == XclTokenArrayHelper::GetTokenId( EXC_TOKID_TBL, EXC_TOKCLASS_NONE ) )
+ {
+ mbEmbedded = true;
+ DBG_ASSERT( nFmlaSize == 5, "XclImpPictureObj::ReadPictFmla - unexpected formula size" );
+ rStrm.Ignore( nFmlaSize - 1 ); // token ID already read
+ if( nFmlaSize & 1 )
+ rStrm.Ignore( 1 ); // padding byte
+
+ // a class name may follow inside the picture link
+ if( rStrm.GetRecPos() + 2 <= nLinkEnd )
+ {
+ sal_uInt16 nLen;
+ rStrm >> nLen;
+ if( nLen > 0 )
+ maClassName = (GetBiff() == EXC_BIFF8) ? rStrm.ReadUniString( nLen ) : rStrm.ReadRawByteString( nLen );
+ }
+ }
+ // else: ignore other formulas, e.g. pictures linked to cell ranges
+ }
+ }
+
+ // seek behind picture link data
+ rStrm.Seek( nLinkEnd );
+
+ // read additional data for embedded OLE objects following the picture link
+ if( IsOcxControl() )
+ {
+ // #i26521# form controls to be ignored
+ if( maClassName.EqualsAscii( "Forms.HTML:Hidden.1" ) )
+ {
+ SetProcessSdrObj( false );
+ return;
+ }
+
+ if( rStrm.GetRecLeft() <= 8 ) return;
+
+ // position and size of control data in 'Ctls' stream
+ mnCtlsStrmPos = static_cast< sal_Size >( rStrm.ReaduInt32() );
+ mnCtlsStrmSize = static_cast< sal_Size >( rStrm.ReaduInt32() );
+
+ if( rStrm.GetRecLeft() <= 8 ) return;
+
+ // additional string (16-bit characters), e.g. for progress bar control
+ sal_uInt32 nAddStrSize;
+ rStrm >> nAddStrSize;
+ DBG_ASSERT( rStrm.GetRecLeft() >= nAddStrSize + 4, "XclImpPictureObj::ReadPictFmla - missing data" );
+ if( rStrm.GetRecLeft() >= nAddStrSize + 4 )
+ {
+ rStrm.Ignore( nAddStrSize );
+ // cell link and source range
+ ReadCellLinkFormula( rStrm, true );
+ ReadSourceRangeFormula( rStrm, true );
+ }
+ }
+ else if( mbEmbedded && (rStrm.GetRecLeft() >= 4) )
+ {
+ rStrm >> mnStorageId;
+ }
+}
+
+// DFF stream conversion ======================================================
+
+void XclImpSolverContainer::InsertSdrObjectInfo( SdrObject& rSdrObj, sal_uInt32 nDffShapeId, sal_uInt32 nDffFlags )
+{
+ if( nDffShapeId > 0 )
+ {
+ maSdrInfoMap[ nDffShapeId ].Set( &rSdrObj, nDffFlags );
+ maSdrObjMap[ &rSdrObj ] = nDffShapeId;
+ }
+}
+
+void XclImpSolverContainer::RemoveSdrObjectInfo( SdrObject& rSdrObj )
+{
+ // remove info of passed object from the maps
+ XclImpSdrObjMap::iterator aIt = maSdrObjMap.find( &rSdrObj );
+ if( aIt != maSdrObjMap.end() )
+ {
+ maSdrInfoMap.erase( aIt->second );
+ maSdrObjMap.erase( aIt );
+ }
+
+ // remove info of all child objects of a group object
+ if( SdrObjGroup* pGroupObj = dynamic_cast< SdrObjGroup* >( &rSdrObj ) )
+ {
+ if( SdrObjList* pSubList = pGroupObj->GetSubList() )
+ {
+ // iterate flat over the list because this function already works recursively
+ SdrObjListIter aObjIt( *pSubList, IM_FLAT );
+ for( SdrObject* pChildObj = aObjIt.Next(); pChildObj; pChildObj = aObjIt.Next() )
+ RemoveSdrObjectInfo( *pChildObj );
+ }
+ }
+}
+
+void XclImpSolverContainer::UpdateConnectorRules()
+{
+ for( SvxMSDffConnectorRule* pRule = GetFirstRule(); pRule; pRule = GetNextRule() )
+ {
+ UpdateConnection( pRule->nShapeA, pRule->pAObj, &pRule->nSpFlagsA );
+ UpdateConnection( pRule->nShapeB, pRule->pBObj, &pRule->nSpFlagsB );
+ UpdateConnection( pRule->nShapeC, pRule->pCObj );
+ }
+}
+
+void XclImpSolverContainer::RemoveConnectorRules()
+{
+ // base class from SVX uses plain untyped tools/List
+ for( SvxMSDffConnectorRule* pRule = GetFirstRule(); pRule; pRule = GetNextRule() )
+ delete pRule;
+ aCList.Clear();
+
+ maSdrInfoMap.clear();
+ maSdrObjMap.clear();
+}
+
+SvxMSDffConnectorRule* XclImpSolverContainer::GetFirstRule()
+{
+ return static_cast< SvxMSDffConnectorRule* >( aCList.First() );
+}
+
+SvxMSDffConnectorRule* XclImpSolverContainer::GetNextRule()
+{
+ return static_cast< SvxMSDffConnectorRule* >( aCList.Next() );
+}
+
+void XclImpSolverContainer::UpdateConnection( sal_uInt32 nDffShapeId, SdrObject*& rpSdrObj, sal_uInt32* pnDffFlags )
+{
+ XclImpSdrInfoMap::const_iterator aIt = maSdrInfoMap.find( nDffShapeId );
+ if( aIt != maSdrInfoMap.end() )
+ {
+ rpSdrObj = aIt->second.mpSdrObj;
+ if( pnDffFlags )
+ *pnDffFlags = aIt->second.mnDffFlags;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpSimpleDffConverter::XclImpSimpleDffConverter( const XclImpRoot& rRoot, SvStream& rDffStrm ) :
+ SvxMSDffManager( rDffStrm, rRoot.GetBasePath(), 0, 0, rRoot.GetDoc().GetDrawLayer(), 1440, COL_DEFAULT, 24, 0, &rRoot.GetTracer().GetBaseTracer() ),
+ XclImpRoot( rRoot )
+{
+ SetSvxMSDffSettings( SVXMSDFF_SETTINGS_CROP_BITMAPS | SVXMSDFF_SETTINGS_IMPORT_EXCEL );
+}
+
+XclImpSimpleDffConverter::~XclImpSimpleDffConverter()
+{
+}
+
+bool XclImpSimpleDffConverter::GetColorFromPalette( sal_uInt16 nIndex, Color& rColor ) const
+{
+ ColorData nColor = GetPalette().GetColorData( static_cast< sal_uInt16 >( nIndex ) );
+
+ if( nColor == COL_AUTO )
+ return 0;
+
+ rColor.SetColor( nColor );
+ return 1;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpDffConverter::XclImpDffConvData::XclImpDffConvData(
+ XclImpDrawing& rDrawing, SdrModel& rSdrModel, SdrPage& rSdrPage ) :
+ mrDrawing( rDrawing ),
+ mrSdrModel( rSdrModel ),
+ mrSdrPage( rSdrPage ),
+ mnLastCtrlIndex( -1 ),
+ mbHasCtrlForm( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpDffConverter::XclImpDffConverter( const XclImpRoot& rRoot, SvStream& rDffStrm ) :
+ XclImpSimpleDffConverter( rRoot, rDffStrm ),
+ SvxMSConvertOCXControls( rRoot.GetDocShell(), 0 ),
+ maStdFormName( CREATE_OUSTRING( "Standard" ) ),
+ mnOleImpFlags( 0 )
+{
+ if( SvtFilterOptions* pFilterOpt = SvtFilterOptions::Get() )
+ {
+ if( pFilterOpt->IsMathType2Math() )
+ mnOleImpFlags |= OLE_MATHTYPE_2_STARMATH;
+ if( pFilterOpt->IsWinWord2Writer() )
+ mnOleImpFlags |= OLE_WINWORD_2_STARWRITER;
+ if( pFilterOpt->IsPowerPoint2Impress() )
+ mnOleImpFlags |= OLE_POWERPOINT_2_STARIMPRESS;
+ }
+
+ // try to open the 'Ctls' storage stream containing OCX control properties
+ mxCtlsStrm = OpenStream( EXC_STREAM_CTLS );
+
+ // default text margin (convert EMU to drawing layer units)
+ mnDefTextMargin = EXC_OBJ_TEXT_MARGIN;
+ ScaleEmu( mnDefTextMargin );
+}
+
+XclImpDffConverter::~XclImpDffConverter()
+{
+}
+
+String XclImpObjectManager::GetOleNameOverride( SCTAB nTab, sal_uInt16 nObjId )
+{
+ rtl::OUString sOleName;
+ String sCodeName = GetExtDocOptions().GetCodeName( nTab );
+
+ if ( mxOleCtrlNameOverride->hasByName( sCodeName ) )
+ {
+ Reference< XIndexContainer > xIdToOleName;
+ mxOleCtrlNameOverride->getByName( sCodeName ) >>= xIdToOleName;
+ xIdToOleName->getByIndex( nObjId ) >>= sOleName;
+ }
+ OSL_TRACE("XclImpObjectManager::GetOleNameOverride tab %d, ( module %s ) object id ( %d ) is %s", nTab,
+ rtl::OUStringToOString( sCodeName, RTL_TEXTENCODING_UTF8 ).getStr(), nObjId,
+ rtl::OUStringToOString( sOleName, RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ return sOleName;
+}
+
+void XclImpDffConverter::StartProgressBar( sal_Size nProgressSize )
+{
+ mxProgress.reset( new ScfProgressBar( GetDocShell(), STR_PROGRESS_CALCULATING ) );
+ mxProgress->AddSegment( nProgressSize );
+ mxProgress->Activate();
+}
+
+void XclImpDffConverter::Progress( sal_Size nDelta )
+{
+ DBG_ASSERT( mxProgress, "XclImpDffConverter::Progress - invalid call, no progress bar" );
+ mxProgress->Progress( nDelta );
+}
+
+void XclImpDffConverter::InitializeDrawing( XclImpDrawing& rDrawing, SdrModel& rSdrModel, SdrPage& rSdrPage )
+{
+ XclImpDffConvDataRef xConvData( new XclImpDffConvData( rDrawing, rSdrModel, rSdrPage ) );
+ maDataStack.push_back( xConvData );
+ SetModel( &xConvData->mrSdrModel, 1440 );
+}
+
+void XclImpDffConverter::ProcessObject( SdrObjList& rObjList, const XclImpDrawObjBase& rDrawObj )
+{
+ if( rDrawObj.IsProcessSdrObj() )
+ {
+ if( const XclObjAnchor* pAnchor = rDrawObj.GetAnchor() )
+ {
+ Rectangle aAnchorRect = GetConvData().mrDrawing.CalcAnchorRect( *pAnchor, false );
+ if( rDrawObj.IsValidSize( aAnchorRect ) )
+ {
+ // CreateSdrObject() recursively creates embedded child objects
+ SdrObjectPtr xSdrObj( rDrawObj.CreateSdrObject( *this, aAnchorRect, false ) );
+ if( xSdrObj.is() )
+ rDrawObj.PreProcessSdrObject( *this, *xSdrObj );
+ // call InsertSdrObject() also, if SdrObject is missing
+ InsertSdrObject( rObjList, rDrawObj, xSdrObj.release() );
+ }
+ }
+ }
+}
+
+void XclImpDffConverter::ProcessDrawing( const XclImpDrawObjVector& rDrawObjs )
+{
+ SdrPage& rSdrPage = GetConvData().mrSdrPage;
+ for( XclImpDrawObjVector::const_iterator aIt = rDrawObjs.begin(), aEnd = rDrawObjs.end(); aIt != aEnd; ++aIt )
+ ProcessObject( rSdrPage, **aIt );
+}
+
+void XclImpDffConverter::ProcessDrawing( SvStream& rDffStrm )
+{
+ rDffStrm.Seek( STREAM_SEEK_TO_END );
+ if( rDffStrm.Tell() > 0 )
+ {
+ rDffStrm.Seek( STREAM_SEEK_TO_BEGIN );
+ DffRecordHeader aHeader;
+ rDffStrm >> aHeader;
+ DBG_ASSERT( aHeader.nRecType == DFF_msofbtDgContainer, "XclImpDffConverter::ProcessDrawing - unexpected record" );
+ if( aHeader.nRecType == DFF_msofbtDgContainer )
+ ProcessDgContainer( rDffStrm, aHeader );
+ }
+}
+
+void XclImpDffConverter::FinalizeDrawing()
+{
+ DBG_ASSERT( !maDataStack.empty(), "XclImpDffConverter::FinalizeDrawing - no drawing manager on stack" );
+ maDataStack.pop_back();
+ // restore previous model at core DFF converter
+ if( !maDataStack.empty() )
+ SetModel( &maDataStack.back()->mrSdrModel, 1440 );
+}
+
+SdrObject* XclImpDffConverter::CreateSdrObject( const XclImpTbxObjBase& rTbxObj, const Rectangle& rAnchorRect )
+{
+ SdrObjectPtr xSdrObj;
+
+ OUString aServiceName = rTbxObj.GetServiceName();
+ if( SupportsOleObjects() && (aServiceName.getLength() > 0) ) try
+ {
+ // create the form control from scratch
+ Reference< XFormComponent > xFormComp( ScfApiHelper::CreateInstance( GetDocShell(), aServiceName ), UNO_QUERY_THROW );
+ // set controls form, needed in virtual function InsertControl()
+ InitControlForm();
+ // try to insert the control into the form
+ ::com::sun::star::awt::Size aDummySize;
+ Reference< XShape > xShape;
+ XclImpDffConvData& rConvData = GetConvData();
+ if( rConvData.mxCtrlForm.is() && InsertControl( xFormComp, aDummySize, &xShape, sal_True ) )
+ {
+ xSdrObj.reset( rTbxObj.CreateSdrObjectFromShape( xShape, rAnchorRect ) );
+ // try to attach a macro to the control
+ ScriptEventDescriptor aDescriptor;
+ if( (rConvData.mnLastCtrlIndex >= 0) && rTbxObj.FillMacroDescriptor( aDescriptor ) )
+ {
+ Reference< XEventAttacherManager > xEventMgr( rConvData.mxCtrlForm, UNO_QUERY_THROW );
+ xEventMgr->registerScriptEvent( rConvData.mnLastCtrlIndex, aDescriptor );
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ }
+
+ return xSdrObj.release();
+}
+
+SdrObject* XclImpDffConverter::CreateSdrObject( const XclImpPictureObj& rPicObj, const Rectangle& rAnchorRect )
+{
+ SdrObjectPtr xSdrObj;
+
+ if( SupportsOleObjects() )
+ {
+ if( rPicObj.IsOcxControl() )
+ {
+ if( mxCtlsStrm.Is() ) try
+ {
+ /* set controls form, needed in virtual function InsertControl()
+ called from ReadOCXExcelKludgeStream() */
+ InitControlForm();
+ // seek to stream position of the extra data for this control
+ mxCtlsStrm->Seek( rPicObj.GetCtlsStreamPos() );
+ // read from mxCtlsStrm into xShape, insert the control model into the form
+ Reference< XShape > xShape;
+ if( GetConvData().mxCtrlForm.is() && ReadOCXExcelKludgeStream( mxCtlsStrm, &xShape, sal_True ) )
+ xSdrObj.reset( rPicObj.CreateSdrObjectFromShape( xShape, rAnchorRect ) );
+ }
+ catch( Exception& )
+ {
+ }
+ }
+ else
+ {
+ SfxObjectShell* pDocShell = GetDocShell();
+ SotStorageRef xSrcStrg = GetRootStorage();
+ String aStrgName = rPicObj.GetOleStorageName();
+ if( pDocShell && xSrcStrg.Is() && (aStrgName.Len() > 0) )
+ {
+ // first try to resolve graphic from DFF storage
+ Graphic aGraphic;
+ Rectangle aVisArea;
+ if( !GetBLIP( GetPropertyValue( DFF_Prop_pib ), aGraphic, &aVisArea ) )
+ {
+ // if not found, use graphic from object (imported from IMGDATA record)
+ aGraphic = rPicObj.GetGraphic();
+ aVisArea = rPicObj.GetVisArea();
+ }
+ if( aGraphic.GetType() != GRAPHIC_NONE )
+ {
+ ErrCode nError = ERRCODE_NONE;
+ namespace cssea = ::com::sun::star::embed::Aspects;
+ sal_Int64 nAspects = rPicObj.IsSymbol() ? cssea::MSOLE_ICON : cssea::MSOLE_CONTENT;
+ xSdrObj.reset( CreateSdrOLEFromStorage(
+ aStrgName, xSrcStrg, pDocShell->GetStorage(), aGraphic,
+ rAnchorRect, aVisArea, 0, nError, mnOleImpFlags, nAspects ) );
+ }
+ }
+ }
+ }
+
+ return xSdrObj.release();
+}
+
+bool XclImpDffConverter::SupportsOleObjects() const
+{
+ return GetConvData().mrDrawing.SupportsOleObjects();
+}
+
+// virtual functions ----------------------------------------------------------
+
+void XclImpDffConverter::ProcessClientAnchor2( SvStream& rDffStrm,
+ DffRecordHeader& rHeader, void* /*pClientData*/, DffObjData& rObjData )
+{
+ // find the OBJ record data related to the processed shape
+ XclImpDffConvData& rConvData = GetConvData();
+ if( XclImpDrawObjBase* pDrawObj = rConvData.mrDrawing.FindDrawObj( rObjData.rSpHd ).get() )
+ {
+ DBG_ASSERT( rHeader.nRecType == DFF_msofbtClientAnchor, "XclImpDffConverter::ProcessClientAnchor2 - no client anchor record" );
+ XclObjAnchor aAnchor;
+ rHeader.SeekToContent( rDffStrm );
+ rDffStrm.SeekRel( 2 ); // flags
+ rDffStrm >> aAnchor; // anchor format equal to BIFF5 OBJ records
+ pDrawObj->SetAnchor( aAnchor );
+ rObjData.aChildAnchor = rConvData.mrDrawing.CalcAnchorRect( aAnchor, true );
+ rObjData.bChildAnchor = sal_True;
+ }
+}
+
+SdrObject* XclImpDffConverter::ProcessObj( SvStream& rDffStrm, DffObjData& rDffObjData,
+ void* pClientData, Rectangle& /*rTextRect*/, SdrObject* pOldSdrObj )
+{
+ XclImpDffConvData& rConvData = GetConvData();
+
+ /* pOldSdrObj passes a generated SdrObject. This function owns this object
+ and can modify it. The function has either to return it back to caller
+ or to delete it by itself. */
+ SdrObjectPtr xSdrObj( pOldSdrObj );
+
+ // find the OBJ record data related to the processed shape
+ XclImpDrawObjRef xDrawObj = rConvData.mrDrawing.FindDrawObj( rDffObjData.rSpHd );
+ const Rectangle& rAnchorRect = rDffObjData.aChildAnchor;
+
+ // Do not process the global page group shape (flag SP_FPATRIARCH)
+ bool bGlobalPageGroup = ::get_flag< sal_uInt32 >( rDffObjData.nSpFlags, SP_FPATRIARCH );
+ if( !xDrawObj || !xDrawObj->IsProcessSdrObj() || bGlobalPageGroup )
+ return 0; // simply return, xSdrObj will be destroyed
+
+ /* Pass pointer to top-level object back to caller. If the processed
+ object is embedded in a group, the pointer is already set to the
+ top-level parent object. */
+ XclImpDrawObjBase** ppTopLevelObj = reinterpret_cast< XclImpDrawObjBase** >( pClientData );
+ bool bIsTopLevel = !ppTopLevelObj || !*ppTopLevelObj;
+ if( ppTopLevelObj && bIsTopLevel )
+ *ppTopLevelObj = xDrawObj.get();
+
+ // connectors don't have to be area objects
+ if( dynamic_cast< SdrEdgeObj* >( xSdrObj.get() ) )
+ xDrawObj->SetAreaObj( false );
+
+ /* Check for valid size for all objects. Needed to ignore lots of invisible
+ phantom objects from deleted rows or columns (for performance reasons).
+ #i30816# Include objects embedded in groups.
+ #i58780# Ignore group shapes, size is not initialized. */
+ bool bEmbeddedGroup = !bIsTopLevel && dynamic_cast< SdrObjGroup* >( xSdrObj.get() );
+ if( !bEmbeddedGroup && !xDrawObj->IsValidSize( rAnchorRect ) )
+ return 0; // simply return, xSdrObj will be destroyed
+
+ // set shape information from DFF stream
+ String aObjName = GetPropertyString( DFF_Prop_wzName, rDffStrm );
+ String aHyperlink = ReadHlinkProperty( rDffStrm );
+ bool bVisible = !GetPropertyBool( DFF_Prop_fHidden );
+ bool bAutoMargin = GetPropertyBool( DFF_Prop_AutoTextMargin );
+ xDrawObj->SetDffData( rDffObjData, aObjName, aHyperlink, bVisible, bAutoMargin );
+
+ /* Connect textbox data (string, alignment, text orientation) to object.
+ don't ask for a text-ID, DFF export doesn't set one. */
+ if( XclImpTextObj* pTextObj = dynamic_cast< XclImpTextObj* >( xDrawObj.get() ) )
+ if( const XclImpObjTextData* pTextData = rConvData.mrDrawing.FindTextData( rDffObjData.rSpHd ) )
+ pTextObj->SetTextData( *pTextData );
+
+ // copy line and fill formatting of TBX form controls from DFF properties
+ if( XclImpTbxObjBase* pTbxObj = dynamic_cast< XclImpTbxObjBase* >( xDrawObj.get() ) )
+ pTbxObj->SetDffProperties( *this );
+
+ // try to create a custom SdrObject that overwrites the passed object
+ SdrObjectPtr xNewSdrObj( xDrawObj->CreateSdrObject( *this, rAnchorRect, true ) );
+ if( xNewSdrObj.is() )
+ xSdrObj.reset( xNewSdrObj.release() );
+
+ // process the SdrObject
+ if( xSdrObj.is() )
+ {
+ // filled without color -> set system window color
+ if( GetPropertyBool( DFF_Prop_fFilled ) && !IsProperty( DFF_Prop_fillColor ) )
+ xSdrObj->SetMergedItem( XFillColorItem( EMPTY_STRING, GetPalette().GetColor( EXC_COLOR_WINDOWBACK ) ) );
+
+ // additional processing on the SdrObject
+ xDrawObj->PreProcessSdrObject( *this, *xSdrObj );
+
+ /* If the SdrObject will not be inserted into the draw page, delete it
+ here. Happens e.g. for notes: The PreProcessSdrObject() call above
+ has inserted the note into the document, and the SdrObject is not
+ needed anymore. */
+ if( !xDrawObj->IsInsertSdrObj() )
+ xSdrObj.reset();
+ }
+
+ if( xSdrObj.is() )
+ {
+ /* Store the relation between shape ID and SdrObject for connectors.
+ Must be done here (and not in InsertSdrObject() function),
+ otherwise all SdrObjects embedded in groups would be lost. */
+ rConvData.maSolverCont.InsertSdrObjectInfo( *xSdrObj, xDrawObj->GetDffShapeId(), xDrawObj->GetDffFlags() );
+
+ /* If the drawing object is embedded in a group object, call
+ PostProcessSdrObject() here. For top-level objects this will be
+ done automatically in InsertSdrObject() but grouped shapes are
+ inserted into their groups somewhere in the SvxMSDffManager base
+ class without chance of notification. Unfortunately, now this is
+ called before the object is really inserted into its group object,
+ but that should not have any effect for grouped objects. */
+ if( !bIsTopLevel )
+ xDrawObj->PostProcessSdrObject( *this, *xSdrObj );
+ }
+
+ return xSdrObj.release();
+}
+
+sal_uLong XclImpDffConverter::Calc_nBLIPPos( sal_uLong /*nOrgVal*/, sal_uLong nStreamPos ) const
+{
+ return nStreamPos + 4;
+}
+
+sal_Bool XclImpDffConverter::InsertControl( const Reference< XFormComponent >& rxFormComp,
+ const ::com::sun::star::awt::Size& /*rSize*/, Reference< XShape >* pxShape,
+ sal_Bool /*bFloatingCtrl*/ )
+{
+ if( GetDocShell() ) try
+ {
+ XclImpDffConvData& rConvData = GetConvData();
+ Reference< XIndexContainer > xFormIC( rConvData.mxCtrlForm, UNO_QUERY_THROW );
+ Reference< XControlModel > xCtrlModel( rxFormComp, UNO_QUERY_THROW );
+
+ // create the control shape
+ Reference< XShape > xShape( ScfApiHelper::CreateInstance( GetDocShell(), CREATE_OUSTRING( "com.sun.star.drawing.ControlShape" ) ), UNO_QUERY_THROW );
+ Reference< XControlShape > xCtrlShape( xShape, UNO_QUERY_THROW );
+
+ // insert the new control into the form
+ sal_Int32 nNewIndex = xFormIC->getCount();
+ xFormIC->insertByIndex( nNewIndex, Any( rxFormComp ) );
+ // on success: store new index of the control for later use (macro events)
+ rConvData.mnLastCtrlIndex = nNewIndex;
+
+ // set control model at control shape and pass back shape to caller
+ xCtrlShape->setControl( xCtrlModel );
+ if( pxShape ) *pxShape = xShape;
+ return sal_True;
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "XclImpDffConverter::InsertControl - cannot create form control" );
+ }
+
+ return false;
+}
+
+// private --------------------------------------------------------------------
+
+XclImpDffConverter::XclImpDffConvData& XclImpDffConverter::GetConvData()
+{
+ DBG_ASSERT( !maDataStack.empty(), "XclImpDffConverter::GetConvData - no drawing manager on stack" );
+ return *maDataStack.back();
+}
+
+const XclImpDffConverter::XclImpDffConvData& XclImpDffConverter::GetConvData() const
+{
+ DBG_ASSERT( !maDataStack.empty(), "XclImpDffConverter::GetConvData - no drawing manager on stack" );
+ return *maDataStack.back();
+}
+
+String XclImpDffConverter::ReadHlinkProperty( SvStream& rDffStrm ) const
+{
+ /* Reads hyperlink data from a complex DFF property. Contents of this
+ property are equal to the HLINK record, import of this record is
+ implemented in class XclImpHyperlink. This function has to create an
+ instance of the XclImpStream class to be able to reuse the
+ functionality of XclImpHyperlink. */
+ String aString;
+ sal_uInt32 nBufferSize = GetPropertyValue( DFF_Prop_pihlShape );
+ if( (0 < nBufferSize) && (nBufferSize <= 0xFFFF) && SeekToContent( DFF_Prop_pihlShape, rDffStrm ) )
+ {
+ // create a faked BIFF record that can be read by XclImpStream class
+ SvMemoryStream aMemStream;
+ aMemStream << sal_uInt16( 0 ) << static_cast< sal_uInt16 >( nBufferSize );
+
+ // copy from DFF stream to memory stream
+ ::std::vector< sal_uInt8 > aBuffer( nBufferSize );
+ sal_uInt8* pnData = &aBuffer.front();
+ if( rDffStrm.Read( pnData, nBufferSize ) == nBufferSize )
+ {
+ aMemStream.Write( pnData, nBufferSize );
+
+ // create BIFF import stream to be able to use XclImpHyperlink class
+ XclImpStream aXclStrm( aMemStream, GetRoot() );
+ if( aXclStrm.StartNextRecord() )
+ aString = XclImpHyperlink::ReadEmbeddedData( aXclStrm );
+ }
+ }
+ return aString;
+}
+
+void XclImpDffConverter::ProcessDgContainer( SvStream& rDffStrm, const DffRecordHeader& rDgHeader )
+{
+ sal_Size nEndPos = rDgHeader.GetRecEndFilePos();
+ while( rDffStrm.Tell() < nEndPos )
+ {
+ DffRecordHeader aHeader;
+ rDffStrm >> aHeader;
+ switch( aHeader.nRecType )
+ {
+ case DFF_msofbtSolverContainer:
+ ProcessSolverContainer( rDffStrm, aHeader );
+ break;
+ case DFF_msofbtSpgrContainer:
+ ProcessShGrContainer( rDffStrm, aHeader );
+ break;
+ default:
+ aHeader.SeekToEndOfRecord( rDffStrm );
+ }
+ }
+ // seek to end of drawing page container
+ rDgHeader.SeekToEndOfRecord( rDffStrm );
+
+ // #i12638# #i37900# connector rules
+ XclImpSolverContainer& rSolverCont = GetConvData().maSolverCont;
+ rSolverCont.UpdateConnectorRules();
+ SolveSolver( rSolverCont );
+ rSolverCont.RemoveConnectorRules();
+}
+
+void XclImpDffConverter::ProcessShGrContainer( SvStream& rDffStrm, const DffRecordHeader& rShGrHeader )
+{
+ sal_Size nEndPos = rShGrHeader.GetRecEndFilePos();
+ while( rDffStrm.Tell() < nEndPos )
+ {
+ DffRecordHeader aHeader;
+ rDffStrm >> aHeader;
+ switch( aHeader.nRecType )
+ {
+ case DFF_msofbtSpgrContainer:
+ case DFF_msofbtSpContainer:
+ ProcessShContainer( rDffStrm, aHeader );
+ break;
+ default:
+ aHeader.SeekToEndOfRecord( rDffStrm );
+ }
+ }
+ // seek to end of shape group container
+ rShGrHeader.SeekToEndOfRecord( rDffStrm );
+}
+
+void XclImpDffConverter::ProcessSolverContainer( SvStream& rDffStrm, const DffRecordHeader& rSolverHeader )
+{
+ // solver container wants to read the solver container header again
+ rSolverHeader.SeekToBegOfRecord( rDffStrm );
+ // read the entire solver container
+ rDffStrm >> GetConvData().maSolverCont;
+ // seek to end of solver container
+ rSolverHeader.SeekToEndOfRecord( rDffStrm );
+}
+
+void XclImpDffConverter::ProcessShContainer( SvStream& rDffStrm, const DffRecordHeader& rShHeader )
+{
+ rShHeader.SeekToBegOfRecord( rDffStrm );
+ Rectangle aDummy;
+ const XclImpDrawObjBase* pDrawObj = 0;
+ /* The call to ImportObj() creates and returns a new SdrObject for the
+ processed shape. We take ownership of the returned object here. If the
+ shape is a group object, all embedded objects are created recursively,
+ and the returned group object contains them all. ImportObj() calls the
+ virtual functions ProcessClientAnchor2() and ProcessObj() and writes
+ the pointer to the related draw object data (OBJ record) into pDrawObj. */
+ SdrObjectPtr xSdrObj( ImportObj( rDffStrm, &pDrawObj, aDummy, aDummy, 0, 0 ) );
+ if( pDrawObj && xSdrObj.is() )
+ InsertSdrObject( GetConvData().mrSdrPage, *pDrawObj, xSdrObj.release() );
+ rShHeader.SeekToEndOfRecord( rDffStrm );
+}
+
+void XclImpDffConverter::InsertSdrObject( SdrObjList& rObjList, const XclImpDrawObjBase& rDrawObj, SdrObject* pSdrObj )
+{
+ XclImpDffConvData& rConvData = GetConvData();
+ /* Take ownership of the passed object. If insertion fails (e.g. rDrawObj
+ states to skip insertion), the object is automatically deleted. */
+ SdrObjectPtr xSdrObj( pSdrObj );
+ if( xSdrObj.is() && rDrawObj.IsInsertSdrObj() )
+ {
+ rObjList.NbcInsertObject( xSdrObj.release() );
+ // callback to drawing manager for e.g. tracking of used sheet area
+ rConvData.mrDrawing.OnObjectInserted( rDrawObj );
+ // callback to drawing object for post processing (use pSdrObj, xSdrObj already released)
+ rDrawObj.PostProcessSdrObject( *this, *pSdrObj );
+ }
+ /* SdrObject still here? Insertion failed, remove data from shape ID map.
+ The SdrObject will be destructed then. */
+ if( xSdrObj.is() )
+ rConvData.maSolverCont.RemoveSdrObjectInfo( *xSdrObj );
+}
+
+void XclImpDffConverter::InitControlForm()
+{
+ XclImpDffConvData& rConvData = GetConvData();
+ if( rConvData.mbHasCtrlForm )
+ return;
+
+ rConvData.mbHasCtrlForm = true;
+ if( SupportsOleObjects() ) try
+ {
+ Reference< XFormsSupplier > xFormsSupplier( rConvData.mrSdrPage.getUnoPage(), UNO_QUERY_THROW );
+ Reference< XNameContainer > xFormsNC( xFormsSupplier->getForms(), UNO_SET_THROW );
+ // find or create the Standard form used to insert the imported controls
+ if( xFormsNC->hasByName( maStdFormName ) )
+ {
+ xFormsNC->getByName( maStdFormName ) >>= rConvData.mxCtrlForm;
+ }
+ else if( SfxObjectShell* pDocShell = GetDocShell() )
+ {
+ rConvData.mxCtrlForm.set( ScfApiHelper::CreateInstance( pDocShell, CREATE_OUSTRING( "com.sun.star.form.component.Form" ) ), UNO_QUERY_THROW );
+ xFormsNC->insertByName( maStdFormName, Any( rConvData.mxCtrlForm ) );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+// Drawing manager ============================================================
+
+XclImpDrawing::XclImpDrawing( const XclImpRoot& rRoot, bool bOleObjects ) :
+ XclImpRoot( rRoot ),
+ mbOleObjs( bOleObjects )
+{
+}
+
+XclImpDrawing::~XclImpDrawing()
+{
+}
+
+Graphic XclImpDrawing::ReadImgData( const XclImpRoot& rRoot, XclImpStream& rStrm )
+{
+ Graphic aGraphic;
+ sal_uInt16 nFormat, nEnv;
+ sal_uInt32 nDataSize;
+ rStrm >> nFormat >> nEnv >> nDataSize;
+ if( nDataSize <= rStrm.GetRecLeft() )
+ {
+ switch( nFormat )
+ {
+ case EXC_IMGDATA_WMF: ReadWmf( aGraphic, rRoot, rStrm ); break;
+ case EXC_IMGDATA_BMP: ReadBmp( aGraphic, rRoot, rStrm ); break;
+ default: DBG_ERRORFILE( "XclImpDrawing::ReadImgData - unknown image format" );
+ }
+ }
+ return aGraphic;
+}
+
+void XclImpDrawing::ReadObj( XclImpStream& rStrm )
+{
+ XclImpDrawObjRef xDrawObj;
+
+ /* #i61786# In BIFF8 streams, OBJ records may occur without MSODRAWING
+ records. In this case, the OBJ records are in BIFF5 format. Do a sanity
+ check here that there is no DFF data loaded before. */
+ DBG_ASSERT( maDffStrm.Tell() == 0, "XclImpDrawing::ReadObj - unexpected DFF stream data, OBJ will be ignored" );
+ if( maDffStrm.Tell() == 0 ) switch( GetBiff() )
+ {
+ case EXC_BIFF3:
+ xDrawObj = XclImpDrawObjBase::ReadObj3( GetRoot(), rStrm );
+ break;
+ case EXC_BIFF4:
+ xDrawObj = XclImpDrawObjBase::ReadObj4( GetRoot(), rStrm );
+ break;
+ case EXC_BIFF5:
+ case EXC_BIFF8:
+ xDrawObj = XclImpDrawObjBase::ReadObj5( GetRoot(), rStrm );
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+
+ if( xDrawObj )
+ {
+ // insert into maRawObjs or into the last open group object
+ maRawObjs.InsertGrouped( xDrawObj );
+ // to be able to find objects by ID
+ maObjMapId[ xDrawObj->GetObjId() ] = xDrawObj;
+ }
+}
+
+void XclImpDrawing::ReadMsoDrawing( XclImpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF8 );
+ // disable internal CONTINUE handling
+ rStrm.ResetRecord( false );
+ // read leading MSODRAWING record
+ ReadDffRecord( rStrm );
+
+ // read following drawing records, but do not start following unrelated record
+ bool bLoop = true;
+ while( bLoop ) switch( rStrm.GetNextRecId() )
+ {
+ case EXC_ID_MSODRAWING:
+ case EXC_ID_MSODRAWINGSEL:
+ case EXC_ID_CONT:
+ rStrm.StartNextRecord();
+ ReadDffRecord( rStrm );
+ break;
+ case EXC_ID_OBJ:
+ rStrm.StartNextRecord();
+ ReadObj8( rStrm );
+ break;
+ case EXC_ID_TXO:
+ rStrm.StartNextRecord();
+ ReadTxo( rStrm );
+ break;
+ default:
+ bLoop = false;
+ }
+
+ // re-enable internal CONTINUE handling
+ rStrm.ResetRecord( true );
+}
+
+XclImpDrawObjRef XclImpDrawing::FindDrawObj( const DffRecordHeader& rHeader ) const
+{
+ /* maObjMap stores objects by position of the client data (OBJ record) in
+ the DFF stream, which is always behind shape start position of the
+ passed header. The function upper_bound() finds the first element in
+ the map whose key is greater than the start position of the header. Its
+ end position is used to test whether the found object is really related
+ to the shape. */
+ XclImpDrawObjRef xDrawObj;
+ XclImpObjMap::const_iterator aIt = maObjMap.upper_bound( rHeader.GetRecBegFilePos() );
+ if( (aIt != maObjMap.end()) && (aIt->first <= rHeader.GetRecEndFilePos()) )
+ xDrawObj = aIt->second;
+ return xDrawObj;
+}
+
+XclImpDrawObjRef XclImpDrawing::FindDrawObj( sal_uInt16 nObjId ) const
+{
+ XclImpDrawObjRef xDrawObj;
+ XclImpObjMapById::const_iterator aIt = maObjMapId.find( nObjId );
+ if( aIt != maObjMapId.end() )
+ xDrawObj = aIt->second;
+ return xDrawObj;
+}
+
+const XclImpObjTextData* XclImpDrawing::FindTextData( const DffRecordHeader& rHeader ) const
+{
+ /* maTextMap stores textbox data by position of the client data (TXO
+ record) in the DFF stream, which is always behind shape start position
+ of the passed header. The function upper_bound() finds the first
+ element in the map whose key is greater than the start position of the
+ header. Its end position is used to test whether the found object is
+ really related to the shape. */
+ XclImpObjTextMap::const_iterator aIt = maTextMap.upper_bound( rHeader.GetRecBegFilePos() );
+ if( (aIt != maTextMap.end()) && (aIt->first <= rHeader.GetRecEndFilePos()) )
+ return aIt->second.get();
+ return 0;
+}
+
+void XclImpDrawing::SetSkipObj( sal_uInt16 nObjId )
+{
+ maSkipObjs.push_back( nObjId );
+}
+
+sal_Size XclImpDrawing::GetProgressSize() const
+{
+ sal_Size nProgressSize = maRawObjs.GetProgressSize();
+ for( XclImpObjMap::const_iterator aIt = maObjMap.begin(), aEnd = maObjMap.end(); aIt != aEnd; ++aIt )
+ nProgressSize += aIt->second->GetProgressSize();
+ return nProgressSize;
+}
+
+void XclImpDrawing::ImplConvertObjects( XclImpDffConverter& rDffConv, SdrModel& rSdrModel, SdrPage& rSdrPage )
+{
+ //rhbz#636521, disable undo during conversion. faster, smaller and stops
+ //temp objects being inserted into the undo list
+ bool bOrigUndoStatus = rSdrModel.IsUndoEnabled();
+ rSdrModel.EnableUndo(false);
+ // register this drawing manager at the passed (global) DFF manager
+ rDffConv.InitializeDrawing( *this, rSdrModel, rSdrPage );
+ // process list of objects to be skipped
+ for( ScfUInt16Vec::const_iterator aIt = maSkipObjs.begin(), aEnd = maSkipObjs.end(); aIt != aEnd; ++aIt )
+ if( XclImpDrawObjBase* pDrawObj = FindDrawObj( *aIt ).get() )
+ pDrawObj->SetProcessSdrObj( false );
+ // process drawing objects without DFF data
+ rDffConv.ProcessDrawing( maRawObjs );
+ // process all objects in the DFF stream
+ rDffConv.ProcessDrawing( maDffStrm );
+ // unregister this drawing manager at the passed (global) DFF manager
+ rDffConv.FinalizeDrawing();
+ rSdrModel.EnableUndo(bOrigUndoStatus);
+}
+
+// protected ------------------------------------------------------------------
+
+void XclImpDrawing::AppendRawObject( const XclImpDrawObjRef& rxDrawObj )
+{
+ DBG_ASSERT( rxDrawObj, "XclImpDrawing::AppendRawObject - unexpected empty reference" );
+ maRawObjs.push_back( rxDrawObj );
+}
+
+// private --------------------------------------------------------------------
+
+void XclImpDrawing::ReadWmf( Graphic& rGraphic, const XclImpRoot&, XclImpStream& rStrm ) // static helper
+{
+ // extract graphic data from IMGDATA and following CONTINUE records
+ rStrm.Ignore( 8 );
+ SvMemoryStream aMemStrm;
+ rStrm.CopyToStream( aMemStrm, rStrm.GetRecLeft() );
+ aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
+ // import the graphic from memory stream
+ GDIMetaFile aGDIMetaFile;
+ if( ::ReadWindowMetafile( aMemStrm, aGDIMetaFile, 0 ) )
+ rGraphic = aGDIMetaFile;
+}
+
+void XclImpDrawing::ReadBmp( Graphic& rGraphic, const XclImpRoot& rRoot, XclImpStream& rStrm ) // static helper
+{
+ // extract graphic data from IMGDATA and following CONTINUE records
+ SvMemoryStream aMemStrm;
+
+ /* Excel 3 and 4 seem to write broken BMP data. Usually they write a
+ DIBCOREHEADER (12 bytes) containing width, height, planes = 1, and
+ pixel depth = 32 bit. After that, 3 unused bytes are added before the
+ actual pixel data. This does even confuse Excel 5 and later, which
+ cannot read the image data correctly. */
+ if( rRoot.GetBiff() <= EXC_BIFF4 )
+ {
+ rStrm.PushPosition();
+ sal_uInt32 nHdrSize;
+ sal_uInt16 nWidth, nHeight, nPlanes, nDepth;
+ rStrm >> nHdrSize >> nWidth >> nHeight >> nPlanes >> nDepth;
+ if( (nHdrSize == 12) && (nPlanes == 1) && (nDepth == 32) )
+ {
+ rStrm.Ignore( 3 );
+ aMemStrm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
+ aMemStrm << nHdrSize << nWidth << nHeight << nPlanes << nDepth;
+ rStrm.CopyToStream( aMemStrm, rStrm.GetRecLeft() );
+ }
+ rStrm.PopPosition();
+ }
+
+ // no special handling above -> just copy the remaining record data
+ if( aMemStrm.Tell() == 0 )
+ rStrm.CopyToStream( aMemStrm, rStrm.GetRecLeft() );
+
+ // import the graphic from memory stream
+ aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
+ Bitmap aBitmap;
+ if( aBitmap.Read( aMemStrm, false ) ) // read DIB without file header
+ rGraphic = aBitmap;
+}
+
+void XclImpDrawing::ReadDffRecord( XclImpStream& rStrm )
+{
+ maDffStrm.Seek( STREAM_SEEK_TO_END );
+ rStrm.CopyRecordToStream( maDffStrm );
+}
+
+void XclImpDrawing::ReadObj8( XclImpStream& rStrm )
+{
+ XclImpDrawObjRef xDrawObj = XclImpDrawObjBase::ReadObj8( GetRoot(), rStrm );
+ // store the new object in the internal containers
+ maObjMap[ maDffStrm.Tell() ] = xDrawObj;
+ maObjMapId[ xDrawObj->GetObjId() ] = xDrawObj;
+}
+
+void XclImpDrawing::ReadTxo( XclImpStream& rStrm )
+{
+ XclImpObjTextRef xTextData( new XclImpObjTextData );
+ maTextMap[ maDffStrm.Tell() ] = xTextData;
+
+ // 1) read the TXO record
+ xTextData->maData.ReadTxo8( rStrm );
+
+ // 2) first CONTINUE with string
+ xTextData->mxString.reset();
+ bool bValid = true;
+ if( xTextData->maData.mnTextLen > 0 )
+ {
+ bValid = (rStrm.GetNextRecId() == EXC_ID_CONT) && rStrm.StartNextRecord();
+ DBG_ASSERT( bValid, "XclImpDrawing::ReadTxo - missing CONTINUE record" );
+ if( bValid )
+ xTextData->mxString.reset( new XclImpString( rStrm.ReadUniString( xTextData->maData.mnTextLen ) ) );
+ }
+
+ // 3) second CONTINUE with formatting runs
+ if( xTextData->maData.mnFormatSize > 0 )
+ {
+ bValid = (rStrm.GetNextRecId() == EXC_ID_CONT) && rStrm.StartNextRecord();
+ DBG_ASSERT( bValid, "XclImpDrawing::ReadTxo - missing CONTINUE record" );
+ if( bValid )
+ xTextData->ReadFormats( rStrm );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpSheetDrawing::XclImpSheetDrawing( const XclImpRoot& rRoot, SCTAB nScTab ) :
+ XclImpDrawing( rRoot, true ),
+ maScUsedArea( ScAddress::INITIALIZE_INVALID )
+{
+ maScUsedArea.aStart.SetTab( nScTab );
+ maScUsedArea.aEnd.SetTab( nScTab );
+}
+
+void XclImpSheetDrawing::ReadNote( XclImpStream& rStrm )
+{
+ switch( GetBiff() )
+ {
+ case EXC_BIFF2:
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ case EXC_BIFF5:
+ ReadNote3( rStrm );
+ break;
+ case EXC_BIFF8:
+ ReadNote8( rStrm );
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+}
+
+void XclImpSheetDrawing::ReadTabChart( XclImpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( GetBiff() >= EXC_BIFF5 );
+ boost::shared_ptr< XclImpChartObj > xChartObj( new XclImpChartObj( GetRoot(), true ) );
+ xChartObj->ReadChartSubStream( rStrm );
+ // insert the chart as raw object without connected DFF data
+ AppendRawObject( xChartObj );
+}
+
+void XclImpSheetDrawing::ConvertObjects( XclImpDffConverter& rDffConv )
+{
+ if( SdrModel* pSdrModel = GetDoc().GetDrawLayer() )
+ if( SdrPage* pSdrPage = GetSdrPage( maScUsedArea.aStart.Tab() ) )
+ ImplConvertObjects( rDffConv, *pSdrModel, *pSdrPage );
+}
+
+Rectangle XclImpSheetDrawing::CalcAnchorRect( const XclObjAnchor& rAnchor, bool /*bDffAnchor*/ ) const
+{
+ return rAnchor.GetRect( GetRoot(), maScUsedArea.aStart.Tab(), MAP_100TH_MM );
+}
+
+void XclImpSheetDrawing::OnObjectInserted( const XclImpDrawObjBase& rDrawObj )
+{
+ ScRange aScObjArea = rDrawObj.GetUsedArea( maScUsedArea.aStart.Tab() );
+ if( aScObjArea.IsValid() )
+ maScUsedArea.ExtendTo( aScObjArea );
+}
+
+// private --------------------------------------------------------------------
+
+void XclImpSheetDrawing::ReadNote3( XclImpStream& rStrm )
+{
+ XclAddress aXclPos;
+ sal_uInt16 nTotalLen;
+ rStrm >> aXclPos >> nTotalLen;
+
+ ScAddress aScNotePos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScNotePos, aXclPos, maScUsedArea.aStart.Tab(), true ) )
+ {
+ sal_uInt16 nPartLen = ::std::min( nTotalLen, static_cast< sal_uInt16 >( rStrm.GetRecLeft() ) );
+ String aNoteText = rStrm.ReadRawByteString( nPartLen );
+ nTotalLen = nTotalLen - nPartLen;
+ while( (nTotalLen > 0) && (rStrm.GetNextRecId() == EXC_ID_NOTE) && rStrm.StartNextRecord() )
+ {
+ rStrm >> aXclPos >> nPartLen;
+ DBG_ASSERT( aXclPos.mnRow == 0xFFFF, "XclImpObjectManager::ReadNote3 - missing continuation NOTE record" );
+ if( aXclPos.mnRow == 0xFFFF )
+ {
+ DBG_ASSERT( nPartLen <= nTotalLen, "XclImpObjectManager::ReadNote3 - string too long" );
+ aNoteText.Append( rStrm.ReadRawByteString( nPartLen ) );
+ nTotalLen = nTotalLen - ::std::min( nTotalLen, nPartLen );
+ }
+ else
+ {
+ // seems to be a new note, record already started -> load the note
+ rStrm.Seek( EXC_REC_SEEK_TO_BEGIN );
+ ReadNote( rStrm );
+ nTotalLen = 0;
+ }
+ }
+ ScNoteUtil::CreateNoteFromString( GetDoc(), aScNotePos, aNoteText, false, false );
+ }
+}
+
+void XclImpSheetDrawing::ReadNote8( XclImpStream& rStrm )
+{
+ XclAddress aXclPos;
+ sal_uInt16 nFlags, nObjId;
+ rStrm >> aXclPos >> nFlags >> nObjId;
+
+ ScAddress aScNotePos( ScAddress::UNINITIALIZED );
+ if( GetAddressConverter().ConvertAddress( aScNotePos, aXclPos, maScUsedArea.aStart.Tab(), true ) )
+ if( nObjId != EXC_OBJ_INVALID_ID )
+ if( XclImpNoteObj* pNoteObj = dynamic_cast< XclImpNoteObj* >( FindDrawObj( nObjId ).get() ) )
+ pNoteObj->SetNoteData( aScNotePos, nFlags );
+}
+
+// The object manager =========================================================
+
+XclImpObjectManager::XclImpObjectManager( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+ maDefObjNames[ EXC_OBJTYPE_GROUP ] = CREATE_STRING( "Group" );
+ maDefObjNames[ EXC_OBJTYPE_LINE ] = ScGlobal::GetRscString( STR_SHAPE_LINE );
+ maDefObjNames[ EXC_OBJTYPE_RECTANGLE ] = ScGlobal::GetRscString( STR_SHAPE_RECTANGLE );
+ maDefObjNames[ EXC_OBJTYPE_OVAL ] = ScGlobal::GetRscString( STR_SHAPE_OVAL );
+ maDefObjNames[ EXC_OBJTYPE_ARC ] = CREATE_STRING( "Arc" );
+ maDefObjNames[ EXC_OBJTYPE_CHART ] = CREATE_STRING( "Chart" );
+ maDefObjNames[ EXC_OBJTYPE_TEXT ] = CREATE_STRING( "Text" );
+ maDefObjNames[ EXC_OBJTYPE_BUTTON ] = ScGlobal::GetRscString( STR_FORM_BUTTON );
+ maDefObjNames[ EXC_OBJTYPE_PICTURE ] = CREATE_STRING( "Picture" );
+ maDefObjNames[ EXC_OBJTYPE_POLYGON ] = CREATE_STRING( "Freeform" );
+ maDefObjNames[ EXC_OBJTYPE_CHECKBOX ] = ScGlobal::GetRscString( STR_FORM_CHECKBOX );
+ maDefObjNames[ EXC_OBJTYPE_OPTIONBUTTON ] = ScGlobal::GetRscString( STR_FORM_OPTIONBUTTON );
+ maDefObjNames[ EXC_OBJTYPE_EDIT ] = CREATE_STRING( "Edit Box" );
+ maDefObjNames[ EXC_OBJTYPE_LABEL ] = ScGlobal::GetRscString( STR_FORM_LABEL );
+ maDefObjNames[ EXC_OBJTYPE_DIALOG ] = CREATE_STRING( "Dialog Frame" );
+ maDefObjNames[ EXC_OBJTYPE_SPIN ] = ScGlobal::GetRscString( STR_FORM_SPINNER );
+ maDefObjNames[ EXC_OBJTYPE_SCROLLBAR ] = ScGlobal::GetRscString( STR_FORM_SCROLLBAR );
+ maDefObjNames[ EXC_OBJTYPE_LISTBOX ] = ScGlobal::GetRscString( STR_FORM_LISTBOX );
+ maDefObjNames[ EXC_OBJTYPE_GROUPBOX ] = ScGlobal::GetRscString( STR_FORM_GROUPBOX );
+ maDefObjNames[ EXC_OBJTYPE_DROPDOWN ] = ScGlobal::GetRscString( STR_FORM_DROPDOWN );
+ maDefObjNames[ EXC_OBJTYPE_NOTE ] = CREATE_STRING( "Comment" );
+ maDefObjNames[ EXC_OBJTYPE_DRAWING ] = ScGlobal::GetRscString( STR_SHAPE_AUTOSHAPE );
+}
+
+XclImpObjectManager::~XclImpObjectManager()
+{
+}
+
+void XclImpObjectManager::ReadMsoDrawingGroup( XclImpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF8 );
+ // Excel continues this record with MSODRAWINGGROUP and CONTINUE records, hmm.
+ rStrm.ResetRecord( true, EXC_ID_MSODRAWINGGROUP );
+ maDggStrm.Seek( STREAM_SEEK_TO_END );
+ rStrm.CopyRecordToStream( maDggStrm );
+}
+
+XclImpSheetDrawing& XclImpObjectManager::GetSheetDrawing( SCTAB nScTab )
+{
+ XclImpSheetDrawingRef& rxDrawing = maSheetDrawings[ nScTab ];
+ if( !rxDrawing )
+ rxDrawing.reset( new XclImpSheetDrawing( GetRoot(), nScTab ) );
+ return *rxDrawing;
+}
+
+void XclImpObjectManager::ConvertObjects()
+{
+ RTL_LOGFILE_CONTEXT_AUTHOR( aLog, "sc", "dr104026", "XclImpObjectManager::ConvertObjects" );
+
+ // do nothing if the document does not contain a drawing layer
+ if( !GetDoc().GetDrawLayer() )
+ return;
+
+ // get total progress bar size for all sheet drawing managers
+ sal_Size nProgressSize = 0;
+ for( XclImpSheetDrawingMap::iterator aIt = maSheetDrawings.begin(), aEnd = maSheetDrawings.end(); aIt != aEnd; ++aIt )
+ nProgressSize += aIt->second->GetProgressSize();
+ // nothing to do if progress bar is zero (no objects present)
+ if( nProgressSize == 0 )
+ return;
+
+ XclImpDffConverter aDffConv( GetRoot(), maDggStrm );
+ aDffConv.StartProgressBar( nProgressSize );
+ for( XclImpSheetDrawingMap::iterator aIt = maSheetDrawings.begin(), aEnd = maSheetDrawings.end(); aIt != aEnd; ++aIt )
+ aIt->second->ConvertObjects( aDffConv );
+
+ // #i112436# don't call ScChartListenerCollection::SetDirty here,
+ // instead use InterpretDirtyCells in ScDocument::CalcAfterLoad.
+}
+
+String XclImpObjectManager::GetDefaultObjName( const XclImpDrawObjBase& rDrawObj ) const
+{
+ String aDefName;
+ DefObjNameMap::const_iterator aIt = maDefObjNames.find( rDrawObj.GetObjType() );
+ if( aIt != maDefObjNames.end() )
+ aDefName.Append( aIt->second );
+ return aDefName.Append( sal_Unicode( ' ' ) ).Append( String::CreateFromInt32( rDrawObj.GetObjId() ) );
+}
+
+ScRange XclImpObjectManager::GetUsedArea( SCTAB nScTab ) const
+{
+ XclImpSheetDrawingMap::const_iterator aIt = maSheetDrawings.find( nScTab );
+ if( aIt != maSheetDrawings.end() )
+ return aIt->second->GetUsedArea();
+ return ScRange( ScAddress::INITIALIZE_INVALID );
+}
+
+// DFF property set helper ====================================================
+
+XclImpDffPropSet::XclImpDffPropSet( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ maDffConv( rRoot, maDummyStrm )
+{
+}
+
+void XclImpDffPropSet::Read( XclImpStream& rStrm )
+{
+ sal_uInt32 nPropSetSize;
+
+ rStrm.PushPosition();
+ rStrm.Ignore( 4 );
+ rStrm >> nPropSetSize;
+ rStrm.PopPosition();
+
+ mxMemStrm.reset( new SvMemoryStream );
+ rStrm.CopyToStream( *mxMemStrm, 8 + nPropSetSize );
+ mxMemStrm->Seek( STREAM_SEEK_TO_BEGIN );
+ maDffConv.ReadPropSet( *mxMemStrm, 0 );
+}
+
+sal_uInt32 XclImpDffPropSet::GetPropertyValue( sal_uInt16 nPropId, sal_uInt32 nDefault ) const
+{
+ return maDffConv.GetPropertyValue( nPropId, nDefault );
+}
+
+void XclImpDffPropSet::FillToItemSet( SfxItemSet& rItemSet ) const
+{
+ if( mxMemStrm.get() )
+ maDffConv.ApplyAttributes( *mxMemStrm, rItemSet );
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclImpDffPropSet& rPropSet )
+{
+ rPropSet.Read( rStrm );
+ return rStrm;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xiformula.cxx b/sc/source/filter/excel/xiformula.cxx
new file mode 100644
index 000000000000..c9927ff570fd
--- /dev/null
+++ b/sc/source/filter/excel/xiformula.cxx
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_sc.hxx"
+#include "xiformula.hxx"
+#include "rangelst.hxx"
+#include "xistream.hxx"
+
+#include "excform.hxx"
+
+// Formula compiler ===========================================================
+
+/** Implementation class of the export formula compiler. */
+class XclImpFmlaCompImpl : protected XclImpRoot, protected XclTokenArrayHelper
+{
+public:
+ explicit XclImpFmlaCompImpl( const XclImpRoot& rRoot );
+
+ /** Creates a range list from the passed Excel token array. */
+ void CreateRangeList(
+ ScRangeList& rScRanges, XclFormulaType eType,
+ const XclTokenArray& rXclTokArr, XclImpStream& rStrm );
+
+ const ScTokenArray* CreateFormula( XclFormulaType eType, const XclTokenArray& rXclTokArr );
+
+ // ------------------------------------------------------------------------
+private:
+ XclFunctionProvider maFuncProv; /// Excel function data provider.
+ const XclBiff meBiff; /// Cached BIFF version to save GetBiff() calls.
+};
+
+// ----------------------------------------------------------------------------
+
+XclImpFmlaCompImpl::XclImpFmlaCompImpl( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ maFuncProv( rRoot ),
+ meBiff( rRoot.GetBiff() )
+{
+}
+
+void XclImpFmlaCompImpl::CreateRangeList(
+ ScRangeList& rScRanges, XclFormulaType /*eType*/,
+ const XclTokenArray& rXclTokArr, XclImpStream& /*rStrm*/ )
+{
+ rScRanges.RemoveAll();
+
+ //! evil hack, using old formula import :-)
+ if( !rXclTokArr.Empty() )
+ {
+ SvMemoryStream aMemStrm;
+ aMemStrm << EXC_ID_EOF << rXclTokArr.GetSize();
+ aMemStrm.Write( rXclTokArr.GetData(), rXclTokArr.GetSize() );
+ XclImpStream aFmlaStrm( aMemStrm, GetRoot() );
+ aFmlaStrm.StartNextRecord();
+ GetOldFmlaConverter().GetAbsRefs( rScRanges, aFmlaStrm, aFmlaStrm.GetRecSize() );
+ }
+}
+
+const ScTokenArray* XclImpFmlaCompImpl::CreateFormula(
+ XclFormulaType /*eType*/, const XclTokenArray& rXclTokArr )
+{
+ if (rXclTokArr.Empty())
+ return NULL;
+
+ // evil hack! are we trying to phase out the old style formula converter ?
+ SvMemoryStream aMemStrm;
+ aMemStrm << EXC_ID_EOF << rXclTokArr.GetSize();
+ aMemStrm.Write( rXclTokArr.GetData(), rXclTokArr.GetSize() );
+ XclImpStream aFmlaStrm( aMemStrm, GetRoot() );
+ aFmlaStrm.StartNextRecord();
+ const ScTokenArray* pArray = NULL;
+ GetOldFmlaConverter().Reset();
+ GetOldFmlaConverter().Convert(pArray, aFmlaStrm, aFmlaStrm.GetRecSize(), true);
+ return pArray;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpFormulaCompiler::XclImpFormulaCompiler( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ mxImpl( new XclImpFmlaCompImpl( rRoot ) )
+{
+}
+
+XclImpFormulaCompiler::~XclImpFormulaCompiler()
+{
+}
+
+void XclImpFormulaCompiler::CreateRangeList(
+ ScRangeList& rScRanges, XclFormulaType eType,
+ const XclTokenArray& rXclTokArr, XclImpStream& rStrm )
+{
+ mxImpl->CreateRangeList( rScRanges, eType, rXclTokArr, rStrm );
+}
+
+const ScTokenArray* XclImpFormulaCompiler::CreateFormula(
+ XclFormulaType eType, const XclTokenArray& rXclTokArr )
+{
+ return mxImpl->CreateFormula(eType, rXclTokArr);
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xihelper.cxx b/sc/source/filter/excel/xihelper.cxx
new file mode 100644
index 000000000000..7fd1dd17e65a
--- /dev/null
+++ b/sc/source/filter/excel/xihelper.cxx
@@ -0,0 +1,893 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xihelper.hxx"
+#include <svl/itemset.hxx>
+#include <editeng/editobj.hxx>
+#include <tools/urlobj.hxx>
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include "document.hxx"
+#include "cell.hxx"
+#include "rangelst.hxx"
+#include "editutil.hxx"
+#include "attrib.hxx"
+#include "xltracer.hxx"
+#include "xistream.hxx"
+#include "xistyle.hxx"
+
+#include "excform.hxx"
+
+// Excel->Calc cell address/range conversion ==================================
+
+namespace {
+
+/** Fills the passed Calc address with the passed Excel cell coordinates without checking any limits. */
+inline void lclFillAddress( ScAddress& rScPos, sal_uInt16 nXclCol, sal_uInt32 nXclRow, SCTAB nScTab )
+{
+ rScPos.SetCol( static_cast< SCCOL >( nXclCol ) );
+ rScPos.SetRow( static_cast< SCROW >( nXclRow ) );
+ rScPos.SetTab( nScTab );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclImpAddressConverter::XclImpAddressConverter( const XclImpRoot& rRoot ) :
+ XclAddressConverterBase( rRoot.GetTracer(), rRoot.GetScMaxPos() )
+{
+}
+
+// cell address ---------------------------------------------------------------
+
+bool XclImpAddressConverter::CheckAddress( const XclAddress& rXclPos, bool bWarn )
+{
+ bool bValidCol = rXclPos.mnCol <= mnMaxCol;
+ bool bValidRow = rXclPos.mnRow <= mnMaxRow;
+ bool bValid = bValidCol && bValidRow;
+ if( !bValid && bWarn )
+ {
+ mbColTrunc |= !bValidCol;
+ mbRowTrunc |= !bValidRow;
+ mrTracer.TraceInvalidAddress( ScAddress(
+ static_cast< SCCOL >( rXclPos.mnCol ), static_cast< SCROW >( rXclPos.mnRow ), 0 ), maMaxPos );
+ }
+ return bValid;
+}
+
+bool XclImpAddressConverter::ConvertAddress( ScAddress& rScPos,
+ const XclAddress& rXclPos, SCTAB nScTab, bool bWarn )
+{
+ bool bValid = CheckAddress( rXclPos, bWarn );
+ if( bValid )
+ lclFillAddress( rScPos, rXclPos.mnCol, rXclPos.mnRow, nScTab );
+ return bValid;
+}
+
+ScAddress XclImpAddressConverter::CreateValidAddress(
+ const XclAddress& rXclPos, SCTAB nScTab, bool bWarn )
+{
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( !ConvertAddress( aScPos, rXclPos, nScTab, bWarn ) )
+ {
+ aScPos.SetCol( static_cast< SCCOL >( ::std::min( rXclPos.mnCol, mnMaxCol ) ) );
+ aScPos.SetRow( static_cast< SCROW >( ::std::min( rXclPos.mnRow, mnMaxRow ) ) );
+ aScPos.SetTab( limit_cast< SCTAB >( nScTab, 0, maMaxPos.Tab() ) );
+ }
+ return aScPos;
+}
+
+// cell range -----------------------------------------------------------------
+
+bool XclImpAddressConverter::ConvertRange( ScRange& rScRange,
+ const XclRange& rXclRange, SCTAB nScTab1, SCTAB nScTab2, bool bWarn )
+{
+ // check start position
+ bool bValidStart = CheckAddress( rXclRange.maFirst, bWarn );
+ if( bValidStart )
+ {
+ lclFillAddress( rScRange.aStart, rXclRange.maFirst.mnCol, rXclRange.maFirst.mnRow, nScTab1 );
+
+ // check & correct end position
+ sal_uInt16 nXclCol2 = rXclRange.maLast.mnCol;
+ sal_uInt32 nXclRow2 = rXclRange.maLast.mnRow;
+ if( !CheckAddress( rXclRange.maLast, bWarn ) )
+ {
+ nXclCol2 = ::std::min( nXclCol2, mnMaxCol );
+ nXclRow2 = ::std::min( nXclRow2, mnMaxRow );
+ }
+ lclFillAddress( rScRange.aEnd, nXclCol2, nXclRow2, nScTab2 );
+ }
+ return bValidStart;
+}
+
+// cell range list ------------------------------------------------------------
+
+void XclImpAddressConverter::ConvertRangeList( ScRangeList& rScRanges,
+ const XclRangeList& rXclRanges, SCTAB nScTab, bool bWarn )
+{
+ rScRanges.RemoveAll();
+ for( XclRangeList::const_iterator aIt = rXclRanges.begin(), aEnd = rXclRanges.end(); aIt != aEnd; ++aIt )
+ {
+ ScRange aScRange( ScAddress::UNINITIALIZED );
+ if( ConvertRange( aScRange, *aIt, nScTab, nScTab, bWarn ) )
+ rScRanges.Append( aScRange );
+ }
+}
+
+// String->EditEngine conversion ==============================================
+
+namespace {
+
+EditTextObject* lclCreateTextObject( const XclImpRoot& rRoot,
+ const XclImpString& rString, XclFontItemType eType, sal_uInt16 nXFIndex )
+{
+ EditTextObject* pTextObj = 0;
+
+ const XclImpXFBuffer& rXFBuffer = rRoot.GetXFBuffer();
+ const XclImpFont* pFirstFont = rXFBuffer.GetFont( nXFIndex );
+ bool bFirstEscaped = pFirstFont && pFirstFont->HasEscapement();
+
+ if( rString.IsRich() || bFirstEscaped )
+ {
+ const XclImpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
+ const XclFormatRunVec& rFormats = rString.GetFormats();
+
+ ScEditEngineDefaulter& rEE = (eType == EXC_FONTITEM_NOTE) ?
+ static_cast< ScEditEngineDefaulter& >( rRoot.GetDoc().GetNoteEngine() ) : rRoot.GetEditEngine();
+ rEE.SetText( rString.GetText() );
+
+ SfxItemSet aItemSet( rEE.GetEmptyItemSet() );
+ if( bFirstEscaped )
+ rFontBuffer.FillToItemSet( aItemSet, eType, rXFBuffer.GetFontIndex( nXFIndex ) );
+ ESelection aSelection;
+
+ XclFormatRun aNextRun;
+ XclFormatRunVec::const_iterator aIt = rFormats.begin();
+ XclFormatRunVec::const_iterator aEnd = rFormats.end();
+
+ if( aIt != aEnd )
+ aNextRun = *aIt++;
+ else
+ aNextRun.mnChar = 0xFFFF;
+
+ xub_StrLen nLen = rString.GetText().Len();
+ for( sal_uInt16 nChar = 0; nChar < nLen; ++nChar )
+ {
+ // reached new different formatted text portion
+ if( nChar >= aNextRun.mnChar )
+ {
+ // send items to edit engine
+ rEE.QuickSetAttribs( aItemSet, aSelection );
+
+ // start new item set
+ aItemSet.ClearItem();
+ rFontBuffer.FillToItemSet( aItemSet, eType, aNextRun.mnFontIdx );
+
+ // read new formatting information
+ if( aIt != aEnd )
+ aNextRun = *aIt++;
+ else
+ aNextRun.mnChar = 0xFFFF;
+
+ // reset selection start to current position
+ aSelection.nStartPara = aSelection.nEndPara;
+ aSelection.nStartPos = aSelection.nEndPos;
+ }
+
+ // set end of selection to current position
+ if( rString.GetText().GetChar( nChar ) == '\n' )
+ {
+ ++aSelection.nEndPara;
+ aSelection.nEndPos = 0;
+ }
+ else
+ ++aSelection.nEndPos;
+ }
+
+ // send items of last text portion to edit engine
+ rEE.QuickSetAttribs( aItemSet, aSelection );
+
+ pTextObj = rEE.CreateTextObject();
+ }
+
+ return pTextObj;
+}
+
+} // namespace
+
+EditTextObject* XclImpStringHelper::CreateTextObject(
+ const XclImpRoot& rRoot, const XclImpString& rString )
+{
+ return lclCreateTextObject( rRoot, rString, EXC_FONTITEM_EDITENG, 0 );
+}
+
+ScBaseCell* XclImpStringHelper::CreateCell(
+ const XclImpRoot& rRoot, const XclImpString& rString, sal_uInt16 nXFIndex )
+{
+ ScBaseCell* pCell = 0;
+
+ if( rString.GetText().Len() )
+ {
+ ::std::auto_ptr< EditTextObject > pTextObj( lclCreateTextObject( rRoot, rString, EXC_FONTITEM_EDITENG, nXFIndex ) );
+ ScDocument& rDoc = rRoot.GetDoc();
+
+ if( pTextObj.get() )
+ // ScEditCell creates own copy of text object
+ pCell = new ScEditCell( pTextObj.get(), &rDoc, rRoot.GetEditEngine().GetEditTextObjectPool() );
+ else
+ pCell = ScBaseCell::CreateTextCell( rString.GetText(), &rDoc );
+ }
+
+ return pCell;
+}
+
+// Header/footer conversion ===================================================
+
+XclImpHFConverter::XclImpHFPortionInfo::XclImpHFPortionInfo() :
+ mnHeight( 0 ),
+ mnMaxLineHt( 0 )
+{
+ maSel.nStartPara = maSel.nEndPara = 0;
+ maSel.nStartPos = maSel.nEndPos = 0;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpHFConverter::XclImpHFConverter( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ mrEE( rRoot.GetHFEditEngine() ),
+ mxFontData( new XclFontData ),
+ meCurrObj( EXC_HF_CENTER )
+{
+}
+
+XclImpHFConverter::~XclImpHFConverter()
+{
+}
+
+void XclImpHFConverter::ParseString( const String& rHFString )
+{
+ // edit engine objects
+ mrEE.SetText( EMPTY_STRING );
+ maInfos.clear();
+ maInfos.resize( EXC_HF_PORTION_COUNT );
+ meCurrObj = EXC_HF_CENTER;
+
+ // parser temporaries
+ maCurrText.Erase();
+ String aReadFont; // current font name
+ String aReadStyle; // current font style
+ sal_uInt16 nReadHeight = 0; // current font height
+ ResetFontData();
+
+ /** State of the parser. */
+ enum XclHFParserState
+ {
+ xlPSText, /// Read text, search for functions.
+ xlPSFunc, /// Read function (token following a '&').
+ xlPSFont, /// Read font name ('&' is followed by '"', reads until next '"' or ',').
+ xlPSFontStyle, /// Read font style name (font part after ',', reads until next '"').
+ xlPSHeight /// Read font height ('&' is followed by num. digits, reads until non-digit).
+ } eState = xlPSText;
+
+ const sal_Unicode* pChar = rHFString.GetBuffer();
+ const sal_Unicode* pNull = pChar + rHFString.Len(); // pointer to teminating null char
+ while( *pChar )
+ {
+ switch( eState )
+ {
+
+// --- read text character ---
+
+ case xlPSText:
+ {
+ switch( *pChar )
+ {
+ case '&': // new command
+ InsertText();
+ eState = xlPSFunc;
+ break;
+ case '\n': // line break
+ InsertText();
+ InsertLineBreak();
+ break;
+ default:
+ maCurrText += *pChar;
+ }
+ }
+ break;
+
+// --- read control sequence ---
+
+ case xlPSFunc:
+ {
+ eState = xlPSText;
+ switch( *pChar )
+ {
+ case '&': maCurrText += '&'; break; // the '&' character
+
+ case 'L': SetNewPortion( EXC_HF_LEFT ); break; // Left portion
+ case 'C': SetNewPortion( EXC_HF_CENTER ); break; // Center portion
+ case 'R': SetNewPortion( EXC_HF_RIGHT ); break; // Right portion
+
+ case 'P': InsertField( SvxFieldItem( SvxPageField(), EE_FEATURE_FIELD ) ); break; // page
+ case 'N': InsertField( SvxFieldItem( SvxPagesField(), EE_FEATURE_FIELD ) ); break; // page count
+ case 'D': InsertField( SvxFieldItem( SvxDateField(), EE_FEATURE_FIELD ) ); break; // date
+ case 'T': InsertField( SvxFieldItem( SvxTimeField(), EE_FEATURE_FIELD ) ); break; // time
+ case 'A': InsertField( SvxFieldItem( SvxTableField(), EE_FEATURE_FIELD ) ); break; // table name
+
+ case 'Z': // file path
+ InsertField( SvxFieldItem( SvxExtFileField(), EE_FEATURE_FIELD ) ); // convert to full name
+ if( (pNull - pChar >= 2) && (*(pChar + 1) == '&') && (*(pChar + 2) == 'F') )
+ {
+ // &Z&F found - ignore the &F part
+ pChar += 2;
+ }
+ break;
+ case 'F': // file name
+ InsertField( SvxFieldItem( SvxExtFileField( EMPTY_STRING, SVXFILETYPE_VAR, SVXFILEFORMAT_NAME_EXT ), EE_FEATURE_FIELD ) );
+ break;
+
+ case 'U': // underline
+ SetAttribs();
+ mxFontData->mnUnderline = (mxFontData->mnUnderline == EXC_FONTUNDERL_SINGLE) ?
+ EXC_FONTUNDERL_NONE : EXC_FONTUNDERL_SINGLE;
+ break;
+ case 'E': // double underline
+ SetAttribs();
+ mxFontData->mnUnderline = (mxFontData->mnUnderline == EXC_FONTUNDERL_DOUBLE) ?
+ EXC_FONTUNDERL_NONE : EXC_FONTUNDERL_DOUBLE;
+ break;
+ case 'S': // strikeout
+ SetAttribs();
+ mxFontData->mbStrikeout = !mxFontData->mbStrikeout;
+ break;
+ case 'X': // superscript
+ SetAttribs();
+ mxFontData->mnEscapem = (mxFontData->mnEscapem == EXC_FONTESC_SUPER) ?
+ EXC_FONTESC_NONE : EXC_FONTESC_SUPER;
+ break;
+ case 'Y': // subsrcipt
+ SetAttribs();
+ mxFontData->mnEscapem = (mxFontData->mnEscapem == EXC_FONTESC_SUB) ?
+ EXC_FONTESC_NONE : EXC_FONTESC_SUB;
+ break;
+
+ case '\"': // font name
+ aReadFont.Erase();
+ aReadStyle.Erase();
+ eState = xlPSFont;
+ break;
+ default:
+ if( ('0' <= *pChar) && (*pChar <= '9') ) // font size
+ {
+ nReadHeight = *pChar - '0';
+ eState = xlPSHeight;
+ }
+ }
+ }
+ break;
+
+// --- read font name ---
+
+ case xlPSFont:
+ {
+ switch( *pChar )
+ {
+ case '\"':
+ --pChar;
+ // run through
+ case ',':
+ eState = xlPSFontStyle;
+ break;
+ default:
+ aReadFont += *pChar;
+ }
+ }
+ break;
+
+// --- read font style ---
+
+ case xlPSFontStyle:
+ {
+ switch( *pChar )
+ {
+ case '\"':
+ SetAttribs();
+ if( aReadFont.Len() )
+ mxFontData->maName = aReadFont;
+ mxFontData->maStyle = aReadStyle;
+ eState = xlPSText;
+ break;
+ default:
+ aReadStyle += *pChar;
+ }
+ }
+ break;
+
+// --- read font height ---
+
+ case xlPSHeight:
+ {
+ if( ('0' <= *pChar) && (*pChar <= '9') )
+ {
+ if( nReadHeight != 0xFFFF )
+ {
+ nReadHeight *= 10;
+ nReadHeight += (*pChar - '0');
+ if( nReadHeight > 1600 ) // max 1600pt = 32000twips
+ nReadHeight = 0xFFFF;
+ }
+ }
+ else
+ {
+ if( (nReadHeight != 0) && (nReadHeight != 0xFFFF) )
+ {
+ SetAttribs();
+ mxFontData->mnHeight = nReadHeight * 20;
+ }
+ --pChar;
+ eState = xlPSText;
+ }
+ }
+ break;
+ }
+ ++pChar;
+ }
+
+ // finalize
+ CreateCurrObject();
+ maInfos[ EXC_HF_LEFT ].mnHeight += GetMaxLineHeight( EXC_HF_LEFT );
+ maInfos[ EXC_HF_CENTER ].mnHeight += GetMaxLineHeight( EXC_HF_CENTER );
+ maInfos[ EXC_HF_RIGHT ].mnHeight += GetMaxLineHeight( EXC_HF_RIGHT );
+}
+
+void XclImpHFConverter::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nWhichId ) const
+{
+ ScPageHFItem aHFItem( nWhichId );
+ if( maInfos[ EXC_HF_LEFT ].mxObj.get() )
+ aHFItem.SetLeftArea( *maInfos[ EXC_HF_LEFT ].mxObj );
+ if( maInfos[ EXC_HF_CENTER ].mxObj.get() )
+ aHFItem.SetCenterArea( *maInfos[ EXC_HF_CENTER ].mxObj );
+ if( maInfos[ EXC_HF_RIGHT ].mxObj.get() )
+ aHFItem.SetRightArea( *maInfos[ EXC_HF_RIGHT ].mxObj );
+ rItemSet.Put( aHFItem );
+}
+
+sal_Int32 XclImpHFConverter::GetTotalHeight() const
+{
+ return ::std::max( maInfos[ EXC_HF_LEFT ].mnHeight,
+ ::std::max( maInfos[ EXC_HF_CENTER ].mnHeight, maInfos[ EXC_HF_RIGHT ].mnHeight ) );
+}
+
+// private --------------------------------------------------------------------
+
+sal_uInt16 XclImpHFConverter::GetMaxLineHeight( XclImpHFPortion ePortion ) const
+{
+ sal_uInt16 nMaxHt = maInfos[ ePortion ].mnMaxLineHt;
+ return (nMaxHt == 0) ? mxFontData->mnHeight : nMaxHt;
+}
+
+sal_uInt16 XclImpHFConverter::GetCurrMaxLineHeight() const
+{
+ return GetMaxLineHeight( meCurrObj );
+}
+
+void XclImpHFConverter::UpdateMaxLineHeight( XclImpHFPortion ePortion )
+{
+ sal_uInt16& rnMaxHt = maInfos[ ePortion ].mnMaxLineHt;
+ rnMaxHt = ::std::max( rnMaxHt, mxFontData->mnHeight );
+}
+
+void XclImpHFConverter::UpdateCurrMaxLineHeight()
+{
+ UpdateMaxLineHeight( meCurrObj );
+}
+
+void XclImpHFConverter::SetAttribs()
+{
+ ESelection& rSel = GetCurrSel();
+ if( (rSel.nStartPara != rSel.nEndPara) || (rSel.nStartPos != rSel.nEndPos) )
+ {
+ SfxItemSet aItemSet( mrEE.GetEmptyItemSet() );
+ XclImpFont aFont( GetRoot(), *mxFontData );
+ aFont.FillToItemSet( aItemSet, EXC_FONTITEM_HF );
+ mrEE.QuickSetAttribs( aItemSet, rSel );
+ rSel.nStartPara = rSel.nEndPara;
+ rSel.nStartPos = rSel.nEndPos;
+ }
+}
+
+void XclImpHFConverter::ResetFontData()
+{
+ if( const XclImpFont* pFirstFont = GetFontBuffer().GetFont( EXC_FONT_APP ) )
+ *mxFontData = pFirstFont->GetFontData();
+ else
+ {
+ mxFontData->Clear();
+ mxFontData->mnHeight = 200;
+ }
+}
+
+void XclImpHFConverter::InsertText()
+{
+ if( maCurrText.Len() )
+ {
+ ESelection& rSel = GetCurrSel();
+ mrEE.QuickInsertText( maCurrText, ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
+ rSel.nEndPos = rSel.nEndPos + maCurrText.Len();
+ maCurrText.Erase();
+ UpdateCurrMaxLineHeight();
+ }
+}
+
+void XclImpHFConverter::InsertField( const SvxFieldItem& rFieldItem )
+{
+ ESelection& rSel = GetCurrSel();
+ mrEE.QuickInsertField( rFieldItem, ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
+ ++rSel.nEndPos;
+ UpdateCurrMaxLineHeight();
+}
+
+void XclImpHFConverter::InsertLineBreak()
+{
+ ESelection& rSel = GetCurrSel();
+ mrEE.QuickInsertText( String( '\n' ), ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
+ ++rSel.nEndPara;
+ rSel.nEndPos = 0;
+ GetCurrInfo().mnHeight += GetCurrMaxLineHeight();
+ GetCurrInfo().mnMaxLineHt = 0;
+}
+
+void XclImpHFConverter::CreateCurrObject()
+{
+ InsertText();
+ SetAttribs();
+ GetCurrObj().reset( mrEE.CreateTextObject() );
+}
+
+void XclImpHFConverter::SetNewPortion( XclImpHFPortion eNew )
+{
+ if( eNew != meCurrObj )
+ {
+ CreateCurrObject();
+ meCurrObj = eNew;
+ if( GetCurrObj().get() )
+ mrEE.SetText( *GetCurrObj() );
+ else
+ mrEE.SetText( EMPTY_STRING );
+ ResetFontData();
+ }
+}
+
+// URL conversion =============================================================
+
+namespace {
+
+void lclAppendUrlChar( String& rUrl, sal_Unicode cChar )
+{
+ // encode special characters
+ switch( cChar )
+ {
+ case '#': rUrl.AppendAscii( "%23" ); break;
+ case '%': rUrl.AppendAscii( "%25" ); break;
+ default: rUrl.Append( cChar );
+ }
+}
+
+} // namespace
+
+void XclImpUrlHelper::DecodeUrl(
+ String& rUrl, String& rTabName, bool& rbSameWb,
+ const XclImpRoot& rRoot, const String& rEncodedUrl )
+{
+ enum
+ {
+ xlUrlInit, /// Initial state, read string mode character.
+ xlUrlPath, /// Read URL path.
+ xlUrlFileName, /// Read file name.
+ xlUrlSheetName, /// Read sheet name.
+ xlUrlRaw /// Raw mode. No control characters will occur.
+ } eState = xlUrlInit;
+
+ bool bEncoded = true;
+ rbSameWb = false;
+
+ sal_Unicode cCurrDrive = 0;
+ String aDosBase( INetURLObject( rRoot.GetBasePath() ).getFSysPath( INetURLObject::FSYS_DOS ) );
+ if( (aDosBase.Len() > 2) && aDosBase.EqualsAscii( ":\\", 1, 2 ) )
+ cCurrDrive = aDosBase.GetChar( 0 );
+
+ const sal_Unicode* pChar = rEncodedUrl.GetBuffer();
+ while( *pChar )
+ {
+ switch( eState )
+ {
+
+// --- first character ---
+
+ case xlUrlInit:
+ {
+ switch( *pChar )
+ {
+ case EXC_URLSTART_ENCODED:
+ eState = xlUrlPath;
+ break;
+ case EXC_URLSTART_SELF:
+ case EXC_URLSTART_SELFENCODED:
+ rbSameWb = true;
+ eState = xlUrlSheetName;
+ break;
+ case '[':
+ bEncoded = false;
+ eState = xlUrlFileName;
+ break;
+ default:
+ bEncoded = false;
+ lclAppendUrlChar( rUrl, *pChar );
+ eState = xlUrlPath;
+ }
+ }
+ break;
+
+// --- URL path ---
+
+ case xlUrlPath:
+ {
+ switch( *pChar )
+ {
+ case EXC_URL_DOSDRIVE:
+ {
+ if( *(pChar + 1) )
+ {
+ ++pChar;
+ if( *pChar == '@' )
+ rUrl.AppendAscii( "\\\\" );
+ else
+ {
+ lclAppendUrlChar( rUrl, *pChar );
+ rUrl.AppendAscii( ":\\" );
+ }
+ }
+ else
+ rUrl.AppendAscii( "<NULL-DRIVE!>" );
+ }
+ break;
+ case EXC_URL_DRIVEROOT:
+ if( cCurrDrive )
+ {
+ lclAppendUrlChar( rUrl, cCurrDrive );
+ rUrl.Append( ':' );
+ }
+ // run through
+ case EXC_URL_SUBDIR:
+ if( bEncoded )
+ rUrl.Append( '\\' );
+ else // control character in raw name -> DDE link
+ {
+ rUrl.Append( EXC_DDE_DELIM );
+ eState = xlUrlRaw;
+ }
+ break;
+ case EXC_URL_PARENTDIR:
+ rUrl.AppendAscii( "..\\" );
+ break;
+ case EXC_URL_RAW:
+ {
+ if( *(pChar + 1) )
+ {
+ xub_StrLen nLen = *++pChar;
+ for( xub_StrLen nChar = 0; (nChar < nLen) && *(pChar + 1); ++nChar )
+ lclAppendUrlChar( rUrl, *++pChar );
+// rUrl.Append( ':' );
+ }
+ }
+ break;
+ case '[':
+ eState = xlUrlFileName;
+ break;
+ default:
+ lclAppendUrlChar( rUrl, *pChar );
+ }
+ }
+ break;
+
+// --- file name ---
+
+ case xlUrlFileName:
+ {
+ switch( *pChar )
+ {
+ case ']': eState = xlUrlSheetName; break;
+ default: lclAppendUrlChar( rUrl, *pChar );
+ }
+ }
+ break;
+
+// --- sheet name ---
+
+ case xlUrlSheetName:
+ rTabName.Append( *pChar );
+ break;
+
+// --- raw read mode ---
+
+ case xlUrlRaw:
+ lclAppendUrlChar( rUrl, *pChar );
+ break;
+ }
+
+ ++pChar;
+ }
+}
+
+void XclImpUrlHelper::DecodeUrl(
+ String& rUrl, bool& rbSameWb, const XclImpRoot& rRoot, const String& rEncodedUrl )
+{
+ String aTabName;
+ DecodeUrl( rUrl, aTabName, rbSameWb, rRoot, rEncodedUrl );
+ DBG_ASSERT( !aTabName.Len(), "XclImpUrlHelper::DecodeUrl - sheet name ignored" );
+}
+
+bool XclImpUrlHelper::DecodeLink( String& rApplic, String& rTopic, const String rEncUrl )
+{
+ xub_StrLen nPos = rEncUrl.Search( EXC_DDE_DELIM );
+ if( (nPos != STRING_NOTFOUND) && (0 < nPos) && (nPos + 1 < rEncUrl.Len()) )
+ {
+ rApplic = rEncUrl.Copy( 0, nPos );
+ rTopic = rEncUrl.Copy( nPos + 1 );
+ return true;
+ }
+ return false;
+}
+
+// Cached Values ==============================================================
+
+XclImpCachedValue::XclImpCachedValue( XclImpStream& rStrm ) :
+ mfValue( 0.0 ),
+ mnBoolErr( 0 )
+{
+ rStrm >> mnType;
+ switch( mnType )
+ {
+ case EXC_CACHEDVAL_EMPTY:
+ rStrm.Ignore( 8 );
+ break;
+ case EXC_CACHEDVAL_DOUBLE:
+ rStrm >> mfValue;
+ break;
+ case EXC_CACHEDVAL_STRING:
+ mxStr.reset( new String( rStrm.ReadUniString() ) );
+ break;
+ case EXC_CACHEDVAL_BOOL:
+ case EXC_CACHEDVAL_ERROR:
+ {
+ double fVal;
+ rStrm >> mnBoolErr;
+ rStrm.Ignore( 7 );
+
+ const ScTokenArray* pScTokArr = rStrm.GetRoot().GetOldFmlaConverter().GetBoolErr(
+ XclTools::ErrorToEnum( fVal, mnType == EXC_CACHEDVAL_ERROR, mnBoolErr ) );
+ if( pScTokArr )
+ mxTokArr.reset( pScTokArr->Clone() );
+ }
+ break;
+ default:
+ DBG_ERRORFILE( "XclImpCachedValue::XclImpCachedValue - unknown data type" );
+ }
+}
+
+XclImpCachedValue::~XclImpCachedValue()
+{
+}
+
+sal_uInt16 XclImpCachedValue::GetScError() const
+{
+ return (mnType == EXC_CACHEDVAL_ERROR) ? XclTools::GetScErrorCode( mnBoolErr ) : 0;
+}
+
+// Matrix Cached Values ==============================================================
+
+XclImpCachedMatrix::XclImpCachedMatrix( XclImpStream& rStrm ) :
+ mnScCols( 0 ),
+ mnScRows( 0 )
+{
+ mnScCols = rStrm.ReaduInt8();
+ mnScRows = rStrm.ReaduInt16();
+
+ if( rStrm.GetRoot().GetBiff() <= EXC_BIFF5 )
+ {
+ // in BIFF2-BIFF7: 256 columns represented by 0 columns
+ if( mnScCols == 0 )
+ mnScCols = 256;
+ }
+ else
+ {
+ // in BIFF8: columns and rows decreaed by 1
+ ++mnScCols;
+ ++mnScRows;
+ }
+
+ for( SCSIZE nScRow = 0; nScRow < mnScRows; ++nScRow )
+ for( SCSIZE nScCol = 0; nScCol < mnScCols; ++nScCol )
+ maValueList.push_back( new XclImpCachedValue( rStrm ) );
+}
+
+XclImpCachedMatrix::~XclImpCachedMatrix()
+{
+}
+
+ScMatrixRef XclImpCachedMatrix::CreateScMatrix() const
+{
+ ScMatrixRef xScMatrix;
+ DBG_ASSERT( mnScCols * mnScRows == maValueList.size(), "XclImpCachedMatrix::CreateScMatrix - element count mismatch" );
+ if( mnScCols && mnScRows && static_cast< sal_uLong >( mnScCols * mnScRows ) <= maValueList.size() )
+ {
+ xScMatrix = new ScMatrix( mnScCols, mnScRows );
+ XclImpValueList::const_iterator itValue = maValueList.begin();
+ for( SCSIZE nScRow = 0; nScRow < mnScRows; ++nScRow )
+ {
+ for( SCSIZE nScCol = 0; nScCol < mnScCols; ++nScCol )
+ {
+ switch( itValue->GetType() )
+ {
+ case EXC_CACHEDVAL_EMPTY:
+ // Excel shows 0.0 here, not an empty cell
+ xScMatrix->PutEmpty( nScCol, nScRow );
+ break;
+ case EXC_CACHEDVAL_DOUBLE:
+ xScMatrix->PutDouble( itValue->GetValue(), nScCol, nScRow );
+ break;
+ case EXC_CACHEDVAL_STRING:
+ xScMatrix->PutString( itValue->GetString(), nScCol, nScRow );
+ break;
+ case EXC_CACHEDVAL_BOOL:
+ xScMatrix->PutBoolean( itValue->GetBool(), nScCol, nScRow );
+ break;
+ case EXC_CACHEDVAL_ERROR:
+ xScMatrix->PutError( itValue->GetScError(), nScCol, nScRow );
+ break;
+ default:
+ DBG_ERRORFILE( "XclImpCachedMatrix::CreateScMatrix - unknown value type" );
+ xScMatrix->PutEmpty( nScCol, nScRow );
+ }
+ ++itValue;
+ }
+ }
+ }
+ return xScMatrix;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xilink.cxx b/sc/source/filter/excel/xilink.cxx
new file mode 100644
index 000000000000..492fe5d2033c
--- /dev/null
+++ b/sc/source/filter/excel/xilink.cxx
@@ -0,0 +1,952 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xilink.hxx"
+#include "document.hxx"
+#include "cell.hxx"
+#include "scextopt.hxx"
+#include "tablink.hxx"
+#include "xistream.hxx"
+#include "xihelper.hxx"
+#include "xiname.hxx"
+#include "excform.hxx"
+#include "tokenarray.hxx"
+#include "externalrefmgr.hxx"
+
+#include <vector>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+using ::std::vector;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+
+// ============================================================================
+// *** Helper classes ***
+// ============================================================================
+
+// Cached external cells ======================================================
+
+/**
+ * Contains the address and value of an external referenced cell.
+ * Note that this is non-copyable, so cannot be used in most stl/boost containers.
+ */
+class XclImpCrn : public XclImpCachedValue
+{
+public:
+ /** Reads a cached value and stores it with its cell address. */
+ explicit XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
+
+ const XclAddress& GetAddress() const;
+
+private:
+ XclAddress maXclPos; /// Excel position of the cached cell.
+};
+
+// Sheet in an external document ==============================================
+
+/** Contains the name and sheet index of one sheet in an external document. */
+class XclImpSupbookTab
+{
+public:
+ /** Stores the sheet name and marks the sheet index as invalid.
+ The sheet index is set while creating the Calc sheet with CreateTable(). */
+ explicit XclImpSupbookTab( const String& rTabName );
+ ~XclImpSupbookTab();
+
+ inline const String& GetTabName() const { return maTabName; }
+
+ /** Reads a CRN record (external referenced cell) at the specified address. */
+ void ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
+
+ void LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable);
+
+private:
+ typedef boost::shared_ptr< XclImpCrn > XclImpCrnRef;
+ typedef std::vector< XclImpCrnRef > XclImpCrnList;
+
+ XclImpCrnList maCrnList; /// List of CRN records (cached cell values).
+ String maTabName; /// Name of the external sheet.
+ SCTAB mnScTab; /// New sheet index in Calc document.
+};
+
+// External document (SUPBOOK) ================================================
+
+/** This class represents an external linked document (record SUPBOOK).
+ @descr Contains a list of all referenced sheets in the document. */
+class XclImpSupbook : protected XclImpRoot
+{
+public:
+ /** Reads the SUPBOOK record from stream. */
+ explicit XclImpSupbook( XclImpStream& rStrm );
+
+ /** Reads an XCT record (count of following CRNs and current sheet). */
+ void ReadXct( XclImpStream& rStrm );
+ /** Reads a CRN record (external referenced cell). */
+ void ReadCrn( XclImpStream& rStrm );
+ /** Reads an EXTERNNAME record. */
+ void ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
+
+ /** Returns the SUPBOOK record type. */
+ inline XclSupbookType GetType() const { return meType; }
+
+ /** Returns the URL of the external document. */
+ inline const String& GetXclUrl() const { return maXclUrl; }
+
+ /** Returns the external name specified by an index from the Excel document (one-based). */
+ const XclImpExtName* GetExternName( sal_uInt16 nXclIndex ) const;
+ /** Tries to decode the URL to OLE or DDE link components.
+ @descr For DDE links: Decodes to application name and topic.
+ For OLE object links: Decodes to class name and document URL.
+ @return true = decoding was successful, returned strings are valid (not empty). */
+ bool GetLinkData( String& rApplic, String& rDoc ) const;
+ /** Returns the specified macro name (1-based) or an empty string on error. */
+ const String& GetMacroName( sal_uInt16 nXclNameIdx ) const;
+
+ const String& GetTabName( sal_uInt16 nXtiTab ) const;
+
+ sal_uInt16 GetTabCount() const;
+
+ void LoadCachedValues();
+
+private:
+ typedef boost::ptr_vector< XclImpSupbookTab > XclImpSupbookTabList;
+ typedef boost::ptr_vector< XclImpExtName > XclImpExtNameList;
+
+ XclImpSupbookTabList maSupbTabList; /// All sheet names of the document.
+ XclImpExtNameList maExtNameList; /// All external names of the document.
+ String maXclUrl; /// URL of the external document (Excel mode).
+ String maFilterName; /// Detected filer name.
+ String maFilterOpt; /// Detected filer options.
+ XclSupbookType meType; /// Type of the supbook record.
+ sal_uInt16 mnSBTab; /// Current Excel sheet index from SUPBOOK for XCT/CRN records.
+};
+
+// Import link manager ========================================================
+
+/** Contains the SUPBOOK index and sheet indexes of an external link.
+ @descr It is possible to enter a formula like =SUM(Sheet1:Sheet3!A1),
+ therefore here occurs a sheet range. */
+struct XclImpXti
+{
+ sal_uInt16 mnSupbook; /// Index to SUPBOOK record.
+ sal_uInt16 mnSBTabFirst; /// Index to the first sheet of the range in the SUPBOOK.
+ sal_uInt16 mnSBTabLast; /// Index to the last sheet of the range in the SUPBOOK.
+ inline explicit XclImpXti() : mnSupbook( SAL_MAX_UINT16 ), mnSBTabFirst( SAL_MAX_UINT16 ), mnSBTabLast( SAL_MAX_UINT16 ) {}
+};
+
+inline XclImpStream& operator>>( XclImpStream& rStrm, XclImpXti& rXti )
+{
+ return rStrm >> rXti.mnSupbook >> rXti.mnSBTabFirst >> rXti.mnSBTabLast;
+}
+
+// ----------------------------------------------------------------------------
+
+/** Implementation of the link manager. */
+class XclImpLinkManagerImpl : protected XclImpRoot
+{
+public:
+ explicit XclImpLinkManagerImpl( const XclImpRoot& rRoot );
+
+ /** Reads the EXTERNSHEET record. */
+ void ReadExternsheet( XclImpStream& rStrm );
+ /** Reads a SUPBOOK record. */
+ void ReadSupbook( XclImpStream& rStrm );
+ /** Reads an XCT record and appends it to the current SUPBOOK. */
+ void ReadXct( XclImpStream& rStrm );
+ /** Reads a CRN record and appends it to the current SUPBOOK. */
+ void ReadCrn( XclImpStream& rStrm );
+ /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */
+ void ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
+
+ /** Returns true, if the specified XTI entry contains an internal reference. */
+ bool IsSelfRef( sal_uInt16 nXtiIndex ) const;
+ /** Returns the Calc sheet index range of the specified XTI entry.
+ @return true = XTI data found, returned sheet index range is valid. */
+ bool GetScTabRange(
+ SCTAB& rnFirstScTab, SCTAB& rnLastScTab,
+ sal_uInt16 nXtiIndex ) const;
+ /** Returns the specified external name or 0 on error. */
+ const XclImpExtName* GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const;
+
+ /** Returns the absolute file URL of a supporting workbook specified by
+ the index. */
+ const String* GetSupbookUrl( sal_uInt16 nXtiIndex ) const;
+
+ const String& GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const;
+
+ /** Tries to decode the URL of the specified XTI entry to OLE or DDE link components.
+ @descr For DDE links: Decodes to application name and topic.
+ For OLE object links: Decodes to class name and document URL.
+ @return true = decoding was successful, returned strings are valid (not empty). */
+ bool GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const;
+ /** Returns the specified macro name or an empty string on error. */
+ const String& GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const;
+
+private:
+ /** Returns the specified XTI (link entry from BIFF8 EXTERNSHEET record). */
+ const XclImpXti* GetXti( sal_uInt16 nXtiIndex ) const;
+ /** Returns the specified SUPBOOK (external document). */
+ const XclImpSupbook* GetSupbook( sal_uInt16 nXtiIndex ) const;
+
+ void LoadCachedValues();
+
+private:
+ typedef ::std::vector< XclImpXti > XclImpXtiVector;
+ typedef boost::ptr_vector< XclImpSupbook > XclImpSupbookList;
+
+ XclImpXtiVector maXtiList; /// List of all XTI structures.
+ XclImpSupbookList maSupbookList; /// List of external documents.
+ bool mbCreated; /// true = Calc sheets already created.
+};
+
+// ============================================================================
+// *** Implementation ***
+// ============================================================================
+
+// Excel sheet indexes ========================================================
+
+// original Excel sheet names -------------------------------------------------
+
+void XclImpTabInfo::AppendXclTabName( const String& rXclTabName, SCTAB nScTab )
+{
+ maTabNames[ rXclTabName ] = nScTab;
+}
+
+void XclImpTabInfo::InsertScTab( SCTAB nScTab )
+{
+ for( XclTabNameMap::iterator aIt = maTabNames.begin(), aEnd = maTabNames.end(); aIt != aEnd; ++aIt )
+ if( aIt->second >= nScTab )
+ ++aIt->second;
+}
+
+SCTAB XclImpTabInfo::GetScTabFromXclName( const String& rXclTabName ) const
+{
+ XclTabNameMap::const_iterator aIt = maTabNames.find( rXclTabName );
+ return (aIt != maTabNames.end()) ? aIt->second : SCTAB_INVALID;
+}
+
+// record creation order - TABID record ---------------------------------------
+
+void XclImpTabInfo::ReadTabid( XclImpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
+ if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
+ {
+ rStrm.EnableDecryption();
+ sal_Size nReadCount = rStrm.GetRecLeft() / 2;
+ DBG_ASSERT( nReadCount <= 0xFFFF, "XclImpTabInfo::ReadTabid - record too long" );
+ maTabIdVec.clear();
+ maTabIdVec.reserve( nReadCount );
+ for( sal_Size nIndex = 0; rStrm.IsValid() && (nIndex < nReadCount); ++nIndex )
+ // zero index is not allowed in BIFF8, but it seems that it occurs in real life
+ maTabIdVec.push_back( rStrm.ReaduInt16() );
+ }
+}
+
+sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMaxTabId ) const
+{
+ sal_uInt16 nReturn = 0;
+ for( ScfUInt16Vec::const_iterator aIt = maTabIdVec.begin(), aEnd = maTabIdVec.end(); aIt != aEnd; ++aIt )
+ {
+ sal_uInt16 nValue = *aIt;
+ if( nValue == nCreatedId )
+ return nReturn;
+ if( nValue <= nMaxTabId )
+ ++nReturn;
+ }
+ return 0;
+}
+
+// External names =============================================================
+
+XclImpExtName::MOper::MOper(XclImpStream& rStrm) :
+ mxCached(new ScMatrix(0,0))
+{
+ SCSIZE nLastCol = rStrm.ReaduInt8();
+ SCSIZE nLastRow = rStrm.ReaduInt16();
+ mxCached->Resize(nLastCol+1, nLastRow+1);
+ for (SCSIZE nRow = 0; nRow <= nLastRow; ++nRow)
+ {
+ for (SCSIZE nCol = 0; nCol <= nLastCol; ++nCol)
+ {
+ sal_uInt8 nOp;
+ rStrm >> nOp;
+ switch (nOp)
+ {
+ case 0x01:
+ {
+ double fVal = rStrm.ReadDouble();
+ mxCached->PutDouble(fVal, nCol, nRow);
+ }
+ break;
+ case 0x02:
+ {
+ OUString aStr = rStrm.ReadUniString();
+ mxCached->PutString(aStr, nCol, nRow);
+ }
+ break;
+ case 0x04:
+ {
+ bool bVal = rStrm.ReaduInt8();
+ mxCached->PutBoolean(bVal, nCol, nRow);
+ rStrm.Ignore(7);
+ }
+ break;
+ case 0x10:
+ {
+ sal_uInt8 nErr = rStrm.ReaduInt8();
+ // TODO: Map the error code from xls to calc.
+ mxCached->PutError(nErr, nCol, nRow);
+ rStrm.Ignore(7);
+ }
+ break;
+ default:
+ rStrm.Ignore(8);
+ }
+ }
+ }
+}
+
+const ScMatrix& XclImpExtName::MOper::GetCache() const
+{
+ return *mxCached;
+}
+
+XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv ) :
+ mpMOper(NULL)
+{
+ sal_uInt16 nFlags;
+ sal_uInt8 nLen;
+
+ rStrm >> nFlags >> mnStorageId >> nLen ;
+ maName = rStrm.ReadUniString( nLen );
+ if( ::get_flag( nFlags, EXC_EXTN_BUILTIN ) || !::get_flag( nFlags, EXC_EXTN_OLE_OR_DDE ) )
+ {
+ if( eSubType == EXC_SBTYPE_ADDIN )
+ {
+ meType = xlExtAddIn;
+ maName = rStrm.GetRoot().GetScAddInName( maName );
+ }
+ else if ( (eSubType == EXC_SBTYPE_EUROTOOL) &&
+ maName.EqualsIgnoreCaseAscii( "EUROCONVERT" ) )
+ meType = xlExtEuroConvert;
+ else
+ {
+ meType = xlExtName;
+ ScfTools::ConvertToScDefinedName( maName );
+ }
+ }
+ else
+ {
+ meType = ::get_flagvalue( nFlags, EXC_EXTN_OLE, xlExtOLE, xlExtDDE );
+ }
+
+ switch (meType)
+ {
+ case xlExtDDE:
+ if (rStrm.GetRecLeft() > 1)
+ mxDdeMatrix.reset(new XclImpCachedMatrix(rStrm));
+ break;
+ case xlExtName:
+ // TODO: For now, only global external names are supported. In future
+ // we should extend this to supporting per-sheet external names.
+ if (mnStorageId == 0)
+ {
+ if (pFormulaConv)
+ {
+ const ScTokenArray* pArray = NULL;
+ sal_uInt16 nFmlaLen;
+ rStrm >> nFmlaLen;
+ vector<String> aTabNames;
+ sal_uInt16 nCount = rSupbook.GetTabCount();
+ aTabNames.reserve(nCount);
+ for (sal_uInt16 i = 0; i < nCount; ++i)
+ aTabNames.push_back(rSupbook.GetTabName(i));
+
+ pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames);
+ if (pArray)
+ mxArray.reset(pArray->Clone());
+ }
+ }
+ break;
+ case xlExtOLE:
+ mpMOper = new MOper(rStrm);
+ break;
+ default:
+ ;
+ }
+}
+
+XclImpExtName::~XclImpExtName()
+{
+ delete mpMOper;
+}
+
+void XclImpExtName::CreateDdeData( ScDocument& rDoc, const String& rApplic, const String& rTopic ) const
+{
+ ScMatrixRef xResults;
+ if( mxDdeMatrix.get() )
+ xResults = mxDdeMatrix->CreateScMatrix();
+ rDoc.CreateDdeLink( rApplic, rTopic, maName, SC_DDE_DEFAULT, xResults );
+}
+
+void XclImpExtName::CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const
+{
+ if (!mxArray.get())
+ return;
+
+ ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
+ pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray);
+}
+
+namespace {
+
+/**
+ * Decompose the name into sheet name and range name. An OLE link name is
+ * always formatted like this [ !Sheet1!R1C1:R5C2 ] and it always uses R1C1
+ * notation.
+ */
+bool extractSheetAndRange(const OUString& rName, OUString& rSheet, OUString& rRange)
+{
+ sal_Int32 n = rName.getLength();
+ const sal_Unicode* p = rName.getStr();
+ OUStringBuffer aBuf;
+ bool bInSheet = true;
+ for (sal_Int32 i = 0; i < n; ++i, ++p)
+ {
+ if (i == 0)
+ {
+ // first character must be '!'.
+ if (*p != '!')
+ return false;
+ continue;
+ }
+
+ if (*p == '!')
+ {
+ // sheet name to range separator.
+ if (!bInSheet)
+ return false;
+ rSheet = aBuf.makeStringAndClear();
+ bInSheet = false;
+ continue;
+ }
+
+ aBuf.append(*p);
+ }
+
+ rRange = aBuf.makeStringAndClear();
+ return true;
+}
+
+}
+
+bool XclImpExtName::CreateOleData(ScDocument& rDoc, const OUString& rUrl,
+ sal_uInt16& rFileId, OUString& rTabName, ScRange& rRange) const
+{
+ if (!mpMOper)
+ return false;
+
+ OUString aSheet, aRangeStr;
+ if (!extractSheetAndRange(maName, aSheet, aRangeStr))
+ return false;
+
+ ScRange aRange;
+ sal_uInt16 nRes = aRange.ParseAny(aRangeStr, &rDoc, formula::FormulaGrammar::CONV_XL_R1C1);
+ if ((nRes & SCA_VALID) != SCA_VALID)
+ return false;
+
+ if (aRange.aStart.Tab() != aRange.aEnd.Tab())
+ // We don't support multi-sheet range for this.
+ return false;
+
+ const ScMatrix& rCache = mpMOper->GetCache();
+ SCSIZE nC, nR;
+ rCache.GetDimensions(nC, nR);
+ if (!nC || !nR)
+ // cache matrix is empty.
+ return false;
+
+ ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
+ sal_uInt16 nFileId = pRefMgr->getExternalFileId(rUrl);
+ ScExternalRefCache::TableTypeRef xTab = pRefMgr->getCacheTable(nFileId, aSheet, true, NULL);
+ if (!xTab)
+ // cache table creation failed.
+ return false;
+
+ xTab->setWholeTableCached();
+ for (SCSIZE i = 0; i < nR; ++i)
+ {
+ for (SCSIZE j = 0; j < nC; ++j)
+ {
+ SCCOL nCol = aRange.aStart.Col() + j;
+ SCROW nRow = aRange.aStart.Row() + i;
+
+ ScMatrixValue aVal = rCache.Get(j, i);
+ switch (aVal.nType)
+ {
+ case SC_MATVAL_BOOLEAN:
+ {
+ bool b = aVal.GetBoolean();
+ ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0));
+ xTab->setCell(nCol, nRow, pToken, 0, false);
+ }
+ break;
+ case SC_MATVAL_VALUE:
+ {
+ ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(aVal.fVal));
+ xTab->setCell(nCol, nRow, pToken, 0, false);
+ }
+ break;
+ case SC_MATVAL_STRING:
+ {
+ const String& rStr = aVal.GetString();
+ ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(rStr));
+ xTab->setCell(nCol, nRow, pToken, 0, false);
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ }
+
+ rFileId = nFileId;
+ rTabName = aSheet;
+ rRange = aRange;
+ return true;
+}
+
+bool XclImpExtName::HasFormulaTokens() const
+{
+ return (mxArray.get() != NULL);
+}
+
+// Cached external cells ======================================================
+
+XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) :
+ XclImpCachedValue( rStrm ),
+ maXclPos( rXclPos )
+{
+}
+
+const XclAddress& XclImpCrn::GetAddress() const
+{
+ return maXclPos;
+}
+
+// Sheet in an external document ==============================================
+
+XclImpSupbookTab::XclImpSupbookTab( const String& rTabName ) :
+ maTabName( rTabName ),
+ mnScTab( SCTAB_INVALID )
+{
+}
+
+XclImpSupbookTab::~XclImpSupbookTab()
+{
+}
+
+void XclImpSupbookTab::ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos )
+{
+ XclImpCrnRef crnRef( new XclImpCrn(rStrm, rXclPos) );
+ maCrnList.push_back( crnRef );
+}
+
+void XclImpSupbookTab::LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable)
+{
+ if (maCrnList.empty())
+ return;
+
+ for (XclImpCrnList::iterator itCrnRef = maCrnList.begin(); itCrnRef != maCrnList.end(); ++itCrnRef)
+ {
+ const XclImpCrn* const pCrn = itCrnRef->get();
+ const XclAddress& rAddr = pCrn->GetAddress();
+ switch (pCrn->GetType())
+ {
+ case EXC_CACHEDVAL_BOOL:
+ {
+ bool b = pCrn->GetBool();
+ ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0));
+ pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
+ }
+ break;
+ case EXC_CACHEDVAL_DOUBLE:
+ {
+ double f = pCrn->GetValue();
+ ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(f));
+ pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
+ }
+ break;
+ case EXC_CACHEDVAL_ERROR:
+ {
+ double fError = XclTools::ErrorToDouble( pCrn->GetXclError() );
+ ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(fError));
+ pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
+ }
+ break;
+ case EXC_CACHEDVAL_STRING:
+ {
+ const String& rStr = pCrn->GetString();
+ ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(rStr));
+ pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+// External document (SUPBOOK) ================================================
+
+XclImpSupbook::XclImpSupbook( XclImpStream& rStrm ) :
+ XclImpRoot( rStrm.GetRoot() ),
+ meType( EXC_SBTYPE_UNKNOWN ),
+ mnSBTab( EXC_TAB_DELETED )
+{
+ sal_uInt16 nSBTabCnt;
+ rStrm >> nSBTabCnt;
+
+ if( rStrm.GetRecLeft() == 2 )
+ {
+ switch( rStrm.ReaduInt16() )
+ {
+ case EXC_SUPB_SELF: meType = EXC_SBTYPE_SELF; break;
+ case EXC_SUPB_ADDIN: meType = EXC_SBTYPE_ADDIN; break;
+ default: DBG_ERRORFILE( "XclImpSupbook::XclImpSupbook - unknown special SUPBOOK type" );
+ }
+ return;
+ }
+
+ String aEncUrl( rStrm.ReadUniString() );
+ bool bSelf = false;
+ XclImpUrlHelper::DecodeUrl( maXclUrl, bSelf, GetRoot(), aEncUrl );
+
+ if( maXclUrl.EqualsIgnoreCaseAscii( "\010EUROTOOL.XLA" ) )
+ {
+ meType = EXC_SBTYPE_EUROTOOL;
+ maSupbTabList.push_back( new XclImpSupbookTab( maXclUrl ) );
+ }
+ else if( nSBTabCnt )
+ {
+ meType = EXC_SBTYPE_EXTERN;
+ for( sal_uInt16 nSBTab = 0; nSBTab < nSBTabCnt; ++nSBTab )
+ {
+ String aTabName( rStrm.ReadUniString() );
+ maSupbTabList.push_back( new XclImpSupbookTab( aTabName ) );
+ }
+ }
+ else
+ {
+ meType = EXC_SBTYPE_SPECIAL;
+ // create dummy list entry
+ maSupbTabList.push_back( new XclImpSupbookTab( maXclUrl ) );
+ }
+}
+
+void XclImpSupbook::ReadXct( XclImpStream& rStrm )
+{
+ rStrm.Ignore( 2 );
+ rStrm >> mnSBTab;
+}
+
+void XclImpSupbook::ReadCrn( XclImpStream& rStrm )
+{
+ if (mnSBTab >= maSupbTabList.size())
+ return;
+ XclImpSupbookTab& rSbTab = maSupbTabList[mnSBTab];
+ sal_uInt8 nXclColLast, nXclColFirst;
+ sal_uInt16 nXclRow;
+ rStrm >> nXclColLast >> nXclColFirst >> nXclRow;
+
+ for( sal_uInt8 nXclCol = nXclColFirst; (nXclCol <= nXclColLast) && (rStrm.GetRecLeft() > 1); ++nXclCol )
+ rSbTab.ReadCrn( rStrm, XclAddress( nXclCol, nXclRow ) );
+}
+
+void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
+{
+ maExtNameList.push_back( new XclImpExtName( *this, rStrm, meType, pFormulaConv ) );
+}
+
+const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const
+{
+ DBG_ASSERT( nXclIndex > 0, "XclImpSupbook::GetExternName - index must be >0" );
+ if (meType == EXC_SBTYPE_SELF || nXclIndex > maExtNameList.size())
+ return NULL;
+ return &maExtNameList[nXclIndex-1];
+}
+
+bool XclImpSupbook::GetLinkData( String& rApplic, String& rTopic ) const
+{
+ return (meType == EXC_SBTYPE_SPECIAL) && XclImpUrlHelper::DecodeLink( rApplic, rTopic, maXclUrl );
+}
+
+const String& XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx ) const
+{
+ DBG_ASSERT( nXclNameIdx > 0, "XclImpSupbook::GetMacroName - index must be >0" );
+ const XclImpName* pName = (meType == EXC_SBTYPE_SELF) ? GetNameManager().GetName( nXclNameIdx ) : 0;
+ return (pName && pName->IsVBName()) ? pName->GetScName() : EMPTY_STRING;
+}
+
+const String& XclImpSupbook::GetTabName( sal_uInt16 nXtiTab ) const
+{
+ if (nXtiTab >= maSupbTabList.size())
+ return EMPTY_STRING;
+ return maSupbTabList[nXtiTab].GetTabName();
+}
+
+sal_uInt16 XclImpSupbook::GetTabCount() const
+{
+ return ulimit_cast<sal_uInt16>(maSupbTabList.size());
+}
+
+void XclImpSupbook::LoadCachedValues()
+{
+ if (meType != EXC_SBTYPE_EXTERN || GetExtDocOptions().GetDocSettings().mnLinkCnt > 0 || !GetDocShell())
+ return;
+
+ String aAbsUrl( ScGlobal::GetAbsDocName(maXclUrl, GetDocShell()) );
+
+ ScExternalRefManager* pRefMgr = GetRoot().GetDoc().GetExternalRefManager();
+ sal_uInt16 nFileId = pRefMgr->getExternalFileId(aAbsUrl);
+
+ for (XclImpSupbookTabList::iterator itTab = maSupbTabList.begin(); itTab != maSupbTabList.end(); ++itTab)
+ {
+ const String& rTabName = itTab->GetTabName();
+ ScExternalRefCache::TableTypeRef pCacheTable = pRefMgr->getCacheTable(nFileId, rTabName, true);
+ itTab->LoadCachedValues(pCacheTable);
+ pCacheTable->setWholeTableCached();
+ }
+}
+
+// Import link manager ========================================================
+
+XclImpLinkManagerImpl::XclImpLinkManagerImpl( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ mbCreated( false )
+{
+}
+
+void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream& rStrm )
+{
+ sal_uInt16 nXtiCount;
+ rStrm >> nXtiCount;
+ DBG_ASSERT( static_cast< sal_Size >( nXtiCount * 6 ) == rStrm.GetRecLeft(), "XclImpLinkManagerImpl::ReadExternsheet - invalid count" );
+ nXtiCount = static_cast< sal_uInt16 >( ::std::min< sal_Size >( nXtiCount, rStrm.GetRecLeft() / 6 ) );
+
+ /* #i104057# A weird external XLS generator writes multiple EXTERNSHEET
+ records instead of only one as expected. Surprisingly, Excel seems to
+ insert the entries of the second record before the entries of the first
+ record. */
+ XclImpXtiVector aNewEntries( nXtiCount );
+ for( XclImpXtiVector::iterator aIt = aNewEntries.begin(), aEnd = aNewEntries.end(); rStrm.IsValid() && (aIt != aEnd); ++aIt )
+ rStrm >> *aIt;
+ maXtiList.insert( maXtiList.begin(), aNewEntries.begin(), aNewEntries.end() );
+
+ LoadCachedValues();
+}
+
+void XclImpLinkManagerImpl::ReadSupbook( XclImpStream& rStrm )
+{
+ maSupbookList.push_back( new XclImpSupbook( rStrm ) );
+}
+
+void XclImpLinkManagerImpl::ReadXct( XclImpStream& rStrm )
+{
+ if( !maSupbookList.empty() )
+ maSupbookList.back().ReadXct( rStrm );
+}
+
+void XclImpLinkManagerImpl::ReadCrn( XclImpStream& rStrm )
+{
+ if( !maSupbookList.empty() )
+ maSupbookList.back().ReadCrn( rStrm );
+}
+
+void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
+{
+ if( !maSupbookList.empty() )
+ maSupbookList.back().ReadExternname( rStrm, pFormulaConv );
+}
+
+bool XclImpLinkManagerImpl::IsSelfRef( sal_uInt16 nXtiIndex ) const
+{
+ const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
+ return pSupbook && (pSupbook->GetType() == EXC_SBTYPE_SELF);
+}
+
+bool XclImpLinkManagerImpl::GetScTabRange(
+ SCTAB& rnFirstScTab, SCTAB& rnLastScTab, sal_uInt16 nXtiIndex ) const
+{
+ if( const XclImpXti* pXti = GetXti( nXtiIndex ) )
+ {
+ if (!maSupbookList.empty() && (pXti->mnSupbook < maSupbookList.size()) )
+ {
+ rnFirstScTab = pXti->mnSBTabFirst;
+ rnLastScTab = pXti->mnSBTabLast;
+ return true;
+ }
+ }
+ return false;
+}
+
+const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const
+{
+ const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
+ return pSupbook ? pSupbook->GetExternName( nExtName ) : 0;
+}
+
+const String* XclImpLinkManagerImpl::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
+{
+ const XclImpSupbook* p = GetSupbook( nXtiIndex );
+ if (!p)
+ return NULL;
+ return &p->GetXclUrl();
+}
+
+const String& XclImpLinkManagerImpl::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const
+{
+ const XclImpSupbook* p = GetSupbook(nXti);
+ return p ? p->GetTabName(nXtiTab) : EMPTY_STRING;
+}
+
+bool XclImpLinkManagerImpl::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const
+{
+ const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
+ return pSupbook && pSupbook->GetLinkData( rApplic, rTopic );
+}
+
+const String& XclImpLinkManagerImpl::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const
+{
+ const XclImpSupbook* pSupbook = GetSupbook( nExtSheet );
+ return pSupbook ? pSupbook->GetMacroName( nExtName ) : EMPTY_STRING;
+}
+
+const XclImpXti* XclImpLinkManagerImpl::GetXti( sal_uInt16 nXtiIndex ) const
+{
+ return (nXtiIndex < maXtiList.size()) ? &maXtiList[ nXtiIndex ] : 0;
+}
+
+const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( sal_uInt16 nXtiIndex ) const
+{
+ if ( maSupbookList.empty() )
+ return NULL;
+ const XclImpXti* pXti = GetXti( nXtiIndex );
+ if (!pXti || pXti->mnSupbook >= maSupbookList.size())
+ return NULL;
+ return &(maSupbookList.at( pXti->mnSupbook ));
+}
+
+void XclImpLinkManagerImpl::LoadCachedValues()
+{
+ // Read all CRN records which can be accessed via XclImpSupbook, and store
+ // the cached values to the external reference manager.
+ for (XclImpSupbookList::iterator itSupbook = maSupbookList.begin(); itSupbook != maSupbookList.end(); ++itSupbook)
+ itSupbook->LoadCachedValues();
+}
+
+// ============================================================================
+
+XclImpLinkManager::XclImpLinkManager( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ mxImpl( new XclImpLinkManagerImpl( rRoot ) )
+{
+}
+
+XclImpLinkManager::~XclImpLinkManager()
+{
+}
+
+void XclImpLinkManager::ReadExternsheet( XclImpStream& rStrm )
+{
+ mxImpl->ReadExternsheet( rStrm );
+}
+
+void XclImpLinkManager::ReadSupbook( XclImpStream& rStrm )
+{
+ mxImpl->ReadSupbook( rStrm );
+}
+
+void XclImpLinkManager::ReadXct( XclImpStream& rStrm )
+{
+ mxImpl->ReadXct( rStrm );
+}
+
+void XclImpLinkManager::ReadCrn( XclImpStream& rStrm )
+{
+ mxImpl->ReadCrn( rStrm );
+}
+
+void XclImpLinkManager::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
+{
+ mxImpl->ReadExternname( rStrm, pFormulaConv );
+}
+
+bool XclImpLinkManager::IsSelfRef( sal_uInt16 nXtiIndex ) const
+{
+ return mxImpl->IsSelfRef( nXtiIndex );
+}
+
+bool XclImpLinkManager::GetScTabRange(
+ SCTAB& rnFirstScTab, SCTAB& rnLastScTab, sal_uInt16 nXtiIndex ) const
+{
+ return mxImpl->GetScTabRange( rnFirstScTab, rnLastScTab, nXtiIndex );
+}
+
+const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const
+{
+ return mxImpl->GetExternName( nXtiIndex, nExtName );
+}
+
+const String* XclImpLinkManager::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
+{
+ return mxImpl->GetSupbookUrl(nXtiIndex);
+}
+
+const String& XclImpLinkManager::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const
+{
+ return mxImpl->GetSupbookTabName(nXti, nXtiTab);
+}
+
+bool XclImpLinkManager::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const
+{
+ return mxImpl->GetLinkData( rApplic, rTopic, nXtiIndex );
+}
+
+const String& XclImpLinkManager::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const
+{
+ return mxImpl->GetMacroName( nExtSheet, nExtName );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xiname.cxx b/sc/source/filter/excel/xiname.cxx
new file mode 100644
index 000000000000..8a80f5217dc1
--- /dev/null
+++ b/sc/source/filter/excel/xiname.cxx
@@ -0,0 +1,279 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xiname.hxx"
+#include "rangenam.hxx"
+#include "xistream.hxx"
+
+// for formula compiler
+#include "excform.hxx"
+// for filter manager
+#include "excimp8.hxx"
+#include "scextopt.hxx"
+#include "document.hxx"
+// ============================================================================
+// *** Implementation ***
+// ============================================================================
+
+XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ) :
+ XclImpRoot( rStrm.GetRoot() ),
+ mpScData( 0 ),
+ mcBuiltIn( EXC_BUILTIN_UNKNOWN ),
+ mnScTab( SCTAB_MAX ),
+ mbFunction( false ),
+ mbVBName( false )
+{
+ ExcelToSc& rFmlaConv = GetOldFmlaConverter();
+
+ // 1) *** read data from stream *** ---------------------------------------
+
+ sal_uInt16 nFlags = 0, nFmlaSize = 0, nExtSheet = EXC_NAME_GLOBAL, nXclTab = EXC_NAME_GLOBAL;
+ sal_uInt8 nNameLen = 0, nShortCut;
+
+ switch( GetBiff() )
+ {
+ case EXC_BIFF2:
+ {
+ sal_uInt8 nFlagsBiff2;
+ rStrm >> nFlagsBiff2;
+ rStrm.Ignore( 1 );
+ rStrm >> nShortCut >> nNameLen;
+ nFmlaSize = rStrm.ReaduInt8();
+ ::set_flag( nFlags, EXC_NAME_FUNC, ::get_flag( nFlagsBiff2, EXC_NAME2_FUNC ) );
+ }
+ break;
+
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ {
+ rStrm >> nFlags >> nShortCut >> nNameLen >> nFmlaSize;
+ }
+ break;
+
+ case EXC_BIFF5:
+ case EXC_BIFF8:
+ {
+ rStrm >> nFlags >> nShortCut >> nNameLen >> nFmlaSize >> nExtSheet >> nXclTab;
+ rStrm.Ignore( 4 );
+ }
+ break;
+
+ default: DBG_ERROR_BIFF();
+ }
+
+ if( GetBiff() <= EXC_BIFF5 )
+ maXclName = rStrm.ReadRawByteString( nNameLen );
+ else
+ maXclName = rStrm.ReadUniString( nNameLen );
+
+ // 2) *** convert sheet index and name *** --------------------------------
+
+ // functions and VBA
+ mbFunction = ::get_flag( nFlags, EXC_NAME_FUNC );
+ mbVBName = ::get_flag( nFlags, EXC_NAME_VB );
+
+ // get built-in name, or convert characters invalid in Calc
+ bool bBuiltIn = ::get_flag( nFlags, EXC_NAME_BUILTIN );
+
+ // special case for BIFF5 filter range - name appears as plain text without built-in flag
+ if( (GetBiff() == EXC_BIFF5) && (maXclName == XclTools::GetXclBuiltInDefName( EXC_BUILTIN_FILTERDATABASE )) )
+ {
+ bBuiltIn = true;
+ maXclName.Assign( EXC_BUILTIN_FILTERDATABASE );
+ }
+
+ // convert Excel name to Calc name
+ if( mbVBName )
+ {
+ // VB macro name
+ maScName = maXclName;
+ }
+ else if( bBuiltIn )
+ {
+ // built-in name
+ if( maXclName.Len() )
+ mcBuiltIn = maXclName.GetChar( 0 );
+ if( mcBuiltIn == '?' ) // NUL character is imported as '?'
+ mcBuiltIn = '\0';
+ maScName = XclTools::GetBuiltInDefName( mcBuiltIn );
+ }
+ else
+ {
+ // any other name
+ maScName = maXclName;
+ ScfTools::ConvertToScDefinedName( maScName );
+ }
+ rtl::OUString aRealOrigName = maScName;
+
+ // add index for local names
+ if( nXclTab != EXC_NAME_GLOBAL )
+ {
+ sal_uInt16 nUsedTab = (GetBiff() == EXC_BIFF8) ? nXclTab : nExtSheet;
+ // do not rename sheet-local names by default, this breaks VBA scripts
+// maScName.Append( '_' ).Append( String::CreateFromInt32( nUsedTab ) );
+ // TODO: may not work for BIFF5, handle skipped sheets (all BIFF)
+ mnScTab = static_cast< SCTAB >( nUsedTab - 1 );
+ }
+
+ // 3) *** convert the name definition formula *** -------------------------
+
+ rFmlaConv.Reset();
+ const ScTokenArray* pTokArr = 0; // pointer to token array, owned by rFmlaConv
+ RangeType nNameType = RT_NAME;
+
+ if( ::get_flag( nFlags, EXC_NAME_BIG ) )
+ {
+ // special, unsupported name
+ rFmlaConv.GetDummy( pTokArr );
+ }
+ else if( bBuiltIn )
+ {
+ SCsTAB const nLocalTab = (nXclTab == EXC_NAME_GLOBAL) ? SCTAB_MAX : (nXclTab - 1);
+
+ // --- print ranges or title ranges ---
+ rStrm.PushPosition();
+ switch( mcBuiltIn )
+ {
+ case EXC_BUILTIN_PRINTAREA:
+ if( rFmlaConv.Convert( GetPrintAreaBuffer(), rStrm, nFmlaSize, nLocalTab, FT_RangeName ) == ConvOK )
+ nNameType |= RT_PRINTAREA;
+ break;
+ case EXC_BUILTIN_PRINTTITLES:
+ if( rFmlaConv.Convert( GetTitleAreaBuffer(), rStrm, nFmlaSize, nLocalTab, FT_RangeName ) == ConvOK )
+ nNameType |= RT_COLHEADER | RT_ROWHEADER;
+ break;
+ }
+ rStrm.PopPosition();
+
+ // --- name formula ---
+ // JEG : double check this. It is clearly false for normal names
+ // but some of the builtins (sheettitle?) might be able to handle arrays
+ rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize, false, FT_RangeName );
+
+ // --- auto or advanced filter ---
+ if( (GetBiff() == EXC_BIFF8) && pTokArr && bBuiltIn )
+ {
+ ScRange aRange;
+ if( pTokArr->IsReference( aRange ) )
+ {
+ switch( mcBuiltIn )
+ {
+ case EXC_BUILTIN_FILTERDATABASE:
+ GetFilterManager().Insert( &GetOldRoot(), aRange);
+ break;
+ case EXC_BUILTIN_CRITERIA:
+ GetFilterManager().AddAdvancedRange( aRange );
+ nNameType |= RT_CRITERIA;
+ break;
+ case EXC_BUILTIN_EXTRACT:
+ if( pTokArr->IsValidReference( aRange ) )
+ GetFilterManager().AddExtractPos( aRange );
+ break;
+ }
+ }
+ }
+ }
+ else if( nFmlaSize > 0 )
+ {
+ // regular defined name
+ rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize, true, FT_RangeName );
+ }
+
+ // 4) *** create a defined name in the Calc document *** ------------------
+
+ // do not ignore hidden names (may be regular names created by VBA scripts)
+ if( pTokArr /*&& (bBuiltIn || !::get_flag( nFlags, EXC_NAME_HIDDEN ))*/ && !mbFunction && !mbVBName )
+ {
+ // create the Calc name data
+ ScRangeData* pData = new ScRangeData( GetDocPtr(), maScName, *pTokArr, ScAddress(), nNameType );
+ pData->GuessPosition(); // calculate base position for relative refs
+ pData->SetIndex( nXclNameIdx ); // used as unique identifier in formulas
+ if (nXclTab == EXC_NAME_GLOBAL)
+ GetDoc().GetRangeName()->insert(pData);
+ else
+ {
+ ScRangeName* pLocalNames = GetDoc().GetRangeName(mnScTab);
+ if (pLocalNames)
+ pLocalNames->insert(pData);
+
+ if (GetBiff() == EXC_BIFF8)
+ {
+ ScRange aRange;
+ // discard deleted ranges ( for the moment at least )
+ if ( pData->IsValidReference( aRange ) )
+ {
+ GetExtDocOptions().GetOrCreateTabSettings( nXclTab );
+ }
+ }
+ }
+ mpScData = pData; // cache for later use
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpNameManager::XclImpNameManager( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpNameManager::ReadName( XclImpStream& rStrm )
+{
+ sal_uLong nCount = maNameList.size();
+ if( nCount < 0xFFFF )
+ maNameList.push_back( new XclImpName( rStrm, static_cast< sal_uInt16 >( nCount + 1 ) ) );
+}
+
+const XclImpName* XclImpNameManager::FindName( const String& rXclName, SCTAB nScTab ) const
+{
+ const XclImpName* pGlobalName = 0; // a found global name
+ const XclImpName* pLocalName = 0; // a found local name
+ for( XclImpNameList::const_iterator itName = maNameList.begin(); itName != maNameList.end() && !pLocalName; ++itName )
+ {
+ if( itName->GetXclName() == rXclName )
+ {
+ if( itName->GetScTab() == nScTab )
+ pLocalName = &(*itName);
+ else if( itName->IsGlobal() )
+ pGlobalName = &(*itName);
+ }
+ }
+ return pLocalName ? pLocalName : pGlobalName;
+}
+
+const XclImpName* XclImpNameManager::GetName( sal_uInt16 nXclNameIdx ) const
+{
+ DBG_ASSERT( nXclNameIdx > 0, "XclImpNameManager::GetName - index must be >0" );
+ return ( nXclNameIdx > maNameList.size() ) ? NULL : &(maNameList.at( nXclNameIdx - 1 ));
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xipage.cxx b/sc/source/filter/excel/xipage.cxx
new file mode 100644
index 000000000000..f40743c52146
--- /dev/null
+++ b/sc/source/filter/excel/xipage.cxx
@@ -0,0 +1,392 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xipage.hxx"
+#include <svl/itemset.hxx>
+#include <vcl/graph.hxx>
+#include "scitems.hxx"
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/brshitem.hxx>
+#include "document.hxx"
+#include "stlsheet.hxx"
+#include "attrib.hxx"
+#include "xistream.hxx"
+#include "xihelper.hxx"
+#include "xiescher.hxx"
+
+// Page settings ==============================================================
+
+XclImpPageSettings::XclImpPageSettings( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+ Initialize();
+}
+
+void XclImpPageSettings::Initialize()
+{
+ maData.SetDefaults();
+ mbValidPaper = false;
+}
+
+void XclImpPageSettings::ReadSetup( XclImpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( GetBiff() >= EXC_BIFF4 );
+ if( GetBiff() < EXC_BIFF4 )
+ return;
+
+ // BIFF4 - BIFF8
+ sal_uInt16 nFlags;
+ rStrm >> maData.mnPaperSize >> maData.mnScaling >> maData.mnStartPage
+ >> maData.mnFitToWidth >> maData.mnFitToHeight >> nFlags;
+
+ mbValidPaper = maData.mbValid = !::get_flag( nFlags, EXC_SETUP_INVALID );
+ maData.mbPrintInRows = ::get_flag( nFlags, EXC_SETUP_INROWS );
+ maData.mbPortrait = ::get_flag( nFlags, EXC_SETUP_PORTRAIT );
+ maData.mbBlackWhite = ::get_flag( nFlags, EXC_SETUP_BLACKWHITE );
+ maData.mbManualStart = true;
+
+ // new in BIFF5 - BIFF8
+ if( GetBiff() >= EXC_BIFF5 )
+ {
+ rStrm >> maData.mnHorPrintRes >> maData.mnVerPrintRes
+ >> maData.mfHeaderMargin >> maData.mfFooterMargin >> maData.mnCopies;
+
+ maData.mbDraftQuality = ::get_flag( nFlags, EXC_SETUP_DRAFT );
+ maData.mbPrintNotes = ::get_flag( nFlags, EXC_SETUP_PRINTNOTES );
+ maData.mbManualStart = ::get_flag( nFlags, EXC_SETUP_STARTPAGE );
+ }
+}
+
+void XclImpPageSettings::ReadMargin( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_LEFTMARGIN: rStrm >> maData.mfLeftMargin; break;
+ case EXC_ID_RIGHTMARGIN: rStrm >> maData.mfRightMargin; break;
+ case EXC_ID_TOPMARGIN: rStrm >> maData.mfTopMargin; break;
+ case EXC_ID_BOTTOMMARGIN: rStrm >> maData.mfBottomMargin; break;
+ default: DBG_ERRORFILE( "XclImpPageSettings::ReadMargin - unknown record" );
+ }
+}
+
+void XclImpPageSettings::ReadCenter( XclImpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( GetBiff() >= EXC_BIFF3 ); // read it anyway
+ bool bCenter = (rStrm.ReaduInt16() != 0);
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_HCENTER: maData.mbHorCenter = bCenter; break;
+ case EXC_ID_VCENTER: maData.mbVerCenter = bCenter; break;
+ default: DBG_ERRORFILE( "XclImpPageSettings::ReadCenter - unknown record" );
+ }
+}
+
+void XclImpPageSettings::ReadHeaderFooter( XclImpStream& rStrm )
+{
+ String aString;
+ if( rStrm.GetRecLeft() )
+ aString = (GetBiff() <= EXC_BIFF5) ? rStrm.ReadByteString( false ) : rStrm.ReadUniString();
+
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_HEADER: maData.maHeader = aString; break;
+ case EXC_ID_FOOTER: maData.maFooter = aString; break;
+ default: DBG_ERRORFILE( "XclImpPageSettings::ReadHeaderFooter - unknown record" );
+ }
+}
+
+void XclImpPageSettings::ReadPageBreaks( XclImpStream& rStrm )
+{
+ ScfUInt16Vec* pVec = 0;
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_HORPAGEBREAKS: pVec = &maData.maHorPageBreaks; break;
+ case EXC_ID_VERPAGEBREAKS: pVec = &maData.maVerPageBreaks; break;
+ default: DBG_ERRORFILE( "XclImpPageSettings::ReadPageBreaks - unknown record" );
+ }
+
+ if( pVec )
+ {
+ bool bIgnore = GetBiff() == EXC_BIFF8; // ignore start/end columns or rows in BIFF8
+
+ sal_uInt16 nCount, nBreak;
+ rStrm >> nCount;
+ pVec->clear();
+ pVec->reserve( nCount );
+
+ while( nCount-- )
+ {
+ rStrm >> nBreak;
+ if( nBreak )
+ pVec->push_back( nBreak );
+ if( bIgnore )
+ rStrm.Ignore( 4 );
+ }
+ }
+}
+
+void XclImpPageSettings::ReadPrintHeaders( XclImpStream& rStrm )
+{
+ maData.mbPrintHeadings = (rStrm.ReaduInt16() != 0);
+}
+
+void XclImpPageSettings::ReadPrintGridLines( XclImpStream& rStrm )
+{
+ maData.mbPrintGrid = (rStrm.ReaduInt16() != 0);
+}
+
+void XclImpPageSettings::ReadImgData( XclImpStream& rStrm )
+{
+ Graphic aGraphic = XclImpDrawing::ReadImgData( GetRoot(), rStrm );
+ if( aGraphic.GetType() != GRAPHIC_NONE )
+ maData.mxBrushItem.reset( new SvxBrushItem( aGraphic, GPOS_TILED, ATTR_BACKGROUND ) );
+}
+
+void XclImpPageSettings::SetPaperSize( sal_uInt16 nXclPaperSize, bool bPortrait )
+{
+ maData.mnPaperSize = nXclPaperSize;
+ maData.mbPortrait = bPortrait;
+ mbValidPaper = true;
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+void lclPutMarginItem( SfxItemSet& rItemSet, sal_uInt16 nRecId, double fMarginInch )
+{
+ sal_uInt16 nMarginTwips = XclTools::GetTwipsFromInch( fMarginInch );
+ switch( nRecId )
+ {
+ case EXC_ID_TOPMARGIN:
+ case EXC_ID_BOTTOMMARGIN:
+ {
+ SvxULSpaceItem aItem( GETITEM( rItemSet, SvxULSpaceItem, ATTR_ULSPACE ) );
+ if( nRecId == EXC_ID_TOPMARGIN )
+ aItem.SetUpperValue( nMarginTwips );
+ else
+ aItem.SetLowerValue( nMarginTwips );
+ rItemSet.Put( aItem );
+ }
+ break;
+ case EXC_ID_LEFTMARGIN:
+ case EXC_ID_RIGHTMARGIN:
+ {
+ SvxLRSpaceItem aItem( GETITEM( rItemSet, SvxLRSpaceItem, ATTR_LRSPACE ) );
+ if( nRecId == EXC_ID_LEFTMARGIN )
+ aItem.SetLeftValue( nMarginTwips );
+ else
+ aItem.SetRightValue( nMarginTwips );
+ rItemSet.Put( aItem );
+ }
+ break;
+ default:
+ DBG_ERRORFILE( "XclImpPageSettings::SetMarginItem - unknown record id" );
+ }
+}
+
+} // namespace
+
+void XclImpPageSettings::Finalize()
+{
+ ScDocument& rDoc = GetDoc();
+ SCTAB nScTab = GetCurrScTab();
+
+ // *** create page style sheet ***
+
+ String aStyleName( RTL_CONSTASCII_USTRINGPARAM( "PageStyle_" ) );
+ String aTableName;
+ if( GetDoc().GetName( nScTab, aTableName ) )
+ aStyleName.Append( aTableName );
+ else
+ aStyleName.Append( String::CreateFromInt32( nScTab + 1 ) );
+
+ ScStyleSheet& rStyleSheet = ScfTools::MakePageStyleSheet( GetStyleSheetPool(), aStyleName, false );
+ SfxItemSet& rItemSet = rStyleSheet.GetItemSet();
+
+ // *** page settings ***
+
+ ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_TOPDOWN, !maData.mbPrintInRows ), true );
+ ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_HORCENTER, maData.mbHorCenter ), true );
+ ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_VERCENTER, maData.mbVerCenter ), true );
+ ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_HEADERS, maData.mbPrintHeadings ), true );
+ ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_GRID, maData.mbPrintGrid ), true );
+ ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_NOTES, maData.mbPrintNotes ), true );
+
+ sal_uInt16 nStartPage = maData.mbManualStart ? maData.mnStartPage : 0;
+ ScfTools::PutItem( rItemSet, SfxUInt16Item( ATTR_PAGE_FIRSTPAGENO, nStartPage ), true );
+
+ if( maData.mxBrushItem.get() )
+ rItemSet.Put( *maData.mxBrushItem );
+
+ if( mbValidPaper )
+ {
+ SvxPageItem aPageItem( GETITEM( rItemSet, SvxPageItem, ATTR_PAGE ) );
+ aPageItem.SetLandscape( !maData.mbPortrait );
+ rItemSet.Put( aPageItem );
+ ScfTools::PutItem( rItemSet, SvxSizeItem( ATTR_PAGE_SIZE, maData.GetScPaperSize() ), true );
+ }
+
+ if( maData.mbFitToPages )
+ rItemSet.Put( ScPageScaleToItem( maData.mnFitToWidth, maData.mnFitToHeight ) );
+ else if( maData.mbValid )
+ rItemSet.Put( SfxUInt16Item( ATTR_PAGE_SCALE, maData.mnScaling ) );
+
+ // *** margin preparations ***
+
+ double fLeftMargin = maData.mfLeftMargin;
+ double fRightMargin = maData.mfRightMargin;
+ double fTopMargin = maData.mfTopMargin;
+ double fBottomMargin = maData.mfBottomMargin;
+ // distances between header/footer and page area
+ double fHeaderHeight = 0.0;
+ double fHeaderDist = 0.0;
+ double fFooterHeight = 0.0;
+ double fFooterDist = 0.0;
+ // in Calc, "header/footer left/right margin" is X distance between header/footer and page margin
+ double fHdrLeftMargin = maData.mfHdrLeftMargin - maData.mfLeftMargin;
+ double fHdrRightMargin = maData.mfHdrRightMargin - maData.mfRightMargin;
+ double fFtrLeftMargin = maData.mfFtrLeftMargin - maData.mfLeftMargin;
+ double fFtrRightMargin = maData.mfFtrRightMargin - maData.mfRightMargin;
+
+ // *** header and footer ***
+
+ XclImpHFConverter aHFConv( GetRoot() );
+
+ // header
+ bool bHasHeader = (maData.maHeader.Len() != 0);
+ SvxSetItem aHdrSetItem( GETITEM( rItemSet, SvxSetItem, ATTR_PAGE_HEADERSET ) );
+ SfxItemSet& rHdrItemSet = aHdrSetItem.GetItemSet();
+ rHdrItemSet.Put( SfxBoolItem( ATTR_PAGE_ON, bHasHeader ) );
+ if( bHasHeader )
+ {
+ aHFConv.ParseString( maData.maHeader );
+ aHFConv.FillToItemSet( rItemSet, ATTR_PAGE_HEADERLEFT );
+ aHFConv.FillToItemSet( rItemSet, ATTR_PAGE_HEADERRIGHT );
+ // #i23296# In Calc, "top margin" is distance to header
+ fTopMargin = maData.mfHeaderMargin;
+ // Calc uses distance between header and sheet data area
+ fHeaderHeight = XclTools::GetInchFromTwips( aHFConv.GetTotalHeight() );
+ fHeaderDist = maData.mfTopMargin - maData.mfHeaderMargin - fHeaderHeight;
+ }
+ if( fHeaderDist < 0.0 )
+ {
+ /* #i23296# Header overlays sheet data:
+ -> set fixed header height to get correct sheet data position. */
+ ScfTools::PutItem( rHdrItemSet, SfxBoolItem( ATTR_PAGE_DYNAMIC, false ), true );
+ // shrink header height
+ long nHdrHeight = XclTools::GetTwipsFromInch( fHeaderHeight + fHeaderDist );
+ ScfTools::PutItem( rHdrItemSet, SvxSizeItem( ATTR_PAGE_SIZE, Size( 0, nHdrHeight ) ), true );
+ lclPutMarginItem( rHdrItemSet, EXC_ID_BOTTOMMARGIN, 0.0 );
+ }
+ else
+ {
+ // use dynamic header height
+ ScfTools::PutItem( rHdrItemSet, SfxBoolItem( ATTR_PAGE_DYNAMIC, true ), true );
+ lclPutMarginItem( rHdrItemSet, EXC_ID_BOTTOMMARGIN, fHeaderDist );
+ }
+ lclPutMarginItem( rHdrItemSet, EXC_ID_LEFTMARGIN, fHdrLeftMargin );
+ lclPutMarginItem( rHdrItemSet, EXC_ID_RIGHTMARGIN, fHdrRightMargin );
+ rItemSet.Put( aHdrSetItem );
+
+ // footer
+ bool bHasFooter = (maData.maFooter.Len() != 0);
+ SvxSetItem aFtrSetItem( GETITEM( rItemSet, SvxSetItem, ATTR_PAGE_FOOTERSET ) );
+ SfxItemSet& rFtrItemSet = aFtrSetItem.GetItemSet();
+ rFtrItemSet.Put( SfxBoolItem( ATTR_PAGE_ON, bHasFooter ) );
+ if( bHasFooter )
+ {
+ aHFConv.ParseString( maData.maFooter );
+ aHFConv.FillToItemSet( rItemSet, ATTR_PAGE_FOOTERLEFT );
+ aHFConv.FillToItemSet( rItemSet, ATTR_PAGE_FOOTERRIGHT );
+ // #i23296# In Calc, "bottom margin" is distance to footer
+ fBottomMargin = maData.mfFooterMargin;
+ // Calc uses distance between footer and sheet data area
+ fFooterHeight = XclTools::GetInchFromTwips( aHFConv.GetTotalHeight() );
+ fFooterDist = maData.mfBottomMargin - maData.mfFooterMargin - fFooterHeight;
+ }
+ if( fFooterDist < 0.0 )
+ {
+ /* #i23296# Footer overlays sheet data:
+ -> set fixed footer height to get correct sheet data end position. */
+ ScfTools::PutItem( rFtrItemSet, SfxBoolItem( ATTR_PAGE_DYNAMIC, false ), true );
+ // shrink footer height
+ long nFtrHeight = XclTools::GetTwipsFromInch( fFooterHeight + fFooterDist );
+ ScfTools::PutItem( rFtrItemSet, SvxSizeItem( ATTR_PAGE_SIZE, Size( 0, nFtrHeight ) ), true );
+ lclPutMarginItem( rFtrItemSet, EXC_ID_TOPMARGIN, 0.0 );
+ }
+ else
+ {
+ // use dynamic footer height
+ ScfTools::PutItem( rFtrItemSet, SfxBoolItem( ATTR_PAGE_DYNAMIC, true ), true );
+ lclPutMarginItem( rFtrItemSet, EXC_ID_TOPMARGIN, fFooterDist );
+ }
+ lclPutMarginItem( rFtrItemSet, EXC_ID_LEFTMARGIN, fFtrLeftMargin );
+ lclPutMarginItem( rFtrItemSet, EXC_ID_RIGHTMARGIN, fFtrRightMargin );
+ rItemSet.Put( aFtrSetItem );
+
+ // *** set final margins ***
+
+ lclPutMarginItem( rItemSet, EXC_ID_LEFTMARGIN, fLeftMargin );
+ lclPutMarginItem( rItemSet, EXC_ID_RIGHTMARGIN, fRightMargin );
+ lclPutMarginItem( rItemSet, EXC_ID_TOPMARGIN, fTopMargin );
+ lclPutMarginItem( rItemSet, EXC_ID_BOTTOMMARGIN, fBottomMargin );
+
+ // *** put style sheet into document ***
+
+ rDoc.SetPageStyle( nScTab, rStyleSheet.GetName() );
+
+ // *** page breaks ***
+
+ ScfUInt16Vec::const_iterator aIt, aEnd;
+
+ for( aIt = maData.maHorPageBreaks.begin(), aEnd = maData.maHorPageBreaks.end(); aIt != aEnd; ++aIt )
+ {
+ SCROW nScRow = static_cast< SCROW >( *aIt );
+ if( nScRow <= MAXROW )
+ rDoc.SetRowBreak(nScRow, nScTab, false, true);
+ }
+
+ for( aIt = maData.maVerPageBreaks.begin(), aEnd = maData.maVerPageBreaks.end(); aIt != aEnd; ++aIt )
+ {
+ SCCOL nScCol = static_cast< SCCOL >( *aIt );
+ if( nScCol <= MAXCOL )
+ rDoc.SetColBreak(nScCol, nScTab, false, true);
+ }
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xipivot.cxx b/sc/source/filter/excel/xipivot.cxx
new file mode 100644
index 000000000000..a26b132f198d
--- /dev/null
+++ b/sc/source/filter/excel/xipivot.cxx
@@ -0,0 +1,1678 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "xipivot.hxx"
+
+#include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReference.hpp>
+
+#include <tools/datetime.hxx>
+#include <svl/zformat.hxx>
+#include <svl/intitem.hxx>
+
+#include "document.hxx"
+#include "cell.hxx"
+#include "dpsave.hxx"
+#include "dpdimsave.hxx"
+#include "dpobject.hxx"
+#include "dpshttab.hxx"
+#include "dpoutputgeometry.hxx"
+#include "scitems.hxx"
+#include "attrib.hxx"
+
+#include "xltracer.hxx"
+#include "xistream.hxx"
+#include "xihelper.hxx"
+#include "xilink.hxx"
+#include "xiescher.hxx"
+
+//! TODO ExcelToSc usage
+#include "excform.hxx"
+#include "xltable.hxx"
+
+#include <vector>
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::sheet::DataPilotFieldOrientation;
+using ::com::sun::star::sheet::DataPilotFieldOrientation_DATA;
+using ::com::sun::star::sheet::DataPilotFieldSortInfo;
+using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
+using ::com::sun::star::sheet::DataPilotFieldLayoutInfo;
+using ::com::sun::star::sheet::DataPilotFieldReference;
+using ::std::vector;
+
+// ============================================================================
+// Pivot cache
+// ============================================================================
+
+XclImpPCItem::XclImpPCItem( XclImpStream& rStrm )
+{
+ switch( rStrm.GetRecId() )
+ {
+ case EXC_ID_SXDOUBLE: ReadSxdouble( rStrm ); break;
+ case EXC_ID_SXBOOLEAN: ReadSxboolean( rStrm ); break;
+ case EXC_ID_SXERROR: ReadSxerror( rStrm ); break;
+ case EXC_ID_SXINTEGER: ReadSxinteger( rStrm ); break;
+ case EXC_ID_SXSTRING: ReadSxstring( rStrm ); break;
+ case EXC_ID_SXDATETIME: ReadSxdatetime( rStrm ); break;
+ case EXC_ID_SXEMPTY: ReadSxempty( rStrm ); break;
+ default: DBG_ERRORFILE( "XclImpPCItem::XclImpPCItem - unknown record id" );
+ }
+}
+
+namespace {
+
+void lclSetValue( const XclImpRoot& rRoot, const ScAddress& rScPos, double fValue, short nFormatType )
+{
+ ScDocument& rDoc = rRoot.GetDoc();
+ rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), fValue );
+ sal_uInt32 nScNumFmt = rRoot.GetFormatter().GetStandardFormat( nFormatType, rRoot.GetDocLanguage() );
+ rDoc.ApplyAttr( rScPos.Col(), rScPos.Row(), rScPos.Tab(), SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ) );
+}
+
+} // namespace
+
+void XclImpPCItem::WriteToSource( const XclImpRoot& rRoot, const ScAddress& rScPos ) const
+{
+ ScDocument& rDoc = rRoot.GetDoc();
+ if( const String* pText = GetText() )
+ rDoc.SetString( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pText );
+ else if( const double* pfValue = GetDouble() )
+ rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pfValue );
+ else if( const sal_Int16* pnValue = GetInteger() )
+ rDoc.SetValue( rScPos.Col(), rScPos.Row(), rScPos.Tab(), *pnValue );
+ else if( const bool* pbValue = GetBool() )
+ lclSetValue( rRoot, rScPos, *pbValue ? 1.0 : 0.0, NUMBERFORMAT_LOGICAL );
+ else if( const DateTime* pDateTime = GetDateTime() )
+ {
+ // set number format date, time, or date/time, depending on the value
+ double fValue = rRoot.GetDoubleFromDateTime( *pDateTime );
+ double fInt = 0.0;
+ double fFrac = modf( fValue, &fInt );
+ short nFormatType = ((fFrac == 0.0) && (fInt != 0.0)) ? NUMBERFORMAT_DATE :
+ ((fInt == 0.0) ? NUMBERFORMAT_TIME : NUMBERFORMAT_DATETIME);
+ lclSetValue( rRoot, rScPos, fValue, nFormatType );
+ }
+ else if( const sal_uInt16* pnError = GetError() )
+ {
+ double fValue;
+ sal_uInt8 nErrCode = static_cast< sal_uInt8 >( *pnError );
+ const ScTokenArray* pScTokArr = rRoot.GetOldFmlaConverter().GetBoolErr(
+ XclTools::ErrorToEnum( fValue, EXC_BOOLERR_ERROR, nErrCode ) );
+ ScFormulaCell* pCell = new ScFormulaCell( &rDoc, rScPos, pScTokArr );
+ pCell->SetHybridDouble( fValue );
+ rDoc.PutCell( rScPos, pCell );
+ }
+}
+
+void XclImpPCItem::ReadSxdouble( XclImpStream& rStrm )
+{
+ DBG_ASSERT( rStrm.GetRecSize() == 8, "XclImpPCItem::ReadSxdouble - wrong record size" );
+ SetDouble( rStrm.ReadDouble() );
+}
+
+void XclImpPCItem::ReadSxboolean( XclImpStream& rStrm )
+{
+ DBG_ASSERT( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxboolean - wrong record size" );
+ SetBool( rStrm.ReaduInt16() != 0 );
+}
+
+void XclImpPCItem::ReadSxerror( XclImpStream& rStrm )
+{
+ DBG_ASSERT( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxerror - wrong record size" );
+ SetError( rStrm.ReaduInt16() );
+}
+
+void XclImpPCItem::ReadSxinteger( XclImpStream& rStrm )
+{
+ DBG_ASSERT( rStrm.GetRecSize() == 2, "XclImpPCItem::ReadSxinteger - wrong record size" );
+ SetInteger( rStrm.ReadInt16() );
+}
+
+void XclImpPCItem::ReadSxstring( XclImpStream& rStrm )
+{
+ DBG_ASSERT( rStrm.GetRecSize() >= 3, "XclImpPCItem::ReadSxstring - wrong record size" );
+ SetText( rStrm.ReadUniString() );
+}
+
+void XclImpPCItem::ReadSxdatetime( XclImpStream& rStrm )
+{
+ DBG_ASSERT( rStrm.GetRecSize() == 8, "XclImpPCItem::ReadSxdatetime - wrong record size" );
+ sal_uInt16 nYear, nMonth;
+ sal_uInt8 nDay, nHour, nMin, nSec;
+ rStrm >> nYear >> nMonth >> nDay >> nHour >> nMin >> nSec;
+ SetDateTime( DateTime( Date( nDay, nMonth, nYear ), Time( nHour, nMin, nSec ) ) );
+}
+
+void XclImpPCItem::ReadSxempty( XclImpStream& rStrm )
+{
+ (void)rStrm; // avoid compiler warning
+ DBG_ASSERT( rStrm.GetRecSize() == 0, "XclImpPCItem::ReadSxempty - wrong record size" );
+ SetEmpty();
+}
+
+// ============================================================================
+
+XclImpPCField::XclImpPCField( const XclImpRoot& rRoot, XclImpPivotCache& rPCache, sal_uInt16 nFieldIdx ) :
+ XclPCField( EXC_PCFIELD_UNKNOWN, nFieldIdx ),
+ XclImpRoot( rRoot ),
+ mrPCache( rPCache ),
+ mnSourceScCol( -1 ),
+ mbNumGroupInfoRead( false )
+{
+}
+
+XclImpPCField::~XclImpPCField()
+{
+}
+
+// general field/item access --------------------------------------------------
+
+const String& XclImpPCField::GetFieldName( const ScfStringVec& rVisNames ) const
+{
+ if( IsGroupChildField() && (mnFieldIdx < rVisNames.size()) )
+ {
+ const String& rVisName = rVisNames[ mnFieldIdx ];
+ if( rVisName.Len() > 0 )
+ return rVisName;
+ }
+ return maFieldInfo.maName;
+}
+
+const XclImpPCField* XclImpPCField::GetGroupBaseField() const
+{
+ DBG_ASSERT( IsGroupChildField(), "XclImpPCField::GetGroupBaseField - this field type does not have a base field" );
+ return IsGroupChildField() ? mrPCache.GetField( maFieldInfo.mnGroupBase ) : 0;
+}
+
+const XclImpPCItem* XclImpPCField::GetItem( sal_uInt16 nItemIdx ) const
+{
+ return (nItemIdx < maItems.size()) ? maItems[ nItemIdx ].get() : 0;
+}
+
+const XclImpPCItem* XclImpPCField::GetLimitItem( sal_uInt16 nItemIdx ) const
+{
+ DBG_ASSERT( nItemIdx < 3, "XclImpPCField::GetLimitItem - invalid item index" );
+ DBG_ASSERT( nItemIdx < maNumGroupItems.size(), "XclImpPCField::GetLimitItem - no item found" );
+ return (nItemIdx < maNumGroupItems.size()) ? maNumGroupItems[ nItemIdx ].get() : 0;
+}
+
+void XclImpPCField::WriteFieldNameToSource( SCCOL nScCol, SCTAB nScTab ) const
+{
+ DBG_ASSERT( HasOrigItems(), "XclImpPCField::WriteFieldNameToSource - only for standard fields" );
+ GetDoc().SetString( nScCol, 0, nScTab, maFieldInfo.maName );
+ mnSourceScCol = nScCol;
+}
+
+void XclImpPCField::WriteOrigItemToSource( SCROW nScRow, SCTAB nScTab, sal_uInt16 nItemIdx ) const
+{
+ if( nItemIdx < maOrigItems.size() )
+ maOrigItems[ nItemIdx ]->WriteToSource( GetRoot(), ScAddress( mnSourceScCol, nScRow, nScTab ) );
+}
+
+void XclImpPCField::WriteLastOrigItemToSource( SCROW nScRow, SCTAB nScTab ) const
+{
+ if( !maOrigItems.empty() )
+ maOrigItems.back()->WriteToSource( GetRoot(), ScAddress( mnSourceScCol, nScRow, nScTab ) );
+}
+
+// records --------------------------------------------------------------------
+
+void XclImpPCField::ReadSxfield( XclImpStream& rStrm )
+{
+ rStrm >> maFieldInfo;
+
+ /* Detect the type of this field. This is done very restrictive to detect
+ any unexpected state. */
+ meFieldType = EXC_PCFIELD_UNKNOWN;
+
+ bool bItems = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASITEMS );
+ bool bPostp = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_POSTPONE );
+ bool bCalced = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_CALCED );
+ bool bChild = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD );
+ bool bNum = ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_NUMGROUP );
+
+ sal_uInt16 nVisC = maFieldInfo.mnVisItems;
+ sal_uInt16 nGroupC = maFieldInfo.mnGroupItems;
+ sal_uInt16 nBaseC = maFieldInfo.mnBaseItems;
+ sal_uInt16 nOrigC = maFieldInfo.mnOrigItems;
+ DBG_ASSERT( nVisC > 0, "XclImpPCField::ReadSxfield - field without visible items" );
+
+ sal_uInt16 nType = maFieldInfo.mnFlags & EXC_SXFIELD_DATA_MASK;
+ bool bType =
+ (nType == EXC_SXFIELD_DATA_STR) ||
+ (nType == EXC_SXFIELD_DATA_INT) ||
+ (nType == EXC_SXFIELD_DATA_DBL) ||
+ (nType == EXC_SXFIELD_DATA_STR_INT) ||
+ (nType == EXC_SXFIELD_DATA_STR_DBL) ||
+ (nType == EXC_SXFIELD_DATA_DATE) ||
+ (nType == EXC_SXFIELD_DATA_DATE_EMP) ||
+ (nType == EXC_SXFIELD_DATA_DATE_NUM) ||
+ (nType == EXC_SXFIELD_DATA_DATE_STR);
+ bool bTypeNone =
+ (nType == EXC_SXFIELD_DATA_NONE);
+ // for now, ignore data type of calculated fields
+ DBG_ASSERT( bCalced || bType || bTypeNone, "XclImpPCField::ReadSxfield - unknown item data type" );
+
+ if( nVisC > 0 || bPostp )
+ {
+ if( bItems && !bPostp )
+ {
+ if( !bCalced )
+ {
+ // 1) standard fields and standard grouping fields
+ if( !bNum )
+ {
+ // 1a) standard field without grouping
+ if( bType && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == nVisC) )
+ meFieldType = EXC_PCFIELD_STANDARD;
+
+ // 1b) standard grouping field
+ else if( bTypeNone && (nGroupC == nVisC) && (nBaseC > 0) && (nOrigC == 0) )
+ meFieldType = EXC_PCFIELD_STDGROUP;
+ }
+ // 2) numerical grouping fields
+ else if( (nGroupC == nVisC) && (nBaseC == 0) )
+ {
+ // 2a) single num/date grouping field without child grouping field
+ if( !bChild && bType && (nOrigC > 0) )
+ {
+ switch( nType )
+ {
+ case EXC_SXFIELD_DATA_INT:
+ case EXC_SXFIELD_DATA_DBL: meFieldType = EXC_PCFIELD_NUMGROUP; break;
+ case EXC_SXFIELD_DATA_DATE: meFieldType = EXC_PCFIELD_DATEGROUP; break;
+ default: DBG_ERRORFILE( "XclImpPCField::ReadSxfield - numeric group with wrong data type" );
+ }
+ }
+
+ // 2b) first date grouping field with child grouping field
+ else if( bChild && (nType == EXC_SXFIELD_DATA_DATE) && (nOrigC > 0) )
+ meFieldType = EXC_PCFIELD_DATEGROUP;
+
+ // 2c) additional date grouping field
+ else if( bTypeNone && (nOrigC == 0) )
+ meFieldType = EXC_PCFIELD_DATECHILD;
+ }
+ DBG_ASSERT( meFieldType != EXC_PCFIELD_UNKNOWN, "XclImpPCField::ReadSxfield - invalid standard or grouped field" );
+ }
+
+ // 3) calculated field
+ else
+ {
+ if( !bChild && !bNum && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == 0) )
+ meFieldType = EXC_PCFIELD_CALCED;
+ DBG_ASSERT( meFieldType == EXC_PCFIELD_CALCED, "XclImpPCField::ReadSxfield - invalid calculated field" );
+ }
+ }
+
+ else if( !bItems && bPostp )
+ {
+ // 4) standard field with postponed items
+ if( !bCalced && !bChild && !bNum && bType && (nGroupC == 0) && (nBaseC == 0) && (nOrigC == 0) )
+ meFieldType = EXC_PCFIELD_STANDARD;
+ DBG_ASSERT( meFieldType == EXC_PCFIELD_STANDARD, "XclImpPCField::ReadSxfield - invalid postponed field" );
+ }
+ }
+}
+
+void XclImpPCField::ReadItem( XclImpStream& rStrm )
+{
+ DBG_ASSERT( HasInlineItems() || HasPostponedItems(), "XclImpPCField::ReadItem - field does not expect items" );
+
+ // read the item
+ XclImpPCItemRef xItem( new XclImpPCItem( rStrm ) );
+
+ // try to insert into an item list
+ if( mbNumGroupInfoRead )
+ {
+ // there are 3 items after SXNUMGROUP that contain grouping limits and step count
+ if( maNumGroupItems.size() < 3 )
+ maNumGroupItems.push_back( xItem );
+ else
+ maOrigItems.push_back( xItem );
+ }
+ else if( HasInlineItems() || HasPostponedItems() )
+ {
+ maItems.push_back( xItem );
+ // visible item is original item in standard fields
+ if( IsStandardField() )
+ maOrigItems.push_back( xItem );
+ }
+}
+
+void XclImpPCField::ReadSxnumgroup( XclImpStream& rStrm )
+{
+ DBG_ASSERT( IsNumGroupField() || IsDateGroupField(), "XclImpPCField::ReadSxnumgroup - SXNUMGROUP outside numeric grouping field" );
+ DBG_ASSERT( !mbNumGroupInfoRead, "XclImpPCField::ReadSxnumgroup - multiple SXNUMGROUP records" );
+ DBG_ASSERT( maItems.size() == maFieldInfo.mnGroupItems, "XclImpPCField::ReadSxnumgroup - SXNUMGROUP out of record order" );
+ rStrm >> maNumGroupInfo;
+ mbNumGroupInfoRead = IsNumGroupField() || IsDateGroupField();
+}
+
+void XclImpPCField::ReadSxgroupinfo( XclImpStream& rStrm )
+{
+ DBG_ASSERT( IsStdGroupField(), "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO outside grouping field" );
+ DBG_ASSERT( maGroupOrder.empty(), "XclImpPCField::ReadSxgroupinfo - multiple SXGROUPINFO records" );
+ DBG_ASSERT( maItems.size() == maFieldInfo.mnGroupItems, "XclImpPCField::ReadSxgroupinfo - SXGROUPINFO out of record order" );
+ DBG_ASSERT( (rStrm.GetRecLeft() / 2) == maFieldInfo.mnBaseItems, "XclImpPCField::ReadSxgroupinfo - wrong SXGROUPINFO size" );
+ maGroupOrder.clear();
+ size_t nSize = rStrm.GetRecLeft() / 2;
+ maGroupOrder.resize( nSize, 0 );
+ for( size_t nIdx = 0; nIdx < nSize; ++nIdx )
+ rStrm >> maGroupOrder[ nIdx ];
+}
+
+// grouping -------------------------------------------------------------------
+
+void XclImpPCField::ConvertGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
+{
+ if( GetFieldName( rVisNames ).Len() > 0 )
+ {
+ if( IsStdGroupField() )
+ ConvertStdGroupField( rSaveData, rVisNames );
+ else if( IsNumGroupField() )
+ ConvertNumGroupField( rSaveData, rVisNames );
+ else if( IsDateGroupField() )
+ ConvertDateGroupField( rSaveData, rVisNames );
+ }
+}
+
+// private --------------------------------------------------------------------
+
+void XclImpPCField::ConvertStdGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
+{
+ if( const XclImpPCField* pBaseField = GetGroupBaseField() )
+ {
+ const String& rBaseFieldName = pBaseField->GetFieldName( rVisNames );
+ if( rBaseFieldName.Len() > 0 )
+ {
+ // *** create a ScDPSaveGroupItem for each own item, they collect base item names ***
+ ScDPSaveGroupItemVec aGroupItems;
+ aGroupItems.reserve( maItems.size() );
+ // initialize with own item names
+ for( XclImpPCItemVec::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
+ aGroupItems.push_back( ScDPSaveGroupItem( (*aIt)->ConvertToText() ) );
+
+ // *** iterate over all base items, set their names at corresponding own items ***
+ for( sal_uInt16 nItemIdx = 0, nItemCount = static_cast< sal_uInt16 >( maGroupOrder.size() ); nItemIdx < nItemCount; ++nItemIdx )
+ if( maGroupOrder[ nItemIdx ] < aGroupItems.size() )
+ if( const XclImpPCItem* pBaseItem = pBaseField->GetItem( nItemIdx ) )
+ if( const XclImpPCItem* pGroupItem = GetItem( maGroupOrder[ nItemIdx ] ) )
+ if( *pBaseItem != *pGroupItem )
+ aGroupItems[ maGroupOrder[ nItemIdx ] ].AddElement( pBaseItem->ConvertToText() );
+
+ // *** create the ScDPSaveGroupDimension object, fill with grouping info ***
+ ScDPSaveGroupDimension aGroupDim( rBaseFieldName, GetFieldName( rVisNames ) );
+ for( ScDPSaveGroupItemVec::const_iterator aIt = aGroupItems.begin(), aEnd = aGroupItems.end(); aIt != aEnd; ++aIt )
+ if( !aIt->IsEmpty() )
+ aGroupDim.AddGroupItem( *aIt );
+ rSaveData.GetDimensionData()->AddGroupDimension( aGroupDim );
+ }
+ }
+}
+
+void XclImpPCField::ConvertNumGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
+{
+ ScDPNumGroupInfo aNumInfo( GetScNumGroupInfo() );
+ ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), aNumInfo );
+ rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
+}
+
+void XclImpPCField::ConvertDateGroupField( ScDPSaveData& rSaveData, const ScfStringVec& rVisNames ) const
+{
+ ScDPNumGroupInfo aDateInfo( GetScDateGroupInfo() );
+ sal_Int32 nScDateType = maNumGroupInfo.GetScDateType();
+
+ switch( meFieldType )
+ {
+ case EXC_PCFIELD_DATEGROUP:
+ {
+ if( aDateInfo.DateValues )
+ {
+ // special case for days only with step value - create numeric grouping
+ ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), aDateInfo );
+ rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
+ }
+ else
+ {
+ ScDPSaveNumGroupDimension aNumGroupDim( GetFieldName( rVisNames ), ScDPNumGroupInfo() );
+ aNumGroupDim.SetDateInfo( aDateInfo, nScDateType );
+ rSaveData.GetDimensionData()->AddNumGroupDimension( aNumGroupDim );
+ }
+ }
+ break;
+
+ case EXC_PCFIELD_DATECHILD:
+ {
+ if( const XclImpPCField* pBaseField = GetGroupBaseField() )
+ {
+ const String& rBaseFieldName = pBaseField->GetFieldName( rVisNames );
+ if( rBaseFieldName.Len() > 0 )
+ {
+ ScDPSaveGroupDimension aGroupDim( rBaseFieldName, GetFieldName( rVisNames ) );
+ aGroupDim.SetDateInfo( aDateInfo, nScDateType );
+ rSaveData.GetDimensionData()->AddGroupDimension( aGroupDim );
+ }
+ }
+ }
+ break;
+
+ default:
+ DBG_ERRORFILE( "XclImpPCField::ConvertDateGroupField - unknown date field type" );
+ }
+}
+
+ScDPNumGroupInfo XclImpPCField::GetScNumGroupInfo() const
+{
+ ScDPNumGroupInfo aNumInfo;
+ aNumInfo.Enable = sal_True;
+ aNumInfo.DateValues = false;
+ aNumInfo.AutoStart = sal_True;
+ aNumInfo.AutoEnd = sal_True;
+
+ if( const double* pfMinValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_MIN ) )
+ {
+ aNumInfo.Start = *pfMinValue;
+ aNumInfo.AutoStart = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN );
+ }
+ if( const double* pfMaxValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_MAX ) )
+ {
+ aNumInfo.End = *pfMaxValue;
+ aNumInfo.AutoEnd = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX );
+ }
+ if( const double* pfStepValue = GetNumGroupLimit( EXC_SXFIELD_INDEX_STEP ) )
+ aNumInfo.Step = *pfStepValue;
+
+ return aNumInfo;
+}
+
+ScDPNumGroupInfo XclImpPCField::GetScDateGroupInfo() const
+{
+ ScDPNumGroupInfo aDateInfo;
+ aDateInfo.Enable = sal_True;
+ aDateInfo.DateValues = false;
+ aDateInfo.AutoStart = sal_True;
+ aDateInfo.AutoEnd = sal_True;
+
+ if( const DateTime* pMinDate = GetDateGroupLimit( EXC_SXFIELD_INDEX_MIN ) )
+ {
+ aDateInfo.Start = GetDoubleFromDateTime( *pMinDate );
+ aDateInfo.AutoStart = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMIN );
+ }
+ if( const DateTime* pMaxDate = GetDateGroupLimit( EXC_SXFIELD_INDEX_MAX ) )
+ {
+ aDateInfo.End = GetDoubleFromDateTime( *pMaxDate );
+ aDateInfo.AutoEnd = ::get_flag( maNumGroupInfo.mnFlags, EXC_SXNUMGROUP_AUTOMAX );
+ }
+ // GetDateGroupStep() returns a value for date type "day" in single date groups only
+ if( const sal_Int16* pnStepValue = GetDateGroupStep() )
+ {
+ aDateInfo.Step = *pnStepValue;
+ aDateInfo.DateValues = sal_True;
+ }
+
+ return aDateInfo;
+}
+
+const double* XclImpPCField::GetNumGroupLimit( sal_uInt16 nLimitIdx ) const
+{
+ DBG_ASSERT( IsNumGroupField(), "XclImpPCField::GetNumGroupLimit - only for numeric grouping fields" );
+ if( const XclImpPCItem* pItem = GetLimitItem( nLimitIdx ) )
+ {
+ DBG_ASSERT( pItem->GetDouble(), "XclImpPCField::GetNumGroupLimit - SXDOUBLE item expected" );
+ return pItem->GetDouble();
+ }
+ return 0;
+}
+
+const DateTime* XclImpPCField::GetDateGroupLimit( sal_uInt16 nLimitIdx ) const
+{
+ DBG_ASSERT( IsDateGroupField(), "XclImpPCField::GetDateGroupLimit - only for date grouping fields" );
+ if( const XclImpPCItem* pItem = GetLimitItem( nLimitIdx ) )
+ {
+ DBG_ASSERT( pItem->GetDateTime(), "XclImpPCField::GetDateGroupLimit - SXDATETIME item expected" );
+ return pItem->GetDateTime();
+ }
+ return 0;
+}
+
+const sal_Int16* XclImpPCField::GetDateGroupStep() const
+{
+ // only for single date grouping fields, not for grouping chains
+ if( !IsGroupBaseField() && !IsGroupChildField() )
+ {
+ // only days may have a step value, return 0 for all other date types
+ if( maNumGroupInfo.GetXclDataType() == EXC_SXNUMGROUP_TYPE_DAY )
+ {
+ if( const XclImpPCItem* pItem = GetLimitItem( EXC_SXFIELD_INDEX_STEP ) )
+ {
+ DBG_ASSERT( pItem->GetInteger(), "XclImpPCField::GetDateGroupStep - SXINTEGER item expected" );
+ if( const sal_Int16* pnStep = pItem->GetInteger() )
+ {
+ DBG_ASSERT( *pnStep > 0, "XclImpPCField::GetDateGroupStep - invalid step count" );
+ // return nothing for step count 1 - this is also a standard date group in Excel
+ return (*pnStep > 1) ? pnStep : 0;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+// ============================================================================
+
+XclImpPivotCache::XclImpPivotCache( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ maSrcRange( ScAddress::INITIALIZE_INVALID ),
+ mnStrmId( 0 ),
+ mnSrcType( EXC_SXVS_UNKNOWN ),
+ mbSelfRef( false )
+{
+}
+
+XclImpPivotCache::~XclImpPivotCache()
+{
+}
+
+// data access ----------------------------------------------------------------
+
+sal_uInt16 XclImpPivotCache::GetFieldCount() const
+{
+ return static_cast< sal_uInt16 >( maFields.size() );
+}
+
+const XclImpPCField* XclImpPivotCache::GetField( sal_uInt16 nFieldIdx ) const
+{
+ return (nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0;
+}
+
+// records --------------------------------------------------------------------
+
+void XclImpPivotCache::ReadSxidstm( XclImpStream& rStrm )
+{
+ rStrm >> mnStrmId;
+}
+
+void XclImpPivotCache::ReadSxvs( XclImpStream& rStrm )
+{
+ rStrm >> mnSrcType;
+ GetTracer().TracePivotDataSource( mnSrcType != EXC_SXVS_SHEET );
+}
+
+void XclImpPivotCache::ReadDconref( XclImpStream& rStrm )
+{
+ /* Read DCONREF only once (by checking maTabName), there may be other
+ DCONREF records in another context. Read reference only if a leading
+ SXVS record is present (by checking mnSrcType). */
+ if( (maTabName.Len() > 0) || (mnSrcType != EXC_SXVS_SHEET) )
+ return;
+
+ XclRange aXclRange( ScAddress::UNINITIALIZED );
+ aXclRange.Read( rStrm, false );
+ String aEncUrl = rStrm.ReadUniString();
+
+ XclImpUrlHelper::DecodeUrl( maUrl, maTabName, mbSelfRef, GetRoot(), aEncUrl );
+
+ /* Do not convert maTabName to Calc sheet name -> original name is used to
+ find the sheet in the document. Sheet index of source range will be
+ found later in XclImpPivotCache::ReadPivotCacheStream(), because sheet
+ may not exist yet. */
+ if( mbSelfRef )
+ GetAddressConverter().ConvertRange( maSrcRange, aXclRange, 0, 0, true );
+}
+
+void XclImpPivotCache::ReadDConName( XclImpStream& rStrm )
+{
+ maSrcRangeName = rStrm.ReadUniString();
+
+ // This 2-byte value equals the length of string that follows, or if 0 it
+ // indicates that the name has a workbook scope. For now, we only support
+ // internal defined name with a workbook scope.
+ sal_uInt16 nFlag;
+ rStrm >> nFlag;
+ mbSelfRef = (nFlag == 0);
+
+ if (!mbSelfRef)
+ // External name is not supported yet.
+ maSrcRangeName = OUString();
+}
+
+void XclImpPivotCache::ReadPivotCacheStream( XclImpStream& rStrm )
+{
+ if( (mnSrcType != EXC_SXVS_SHEET) && (mnSrcType != EXC_SXVS_EXTERN) )
+ return;
+
+ ScDocument& rDoc = GetDoc();
+ SCCOL nFieldScCol = 0; // column index of source data for next field
+ SCROW nItemScRow = 0; // row index of source data for current items
+ SCTAB nScTab = 0; // sheet index of source data
+ bool bGenerateSource = false; // true = write source data from cache to dummy table
+
+ if( mbSelfRef )
+ {
+ if (!maSrcRangeName.getLength())
+ {
+ // try to find internal sheet containing the source data
+ nScTab = GetTabInfo().GetScTabFromXclName( maTabName );
+ if( rDoc.HasTable( nScTab ) )
+ {
+ // set sheet index to source range
+ maSrcRange.aStart.SetTab( nScTab );
+ maSrcRange.aEnd.SetTab( nScTab );
+ }
+ else
+ {
+ // create dummy sheet for deleted internal sheet
+ bGenerateSource = true;
+ }
+ }
+ }
+ else
+ {
+ // create dummy sheet for external sheet
+ bGenerateSource = true;
+ }
+
+ // create dummy sheet for source data from external or deleted sheet
+ if( bGenerateSource )
+ {
+ if( rDoc.GetTableCount() >= MAXTABCOUNT )
+ // cannot create more sheets -> exit
+ return;
+
+ nScTab = rDoc.GetTableCount();
+ rDoc.MakeTable( nScTab );
+ String aDummyName = CREATE_STRING( "DPCache" );
+ if( maTabName.Len() > 0 )
+ aDummyName.Append( '_' ).Append( maTabName );
+ rDoc.CreateValidTabName( aDummyName );
+ rDoc.RenameTab( nScTab, aDummyName );
+ // set sheet index to source range
+ maSrcRange.aStart.SetTab( nScTab );
+ maSrcRange.aEnd.SetTab( nScTab );
+ }
+
+ // open pivot cache storage stream
+ SotStorageRef xSvStrg = OpenStorage( EXC_STORAGE_PTCACHE );
+ SotStorageStreamRef xSvStrm = OpenStream( xSvStrg, ScfTools::GetHexStr( mnStrmId ) );
+ if( !xSvStrm.Is() )
+ return;
+
+ // create Excel record stream object
+ XclImpStream aPCStrm( *xSvStrm, GetRoot() );
+ aPCStrm.CopyDecrypterFrom( rStrm ); // pivot cache streams are encrypted
+
+ XclImpPCFieldRef xCurrField; // current field for new items
+ XclImpPCFieldVec aOrigFields; // all standard fields with inline original items
+ XclImpPCFieldVec aPostpFields; // all standard fields with postponed original items
+ size_t nPostpIdx = 0; // index to current field with postponed items
+ bool bLoop = true; // true = continue loop
+
+ while( bLoop && aPCStrm.StartNextRecord() )
+ {
+ switch( aPCStrm.GetRecId() )
+ {
+ case EXC_ID_EOF:
+ bLoop = false;
+ break;
+
+ case EXC_ID_SXDB:
+ aPCStrm >> maPCInfo;
+ break;
+
+ case EXC_ID_SXFIELD:
+ {
+ xCurrField.reset();
+ sal_uInt16 nNewFieldIdx = GetFieldCount();
+ if( nNewFieldIdx < EXC_PC_MAXFIELDCOUNT )
+ {
+ xCurrField.reset( new XclImpPCField( GetRoot(), *this, nNewFieldIdx ) );
+ maFields.push_back( xCurrField );
+ xCurrField->ReadSxfield( aPCStrm );
+ if( xCurrField->HasOrigItems() )
+ {
+ if( xCurrField->HasPostponedItems() )
+ aPostpFields.push_back( xCurrField );
+ else
+ aOrigFields.push_back( xCurrField );
+ // insert field name into generated source data, field remembers its column index
+ if( bGenerateSource && (nFieldScCol <= MAXCOL) )
+ xCurrField->WriteFieldNameToSource( nFieldScCol++, nScTab );
+ }
+ // do not read items into invalid/postponed fields
+ if( !xCurrField->HasInlineItems() )
+ xCurrField.reset();
+ }
+ }
+ break;
+
+ case EXC_ID_SXINDEXLIST:
+ // read index list and insert all items into generated source data
+ if( bGenerateSource && (nItemScRow <= MAXROW) && (++nItemScRow <= MAXROW) )
+ {
+ for( XclImpPCFieldVec::const_iterator aIt = aOrigFields.begin(), aEnd = aOrigFields.end(); aIt != aEnd; ++aIt )
+ {
+ sal_uInt16 nItemIdx = (*aIt)->Has16BitIndexes() ? aPCStrm.ReaduInt16() : aPCStrm.ReaduInt8();
+ (*aIt)->WriteOrigItemToSource( nItemScRow, nScTab, nItemIdx );
+ }
+ }
+ xCurrField.reset();
+ break;
+
+ case EXC_ID_SXDOUBLE:
+ case EXC_ID_SXBOOLEAN:
+ case EXC_ID_SXERROR:
+ case EXC_ID_SXINTEGER:
+ case EXC_ID_SXSTRING:
+ case EXC_ID_SXDATETIME:
+ case EXC_ID_SXEMPTY:
+ if( xCurrField ) // inline items
+ {
+ xCurrField->ReadItem( aPCStrm );
+ }
+ else if( !aPostpFields.empty() ) // postponed items
+ {
+ // read postponed item
+ aPostpFields[ nPostpIdx ]->ReadItem( aPCStrm );
+ // write item to source
+ if( bGenerateSource && (nItemScRow <= MAXROW) )
+ {
+ // start new row, if there are only postponed fields
+ if( aOrigFields.empty() && (nPostpIdx == 0) )
+ ++nItemScRow;
+ if( nItemScRow <= MAXROW )
+ aPostpFields[ nPostpIdx ]->WriteLastOrigItemToSource( nItemScRow, nScTab );
+ }
+ // get index of next postponed field
+ ++nPostpIdx;
+ if( nPostpIdx >= aPostpFields.size() )
+ nPostpIdx = 0;
+ }
+ break;
+
+ case EXC_ID_SXNUMGROUP:
+ if( xCurrField )
+ xCurrField->ReadSxnumgroup( aPCStrm );
+ break;
+
+ case EXC_ID_SXGROUPINFO:
+ if( xCurrField )
+ xCurrField->ReadSxgroupinfo( aPCStrm );
+ break;
+
+ // known but ignored records
+ case EXC_ID_SXRULE:
+ case EXC_ID_SXFILT:
+ case EXC_ID_00F5:
+ case EXC_ID_SXNAME:
+ case EXC_ID_SXPAIR:
+ case EXC_ID_SXFMLA:
+ case EXC_ID_SXFORMULA:
+ case EXC_ID_SXDBEX:
+ case EXC_ID_SXFDBTYPE:
+ break;
+
+ default:
+ OSL_TRACE( "XclImpPivotCache::ReadPivotCacheStream - unknown record 0x%04hX", aPCStrm.GetRecId() );
+ }
+ }
+
+ DBG_ASSERT( maPCInfo.mnTotalFields == maFields.size(),
+ "XclImpPivotCache::ReadPivotCacheStream - field count mismatch" );
+
+ if (HasCacheRecords())
+ {
+ SCROW nNewEnd = maSrcRange.aStart.Row() + maPCInfo.mnSrcRecs;
+ maSrcRange.aEnd.SetRow(nNewEnd);
+ }
+
+ // set source range for external source data
+ if( bGenerateSource && (nFieldScCol > 0) )
+ {
+ maSrcRange.aStart.SetCol( 0 );
+ maSrcRange.aStart.SetRow( 0 );
+ // nFieldScCol points to first unused column
+ maSrcRange.aEnd.SetCol( nFieldScCol - 1 );
+ // nItemScRow points to last used row
+ maSrcRange.aEnd.SetRow( nItemScRow );
+ }
+}
+
+bool XclImpPivotCache::HasCacheRecords() const
+{
+ return static_cast<bool>(maPCInfo.mnFlags & EXC_SXDB_SAVEDATA);
+}
+
+bool XclImpPivotCache::IsRefreshOnLoad() const
+{
+ return static_cast<bool>(maPCInfo.mnFlags & EXC_SXDB_REFRESH_LOAD);
+}
+
+bool XclImpPivotCache::IsValid() const
+{
+ if (maSrcRangeName.getLength())
+ return true;
+
+ return maSrcRange.IsValid();
+}
+
+// ============================================================================
+// Pivot table
+// ============================================================================
+
+XclImpPTItem::XclImpPTItem( const XclImpPCField* pCacheField ) :
+ mpCacheField( pCacheField )
+{
+}
+
+const String* XclImpPTItem::GetItemName() const
+{
+ if( mpCacheField )
+ if( const XclImpPCItem* pCacheItem = mpCacheField->GetItem( maItemInfo.mnCacheIdx ) )
+ //! TODO: use XclImpPCItem::ConvertToText(), if all conversions are available
+ return pCacheItem->IsEmpty() ? &String::EmptyString() : pCacheItem->GetText();
+ return 0;
+}
+
+const String* XclImpPTItem::GetVisItemName() const
+{
+ return maItemInfo.HasVisName() ? maItemInfo.GetVisName() : GetItemName();
+}
+
+void XclImpPTItem::ReadSxvi( XclImpStream& rStrm )
+{
+ rStrm >> maItemInfo;
+}
+
+void XclImpPTItem::ConvertItem( ScDPSaveDimension& rSaveDim ) const
+{
+ if( const String* pItemName = GetItemName() )
+ {
+ ScDPSaveMember& rMember = *rSaveDim.GetMemberByName( *pItemName );
+ rMember.SetIsVisible( !::get_flag( maItemInfo.mnFlags, EXC_SXVI_HIDDEN ) );
+ rMember.SetShowDetails( !::get_flag( maItemInfo.mnFlags, EXC_SXVI_HIDEDETAIL ) );
+ if (maItemInfo.HasVisName())
+ rMember.SetLayoutName(*maItemInfo.GetVisName());
+ }
+}
+
+// ============================================================================
+
+XclImpPTField::XclImpPTField( const XclImpPivotTable& rPTable, sal_uInt16 nCacheIdx ) :
+ mrPTable( rPTable )
+{
+ maFieldInfo.mnCacheIdx = nCacheIdx;
+}
+
+// general field/item access --------------------------------------------------
+
+const XclImpPCField* XclImpPTField::GetCacheField() const
+{
+ XclImpPivotCacheRef xPCache = mrPTable.GetPivotCache();
+ return xPCache ? xPCache->GetField( maFieldInfo.mnCacheIdx ) : 0;
+}
+
+const String& XclImpPTField::GetFieldName() const
+{
+ const XclImpPCField* pField = GetCacheField();
+ return pField ? pField->GetFieldName( mrPTable.GetVisFieldNames() ) : String::EmptyString();
+}
+
+const String& XclImpPTField::GetVisFieldName() const
+{
+ const String* pVisName = maFieldInfo.GetVisName();
+ return pVisName ? *pVisName : String::EmptyString();
+}
+
+const XclImpPTItem* XclImpPTField::GetItem( sal_uInt16 nItemIdx ) const
+{
+ return (nItemIdx < maItems.size()) ? maItems[ nItemIdx ].get() : 0;
+}
+
+const String* XclImpPTField::GetItemName( sal_uInt16 nItemIdx ) const
+{
+ const XclImpPTItem* pItem = GetItem( nItemIdx );
+ return pItem ? pItem->GetItemName() : 0;
+}
+
+// records --------------------------------------------------------------------
+
+void XclImpPTField::ReadSxvd( XclImpStream& rStrm )
+{
+ rStrm >> maFieldInfo;
+}
+
+void XclImpPTField::ReadSxvdex( XclImpStream& rStrm )
+{
+ rStrm >> maFieldExtInfo;
+}
+
+void XclImpPTField::ReadSxvi( XclImpStream& rStrm )
+{
+ XclImpPTItemRef xItem( new XclImpPTItem( GetCacheField() ) );
+ maItems.push_back( xItem );
+ xItem->ReadSxvi( rStrm );
+}
+
+// row/column fields ----------------------------------------------------------
+
+void XclImpPTField::ConvertRowColField( ScDPSaveData& rSaveData ) const
+{
+ DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_ROWCOL, "XclImpPTField::ConvertRowColField - no row/column field" );
+ // special data orientation field?
+ if( maFieldInfo.mnCacheIdx == EXC_SXIVD_DATA )
+ rSaveData.GetDataLayoutDimension()->SetOrientation( static_cast< sal_uInt16 >( maFieldInfo.GetApiOrient( EXC_SXVD_AXIS_ROWCOL ) ) );
+ else
+ ConvertRCPField( rSaveData );
+}
+
+// page fields ----------------------------------------------------------------
+
+void XclImpPTField::SetPageFieldInfo( const XclPTPageFieldInfo& rPageInfo )
+{
+ maPageInfo = rPageInfo;
+}
+
+void XclImpPTField::ConvertPageField( ScDPSaveData& rSaveData ) const
+{
+ DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_PAGE, "XclImpPTField::ConvertPageField - no page field" );
+ if( ScDPSaveDimension* pSaveDim = ConvertRCPField( rSaveData ) )
+ {
+ const String* pName = GetItemName( maPageInfo.mnSelItem );
+ if (pName)
+ {
+ const OUString aName(*pName);
+ pSaveDim->SetCurrentPage(&aName);
+ }
+ }
+}
+
+// hidden fields --------------------------------------------------------------
+
+void XclImpPTField::ConvertHiddenField( ScDPSaveData& rSaveData ) const
+{
+ DBG_ASSERT( (maFieldInfo.mnAxes & EXC_SXVD_AXIS_ROWCOLPAGE) == 0, "XclImpPTField::ConvertHiddenField - field not hidden" );
+ ConvertRCPField( rSaveData );
+}
+
+// data fields ----------------------------------------------------------------
+
+bool XclImpPTField::HasDataFieldInfo() const
+{
+ return !maDataInfoList.empty();
+}
+
+void XclImpPTField::AddDataFieldInfo( const XclPTDataFieldInfo& rDataInfo )
+{
+ DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_DATA, "XclImpPTField::AddDataFieldInfo - no data field" );
+ maDataInfoList.push_back( rDataInfo );
+}
+
+void XclImpPTField::ConvertDataField( ScDPSaveData& rSaveData ) const
+{
+ DBG_ASSERT( maFieldInfo.mnAxes & EXC_SXVD_AXIS_DATA, "XclImpPTField::ConvertDataField - no data field" );
+ DBG_ASSERT( !maDataInfoList.empty(), "XclImpPTField::ConvertDataField - no data field info" );
+ if( !maDataInfoList.empty() )
+ {
+ const String& rFieldName = GetFieldName();
+ if( rFieldName.Len() > 0 )
+ {
+ XclPTDataFieldInfoList::const_iterator aIt = maDataInfoList.begin(), aEnd = maDataInfoList.end();
+
+ ScDPSaveDimension& rSaveDim = *rSaveData.GetNewDimensionByName( rFieldName );
+ ConvertDataField( rSaveDim, *aIt );
+
+ // multiple data fields -> clone dimension
+ for( ++aIt; aIt != aEnd; ++aIt )
+ {
+ ScDPSaveDimension& rDupDim = rSaveData.DuplicateDimension( rSaveDim );
+ ConvertDataFieldInfo( rDupDim, *aIt );
+ }
+ }
+ }
+}
+
+// private --------------------------------------------------------------------
+
+/**
+ * Convert Excel-encoded subtotal name to a Calc-encoded one.
+ */
+static OUString lcl_convertExcelSubtotalName(const OUString& rName)
+{
+ OUStringBuffer aBuf;
+ const sal_Unicode* p = rName.getStr();
+ sal_Int32 n = rName.getLength();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ const sal_Unicode c = p[i];
+ if (c == sal_Unicode('\\'))
+ {
+ aBuf.append(c);
+ aBuf.append(c);
+ }
+ else
+ aBuf.append(c);
+ }
+ return aBuf.makeStringAndClear();
+}
+
+ScDPSaveDimension* XclImpPTField::ConvertRCPField( ScDPSaveData& rSaveData ) const
+{
+ const String& rFieldName = GetFieldName();
+ if( rFieldName.Len() == 0 )
+ return 0;
+
+ const XclImpPCField* pCacheField = GetCacheField();
+ if( !pCacheField || !pCacheField->IsSupportedField() )
+ return 0;
+
+ ScDPSaveDimension& rSaveDim = *rSaveData.GetNewDimensionByName( rFieldName );
+
+ // orientation
+ rSaveDim.SetOrientation( static_cast< sal_uInt16 >( maFieldInfo.GetApiOrient( EXC_SXVD_AXIS_ROWCOLPAGE ) ) );
+
+ // general field info
+ ConvertFieldInfo( rSaveDim );
+
+ // visible name
+ if( const String* pVisName = maFieldInfo.GetVisName() )
+ if( pVisName->Len() > 0 )
+ rSaveDim.SetLayoutName( *pVisName );
+
+ // subtotal function(s)
+ XclPTSubtotalVec aSubtotalVec;
+ maFieldInfo.GetSubtotals( aSubtotalVec );
+ if( !aSubtotalVec.empty() )
+ rSaveDim.SetSubTotals( static_cast< long >( aSubtotalVec.size() ), &aSubtotalVec[ 0 ] );
+
+ // sorting
+ DataPilotFieldSortInfo aSortInfo;
+ aSortInfo.Field = mrPTable.GetDataFieldName( maFieldExtInfo.mnSortField );
+ aSortInfo.IsAscending = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SORT_ASC );
+ aSortInfo.Mode = maFieldExtInfo.GetApiSortMode();
+ rSaveDim.SetSortInfo( &aSortInfo );
+
+ // auto show
+ DataPilotFieldAutoShowInfo aShowInfo;
+ aShowInfo.IsEnabled = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_AUTOSHOW );
+ aShowInfo.ShowItemsMode = maFieldExtInfo.GetApiAutoShowMode();
+ aShowInfo.ItemCount = maFieldExtInfo.GetApiAutoShowCount();
+ aShowInfo.DataField = mrPTable.GetDataFieldName( maFieldExtInfo.mnShowField );
+ rSaveDim.SetAutoShowInfo( &aShowInfo );
+
+ // layout
+ DataPilotFieldLayoutInfo aLayoutInfo;
+ aLayoutInfo.LayoutMode = maFieldExtInfo.GetApiLayoutMode();
+ aLayoutInfo.AddEmptyLines = ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_LAYOUT_BLANK );
+ rSaveDim.SetLayoutInfo( &aLayoutInfo );
+
+ // grouping info
+ pCacheField->ConvertGroupField( rSaveData, mrPTable.GetVisFieldNames() );
+
+ // custom subtotal name
+ if (maFieldExtInfo.mpFieldTotalName.get())
+ {
+ OUString aSubName = lcl_convertExcelSubtotalName(*maFieldExtInfo.mpFieldTotalName);
+ rSaveDim.SetSubtotalName(aSubName);
+ }
+
+ return &rSaveDim;
+}
+
+void XclImpPTField::ConvertFieldInfo( ScDPSaveDimension& rSaveDim ) const
+{
+ rSaveDim.SetShowEmpty( ::get_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SHOWALL ) );
+ ConvertItems( rSaveDim );
+}
+
+void XclImpPTField::ConvertDataField( ScDPSaveDimension& rSaveDim, const XclPTDataFieldInfo& rDataInfo ) const
+{
+ // orientation
+ rSaveDim.SetOrientation( DataPilotFieldOrientation_DATA );
+ // general field info
+ ConvertFieldInfo( rSaveDim );
+ // extended data field info
+ ConvertDataFieldInfo( rSaveDim, rDataInfo );
+}
+
+void XclImpPTField::ConvertDataFieldInfo( ScDPSaveDimension& rSaveDim, const XclPTDataFieldInfo& rDataInfo ) const
+{
+ // visible name
+ if( const String* pVisName = rDataInfo.GetVisName() )
+ if( pVisName->Len() > 0 )
+ rSaveDim.SetLayoutName( *pVisName );
+
+ // aggregation function
+ rSaveDim.SetFunction( static_cast< sal_uInt16 >( rDataInfo.GetApiAggFunc() ) );
+
+ // result field reference
+ sal_Int32 nRefType = rDataInfo.GetApiRefType();
+ if( nRefType != ::com::sun::star::sheet::DataPilotFieldReferenceType::NONE )
+ {
+ DataPilotFieldReference aFieldRef;
+ aFieldRef.ReferenceType = nRefType;
+
+ if( const XclImpPTField* pRefField = mrPTable.GetField( rDataInfo.mnRefField ) )
+ {
+ aFieldRef.ReferenceField = pRefField->GetFieldName();
+ aFieldRef.ReferenceItemType = rDataInfo.GetApiRefItemType();
+ if( aFieldRef.ReferenceItemType == ::com::sun::star::sheet::DataPilotFieldReferenceItemType::NAMED )
+ if( const String* pRefItemName = pRefField->GetItemName( rDataInfo.mnRefItem ) )
+ aFieldRef.ReferenceItemName = *pRefItemName;
+ }
+
+ rSaveDim.SetReferenceValue( &aFieldRef );
+ }
+}
+
+void XclImpPTField::ConvertItems( ScDPSaveDimension& rSaveDim ) const
+{
+ for( XclImpPTItemVec::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
+ (*aIt)->ConvertItem( rSaveDim );
+}
+
+// ============================================================================
+
+XclImpPivotTable::XclImpPivotTable( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ maDataOrientField( *this, EXC_SXIVD_DATA ),
+ mpDPObj(NULL)
+{
+}
+
+XclImpPivotTable::~XclImpPivotTable()
+{
+}
+
+// cache/field access, misc. --------------------------------------------------
+
+sal_uInt16 XclImpPivotTable::GetFieldCount() const
+{
+ return static_cast< sal_uInt16 >( maFields.size() );
+}
+
+const XclImpPTField* XclImpPivotTable::GetField( sal_uInt16 nFieldIdx ) const
+{
+ return (nFieldIdx == EXC_SXIVD_DATA) ? &maDataOrientField :
+ ((nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0);
+}
+
+XclImpPTField* XclImpPivotTable::GetFieldAcc( sal_uInt16 nFieldIdx )
+{
+ // do not return maDataOrientField
+ return (nFieldIdx < maFields.size()) ? maFields[ nFieldIdx ].get() : 0;
+}
+
+const XclImpPTField* XclImpPivotTable::GetDataField( sal_uInt16 nDataFieldIdx ) const
+{
+ if( nDataFieldIdx < maOrigDataFields.size() )
+ return GetField( maOrigDataFields[ nDataFieldIdx ] );
+ return 0;
+}
+
+const String& XclImpPivotTable::GetDataFieldName( sal_uInt16 nDataFieldIdx ) const
+{
+ if( const XclImpPTField* pField = GetDataField( nDataFieldIdx ) )
+ return pField->GetFieldName();
+ return EMPTY_STRING;
+}
+
+// records --------------------------------------------------------------------
+
+void XclImpPivotTable::ReadSxview( XclImpStream& rStrm )
+{
+ rStrm >> maPTInfo;
+
+ GetAddressConverter().ConvertRange(
+ maOutScRange, maPTInfo.maOutXclRange, GetCurrScTab(), GetCurrScTab(), true );
+
+ mxPCache = GetPivotTableManager().GetPivotCache( maPTInfo.mnCacheIdx );
+ mxCurrField.reset();
+}
+
+void XclImpPivotTable::ReadSxvd( XclImpStream& rStrm )
+{
+ sal_uInt16 nFieldCount = GetFieldCount();
+ if( nFieldCount < EXC_PT_MAXFIELDCOUNT )
+ {
+ // cache index for the field is equal to the SXVD record index
+ mxCurrField.reset( new XclImpPTField( *this, nFieldCount ) );
+ maFields.push_back( mxCurrField );
+ mxCurrField->ReadSxvd( rStrm );
+ // add visible name of new field to list of visible names
+ maVisFieldNames.push_back( mxCurrField->GetVisFieldName() );
+ DBG_ASSERT( maFields.size() == maVisFieldNames.size(),
+ "XclImpPivotTable::ReadSxvd - wrong size of visible name array" );
+ }
+ else
+ mxCurrField.reset();
+}
+
+void XclImpPivotTable::ReadSxvi( XclImpStream& rStrm )
+{
+ if( mxCurrField )
+ mxCurrField->ReadSxvi( rStrm );
+}
+
+void XclImpPivotTable::ReadSxvdex( XclImpStream& rStrm )
+{
+ if( mxCurrField )
+ mxCurrField->ReadSxvdex( rStrm );
+}
+
+void XclImpPivotTable::ReadSxivd( XclImpStream& rStrm )
+{
+ mxCurrField.reset();
+
+ // find the index vector to fill (row SXIVD doesn't exist without row fields)
+ ScfUInt16Vec* pFieldVec = 0;
+ if( maRowFields.empty() && (maPTInfo.mnRowFields > 0) )
+ pFieldVec = &maRowFields;
+ else if( maColFields.empty() && (maPTInfo.mnColFields > 0) )
+ pFieldVec = &maColFields;
+
+ // fill the vector from record data
+ if( pFieldVec )
+ {
+ sal_uInt16 nSize = ulimit_cast< sal_uInt16 >( rStrm.GetRecSize() / 2, EXC_PT_MAXROWCOLCOUNT );
+ pFieldVec->reserve( nSize );
+ for( sal_uInt16 nIdx = 0; nIdx < nSize; ++nIdx )
+ {
+ sal_uInt16 nFieldIdx;
+ rStrm >> nFieldIdx;
+ pFieldVec->push_back( nFieldIdx );
+
+ // set orientation at special data orientation field
+ if( nFieldIdx == EXC_SXIVD_DATA )
+ {
+ sal_uInt16 nAxis = (pFieldVec == &maRowFields) ? EXC_SXVD_AXIS_ROW : EXC_SXVD_AXIS_COL;
+ maDataOrientField.SetAxes( nAxis );
+ }
+ }
+ }
+}
+
+void XclImpPivotTable::ReadSxpi( XclImpStream& rStrm )
+{
+ mxCurrField.reset();
+
+ sal_uInt16 nSize = ulimit_cast< sal_uInt16 >( rStrm.GetRecSize() / 6 );
+ for( sal_uInt16 nEntry = 0; nEntry < nSize; ++nEntry )
+ {
+ XclPTPageFieldInfo aPageInfo;
+ rStrm >> aPageInfo;
+ if( XclImpPTField* pField = GetFieldAcc( aPageInfo.mnField ) )
+ {
+ maPageFields.push_back( aPageInfo.mnField );
+ pField->SetPageFieldInfo( aPageInfo );
+ }
+ GetCurrSheetDrawing().SetSkipObj( aPageInfo.mnObjId );
+ }
+}
+
+void XclImpPivotTable::ReadSxdi( XclImpStream& rStrm )
+{
+ mxCurrField.reset();
+
+ XclPTDataFieldInfo aDataInfo;
+ rStrm >> aDataInfo;
+ if( XclImpPTField* pField = GetFieldAcc( aDataInfo.mnField ) )
+ {
+ maOrigDataFields.push_back( aDataInfo.mnField );
+ // DataPilot does not support double data fields -> add first appearence to index list only
+ if( !pField->HasDataFieldInfo() )
+ maFiltDataFields.push_back( aDataInfo.mnField );
+ pField->AddDataFieldInfo( aDataInfo );
+ }
+}
+
+void XclImpPivotTable::ReadSxex( XclImpStream& rStrm )
+{
+ rStrm >> maPTExtInfo;
+}
+
+void XclImpPivotTable::ReadSxViewEx9( XclImpStream& rStrm )
+{
+ rStrm >> maPTViewEx9Info;
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpPivotTable::Convert()
+{
+ if( !mxPCache || !mxPCache->IsValid() )
+ return;
+
+ ScDPSaveData aSaveData;
+
+ // *** global settings ***
+
+ aSaveData.SetRowGrand( ::get_flag( maPTInfo.mnFlags, EXC_SXVIEW_ROWGRAND ) );
+ aSaveData.SetColumnGrand( ::get_flag( maPTInfo.mnFlags, EXC_SXVIEW_COLGRAND ) );
+ aSaveData.SetFilterButton( false );
+ aSaveData.SetDrillDown( ::get_flag( maPTExtInfo.mnFlags, EXC_SXEX_DRILLDOWN ) );
+
+ // *** fields ***
+
+ ScfUInt16Vec::const_iterator aIt, aEnd;
+
+ // row fields
+ for( aIt = maRowFields.begin(), aEnd = maRowFields.end(); aIt != aEnd; ++aIt )
+ if( const XclImpPTField* pField = GetField( *aIt ) )
+ pField->ConvertRowColField( aSaveData );
+
+ // column fields
+ for( aIt = maColFields.begin(), aEnd = maColFields.end(); aIt != aEnd; ++aIt )
+ if( const XclImpPTField* pField = GetField( *aIt ) )
+ pField->ConvertRowColField( aSaveData );
+
+ // page fields
+ for( aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
+ if( const XclImpPTField* pField = GetField( *aIt ) )
+ pField->ConvertPageField( aSaveData );
+
+ // We need to import hidden fields because hidden fields may contain
+ // special settings for subtotals (aggregation function, filters, custom
+ // name etc.) and members (hidden, custom name etc.).
+
+ // hidden fields
+ for( sal_uInt16 nField = 0, nCount = GetFieldCount(); nField < nCount; ++nField )
+ if( const XclImpPTField* pField = GetField( nField ) )
+ if( (pField->GetAxes() & EXC_SXVD_AXIS_ROWCOLPAGE) == 0 )
+ pField->ConvertHiddenField( aSaveData );
+
+ // data fields
+ for( aIt = maFiltDataFields.begin(), aEnd = maFiltDataFields.end(); aIt != aEnd; ++aIt )
+ if( const XclImpPTField* pField = GetField( *aIt ) )
+ pField->ConvertDataField( aSaveData );
+
+ // *** insert into Calc document ***
+
+ // create source descriptor
+ ScSheetSourceDesc aDesc(GetDocPtr());
+ const OUString& rSrcName = mxPCache->GetSourceRangeName();
+ if (rSrcName.getLength())
+ // Range name is the data source.
+ aDesc.SetRangeName(rSrcName);
+ else
+ // Normal cell range.
+ aDesc.SetSourceRange(mxPCache->GetSourceRange());
+
+ // adjust output range to include the page fields
+ ScRange aOutRange( maOutScRange );
+ if( !maPageFields.empty() )
+ {
+ SCsROW nDecRows = ::std::min< SCsROW >( aOutRange.aStart.Row(), maPageFields.size() + 1 );
+ aOutRange.aStart.IncRow( -nDecRows );
+ }
+
+ // create the DataPilot
+ ScDPObject* pDPObj = new ScDPObject( GetDocPtr() );
+ pDPObj->SetName( maPTInfo.maTableName );
+ if (maPTInfo.maDataName.Len() > 0)
+ aSaveData.GetDataLayoutDimension()->SetLayoutName(maPTInfo.maDataName);
+
+ if (maPTViewEx9Info.maGrandTotalName.Len() > 0)
+ aSaveData.SetGrandTotalName(maPTViewEx9Info.maGrandTotalName);
+
+ pDPObj->SetSaveData( aSaveData );
+ pDPObj->SetSheetDesc( aDesc );
+ pDPObj->SetOutRange( aOutRange );
+ pDPObj->SetAlive( sal_True );
+ pDPObj->SetHeaderLayout( maPTViewEx9Info.mnGridLayout == 0 );
+
+ GetDoc().GetDPCollection()->InsertNewTable(pDPObj);
+ mpDPObj = pDPObj;
+
+ ApplyMergeFlags(aOutRange, aSaveData);
+}
+
+void XclImpPivotTable::MaybeRefresh()
+{
+ if (mpDPObj && mxPCache->IsRefreshOnLoad())
+ {
+ // 'refresh table on load' flag is set. Refresh the table now. Some
+ // Excel files contain partial table output when this flag is set.
+ ScRange aOutRange = mpDPObj->GetOutRange();
+ mpDPObj->Output(aOutRange.aStart);
+ }
+}
+
+void XclImpPivotTable::ApplyMergeFlags(const ScRange& rOutRange, const ScDPSaveData& rSaveData)
+{
+ // Apply merge flags for varoius datapilot controls.
+
+ ScDPOutputGeometry aGeometry(rOutRange, false, ScDPOutputGeometry::XLS);
+ aGeometry.setColumnFieldCount(maPTInfo.mnColFields);
+ aGeometry.setPageFieldCount(maPTInfo.mnPageFields);
+ aGeometry.setDataFieldCount(maPTInfo.mnDataFields);
+
+ // Excel includes data layout field in the row field count. We need to
+ // subtract it.
+ bool bDataLayout = maPTInfo.mnDataFields > 1;
+ aGeometry.setRowFieldCount(maPTInfo.mnRowFields - static_cast<sal_uInt32>(bDataLayout));
+
+ ScDocument& rDoc = GetDoc();
+
+ vector<ScAddress> aPageBtns;
+ aGeometry.getPageFieldPositions(aPageBtns);
+ vector<ScAddress>::const_iterator itr = aPageBtns.begin(), itrEnd = aPageBtns.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ sal_uInt16 nMFlag = SC_MF_BUTTON;
+ String aName;
+ rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName);
+ if (rSaveData.HasInvisibleMember(aName))
+ nMFlag |= SC_MF_HIDDEN_MEMBER;
+
+ rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
+ rDoc.ApplyFlagsTab(itr->Col()+1, itr->Row(), itr->Col()+1, itr->Row(), itr->Tab(), SC_MF_AUTO);
+ }
+
+ vector<ScAddress> aColBtns;
+ aGeometry.getColumnFieldPositions(aColBtns);
+ itr = aColBtns.begin();
+ itrEnd = aColBtns.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ sal_Int16 nMFlag = SC_MF_BUTTON | SC_MF_BUTTON_POPUP;
+ String aName;
+ rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName);
+ if (rSaveData.HasInvisibleMember(aName))
+ nMFlag |= SC_MF_HIDDEN_MEMBER;
+ rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
+ }
+
+ vector<ScAddress> aRowBtns;
+ aGeometry.getRowFieldPositions(aRowBtns);
+ if (aRowBtns.empty())
+ {
+ if (bDataLayout)
+ {
+ // No row fields, but the data layout button exists.
+ SCROW nRow = aGeometry.getRowFieldHeaderRow();
+ SCCOL nCol = rOutRange.aStart.Col();
+ SCTAB nTab = rOutRange.aStart.Tab();
+ rDoc.ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON);
+ }
+ }
+ else
+ {
+ itr = aRowBtns.begin();
+ itrEnd = aRowBtns.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ sal_Int16 nMFlag = SC_MF_BUTTON | SC_MF_BUTTON_POPUP;
+ String aName;
+ rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName);
+ if (rSaveData.HasInvisibleMember(aName))
+ nMFlag |= SC_MF_HIDDEN_MEMBER;
+ rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag);
+ }
+ if (bDataLayout)
+ {
+ --itr; // move back to the last row field position.
+ rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), SC_MF_BUTTON);
+ }
+ }
+}
+
+// ============================================================================
+// ============================================================================
+
+XclImpPivotTableManager::XclImpPivotTableManager( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+XclImpPivotTableManager::~XclImpPivotTableManager()
+{
+}
+
+// pivot cache records --------------------------------------------------------
+
+XclImpPivotCacheRef XclImpPivotTableManager::GetPivotCache( sal_uInt16 nCacheIdx )
+{
+ XclImpPivotCacheRef xPCache;
+ if( nCacheIdx < maPCaches.size() )
+ xPCache = maPCaches[ nCacheIdx ];
+ return xPCache;
+}
+
+void XclImpPivotTableManager::ReadSxidstm( XclImpStream& rStrm )
+{
+ XclImpPivotCacheRef xPCache( new XclImpPivotCache( GetRoot() ) );
+ maPCaches.push_back( xPCache );
+ xPCache->ReadSxidstm( rStrm );
+}
+
+void XclImpPivotTableManager::ReadSxvs( XclImpStream& rStrm )
+{
+ if( !maPCaches.empty() )
+ maPCaches.back()->ReadSxvs( rStrm );
+}
+
+void XclImpPivotTableManager::ReadDconref( XclImpStream& rStrm )
+{
+ if( !maPCaches.empty() )
+ maPCaches.back()->ReadDconref( rStrm );
+}
+
+void XclImpPivotTableManager::ReadDConName( XclImpStream& rStrm )
+{
+ if( !maPCaches.empty() )
+ maPCaches.back()->ReadDConName( rStrm );
+}
+
+// pivot table records --------------------------------------------------------
+
+void XclImpPivotTableManager::ReadSxview( XclImpStream& rStrm )
+{
+ XclImpPivotTableRef xPTable( new XclImpPivotTable( GetRoot() ) );
+ maPTables.push_back( xPTable );
+ xPTable->ReadSxview( rStrm );
+}
+
+void XclImpPivotTableManager::ReadSxvd( XclImpStream& rStrm )
+{
+ if( !maPTables.empty() )
+ maPTables.back()->ReadSxvd( rStrm );
+}
+
+void XclImpPivotTableManager::ReadSxvdex( XclImpStream& rStrm )
+{
+ if( !maPTables.empty() )
+ maPTables.back()->ReadSxvdex( rStrm );
+}
+
+void XclImpPivotTableManager::ReadSxivd( XclImpStream& rStrm )
+{
+ if( !maPTables.empty() )
+ maPTables.back()->ReadSxivd( rStrm );
+}
+
+void XclImpPivotTableManager::ReadSxpi( XclImpStream& rStrm )
+{
+ if( !maPTables.empty() )
+ maPTables.back()->ReadSxpi( rStrm );
+}
+
+void XclImpPivotTableManager::ReadSxdi( XclImpStream& rStrm )
+{
+ if( !maPTables.empty() )
+ maPTables.back()->ReadSxdi( rStrm );
+}
+
+void XclImpPivotTableManager::ReadSxvi( XclImpStream& rStrm )
+{
+ if( !maPTables.empty() )
+ maPTables.back()->ReadSxvi( rStrm );
+}
+
+void XclImpPivotTableManager::ReadSxex( XclImpStream& rStrm )
+{
+ if( !maPTables.empty() )
+ maPTables.back()->ReadSxex( rStrm );
+}
+
+void XclImpPivotTableManager::ReadSxViewEx9( XclImpStream& rStrm )
+{
+ if( !maPTables.empty() )
+ maPTables.back()->ReadSxViewEx9( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpPivotTableManager::ReadPivotCaches( XclImpStream& rStrm )
+{
+ for( XclImpPivotCacheVec::iterator aIt = maPCaches.begin(), aEnd = maPCaches.end(); aIt != aEnd; ++aIt )
+ (*aIt)->ReadPivotCacheStream( rStrm );
+}
+
+void XclImpPivotTableManager::ConvertPivotTables()
+{
+ for( XclImpPivotTableVec::iterator aIt = maPTables.begin(), aEnd = maPTables.end(); aIt != aEnd; ++aIt )
+ (*aIt)->Convert();
+}
+
+void XclImpPivotTableManager::MaybeRefreshPivotTables()
+{
+ for( XclImpPivotTableVec::iterator aIt = maPTables.begin(), aEnd = maPTables.end(); aIt != aEnd; ++aIt )
+ (*aIt)->MaybeRefresh();
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xiroot.cxx b/sc/source/filter/excel/xiroot.cxx
new file mode 100644
index 000000000000..9180ed401b62
--- /dev/null
+++ b/sc/source/filter/excel/xiroot.cxx
@@ -0,0 +1,311 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xiroot.hxx"
+#include "addincol.hxx"
+#include "document.hxx"
+#include "scextopt.hxx"
+#include "xltracer.hxx"
+#include "xihelper.hxx"
+#include "xiformula.hxx"
+#include "xilink.hxx"
+#include "xiname.hxx"
+#include "xistyle.hxx"
+#include "xicontent.hxx"
+#include "xiescher.hxx"
+#include "xipivot.hxx"
+#include "xipage.hxx"
+#include "xiview.hxx"
+
+#include "root.hxx"
+#include "excimp8.hxx"
+
+// Global data ================================================================
+
+XclImpRootData::XclImpRootData( XclBiff eBiff, SfxMedium& rMedium,
+ SotStorageRef xRootStrg, ScDocument& rDoc, rtl_TextEncoding eTextEnc ) :
+ XclRootData( eBiff, rMedium, xRootStrg, rDoc, eTextEnc, false ),
+ mbHasCodePage( false ),
+ mbHasBasic( false )
+{
+}
+
+XclImpRootData::~XclImpRootData()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpRoot::XclImpRoot( XclImpRootData& rImpRootData ) :
+ XclRoot( rImpRootData ),
+ mrImpData( rImpRootData )
+{
+ mrImpData.mxAddrConv.reset( new XclImpAddressConverter( GetRoot() ) );
+ mrImpData.mxFmlaComp.reset( new XclImpFormulaCompiler( GetRoot() ) );
+ mrImpData.mxPalette.reset( new XclImpPalette( GetRoot() ) );
+ mrImpData.mxFontBfr.reset( new XclImpFontBuffer( GetRoot() ) );
+ mrImpData.mxNumFmtBfr.reset( new XclImpNumFmtBuffer( GetRoot() ) );
+ mrImpData.mpXFBfr.reset( new XclImpXFBuffer( GetRoot() ) );
+ mrImpData.mxXFRangeBfr.reset( new XclImpXFRangeBuffer( GetRoot() ) );
+ mrImpData.mxTabInfo.reset( new XclImpTabInfo );
+ mrImpData.mxNameMgr.reset( new XclImpNameManager( GetRoot() ) );
+ mrImpData.mxObjMgr.reset( new XclImpObjectManager( GetRoot() ) );
+
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ mrImpData.mxLinkMgr.reset( new XclImpLinkManager( GetRoot() ) );
+ mrImpData.mxSst.reset( new XclImpSst( GetRoot() ) );
+ mrImpData.mxCondFmtMgr.reset( new XclImpCondFormatManager( GetRoot() ) );
+ mrImpData.mxValidMgr.reset( new XclImpValidationManager( GetRoot() ) );
+ // TODO still in old RootData (deleted by RootData)
+ GetOldRoot().pAutoFilterBuffer = new XclImpAutoFilterBuffer;
+ mrImpData.mxWebQueryBfr.reset( new XclImpWebQueryBuffer( GetRoot() ) );
+ mrImpData.mxPTableMgr.reset( new XclImpPivotTableManager( GetRoot() ) );
+ mrImpData.mxTabProtect.reset( new XclImpSheetProtectBuffer( GetRoot() ) );
+ mrImpData.mxDocProtect.reset( new XclImpDocProtectBuffer( GetRoot() ) );
+ }
+
+ mrImpData.mxPageSett.reset( new XclImpPageSettings( GetRoot() ) );
+ mrImpData.mxDocViewSett.reset( new XclImpDocViewSettings( GetRoot() ) );
+ mrImpData.mxTabViewSett.reset( new XclImpTabViewSettings( GetRoot() ) );
+}
+
+void XclImpRoot::SetCodePage( sal_uInt16 nCodePage )
+{
+ SetTextEncoding( XclTools::GetTextEncoding( nCodePage ) );
+ mrImpData.mbHasCodePage = true;
+}
+
+void XclImpRoot::SetAppFontEncoding( rtl_TextEncoding eAppFontEnc )
+{
+ if( !mrImpData.mbHasCodePage )
+ SetTextEncoding( eAppFontEnc );
+}
+
+void XclImpRoot::InitializeTable( SCTAB nScTab )
+{
+ if( GetBiff() <= EXC_BIFF4 )
+ {
+ GetPalette().Initialize();
+ GetFontBuffer().Initialize();
+ GetNumFmtBuffer().Initialize();
+ GetXFBuffer().Initialize();
+ }
+ GetXFRangeBuffer().Initialize();
+ GetPageSettings().Initialize();
+ GetTabViewSettings().Initialize();
+ // delete the automatically generated codename
+ GetDoc().SetCodeName( nScTab, String::EmptyString() );
+}
+
+void XclImpRoot::FinalizeTable()
+{
+ GetXFRangeBuffer().Finalize();
+ GetOldRoot().pColRowBuff->Convert( GetCurrScTab() );
+ GetPageSettings().Finalize();
+ GetTabViewSettings().Finalize();
+}
+
+XclImpAddressConverter& XclImpRoot::GetAddressConverter() const
+{
+ return *mrImpData.mxAddrConv;
+}
+
+XclImpFormulaCompiler& XclImpRoot::GetFormulaCompiler() const
+{
+ return *mrImpData.mxFmlaComp;
+}
+
+ExcelToSc& XclImpRoot::GetOldFmlaConverter() const
+{
+ // TODO still in old RootData
+ return *GetOldRoot().pFmlaConverter;
+}
+
+XclImpSst& XclImpRoot::GetSst() const
+{
+ DBG_ASSERT( mrImpData.mxSst, "XclImpRoot::GetSst - invalid call, wrong BIFF" );
+ return *mrImpData.mxSst;
+}
+
+XclImpPalette& XclImpRoot::GetPalette() const
+{
+ return *mrImpData.mxPalette;
+}
+
+XclImpFontBuffer& XclImpRoot::GetFontBuffer() const
+{
+ return *mrImpData.mxFontBfr;
+}
+
+XclImpNumFmtBuffer& XclImpRoot::GetNumFmtBuffer() const
+{
+ return *mrImpData.mxNumFmtBfr;
+}
+
+XclImpXFBuffer& XclImpRoot::GetXFBuffer() const
+{
+ return *mrImpData.mpXFBfr;
+}
+
+XclImpXFRangeBuffer& XclImpRoot::GetXFRangeBuffer() const
+{
+ return *mrImpData.mxXFRangeBfr;
+}
+
+_ScRangeListTabs& XclImpRoot::GetPrintAreaBuffer() const
+{
+ // TODO still in old RootData
+ return *GetOldRoot().pPrintRanges;
+}
+
+_ScRangeListTabs& XclImpRoot::GetTitleAreaBuffer() const
+{
+ // TODO still in old RootData
+ return *GetOldRoot().pPrintTitles;
+}
+
+XclImpTabInfo& XclImpRoot::GetTabInfo() const
+{
+ return *mrImpData.mxTabInfo;
+}
+
+XclImpNameManager& XclImpRoot::GetNameManager() const
+{
+ return *mrImpData.mxNameMgr;
+}
+
+XclImpLinkManager& XclImpRoot::GetLinkManager() const
+{
+ DBG_ASSERT( mrImpData.mxLinkMgr, "XclImpRoot::GetLinkManager - invalid call, wrong BIFF" );
+ return *mrImpData.mxLinkMgr;
+}
+
+XclImpObjectManager& XclImpRoot::GetObjectManager() const
+{
+ return *mrImpData.mxObjMgr;
+}
+
+XclImpSheetDrawing& XclImpRoot::GetCurrSheetDrawing() const
+{
+ DBG_ASSERT( !IsInGlobals(), "XclImpRoot::GetCurrSheetDrawing - must not be called from workbook globals" );
+ return mrImpData.mxObjMgr->GetSheetDrawing( GetCurrScTab() );
+}
+
+XclImpCondFormatManager& XclImpRoot::GetCondFormatManager() const
+{
+ DBG_ASSERT( mrImpData.mxCondFmtMgr, "XclImpRoot::GetCondFormatManager - invalid call, wrong BIFF" );
+ return *mrImpData.mxCondFmtMgr;
+}
+
+XclImpValidationManager& XclImpRoot::GetValidationManager() const
+{
+ DBG_ASSERT( mrImpData.mxValidMgr, "XclImpRoot::GetValidationManager - invalid call, wrong BIFF" );
+ return *mrImpData.mxValidMgr;
+}
+
+XclImpAutoFilterBuffer& XclImpRoot::GetFilterManager() const
+{
+ // TODO still in old RootData
+ DBG_ASSERT( GetOldRoot().pAutoFilterBuffer, "XclImpRoot::GetFilterManager - invalid call, wrong BIFF" );
+ return *GetOldRoot().pAutoFilterBuffer;
+}
+
+XclImpWebQueryBuffer& XclImpRoot::GetWebQueryBuffer() const
+{
+ DBG_ASSERT( mrImpData.mxWebQueryBfr, "XclImpRoot::GetWebQueryBuffer - invalid call, wrong BIFF" );
+ return *mrImpData.mxWebQueryBfr;
+}
+
+XclImpPivotTableManager& XclImpRoot::GetPivotTableManager() const
+{
+ DBG_ASSERT( mrImpData.mxPTableMgr, "XclImpRoot::GetPivotTableManager - invalid call, wrong BIFF" );
+ return *mrImpData.mxPTableMgr;
+}
+
+XclImpSheetProtectBuffer& XclImpRoot::GetSheetProtectBuffer() const
+{
+ DBG_ASSERT( mrImpData.mxTabProtect, "XclImpRoot::GetSheetProtectBuffer - invalid call, wrong BIFF" );
+ return *mrImpData.mxTabProtect;
+}
+
+XclImpDocProtectBuffer& XclImpRoot::GetDocProtectBuffer() const
+{
+ DBG_ASSERT( mrImpData.mxDocProtect, "XclImpRoot::GetDocProtectBuffer - invalid call, wrong BIFF" );
+ return *mrImpData.mxDocProtect;
+}
+
+XclImpPageSettings& XclImpRoot::GetPageSettings() const
+{
+ return *mrImpData.mxPageSett;
+}
+
+XclImpDocViewSettings& XclImpRoot::GetDocViewSettings() const
+{
+ return *mrImpData.mxDocViewSett;
+}
+
+XclImpTabViewSettings& XclImpRoot::GetTabViewSettings() const
+{
+ return *mrImpData.mxTabViewSett;
+}
+
+String XclImpRoot::GetScAddInName( const String& rXclName ) const
+{
+ String aScName;
+ if( ScGlobal::GetAddInCollection()->GetCalcName( rXclName, aScName ) )
+ return aScName;
+ return rXclName;
+}
+
+void XclImpRoot::ReadCodeName( XclImpStream& rStrm, bool bGlobals )
+{
+ if( mrImpData.mbHasBasic && (GetBiff() == EXC_BIFF8) )
+ {
+ String aName = rStrm.ReadUniString();
+ if( aName.Len() > 0 )
+ {
+ if( bGlobals )
+ {
+ GetExtDocOptions().GetDocSettings().maGlobCodeName = aName;
+ GetDoc().SetCodeName( aName );
+ }
+ else
+ {
+ GetExtDocOptions().SetCodeName( GetCurrScTab(), aName );
+ GetDoc().SetCodeName( GetCurrScTab(), aName );
+ }
+ }
+ }
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xistream.cxx b/sc/source/filter/excel/xistream.cxx
new file mode 100644
index 000000000000..94e8c8cd3ae3
--- /dev/null
+++ b/sc/source/filter/excel/xistream.cxx
@@ -0,0 +1,1142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <comphelper/docpasswordhelper.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+
+#include "xistream.hxx"
+#include "xlstring.hxx"
+#include "xiroot.hxx"
+
+#include <vector>
+
+using ::rtl::OString;
+using ::rtl::OUString;
+using ::rtl::OUStringToOString;
+
+using namespace ::com::sun::star;
+
+// ============================================================================
+// Decryption
+// ============================================================================
+
+XclImpDecrypter::XclImpDecrypter() :
+ mnError( EXC_ENCR_ERROR_UNSUPP_CRYPT ),
+ mnOldPos( STREAM_SEEK_TO_END ),
+ mnRecSize( 0 )
+{
+}
+
+XclImpDecrypter::XclImpDecrypter( const XclImpDecrypter& rSrc ) :
+ ::comphelper::IDocPasswordVerifier(),
+ mnError( rSrc.mnError ),
+ mnOldPos( STREAM_SEEK_TO_END ),
+ mnRecSize( 0 )
+{
+}
+
+XclImpDecrypter::~XclImpDecrypter()
+{
+}
+
+XclImpDecrypterRef XclImpDecrypter::Clone() const
+{
+ XclImpDecrypterRef xNewDecr;
+ if( IsValid() )
+ xNewDecr.reset( OnClone() );
+ return xNewDecr;
+}
+
+::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyPassword( const ::rtl::OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
+{
+ o_rEncryptionData = OnVerifyPassword( rPassword );
+ mnError = o_rEncryptionData.getLength() ? ERRCODE_NONE : ERRCODE_ABORT;
+ return o_rEncryptionData.getLength() ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+}
+
+::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
+{
+ bool bValid = OnVerifyEncryptionData( rEncryptionData );
+ mnError = bValid ? ERRCODE_NONE : ERRCODE_ABORT;
+ return bValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+}
+
+void XclImpDecrypter::Update( SvStream& rStrm, sal_uInt16 nRecSize )
+{
+ if( IsValid() )
+ {
+ sal_Size nNewPos = rStrm.Tell();
+ if( (mnOldPos != nNewPos) || (mnRecSize != nRecSize) )
+ {
+ OnUpdate( mnOldPos, nNewPos, nRecSize );
+ mnOldPos = nNewPos;
+ mnRecSize = nRecSize;
+ }
+ }
+}
+
+sal_uInt16 XclImpDecrypter::Read( SvStream& rStrm, void* pData, sal_uInt16 nBytes )
+{
+ sal_uInt16 nRet = 0;
+ if( pData && nBytes )
+ {
+ if( IsValid() )
+ {
+ Update( rStrm, mnRecSize );
+ nRet = OnRead( rStrm, reinterpret_cast< sal_uInt8* >( pData ), nBytes );
+ mnOldPos = rStrm.Tell();
+ }
+ else
+ nRet = static_cast< sal_uInt16 >( rStrm.Read( pData, nBytes ) );
+ }
+ return nRet;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpBiff5Decrypter::XclImpBiff5Decrypter( sal_uInt16 nKey, sal_uInt16 nHash ) :
+ mnKey( nKey ),
+ mnHash( nHash )
+{
+}
+
+XclImpBiff5Decrypter::XclImpBiff5Decrypter( const XclImpBiff5Decrypter& rSrc ) :
+ XclImpDecrypter( rSrc ),
+ maEncryptionData( rSrc.maEncryptionData ),
+ mnKey( rSrc.mnKey ),
+ mnHash( rSrc.mnHash )
+{
+ if( IsValid() )
+ maCodec.InitCodec( maEncryptionData );
+}
+
+XclImpBiff5Decrypter* XclImpBiff5Decrypter::OnClone() const
+{
+ return new XclImpBiff5Decrypter( *this );
+}
+
+uno::Sequence< beans::NamedValue > XclImpBiff5Decrypter::OnVerifyPassword( const ::rtl::OUString& rPassword )
+{
+ maEncryptionData.realloc( 0 );
+
+ /* Convert password to a byte string. TODO: this needs some finetuning
+ according to the spec... */
+ OString aBytePassword = OUStringToOString( rPassword, osl_getThreadTextEncoding() );
+ sal_Int32 nLen = aBytePassword.getLength();
+ if( (0 < nLen) && (nLen < 16) )
+ {
+ // init codec
+ maCodec.InitKey( (sal_uInt8*)aBytePassword.getStr() );
+
+ if ( maCodec.VerifyKey( mnKey, mnHash ) )
+ {
+ maEncryptionData = maCodec.GetEncryptionData();
+
+ // since the export uses Std97 encryption always we have to request it here
+ ::std::vector< sal_uInt16 > aPassVect( 16 );
+ ::std::vector< sal_uInt16 >::iterator aIt = aPassVect.begin();
+ for( sal_Int32 nInd = 0; nInd < nLen; ++nInd, ++aIt )
+ *aIt = static_cast< sal_uInt16 >( rPassword.getStr()[nInd] );
+
+ uno::Sequence< sal_Int8 > aDocId = ::comphelper::DocPasswordHelper::GenerateRandomByteSequence( 16 );
+ OSL_ENSURE( aDocId.getLength() == 16, "Unexpected length of the senquence!" );
+
+ ::msfilter::MSCodec_Std97 aCodec97;
+ aCodec97.InitKey( &aPassVect.front(), (sal_uInt8*)aDocId.getConstArray() );
+
+ // merge the EncryptionData, there should be no conflicts
+ ::comphelper::SequenceAsHashMap aEncryptionHash( maEncryptionData );
+ aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
+ aEncryptionHash >> maEncryptionData;
+ }
+ }
+
+ return maEncryptionData;
+}
+
+bool XclImpBiff5Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
+{
+ maEncryptionData.realloc( 0 );
+
+ if( rEncryptionData.getLength() )
+ {
+ // init codec
+ maCodec.InitCodec( rEncryptionData );
+
+ if ( maCodec.VerifyKey( mnKey, mnHash ) )
+ maEncryptionData = rEncryptionData;
+ }
+
+ return maEncryptionData.getLength();
+}
+
+void XclImpBiff5Decrypter::OnUpdate( sal_Size /*nOldStrmPos*/, sal_Size nNewStrmPos, sal_uInt16 nRecSize )
+{
+ maCodec.InitCipher();
+ maCodec.Skip( (nNewStrmPos + nRecSize) & 0x0F );
+}
+
+sal_uInt16 XclImpBiff5Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
+{
+ sal_uInt16 nRet = static_cast< sal_uInt16 >( rStrm.Read( pnData, nBytes ) );
+ maCodec.Decode( pnData, nRet );
+ return nRet;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpBiff8Decrypter::XclImpBiff8Decrypter( sal_uInt8 pnSalt[ 16 ],
+ sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] ) :
+ maSalt( pnSalt, pnSalt + 16 ),
+ maVerifier( pnVerifier, pnVerifier + 16 ),
+ maVerifierHash( pnVerifierHash, pnVerifierHash + 16 )
+{
+}
+
+XclImpBiff8Decrypter::XclImpBiff8Decrypter( const XclImpBiff8Decrypter& rSrc ) :
+ XclImpDecrypter( rSrc ),
+ maEncryptionData( rSrc.maEncryptionData ),
+ maSalt( rSrc.maSalt ),
+ maVerifier( rSrc.maVerifier ),
+ maVerifierHash( rSrc.maVerifierHash )
+{
+ if( IsValid() )
+ maCodec.InitCodec( maEncryptionData );
+}
+
+XclImpBiff8Decrypter* XclImpBiff8Decrypter::OnClone() const
+{
+ return new XclImpBiff8Decrypter( *this );
+}
+
+uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const ::rtl::OUString& rPassword )
+{
+ maEncryptionData.realloc( 0 );
+
+ sal_Int32 nLen = rPassword.getLength();
+ if( (0 < nLen) && (nLen < 16) )
+ {
+ // copy string to sal_uInt16 array
+ ::std::vector< sal_uInt16 > aPassVect( 16 );
+ const sal_Unicode* pcChar = rPassword.getStr();
+ const sal_Unicode* pcCharEnd = pcChar + nLen;
+ ::std::vector< sal_uInt16 >::iterator aIt = aPassVect.begin();
+ for( ; pcChar < pcCharEnd; ++pcChar, ++aIt )
+ *aIt = static_cast< sal_uInt16 >( *pcChar );
+
+ // init codec
+ maCodec.InitKey( &aPassVect.front(), &maSalt.front() );
+ if ( maCodec.VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
+ maEncryptionData = maCodec.GetEncryptionData();
+ }
+
+ return maEncryptionData;
+}
+
+bool XclImpBiff8Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
+{
+ maEncryptionData.realloc( 0 );
+
+ if( rEncryptionData.getLength() )
+ {
+ // init codec
+ maCodec.InitCodec( rEncryptionData );
+
+ if ( maCodec.VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
+ maEncryptionData = rEncryptionData;
+ }
+
+ return maEncryptionData.getLength();
+}
+
+void XclImpBiff8Decrypter::OnUpdate( sal_Size nOldStrmPos, sal_Size nNewStrmPos, sal_uInt16 /*nRecSize*/ )
+{
+ if( nNewStrmPos != nOldStrmPos )
+ {
+ sal_uInt32 nOldBlock = GetBlock( nOldStrmPos );
+ sal_uInt16 nOldOffset = GetOffset( nOldStrmPos );
+
+ sal_uInt32 nNewBlock = GetBlock( nNewStrmPos );
+ sal_uInt16 nNewOffset = GetOffset( nNewStrmPos );
+
+ /* Rekey cipher, if block changed or if previous offset in same block. */
+ if( (nNewBlock != nOldBlock) || (nNewOffset < nOldOffset) )
+ {
+ maCodec.InitCipher( nNewBlock );
+ nOldOffset = 0; // reset nOldOffset for next if() statement
+ }
+
+ /* Seek to correct offset. */
+ if( nNewOffset > nOldOffset )
+ maCodec.Skip( nNewOffset - nOldOffset );
+ }
+}
+
+sal_uInt16 XclImpBiff8Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
+{
+ sal_uInt16 nRet = 0;
+
+ sal_uInt8* pnCurrData = pnData;
+ sal_uInt16 nBytesLeft = nBytes;
+ while( nBytesLeft )
+ {
+ sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - GetOffset( rStrm.Tell() );
+ sal_uInt16 nDecBytes = ::std::min< sal_uInt16 >( nBytesLeft, nBlockLeft );
+
+ // read the block from stream
+ nRet = nRet + static_cast< sal_uInt16 >( rStrm.Read( pnCurrData, nDecBytes ) );
+ // decode the block inplace
+ maCodec.Decode( pnCurrData, nDecBytes, pnCurrData, nDecBytes );
+ if( GetOffset( rStrm.Tell() ) == 0 )
+ maCodec.InitCipher( GetBlock( rStrm.Tell() ) );
+
+ pnCurrData += nDecBytes;
+ nBytesLeft = nBytesLeft - nDecBytes;
+ }
+
+ return nRet;
+}
+
+sal_uInt32 XclImpBiff8Decrypter::GetBlock( sal_Size nStrmPos ) const
+{
+ return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
+}
+
+sal_uInt16 XclImpBiff8Decrypter::GetOffset( sal_Size nStrmPos ) const
+{
+ return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
+}
+
+// ============================================================================
+// Stream
+// ============================================================================
+
+XclImpStreamPos::XclImpStreamPos() :
+ mnPos( STREAM_SEEK_TO_BEGIN ),
+ mnNextPos( STREAM_SEEK_TO_BEGIN ),
+ mnCurrSize( 0 ),
+ mnRawRecId( EXC_ID_UNKNOWN ),
+ mnRawRecSize( 0 ),
+ mnRawRecLeft( 0 ),
+ mbValid( false )
+{
+}
+
+void XclImpStreamPos::Set(
+ const SvStream& rStrm, sal_Size nNextPos, sal_Size nCurrSize,
+ sal_uInt16 nRawRecId, sal_uInt16 nRawRecSize, sal_uInt16 nRawRecLeft,
+ bool bValid )
+{
+ mnPos = rStrm.Tell();
+ mnNextPos = nNextPos;
+ mnCurrSize = nCurrSize;
+ mnRawRecId = nRawRecId;
+ mnRawRecSize = nRawRecSize;
+ mnRawRecLeft = nRawRecLeft;
+ mbValid = bValid;
+}
+
+void XclImpStreamPos::Get(
+ SvStream& rStrm, sal_Size& rnNextPos, sal_Size& rnCurrSize,
+ sal_uInt16& rnRawRecId, sal_uInt16& rnRawRecSize, sal_uInt16& rnRawRecLeft,
+ bool& rbValid ) const
+{
+ rStrm.Seek( mnPos );
+ rnNextPos = mnNextPos;
+ rnCurrSize = mnCurrSize;
+ rnRawRecId = mnRawRecId;
+ rnRawRecSize = mnRawRecSize;
+ rnRawRecLeft = mnRawRecLeft;
+ rbValid = mbValid;
+}
+
+// ============================================================================
+
+XclBiff XclImpStream::DetectBiffVersion( SvStream& rStrm )
+{
+ XclBiff eBiff = EXC_BIFF_UNKNOWN;
+
+ rStrm.Seek( STREAM_SEEK_TO_BEGIN );
+ sal_uInt16 nBofId, nBofSize;
+ rStrm >> nBofId >> nBofSize;
+
+ if( (4 <= nBofSize) && (nBofSize <= 16) ) switch( nBofId )
+ {
+ case EXC_ID2_BOF:
+ eBiff = EXC_BIFF2;
+ break;
+ case EXC_ID3_BOF:
+ eBiff = EXC_BIFF3;
+ break;
+ case EXC_ID4_BOF:
+ eBiff = EXC_BIFF4;
+ break;
+ case EXC_ID5_BOF:
+ {
+ sal_uInt16 nVersion;
+ rStrm >> nVersion;
+ // #i23425# #i44031# #i62752# there are some *really* broken documents out there...
+ switch( nVersion & 0xFF00 )
+ {
+ case 0: eBiff = EXC_BIFF5; break; // #i44031# #i62752#
+ case EXC_BOF_BIFF2: eBiff = EXC_BIFF2; break;
+ case EXC_BOF_BIFF3: eBiff = EXC_BIFF3; break;
+ case EXC_BOF_BIFF4: eBiff = EXC_BIFF4; break;
+ case EXC_BOF_BIFF5: eBiff = EXC_BIFF5; break;
+ case EXC_BOF_BIFF8: eBiff = EXC_BIFF8; break;
+ default: OSL_TRACE( "XclImpStream::DetectBiffVersion - unknown BIFF version: 0x%04hX", nVersion );
+ }
+ }
+ break;
+ }
+ return eBiff;
+}
+
+XclImpStream::XclImpStream( SvStream& rInStrm, const XclImpRoot& rRoot, bool bContLookup ) :
+ mrStrm( rInStrm ),
+ mrRoot( rRoot ),
+ mnGlobRecId( EXC_ID_UNKNOWN ),
+ mbGlobValidRec( false ),
+ mbHasGlobPos( false ),
+ mnNextRecPos( STREAM_SEEK_TO_BEGIN ),
+ mnCurrRecSize( 0 ),
+ mnComplRecSize( 0 ),
+ mbHasComplRec( false ),
+ mnRecId( EXC_ID_UNKNOWN ),
+ mnAltContId( EXC_ID_UNKNOWN ),
+ mnRawRecId( EXC_ID_UNKNOWN ),
+ mnRawRecSize( 0 ),
+ mnRawRecLeft( 0 ),
+ mcNulSubst( '?' ),
+ mbCont( bContLookup ),
+ mbUseDecr( false ),
+ mbValidRec( false ),
+ mbValid( false )
+{
+ mrStrm.Seek( STREAM_SEEK_TO_END );
+ mnStreamSize = mrStrm.Tell();
+ mrStrm.Seek( STREAM_SEEK_TO_BEGIN );
+ DBG_ASSERT( mnStreamSize < STREAM_SEEK_TO_END, "XclImpStream::XclImpStream - stream error" );
+}
+
+XclImpStream::~XclImpStream()
+{
+}
+
+bool XclImpStream::StartNextRecord()
+{
+ maPosStack.clear();
+
+ /* #i4266# Counter to ignore zero records (id==len==0) (i.e. the application
+ "Crystal Report" writes zero records between other records) */
+ sal_Size nZeroRecCount = 5;
+ bool bIsZeroRec = false;
+
+ do
+ {
+ mbValidRec = ReadNextRawRecHeader();
+ bIsZeroRec = (mnRawRecId == 0) && (mnRawRecSize == 0);
+ if( bIsZeroRec ) --nZeroRecCount;
+ mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
+ }
+ while( mbValidRec && ((mbCont && IsContinueId( mnRawRecId )) || (bIsZeroRec && nZeroRecCount)) );
+
+ mbValidRec = mbValidRec && !bIsZeroRec;
+ mbValid = mbValidRec;
+ SetupRecord();
+
+ return mbValidRec;
+}
+
+bool XclImpStream::StartNextRecord( sal_Size nNextRecPos )
+{
+ mnNextRecPos = nNextRecPos;
+ return StartNextRecord();
+}
+
+void XclImpStream::ResetRecord( bool bContLookup, sal_uInt16 nAltContId )
+{
+ if( mbValidRec )
+ {
+ maPosStack.clear();
+ RestorePosition( maFirstRec );
+ mnCurrRecSize = mnComplRecSize = mnRawRecSize;
+ mbHasComplRec = !bContLookup;
+ mbCont = bContLookup;
+ mnAltContId = nAltContId;
+ EnableDecryption();
+ }
+}
+
+void XclImpStream::SetDecrypter( XclImpDecrypterRef xDecrypter )
+{
+ mxDecrypter = xDecrypter;
+ EnableDecryption();
+ SetupDecrypter();
+}
+
+void XclImpStream::CopyDecrypterFrom( const XclImpStream& rStrm )
+{
+ XclImpDecrypterRef xNewDecr;
+ if( rStrm.mxDecrypter )
+ xNewDecr = rStrm.mxDecrypter->Clone();
+ SetDecrypter( xNewDecr );
+}
+
+bool XclImpStream::HasValidDecrypter() const
+{
+ return mxDecrypter && mxDecrypter->IsValid();
+}
+
+void XclImpStream::EnableDecryption( bool bEnable )
+{
+ mbUseDecr = bEnable && HasValidDecrypter();
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpStream::PushPosition()
+{
+ maPosStack.push_back( XclImpStreamPos() );
+ StorePosition( maPosStack.back() );
+}
+
+void XclImpStream::PopPosition()
+{
+ DBG_ASSERT( !maPosStack.empty(), "XclImpStream::PopPosition - stack empty" );
+ if( !maPosStack.empty() )
+ {
+ RestorePosition( maPosStack.back() );
+ maPosStack.pop_back();
+ }
+}
+
+void XclImpStream::StoreGlobalPosition()
+{
+ StorePosition( maGlobPos );
+ mnGlobRecId = mnRecId;
+ mbGlobValidRec = mbValidRec;
+ mbHasGlobPos = true;
+}
+
+void XclImpStream::SeekGlobalPosition()
+{
+ DBG_ASSERT( mbHasGlobPos, "XclImpStream::SeekGlobalPosition - no position stored" );
+ if( mbHasGlobPos )
+ {
+ RestorePosition( maGlobPos );
+ mnRecId = mnGlobRecId;
+ mnComplRecSize = mnCurrRecSize;
+ mbHasComplRec = !mbCont;
+ mbValidRec = mbGlobValidRec;
+ }
+}
+
+sal_Size XclImpStream::GetRecPos() const
+{
+ return mbValid ? (mnCurrRecSize - mnRawRecLeft) : EXC_REC_SEEK_TO_END;
+}
+
+sal_Size XclImpStream::GetRecSize()
+{
+ if( !mbHasComplRec )
+ {
+ PushPosition();
+ while( JumpToNextContinue() ) ; // JumpToNextContinue() adds up mnCurrRecSize
+ mnComplRecSize = mnCurrRecSize;
+ mbHasComplRec = true;
+ PopPosition();
+ }
+ return mnComplRecSize;
+}
+
+sal_Size XclImpStream::GetRecLeft()
+{
+ return mbValid ? (GetRecSize() - GetRecPos()) : 0;
+}
+
+sal_uInt16 XclImpStream::GetNextRecId()
+{
+ sal_uInt16 nRecId = EXC_ID_UNKNOWN;
+ if( mbValidRec )
+ {
+ PushPosition();
+ while( JumpToNextContinue() ) ; // skip following CONTINUE records
+ if( mnNextRecPos < mnStreamSize )
+ {
+ mrStrm.Seek( mnNextRecPos );
+ mrStrm >> nRecId;
+ }
+ PopPosition();
+ }
+ return nRecId;
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpStream& XclImpStream::operator>>( sal_Int8& rnValue )
+{
+ if( EnsureRawReadSize( 1 ) )
+ {
+ if( mbUseDecr )
+ mxDecrypter->Read( mrStrm, &rnValue, 1 );
+ else
+ mrStrm >> rnValue;
+ --mnRawRecLeft;
+ }
+ return *this;
+}
+
+XclImpStream& XclImpStream::operator>>( sal_uInt8& rnValue )
+{
+ if( EnsureRawReadSize( 1 ) )
+ {
+ if( mbUseDecr )
+ mxDecrypter->Read( mrStrm, &rnValue, 1 );
+ else
+ mrStrm >> rnValue;
+ --mnRawRecLeft;
+ }
+ return *this;
+}
+
+XclImpStream& XclImpStream::operator>>( sal_Int16& rnValue )
+{
+ if( EnsureRawReadSize( 2 ) )
+ {
+ if( mbUseDecr )
+ {
+ SVBT16 pnBuffer;
+ mxDecrypter->Read( mrStrm, pnBuffer, 2 );
+ rnValue = static_cast< sal_Int16 >( SVBT16ToShort( pnBuffer ) );
+ }
+ else
+ mrStrm >> rnValue;
+ mnRawRecLeft -= 2;
+ }
+ return *this;
+}
+
+XclImpStream& XclImpStream::operator>>( sal_uInt16& rnValue )
+{
+ if( EnsureRawReadSize( 2 ) )
+ {
+ if( mbUseDecr )
+ {
+ SVBT16 pnBuffer;
+ mxDecrypter->Read( mrStrm, pnBuffer, 2 );
+ rnValue = SVBT16ToShort( pnBuffer );
+ }
+ else
+ mrStrm >> rnValue;
+ mnRawRecLeft -= 2;
+ }
+ return *this;
+}
+
+XclImpStream& XclImpStream::operator>>( sal_Int32& rnValue )
+{
+ if( EnsureRawReadSize( 4 ) )
+ {
+ if( mbUseDecr )
+ {
+ SVBT32 pnBuffer;
+ mxDecrypter->Read( mrStrm, pnBuffer, 4 );
+ rnValue = static_cast< sal_Int32 >( SVBT32ToUInt32( pnBuffer ) );
+ }
+ else
+ mrStrm >> rnValue;
+ mnRawRecLeft -= 4;
+ }
+ return *this;
+}
+
+XclImpStream& XclImpStream::operator>>( sal_uInt32& rnValue )
+{
+ if( EnsureRawReadSize( 4 ) )
+ {
+ if( mbUseDecr )
+ {
+ SVBT32 pnBuffer;
+ mxDecrypter->Read( mrStrm, pnBuffer, 4 );
+ rnValue = SVBT32ToUInt32( pnBuffer );
+ }
+ else
+ mrStrm >> rnValue;
+ mnRawRecLeft -= 4;
+ }
+ return *this;
+}
+
+XclImpStream& XclImpStream::operator>>( float& rfValue )
+{
+ if( EnsureRawReadSize( 4 ) )
+ {
+ if( mbUseDecr )
+ {
+ SVBT32 pnBuffer;
+ mxDecrypter->Read( mrStrm, pnBuffer, 4 );
+ sal_uInt32 nValue = SVBT32ToUInt32( pnBuffer );
+ memcpy( &rfValue, &nValue, 4 );
+ }
+ else
+ mrStrm >> rfValue;
+ mnRawRecLeft -= 4;
+ }
+ return *this;
+}
+
+XclImpStream& XclImpStream::operator>>( double& rfValue )
+{
+ if( EnsureRawReadSize( 8 ) )
+ {
+ if( mbUseDecr )
+ {
+ SVBT64 pnBuffer;
+ mxDecrypter->Read( mrStrm, pnBuffer, 8 );
+ rfValue = SVBT64ToDouble( pnBuffer );
+ }
+ else
+ mrStrm >> rfValue;
+ mnRawRecLeft -= 8;
+ }
+ return *this;
+}
+
+sal_uInt8 XclImpStream::ReaduInt8()
+{
+ sal_uInt8 nValue(0);
+ operator>>( nValue );
+ return nValue;
+}
+
+sal_Int16 XclImpStream::ReadInt16()
+{
+ sal_Int16 nValue(0);
+ operator>>( nValue );
+ return nValue;
+}
+
+sal_uInt16 XclImpStream::ReaduInt16()
+{
+ sal_uInt16 nValue(0);
+ operator>>( nValue );
+ return nValue;
+}
+
+sal_Int32 XclImpStream::ReadInt32()
+{
+ sal_Int32 nValue(0);
+ operator>>( nValue );
+ return nValue;
+}
+
+sal_uInt32 XclImpStream::ReaduInt32()
+{
+ sal_uInt32 nValue(0);
+ operator>>( nValue );
+ return nValue;
+}
+
+double XclImpStream::ReadDouble()
+{
+ double fValue(0.0);
+ operator>>( fValue );
+ return fValue;
+}
+
+sal_Size XclImpStream::Read( void* pData, sal_Size nBytes )
+{
+ sal_Size nRet = 0;
+ if( mbValid && pData && (nBytes > 0) )
+ {
+ sal_uInt8* pnBuffer = reinterpret_cast< sal_uInt8* >( pData );
+ sal_Size nBytesLeft = nBytes;
+
+ while( mbValid && (nBytesLeft > 0) )
+ {
+ sal_uInt16 nReadSize = GetMaxRawReadSize( nBytesLeft );
+ sal_uInt16 nReadRet = ReadRawData( pnBuffer, nReadSize );
+ nRet += nReadRet;
+ mbValid = (nReadSize == nReadRet);
+ DBG_ASSERT( mbValid, "XclImpStream::Read - stream read error" );
+ pnBuffer += nReadRet;
+ nBytesLeft -= nReadRet;
+ if( mbValid && (nBytesLeft > 0) )
+ JumpToNextContinue();
+ DBG_ASSERT( mbValid, "XclImpStream::Read - record overread" );
+ }
+ }
+ return nRet;
+}
+
+sal_Size XclImpStream::CopyToStream( SvStream& rOutStrm, sal_Size nBytes )
+{
+ sal_Size nRet = 0;
+ if( mbValid && (nBytes > 0) )
+ {
+ const sal_Size nMaxBuffer = 4096;
+ sal_uInt8* pnBuffer = new sal_uInt8[ ::std::min( nBytes, nMaxBuffer ) ];
+ sal_Size nBytesLeft = nBytes;
+
+ while( mbValid && (nBytesLeft > 0) )
+ {
+ sal_Size nReadSize = ::std::min( nBytesLeft, nMaxBuffer );
+ nRet += Read( pnBuffer, nReadSize );
+ rOutStrm.Write( pnBuffer, nReadSize );
+ nBytesLeft -= nReadSize;
+ }
+
+ delete[] pnBuffer;
+ }
+ return nRet;
+}
+
+sal_Size XclImpStream::CopyRecordToStream( SvStream& rOutStrm )
+{
+ sal_Size nRet = 0;
+ if( mbValidRec )
+ {
+ PushPosition();
+ RestorePosition( maFirstRec );
+ nRet = CopyToStream( rOutStrm, GetRecSize() );
+ PopPosition();
+ }
+ return nRet;
+}
+
+void XclImpStream::Seek( sal_Size nPos )
+{
+ if( mbValidRec )
+ {
+ sal_Size nCurrPos = GetRecPos();
+ if( !mbValid || (nPos < nCurrPos) ) // from invalid state or backward
+ {
+ RestorePosition( maFirstRec );
+ Ignore( nPos );
+ }
+ else if( nPos > nCurrPos ) // forward
+ {
+ Ignore( nPos - nCurrPos );
+ }
+ }
+}
+
+void XclImpStream::Ignore( sal_Size nBytes )
+{
+ // implementation similar to Read(), but without really reading anything
+ sal_Size nBytesLeft = nBytes;
+ while( mbValid && (nBytesLeft > 0) )
+ {
+ sal_uInt16 nReadSize = GetMaxRawReadSize( nBytesLeft );
+ mrStrm.SeekRel( nReadSize );
+ mnRawRecLeft = mnRawRecLeft - nReadSize;
+ nBytesLeft -= nReadSize;
+ if( nBytesLeft > 0 )
+ JumpToNextContinue();
+ DBG_ASSERT( mbValid, "XclImpStream::Ignore - record overread" );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+sal_Size XclImpStream::ReadUniStringExtHeader(
+ bool& rb16Bit, bool& rbRich, bool& rbFareast,
+ sal_uInt16& rnFormatRuns, sal_uInt32& rnExtInf, sal_uInt8 nFlags )
+{
+ DBG_ASSERT( !::get_flag( nFlags, EXC_STRF_UNKNOWN ), "XclImpStream::ReadUniStringExt - unknown flags" );
+ rb16Bit = ::get_flag( nFlags, EXC_STRF_16BIT );
+ rbRich = ::get_flag( nFlags, EXC_STRF_RICH );
+ rbFareast = ::get_flag( nFlags, EXC_STRF_FAREAST );
+ rnFormatRuns = rbRich ? ReaduInt16() : 0;
+ rnExtInf = rbFareast ? ReaduInt32() : 0;
+ return rnExtInf + 4 * rnFormatRuns;
+}
+
+sal_Size XclImpStream::ReadUniStringExtHeader( bool& rb16Bit, sal_uInt8 nFlags )
+{
+ bool bRich, bFareast;
+ sal_uInt16 nCrun;
+ sal_uInt32 nExtInf;
+ return ReadUniStringExtHeader( rb16Bit, bRich, bFareast, nCrun, nExtInf, nFlags );
+}
+
+// ----------------------------------------------------------------------------
+
+String XclImpStream::ReadRawUniString( sal_uInt16 nChars, bool b16Bit )
+{
+ String aRet;
+ sal_uInt16 nCharsLeft = nChars;
+ sal_uInt16 nReadSize;
+
+ sal_Unicode* pcBuffer = new sal_Unicode[ nCharsLeft + 1 ];
+
+ while( IsValid() && (nCharsLeft > 0) )
+ {
+ if( b16Bit )
+ {
+ nReadSize = ::std::min< sal_uInt16 >( nCharsLeft, mnRawRecLeft / 2 );
+ DBG_ASSERT( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
+ "XclImpStream::ReadRawUniString - missing a byte" );
+ }
+ else
+ nReadSize = GetMaxRawReadSize( nCharsLeft );
+
+ sal_Unicode* pcUniChar = pcBuffer;
+ sal_Unicode* pcEndChar = pcBuffer + nReadSize;
+
+ if( b16Bit )
+ {
+ sal_uInt16 nReadChar;
+ for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
+ {
+ operator>>( nReadChar );
+ (*pcUniChar) = (nReadChar == EXC_NUL) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
+ }
+ }
+ else
+ {
+ sal_uInt8 nReadChar;
+ for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
+ {
+ operator>>( nReadChar );
+ (*pcUniChar) = (nReadChar == EXC_NUL_C) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
+ }
+ }
+
+ *pcEndChar = '\0';
+ aRet.Append( pcBuffer );
+
+ nCharsLeft = nCharsLeft - nReadSize;
+ if( nCharsLeft > 0 )
+ JumpToNextStringContinue( b16Bit );
+ }
+
+ delete[] pcBuffer;
+ return aRet;
+}
+
+String XclImpStream::ReadUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
+{
+ bool b16Bit;
+ sal_Size nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
+ String aRet( ReadRawUniString( nChars, b16Bit ) );
+ Ignore( nExtSize );
+ return aRet;
+}
+
+String XclImpStream::ReadUniString( sal_uInt16 nChars )
+{
+ return ReadUniString( nChars, ReaduInt8() );
+}
+
+String XclImpStream::ReadUniString()
+{
+ return ReadUniString( ReaduInt16() );
+}
+
+void XclImpStream::IgnoreRawUniString( sal_uInt16 nChars, bool b16Bit )
+{
+ sal_uInt16 nCharsLeft = nChars;
+ sal_uInt16 nReadSize;
+
+ while( IsValid() && (nCharsLeft > 0) )
+ {
+ if( b16Bit )
+ {
+ nReadSize = ::std::min< sal_uInt16 >( nCharsLeft, mnRawRecLeft / 2 );
+ DBG_ASSERT( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
+ "XclImpStream::IgnoreRawUniString - missing a byte" );
+ Ignore( nReadSize * 2 );
+ }
+ else
+ {
+ nReadSize = GetMaxRawReadSize( nCharsLeft );
+ Ignore( nReadSize );
+ }
+
+ nCharsLeft = nCharsLeft - nReadSize;
+ if( nCharsLeft > 0 )
+ JumpToNextStringContinue( b16Bit );
+ }
+}
+
+void XclImpStream::IgnoreUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
+{
+ bool b16Bit;
+ sal_Size nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
+ IgnoreRawUniString( nChars, b16Bit );
+ Ignore( nExtSize );
+}
+
+void XclImpStream::IgnoreUniString( sal_uInt16 nChars )
+{
+ IgnoreUniString( nChars, ReaduInt8() );
+}
+
+// ----------------------------------------------------------------------------
+
+String XclImpStream::ReadRawByteString( sal_uInt16 nChars )
+{
+ sal_Char* pcBuffer = new sal_Char[ nChars + 1 ];
+ sal_uInt16 nCharsRead = ReadRawData( pcBuffer, nChars );
+ pcBuffer[ nCharsRead ] = '\0';
+ String aRet( pcBuffer, mrRoot.GetTextEncoding() );
+ delete[] pcBuffer;
+ return aRet;
+}
+
+String XclImpStream::ReadByteString( bool b16BitLen )
+{
+ return ReadRawByteString( ReadByteStrLen( b16BitLen ) );
+}
+
+// private --------------------------------------------------------------------
+
+void XclImpStream::StorePosition( XclImpStreamPos& rPos )
+{
+ rPos.Set( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
+}
+
+void XclImpStream::RestorePosition( const XclImpStreamPos& rPos )
+{
+ rPos.Get( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
+ SetupDecrypter();
+}
+
+bool XclImpStream::ReadNextRawRecHeader()
+{
+ mrStrm.Seek( mnNextRecPos );
+ bool bRet = mnNextRecPos + 4 <= mnStreamSize;
+ if( bRet )
+ mrStrm >> mnRawRecId >> mnRawRecSize;
+ return bRet;
+}
+
+void XclImpStream::SetupDecrypter()
+{
+ if( mxDecrypter )
+ mxDecrypter->Update( mrStrm, mnRawRecSize );
+}
+
+void XclImpStream::SetupRawRecord()
+{
+ // pre: mnRawRecSize contains current raw record size
+ // pre: mrStrm points to start of raw record data
+ mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
+ mnRawRecLeft = mnRawRecSize;
+ mnCurrRecSize += mnRawRecSize;
+ SetupDecrypter(); // decrypter works on raw record level
+}
+
+void XclImpStream::SetupRecord()
+{
+ mnRecId = mnRawRecId;
+ mnAltContId = EXC_ID_UNKNOWN;
+ mnCurrRecSize = 0;
+ mnComplRecSize = mnRawRecSize;
+ mbHasComplRec = !mbCont;
+ SetupRawRecord();
+ SetNulSubstChar();
+ EnableDecryption();
+ StorePosition( maFirstRec );
+}
+
+bool XclImpStream::IsContinueId( sal_uInt16 nRecId ) const
+{
+ return (nRecId == EXC_ID_CONT) || (nRecId == mnAltContId);
+}
+
+bool XclImpStream::JumpToNextContinue()
+{
+ mbValid = mbValid && mbCont && ReadNextRawRecHeader() && IsContinueId( mnRawRecId );
+ if( mbValid ) // do not setup a following non-CONTINUE record
+ SetupRawRecord();
+ return mbValid;
+}
+
+bool XclImpStream::JumpToNextStringContinue( bool& rb16Bit )
+{
+ DBG_ASSERT( mnRawRecLeft == 0, "XclImpStream::JumpToNextStringContinue - unexpected garbage" );
+
+ if( mbCont && (GetRecLeft() > 0) )
+ {
+ JumpToNextContinue();
+ }
+ else if( mnRecId == EXC_ID_CONT )
+ {
+ // CONTINUE handling is off, but we have started reading in a CONTINUE record
+ // -> start next CONTINUE for TXO import
+ mbValidRec = ReadNextRawRecHeader() && ((mnRawRecId != 0) || (mnRawRecSize > 0));
+ mbValid = mbValidRec && (mnRawRecId == EXC_ID_CONT);
+ // we really start a new record here - no chance to return to string origin
+ if( mbValid )
+ SetupRecord();
+ }
+ else
+ mbValid = false;
+
+ if( mbValid )
+ rb16Bit = ::get_flag( ReaduInt8(), EXC_STRF_16BIT );
+ return mbValid;
+}
+
+bool XclImpStream::EnsureRawReadSize( sal_uInt16 nBytes )
+{
+ if( mbValid && nBytes )
+ {
+ while( mbValid && !mnRawRecLeft ) JumpToNextContinue();
+ mbValid = mbValid && (nBytes <= mnRawRecLeft);
+ DBG_ASSERT( mbValid, "XclImpStream::EnsureRawReadSize - record overread" );
+ }
+ return mbValid;
+}
+
+sal_uInt16 XclImpStream::GetMaxRawReadSize( sal_Size nBytes ) const
+{
+ return static_cast< sal_uInt16 >( ::std::min< sal_Size >( nBytes, mnRawRecLeft ) );
+}
+
+sal_uInt16 XclImpStream::ReadRawData( void* pData, sal_uInt16 nBytes )
+{
+ DBG_ASSERT( (nBytes <= mnRawRecLeft), "XclImpStream::ReadRawData - record overread" );
+ sal_uInt16 nRet = 0;
+ if( mbUseDecr )
+ nRet = mxDecrypter->Read( mrStrm, pData, nBytes );
+ else
+ nRet = static_cast< sal_uInt16 >( mrStrm.Read( pData, nBytes ) );
+ mnRawRecLeft = mnRawRecLeft - nRet;
+ return nRet;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xistring.cxx b/sc/source/filter/excel/xistring.cxx
new file mode 100644
index 000000000000..c50b0605e3ee
--- /dev/null
+++ b/sc/source/filter/excel/xistring.cxx
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_sc.hxx"
+#include "xistring.hxx"
+#include "xlstyle.hxx"
+#include "xistream.hxx"
+#include "xiroot.hxx"
+
+// Byte/Unicode strings =======================================================
+
+/** All allowed flags for import. */
+const XclStrFlags nAllowedFlags = EXC_STR_8BITLENGTH | EXC_STR_SMARTFLAGS | EXC_STR_SEPARATEFORMATS;
+
+// ----------------------------------------------------------------------------
+
+XclImpString::XclImpString()
+{
+}
+
+XclImpString::XclImpString( const String& rString ) :
+ maString( rString )
+{
+}
+
+XclImpString::~XclImpString()
+{
+}
+
+void XclImpString::Read( XclImpStream& rStrm, XclStrFlags nFlags )
+{
+ if( !::get_flag( nFlags, EXC_STR_SEPARATEFORMATS ) )
+ maFormats.clear();
+
+ DBG_ASSERT( (nFlags & ~nAllowedFlags) == 0, "XclImpString::Read - unknown flag" );
+ bool b16BitLen = !::get_flag( nFlags, EXC_STR_8BITLENGTH );
+
+ switch( rStrm.GetRoot().GetBiff() )
+ {
+ case EXC_BIFF2:
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ case EXC_BIFF5:
+ // no integrated formatting in BIFF2-BIFF7
+ maString = rStrm.ReadByteString( b16BitLen );
+ break;
+
+ case EXC_BIFF8:
+ {
+ // --- string header ---
+ sal_uInt16 nChars = b16BitLen ? rStrm.ReaduInt16() : rStrm.ReaduInt8();
+ sal_uInt8 nFlagField = 0;
+ if( nChars || !::get_flag( nFlags, EXC_STR_SMARTFLAGS ) )
+ rStrm >> nFlagField;
+
+ bool b16Bit, bRich, bFarEast;
+ sal_uInt16 nRunCount;
+ sal_uInt32 nExtInf;
+ rStrm.ReadUniStringExtHeader( b16Bit, bRich, bFarEast, nRunCount, nExtInf, nFlagField );
+ // ignore the flags, they may be wrong
+
+ // --- character array ---
+ maString = rStrm.ReadRawUniString( nChars, b16Bit );
+
+ // --- formatting ---
+ if( nRunCount > 0 )
+ ReadFormats( rStrm, nRunCount );
+
+ // --- extended (FarEast) information ---
+ rStrm.Ignore( nExtInf );
+ }
+ break;
+
+ default:
+ DBG_ERROR_BIFF();
+ }
+}
+
+void XclImpString::AppendFormat( XclFormatRunVec& rFormats, sal_uInt16 nChar, sal_uInt16 nFontIdx )
+{
+ // #i33341# real life -- same character index may occur several times
+ DBG_ASSERT( rFormats.empty() || (rFormats.back().mnChar <= nChar), "XclImpString::AppendFormat - wrong char order" );
+ if( rFormats.empty() || (rFormats.back().mnChar < nChar) )
+ rFormats.push_back( XclFormatRun( nChar, nFontIdx ) );
+ else
+ rFormats.back().mnFontIdx = nFontIdx;
+}
+
+void XclImpString::ReadFormats( XclImpStream& rStrm, XclFormatRunVec& rFormats )
+{
+ bool bBiff8 = rStrm.GetRoot().GetBiff() == EXC_BIFF8;
+ sal_uInt16 nRunCount = bBiff8 ? rStrm.ReaduInt16() : rStrm.ReaduInt8();
+ ReadFormats( rStrm, rFormats, nRunCount );
+}
+
+void XclImpString::ReadFormats( XclImpStream& rStrm, XclFormatRunVec& rFormats, sal_uInt16 nRunCount )
+{
+ rFormats.clear();
+ rFormats.reserve( nRunCount );
+ /* #i33341# real life -- same character index may occur several times
+ -> use AppendFormat() to validate formats */
+ if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
+ {
+ for( sal_uInt16 nIdx = 0; nIdx < nRunCount; ++nIdx )
+ {
+ sal_uInt16 nChar, nFontIdx;
+ rStrm >> nChar >> nFontIdx;
+ AppendFormat( rFormats, nChar, nFontIdx );
+ }
+ }
+ else
+ {
+ for( sal_uInt16 nIdx = 0; nIdx < nRunCount; ++nIdx )
+ {
+ sal_uInt8 nChar, nFontIdx;
+ rStrm >> nChar >> nFontIdx;
+ AppendFormat( rFormats, nChar, nFontIdx );
+ }
+ }
+}
+
+void XclImpString::ReadObjFormats( XclImpStream& rStrm, XclFormatRunVec& rFormats, sal_uInt16 nFormatSize )
+{
+ // number of formatting runs, each takes 8 bytes
+ sal_uInt16 nRunCount = nFormatSize / 8;
+ rFormats.clear();
+ rFormats.reserve( nRunCount );
+ for( sal_uInt16 nIdx = 0; nIdx < nRunCount; ++nIdx )
+ {
+ sal_uInt16 nChar, nFontIdx;
+ rStrm >> nChar >> nFontIdx;
+ rStrm.Ignore( 4 );
+ AppendFormat( rFormats, nChar, nFontIdx );
+ }
+}
+
+// String iterator ============================================================
+
+XclImpStringIterator::XclImpStringIterator( const XclImpString& rString ) :
+ mrText( rString.GetText() ),
+ mrFormats( rString.GetFormats() ),
+ mnPortion( 0 ),
+ mnTextBeg( 0 ),
+ mnTextEnd( 0 ),
+ mnFormatsBeg( 0 ),
+ mnFormatsEnd( 0 )
+{
+ // first portion is formatted, adjust vector index to next portion
+ if( !mrFormats.empty() && (mrFormats.front().mnChar == 0) )
+ ++mnFormatsEnd;
+ // find end position of the first portion
+ mnTextEnd = static_cast< xub_StrLen >( (mnFormatsEnd < mrFormats.size()) ?
+ mrFormats[ mnFormatsEnd ].mnChar : mrText.Len() );
+}
+
+String XclImpStringIterator::GetPortionText() const
+{
+ return String( mrText, mnTextBeg, mnTextEnd - mnTextBeg );
+}
+
+sal_uInt16 XclImpStringIterator::GetPortionFont() const
+{
+ return (mnFormatsBeg < mnFormatsEnd) ? mrFormats[ mnFormatsBeg ].mnFontIdx : EXC_FONT_NOTFOUND;
+}
+
+XclImpStringIterator& XclImpStringIterator::operator++()
+{
+ if( Is() )
+ {
+ ++mnPortion;
+ do
+ {
+ // indexes into vector of formatting runs
+ if( mnFormatsBeg < mnFormatsEnd )
+ ++mnFormatsBeg;
+ if( mnFormatsEnd < mrFormats.size() )
+ ++mnFormatsEnd;
+ // character positions of next portion
+ mnTextBeg = mnTextEnd;
+ mnTextEnd = static_cast< xub_StrLen >( (mnFormatsEnd < mrFormats.size()) ?
+ mrFormats[ mnFormatsEnd ].mnChar : mrText.Len() );
+ }
+ while( Is() && (mnTextBeg == mnTextEnd) );
+ }
+ return *this;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xistyle.cxx b/sc/source/filter/excel/xistyle.cxx
new file mode 100644
index 000000000000..1f6e680897b5
--- /dev/null
+++ b/sc/source/filter/excel/xistyle.cxx
@@ -0,0 +1,2000 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xistyle.hxx"
+#include <sfx2/printer.hxx>
+#include <sfx2/objsh.hxx>
+#include <svtools/ctrltool.hxx>
+#include <editeng/editobj.hxx>
+#include "scitems.hxx"
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/crsditem.hxx>
+#include <editeng/cntritem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/escpitem.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/bolnitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/flstitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <sal/macros.h>
+#include "document.hxx"
+#include "docpool.hxx"
+#include "attrib.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "cell.hxx"
+#include "globstr.hrc"
+#include "attarray.hxx"
+#include "xltracer.hxx"
+#include "xistream.hxx"
+#include "xicontent.hxx"
+
+#include "root.hxx"
+#include "colrowst.hxx"
+#include "svl/poolcach.hxx"
+
+#include <list>
+
+using ::std::list;
+
+#include <cppuhelper/implbase1.hxx>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+using namespace ::com::sun::star;
+
+typedef ::cppu::WeakImplHelper1< container::XIndexAccess > XIndexAccess_BASE;
+typedef ::std::vector< ColorData > ColorDataVec;
+
+class PaletteIndex : public XIndexAccess_BASE
+{
+public:
+ PaletteIndex( const ColorDataVec& rColorDataTable ) : maColorData( rColorDataTable ) {}
+
+ // Methods XIndexAccess
+ virtual ::sal_Int32 SAL_CALL getCount() throw (uno::RuntimeException)
+ {
+ return maColorData.size();
+ }
+
+ virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException)
+ {
+ //--Index; // apparently the palette is already 1 based
+ return uno::makeAny( sal_Int32( maColorData[ Index ] ) );
+ }
+
+ // Methods XElementAcess
+ virtual uno::Type SAL_CALL getElementType() throw (uno::RuntimeException)
+ {
+ return ::getCppuType( (sal_Int32*)0 );
+ }
+ virtual ::sal_Bool SAL_CALL hasElements() throw (uno::RuntimeException)
+ {
+ return (maColorData.size() > 0);
+ }
+
+private:
+ ColorDataVec maColorData;
+};
+
+void
+XclImpPalette::ExportPalette()
+{
+ if( SfxObjectShell* pDocShell = mrRoot.GetDocShell() )
+ {
+ // copy values in color palette
+ sal_Int16 nColors = maColorTable.size();
+ ColorDataVec aColors;
+ aColors.resize( nColors );
+ for( sal_uInt16 nIndex = 0; nIndex < nColors; ++nIndex )
+ aColors[ nIndex ] = GetColorData( nIndex );
+
+ uno::Reference< beans::XPropertySet > xProps( pDocShell->GetModel(), uno::UNO_QUERY );
+ if ( xProps.is() )
+ {
+ uno::Reference< container::XIndexAccess > xIndex( new PaletteIndex( aColors ) );
+ xProps->setPropertyValue( CREATE_OUSTRING("ColorPalette"), uno::makeAny( xIndex ) );
+ }
+ }
+
+}
+// PALETTE record - color information =========================================
+
+XclImpPalette::XclImpPalette( const XclImpRoot& rRoot ) :
+ XclDefaultPalette( rRoot ), mrRoot( rRoot )
+{
+}
+
+void XclImpPalette::Initialize()
+{
+ maColorTable.clear();
+}
+
+ColorData XclImpPalette::GetColorData( sal_uInt16 nXclIndex ) const
+{
+ if( nXclIndex >= EXC_COLOR_USEROFFSET )
+ {
+ sal_uInt32 nIx = nXclIndex - EXC_COLOR_USEROFFSET;
+ if( nIx < maColorTable.size() )
+ return maColorTable[ nIx ];
+ }
+ return GetDefColorData( nXclIndex );
+}
+
+::com::sun::star::uno::Sequence< sal_Int32 > XclImpPalette::CreateColorSequence() const
+{
+ sal_Int32 nCount = static_cast< sal_Int32 >( maColorTable.size() );
+ ::com::sun::star::uno::Sequence< sal_Int32 > aSeq( nCount );
+ if( nCount > 0 )
+ {
+ sal_Int32* pnSeqColor = aSeq.getArray();
+ for( ColorDataVec::const_iterator aIt = maColorTable.begin(), aEnd = maColorTable.end(); aIt != aEnd; ++aIt, ++pnSeqColor )
+ *pnSeqColor = static_cast< sal_Int32 >( *aIt );
+ }
+ return aSeq;
+}
+
+void XclImpPalette::ReadPalette( XclImpStream& rStrm )
+{
+ sal_uInt16 nCount;
+ rStrm >> nCount;
+ DBG_ASSERT( rStrm.GetRecLeft() == static_cast< sal_Size >( 4 * nCount ),
+ "XclImpPalette::ReadPalette - size mismatch" );
+
+ maColorTable.resize( nCount );
+ Color aColor;
+ for( sal_uInt16 nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ rStrm >> aColor;
+ maColorTable[ nIndex ] = aColor.GetColor();
+ }
+ ExportPalette();
+}
+
+// FONT record - font information =============================================
+
+XclImpFont::XclImpFont( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ mbHasCharSet( false ),
+ mbHasWstrn( true ),
+ mbHasAsian( false ),
+ mbHasCmplx( false )
+{
+ SetAllUsedFlags( false );
+}
+
+XclImpFont::XclImpFont( const XclImpRoot& rRoot, const XclFontData& rFontData ) :
+ XclImpRoot( rRoot )
+{
+ SetFontData( rFontData, false );
+}
+
+void XclImpFont::SetAllUsedFlags( bool bUsed )
+{
+ mbFontNameUsed = mbHeightUsed = mbColorUsed = mbWeightUsed = mbEscapemUsed =
+ mbUnderlUsed = mbItalicUsed = mbStrikeUsed = mbOutlineUsed = mbShadowUsed = bUsed;
+}
+
+void XclImpFont::SetFontData( const XclFontData& rFontData, bool bHasCharSet )
+{
+ maData = rFontData;
+ mbHasCharSet = bHasCharSet;
+ if( maData.maStyle.Len() )
+ {
+ if( SfxObjectShell* pDocShell = GetDocShell() )
+ {
+ if( const SvxFontListItem* pInfoItem = static_cast< const SvxFontListItem* >(
+ pDocShell->GetItem( SID_ATTR_CHAR_FONTLIST ) ) )
+ {
+ if( const FontList* pFontList = pInfoItem->GetFontList() )
+ {
+ FontInfo aFontInfo( pFontList->Get( maData.maName, maData.maStyle ) );
+ maData.SetScWeight( aFontInfo.GetWeight() );
+ maData.SetScPosture( aFontInfo.GetItalic() );
+ }
+ }
+ }
+ maData.maStyle.Erase();
+ }
+ GuessScriptType();
+ SetAllUsedFlags( true );
+}
+
+rtl_TextEncoding XclImpFont::GetFontEncoding() const
+{
+ // #i63105# use text encoding from FONT record
+ // #i67768# BIFF2-BIFF4 FONT records do not contain character set
+ rtl_TextEncoding eFontEnc = mbHasCharSet ? maData.GetFontEncoding() : GetTextEncoding();
+ return (eFontEnc == RTL_TEXTENCODING_DONTKNOW) ? GetTextEncoding() : eFontEnc;
+}
+
+void XclImpFont::ReadFont( XclImpStream& rStrm )
+{
+ switch( GetBiff() )
+ {
+ case EXC_BIFF2:
+ ReadFontData2( rStrm );
+ ReadFontName2( rStrm );
+ break;
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ ReadFontData2( rStrm );
+ ReadFontColor( rStrm );
+ ReadFontName2( rStrm );
+ break;
+ case EXC_BIFF5:
+ ReadFontData5( rStrm );
+ ReadFontName2( rStrm );
+ break;
+ case EXC_BIFF8:
+ ReadFontData5( rStrm );
+ ReadFontName8( rStrm );
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ return;
+ }
+ GuessScriptType();
+ SetAllUsedFlags( true );
+}
+
+void XclImpFont::ReadEfont( XclImpStream& rStrm )
+{
+ ReadFontColor( rStrm );
+}
+
+void XclImpFont::ReadCFFontBlock( XclImpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF8 );
+ if( GetBiff() != EXC_BIFF8 )
+ return;
+
+ sal_uInt32 nHeight, nStyle, nColor, nFontFlags1, nFontFlags2, nFontFlags3;
+ sal_uInt16 nWeight, nEscapem;
+ sal_uInt8 nUnderl;
+
+ rStrm.Ignore( 64 );
+ rStrm >> nHeight >> nStyle >> nWeight >> nEscapem >> nUnderl;
+ rStrm.Ignore( 3 );
+ rStrm >> nColor;
+ rStrm.Ignore( 4 );
+ rStrm >> nFontFlags1 >> nFontFlags2 >> nFontFlags3;
+ rStrm.Ignore( 18 );
+
+ if( (mbHeightUsed = (nHeight <= 0x7FFF)) == true )
+ maData.mnHeight = static_cast< sal_uInt16 >( nHeight );
+ if( (mbWeightUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE ) && (nWeight < 0x7FFF)) == true )
+ maData.mnWeight = static_cast< sal_uInt16 >( nWeight );
+ if( (mbItalicUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE )) == true )
+ maData.mbItalic = ::get_flag( nStyle, EXC_CF_FONT_STYLE );
+ if( (mbUnderlUsed = !::get_flag( nFontFlags3, EXC_CF_FONT_UNDERL ) && (nUnderl <= 0x7F)) == true )
+ maData.mnUnderline = nUnderl;
+ if( (mbColorUsed = (nColor <= 0x7FFF)) == true )
+ maData.maColor = GetPalette().GetColor( static_cast< sal_uInt16 >( nColor ) );
+ if( (mbStrikeUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STRIKEOUT )) == true )
+ maData.mbStrikeout = ::get_flag( nStyle, EXC_CF_FONT_STRIKEOUT );
+}
+
+void XclImpFont::FillToItemSet( SfxItemSet& rItemSet, XclFontItemType eType, bool bSkipPoolDefs ) const
+{
+ // true = edit engine Which-IDs (EE_CHAR_*); false = Calc Which-IDs (ATTR_*)
+ bool bEE = eType != EXC_FONTITEM_CELL;
+
+// item = the item to put into the item set
+// sc_which = the Calc Which-ID of the item
+// ee_which = the edit engine Which-ID of the item
+#define PUTITEM( item, sc_which, ee_which ) \
+ ScfTools::PutItem( rItemSet, item, (bEE ? (ee_which) : (sc_which)), bSkipPoolDefs )
+
+// Font item
+ // #i36997# do not set default Tahoma font from notes
+ bool bDefNoteFont = (eType == EXC_FONTITEM_NOTE) && (maData.maName.EqualsIgnoreCaseAscii( "Tahoma" ));
+ if( mbFontNameUsed && !bDefNoteFont )
+ {
+ rtl_TextEncoding eFontEnc = maData.GetFontEncoding();
+ rtl_TextEncoding eTempTextEnc = (bEE && (eFontEnc == GetTextEncoding())) ?
+ ScfTools::GetSystemTextEncoding() : eFontEnc;
+
+ SvxFontItem aFontItem( maData.GetScFamily( GetTextEncoding() ), maData.maName, EMPTY_STRING,
+ PITCH_DONTKNOW, eTempTextEnc, ATTR_FONT );
+ // set only for valid script types
+ if( mbHasWstrn )
+ PUTITEM( aFontItem, ATTR_FONT, EE_CHAR_FONTINFO );
+ if( mbHasAsian )
+ PUTITEM( aFontItem, ATTR_CJK_FONT, EE_CHAR_FONTINFO_CJK );
+ if( mbHasCmplx )
+ PUTITEM( aFontItem, ATTR_CTL_FONT, EE_CHAR_FONTINFO_CTL );
+ }
+
+// Font height (for all script types)
+ if( mbHeightUsed )
+ {
+ sal_Int32 nHeight = maData.mnHeight;
+ if( bEE && (eType != EXC_FONTITEM_HF) ) // do not convert header/footer height
+ nHeight = (nHeight * 127 + 36) / EXC_POINTS_PER_INCH; // 1 in == 72 pt
+
+ SvxFontHeightItem aHeightItem( nHeight, 100, ATTR_FONT_HEIGHT );
+ PUTITEM( aHeightItem, ATTR_FONT_HEIGHT, EE_CHAR_FONTHEIGHT );
+ PUTITEM( aHeightItem, ATTR_CJK_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CJK );
+ PUTITEM( aHeightItem, ATTR_CTL_FONT_HEIGHT, EE_CHAR_FONTHEIGHT_CTL );
+ }
+
+// Font color - pass AUTO_COL to item
+ if( mbColorUsed )
+ PUTITEM( SvxColorItem( maData.maColor, ATTR_FONT_COLOR ), ATTR_FONT_COLOR, EE_CHAR_COLOR );
+
+// Font weight (for all script types)
+ if( mbWeightUsed )
+ {
+ SvxWeightItem aWeightItem( maData.GetScWeight(), ATTR_FONT_WEIGHT );
+ PUTITEM( aWeightItem, ATTR_FONT_WEIGHT, EE_CHAR_WEIGHT );
+ PUTITEM( aWeightItem, ATTR_CJK_FONT_WEIGHT, EE_CHAR_WEIGHT_CJK );
+ PUTITEM( aWeightItem, ATTR_CTL_FONT_WEIGHT, EE_CHAR_WEIGHT_CTL );
+ }
+
+// Font underline
+ if( mbUnderlUsed )
+ {
+ SvxUnderlineItem aUnderlItem( maData.GetScUnderline(), ATTR_FONT_UNDERLINE );
+ PUTITEM( aUnderlItem, ATTR_FONT_UNDERLINE, EE_CHAR_UNDERLINE );
+ }
+
+// Font posture (for all script types)
+ if( mbItalicUsed )
+ {
+ SvxPostureItem aPostItem( maData.GetScPosture(), ATTR_FONT_POSTURE );
+ PUTITEM( aPostItem, ATTR_FONT_POSTURE, EE_CHAR_ITALIC );
+ PUTITEM( aPostItem, ATTR_CJK_FONT_POSTURE, EE_CHAR_ITALIC_CJK );
+ PUTITEM( aPostItem, ATTR_CTL_FONT_POSTURE, EE_CHAR_ITALIC_CTL );
+ }
+
+// Boolean attributes crossed out, contoured, shadowed
+ if( mbStrikeUsed )
+ PUTITEM( SvxCrossedOutItem( maData.GetScStrikeout(), ATTR_FONT_CROSSEDOUT ), ATTR_FONT_CROSSEDOUT, EE_CHAR_STRIKEOUT );
+ if( mbOutlineUsed )
+ PUTITEM( SvxContourItem( maData.mbOutline, ATTR_FONT_CONTOUR ), ATTR_FONT_CONTOUR, EE_CHAR_OUTLINE );
+ if( mbShadowUsed )
+ PUTITEM( SvxShadowedItem( maData.mbShadow, ATTR_FONT_SHADOWED ), ATTR_FONT_SHADOWED, EE_CHAR_SHADOW );
+
+// Super-/subscript: only on edit engine objects
+ if( mbEscapemUsed && bEE )
+ rItemSet.Put( SvxEscapementItem( maData.GetScEscapement(), EE_CHAR_ESCAPEMENT ) );
+
+#undef PUTITEM
+}
+
+void XclImpFont::WriteFontProperties( ScfPropertySet& rPropSet,
+ XclFontPropSetType eType, const Color* pFontColor ) const
+{
+ GetFontPropSetHelper().WriteFontProperties(
+ rPropSet, eType, maData, mbHasWstrn, mbHasAsian, mbHasCmplx, pFontColor );
+}
+
+void XclImpFont::ReadFontData2( XclImpStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm >> maData.mnHeight >> nFlags;
+
+ maData.mnWeight = ::get_flagvalue( nFlags, EXC_FONTATTR_BOLD, EXC_FONTWGHT_BOLD, EXC_FONTWGHT_NORMAL );
+ maData.mnUnderline = ::get_flagvalue( nFlags, EXC_FONTATTR_UNDERLINE, EXC_FONTUNDERL_SINGLE, EXC_FONTUNDERL_NONE );
+ maData.mbItalic = ::get_flag( nFlags, EXC_FONTATTR_ITALIC );
+ maData.mbStrikeout = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT );
+ maData.mbOutline = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE );
+ maData.mbShadow = ::get_flag( nFlags, EXC_FONTATTR_SHADOW );
+ mbHasCharSet = false;
+}
+
+void XclImpFont::ReadFontData5( XclImpStream& rStrm )
+{
+ sal_uInt16 nFlags;
+
+ rStrm >> maData.mnHeight >> nFlags;
+ ReadFontColor( rStrm );
+ rStrm >> maData.mnWeight >> maData.mnEscapem >> maData.mnUnderline >> maData.mnFamily >> maData.mnCharSet;
+ rStrm.Ignore( 1 );
+
+ maData.mbItalic = ::get_flag( nFlags, EXC_FONTATTR_ITALIC );
+ maData.mbStrikeout = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT );
+ maData.mbOutline = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE );
+ maData.mbShadow = ::get_flag( nFlags, EXC_FONTATTR_SHADOW );
+ mbHasCharSet = true;
+}
+
+void XclImpFont::ReadFontColor( XclImpStream& rStrm )
+{
+ maData.maColor = GetPalette().GetColor( rStrm.ReaduInt16() );
+}
+
+void XclImpFont::ReadFontName2( XclImpStream& rStrm )
+{
+ maData.maName = rStrm.ReadByteString( false );
+}
+
+void XclImpFont::ReadFontName8( XclImpStream& rStrm )
+{
+ maData.maName = rStrm.ReadUniString( rStrm.ReaduInt8() );
+}
+
+void XclImpFont::GuessScriptType()
+{
+ mbHasWstrn = true;
+ mbHasAsian = mbHasCmplx = false;
+
+ // find the script types for which the font contains characters
+ if( OutputDevice* pPrinter = GetPrinter() )
+ {
+ Font aFont( maData.maName, Size( 0, 10 ) );
+ FontCharMap aCharMap;
+
+ pPrinter->SetFont( aFont );
+ if( pPrinter->GetFontCharMap( aCharMap ) )
+ {
+ // CJK fonts
+ mbHasAsian =
+ aCharMap.HasChar( 0x3041 ) || // 3040-309F: Hiragana
+ aCharMap.HasChar( 0x30A1 ) || // 30A0-30FF: Katakana
+ aCharMap.HasChar( 0x3111 ) || // 3100-312F: Bopomofo
+ aCharMap.HasChar( 0x3131 ) || // 3130-318F: Hangul Compatibility Jamo
+ aCharMap.HasChar( 0x3301 ) || // 3300-33FF: CJK Compatibility
+ aCharMap.HasChar( 0x3401 ) || // 3400-4DBF: CJK Unified Ideographs Extension A
+ aCharMap.HasChar( 0x4E01 ) || // 4E00-9FAF: CJK Unified Ideographs
+ aCharMap.HasChar( 0x7E01 ) || // 4E00-9FAF: CJK unified ideographs
+ aCharMap.HasChar( 0xA001 ) || // A001-A48F: Yi Syllables
+ aCharMap.HasChar( 0xAC01 ) || // AC00-D7AF: Hangul Syllables
+ aCharMap.HasChar( 0xCC01 ) || // AC00-D7AF: Hangul Syllables
+ aCharMap.HasChar( 0xF901 ) || // F900-FAFF: CJK Compatibility Ideographs
+ aCharMap.HasChar( 0xFF71 ); // FF00-FFEF: Halfwidth/Fullwidth Forms
+ // CTL fonts
+ mbHasCmplx =
+ aCharMap.HasChar( 0x05D1 ) || // 0590-05FF: Hebrew
+ aCharMap.HasChar( 0x0631 ) || // 0600-06FF: Arabic
+ aCharMap.HasChar( 0x0721 ) || // 0700-074F: Syriac
+ aCharMap.HasChar( 0x0911 ) || // 0900-0DFF: Indic scripts
+ aCharMap.HasChar( 0x0E01 ) || // 0E00-0E7F: Thai
+ aCharMap.HasChar( 0xFB21 ) || // FB1D-FB4F: Hebrew Presentation Forms
+ aCharMap.HasChar( 0xFB51 ) || // FB50-FDFF: Arabic Presentation Forms-A
+ aCharMap.HasChar( 0xFE71 ); // FE70-FEFF: Arabic Presentation Forms-B
+ // Western fonts
+ mbHasWstrn = (!mbHasAsian && !mbHasCmplx) || aCharMap.HasChar( 'A' );
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpFontBuffer::XclImpFontBuffer( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ maFont4( rRoot ),
+ maCtrlFont( rRoot )
+{
+ Initialize();
+
+ // default font for form controls without own font information
+ XclFontData aCtrlFontData;
+ switch( GetBiff() )
+ {
+ case EXC_BIFF2:
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ case EXC_BIFF5:
+ aCtrlFontData.maName.AssignAscii( "Helv" );
+ aCtrlFontData.mnHeight = 160;
+ aCtrlFontData.mnWeight = EXC_FONTWGHT_BOLD;
+ break;
+ case EXC_BIFF8:
+ aCtrlFontData.maName.AssignAscii( "Tahoma" );
+ aCtrlFontData.mnHeight = 160;
+ aCtrlFontData.mnWeight = EXC_FONTWGHT_NORMAL;
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+ maCtrlFont.SetFontData( aCtrlFontData, false );
+}
+
+void XclImpFontBuffer::Initialize()
+{
+ maFontList.clear();
+
+ // application font for column width calculation, later filled with first font from font list
+ XclFontData aAppFontData;
+ aAppFontData.maName.AssignAscii( "Arial" );
+ aAppFontData.mnHeight = 200;
+ aAppFontData.mnWeight = EXC_FONTWGHT_NORMAL;
+ UpdateAppFont( aAppFontData, false );
+}
+
+const XclImpFont* XclImpFontBuffer::GetFont( sal_uInt16 nFontIndex ) const
+{
+ /* Font with index 4 is not stored in an Excel file, but used e.g. by
+ BIFF5 form pushbutton objects. It is the bold default font.
+ This also means that entries above 4 are out by one in the list. */
+
+ if (nFontIndex == 4)
+ return &maFont4;
+
+ if (nFontIndex < 4)
+ {
+ // Font ID is zero-based when it's less than 4.
+ return nFontIndex >= maFontList.size() ? NULL : &maFontList[nFontIndex];
+ }
+
+ // Font ID is greater than 4. It is now 1-based.
+ return nFontIndex > maFontList.size() ? NULL : &maFontList[nFontIndex-1];
+}
+
+void XclImpFontBuffer::ReadFont( XclImpStream& rStrm )
+{
+ XclImpFont* pFont = new XclImpFont( GetRoot() );
+ pFont->ReadFont( rStrm );
+ maFontList.push_back( pFont );
+
+ if( maFontList.size() == 1 )
+ {
+ UpdateAppFont( pFont->GetFontData(), pFont->HasCharSet() );
+ // #i71033# set text encoding from application font, if CODEPAGE is missing
+ SetAppFontEncoding( pFont->GetFontEncoding() );
+ }
+}
+
+void XclImpFontBuffer::ReadEfont( XclImpStream& rStrm )
+{
+ if( !maFontList.empty() )
+ maFontList.back().ReadEfont( rStrm );
+}
+
+void XclImpFontBuffer::FillToItemSet(
+ SfxItemSet& rItemSet, XclFontItemType eType,
+ sal_uInt16 nFontIdx, bool bSkipPoolDefs ) const
+{
+ if( const XclImpFont* pFont = GetFont( nFontIdx ) )
+ pFont->FillToItemSet( rItemSet, eType, bSkipPoolDefs );
+}
+
+void XclImpFontBuffer::WriteFontProperties( ScfPropertySet& rPropSet,
+ XclFontPropSetType eType, sal_uInt16 nFontIdx, const Color* pFontColor ) const
+{
+ if( const XclImpFont* pFont = GetFont( nFontIdx ) )
+ pFont->WriteFontProperties( rPropSet, eType, pFontColor );
+}
+
+void XclImpFontBuffer::WriteDefaultCtrlFontProperties( ScfPropertySet& rPropSet ) const
+{
+ maCtrlFont.WriteFontProperties( rPropSet, EXC_FONTPROPSET_CONTROL );
+}
+
+void XclImpFontBuffer::UpdateAppFont( const XclFontData& rFontData, bool bHasCharSet )
+{
+ maAppFont = rFontData;
+ // #i3006# Calculate the width of '0' from first font and current printer.
+ SetCharWidth( maAppFont );
+
+ // font 4 is bold font 0
+ XclFontData aFont4Data( maAppFont );
+ aFont4Data.mnWeight = EXC_FONTWGHT_BOLD;
+ maFont4.SetFontData( aFont4Data, bHasCharSet );
+}
+
+// FORMAT record - number formats =============================================
+
+XclImpNumFmtBuffer::XclImpNumFmtBuffer( const XclImpRoot& rRoot ) :
+ XclNumFmtBuffer( rRoot ),
+ XclImpRoot( rRoot ),
+ mnNextXclIdx( 0 )
+{
+}
+
+void XclImpNumFmtBuffer::Initialize()
+{
+ maIndexMap.clear();
+ mnNextXclIdx = 0;
+ InitializeImport(); // base class
+}
+
+void XclImpNumFmtBuffer::ReadFormat( XclImpStream& rStrm )
+{
+ String aFormat;
+ switch( GetBiff() )
+ {
+ case EXC_BIFF2:
+ case EXC_BIFF3:
+ aFormat = rStrm.ReadByteString( false );
+ break;
+
+ case EXC_BIFF4:
+ rStrm.Ignore( 2 ); // in BIFF4 the index field exists, but is undefined
+ aFormat = rStrm.ReadByteString( false );
+ break;
+
+ case EXC_BIFF5:
+ rStrm >> mnNextXclIdx;
+ aFormat = rStrm.ReadByteString( false );
+ break;
+
+ case EXC_BIFF8:
+ rStrm >> mnNextXclIdx;
+ aFormat = rStrm.ReadUniString();
+ break;
+
+ default:
+ DBG_ERROR_BIFF();
+ return;
+ }
+
+ if( mnNextXclIdx < 0xFFFF )
+ {
+ InsertFormat( mnNextXclIdx, aFormat );
+ ++mnNextXclIdx;
+ }
+}
+
+void XclImpNumFmtBuffer::CreateScFormats()
+{
+ DBG_ASSERT( maIndexMap.empty(), "XclImpNumFmtBuffer::CreateScFormats - already created" );
+
+ SvNumberFormatter& rFormatter = GetFormatter();
+ for( XclNumFmtMap::const_iterator aIt = GetFormatMap().begin(), aEnd = GetFormatMap().end(); aIt != aEnd; ++aIt )
+ {
+ const XclNumFmt& rNumFmt = aIt->second;
+
+ // insert/convert the Excel number format
+ xub_StrLen nCheckPos;
+ short nType = NUMBERFORMAT_DEFINED;
+ sal_uInt32 nKey;
+ if( rNumFmt.maFormat.Len() )
+ {
+ String aFormat( rNumFmt.maFormat );
+ rFormatter.PutandConvertEntry( aFormat, nCheckPos,
+ nType, nKey, LANGUAGE_ENGLISH_US, rNumFmt.meLanguage );
+ }
+ else
+ nKey = rFormatter.GetFormatIndex( rNumFmt.meOffset, rNumFmt.meLanguage );
+
+ // insert the resulting format key into the Excel->Calc index map
+ maIndexMap[ aIt->first ] = nKey;
+ }
+}
+
+sal_uLong XclImpNumFmtBuffer::GetScFormat( sal_uInt16 nXclNumFmt ) const
+{
+ XclImpIndexMap::const_iterator aIt = maIndexMap.find( nXclNumFmt );
+ return (aIt != maIndexMap.end()) ? aIt->second : NUMBERFORMAT_ENTRY_NOT_FOUND;
+}
+
+void XclImpNumFmtBuffer::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nXclNumFmt, bool bSkipPoolDefs ) const
+{
+ sal_uLong nScNumFmt = GetScFormat( nXclNumFmt );
+ if( nScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND )
+ nScNumFmt = GetStdScNumFmt();
+ FillScFmtToItemSet( rItemSet, nScNumFmt, bSkipPoolDefs );
+}
+
+void XclImpNumFmtBuffer::FillScFmtToItemSet( SfxItemSet& rItemSet, sal_uLong nScNumFmt, bool bSkipPoolDefs ) const
+{
+ DBG_ASSERT( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND, "XclImpNumFmtBuffer::FillScFmtToItemSet - invalid number format" );
+ ScfTools::PutItem( rItemSet, SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ), bSkipPoolDefs );
+ if( rItemSet.GetItemState( ATTR_VALUE_FORMAT, false ) == SFX_ITEM_SET )
+ ScGlobal::AddLanguage( rItemSet, GetFormatter() );
+}
+
+// XF, STYLE record - Cell formatting =========================================
+
+void XclImpCellProt::FillFromXF2( sal_uInt8 nNumFmt )
+{
+ mbLocked = ::get_flag( nNumFmt, EXC_XF2_LOCKED );
+ mbHidden = ::get_flag( nNumFmt, EXC_XF2_HIDDEN );
+}
+
+void XclImpCellProt::FillFromXF3( sal_uInt16 nProt )
+{
+ mbLocked = ::get_flag( nProt, EXC_XF_LOCKED );
+ mbHidden = ::get_flag( nProt, EXC_XF_HIDDEN );
+}
+
+void XclImpCellProt::FillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const
+{
+ ScfTools::PutItem( rItemSet, ScProtectionAttr( mbLocked, mbHidden ), bSkipPoolDefs );
+}
+
+
+// ----------------------------------------------------------------------------
+
+void XclImpCellAlign::FillFromXF2( sal_uInt8 nFlags )
+{
+ mnHorAlign = ::extract_value< sal_uInt8 >( nFlags, 0, 3 );
+}
+
+void XclImpCellAlign::FillFromXF3( sal_uInt16 nAlign )
+{
+ mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
+ mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK ); // new in BIFF3
+}
+
+void XclImpCellAlign::FillFromXF4( sal_uInt16 nAlign )
+{
+ FillFromXF3( nAlign );
+ mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 2 ); // new in BIFF4
+ mnOrient = ::extract_value< sal_uInt8 >( nAlign, 6, 2 ); // new in BIFF4
+}
+
+void XclImpCellAlign::FillFromXF5( sal_uInt16 nAlign )
+{
+ mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
+ mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
+ mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK );
+ mnOrient = ::extract_value< sal_uInt8 >( nAlign, 8, 2 );
+}
+
+void XclImpCellAlign::FillFromXF8( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
+{
+ mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
+ mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
+ mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK );
+ mnRotation = ::extract_value< sal_uInt8 >( nAlign, 8, 8 ); // new in BIFF8
+ mnIndent = ::extract_value< sal_uInt8 >( nMiscAttrib, 0, 4 ); // new in BIFF8
+ mbShrink = ::get_flag( nMiscAttrib, EXC_XF8_SHRINK ); // new in BIFF8
+ mnTextDir = ::extract_value< sal_uInt8 >( nMiscAttrib, 6, 2 ); // new in BIFF8
+}
+
+void XclImpCellAlign::FillToItemSet( SfxItemSet& rItemSet, const XclImpFont* pFont, bool bSkipPoolDefs ) const
+{
+ // horizontal alignment
+ ScfTools::PutItem( rItemSet, SvxHorJustifyItem( GetScHorAlign(), ATTR_HOR_JUSTIFY ), bSkipPoolDefs );
+ ScfTools::PutItem( rItemSet, SvxJustifyMethodItem( GetScHorJustifyMethod(), ATTR_HOR_JUSTIFY_METHOD ), bSkipPoolDefs );
+
+ // text wrap (#i74508# always if vertical alignment is justified or distributed)
+ bool bLineBreak = mbLineBreak || (mnVerAlign == EXC_XF_VER_JUSTIFY) || (mnVerAlign == EXC_XF_VER_DISTRIB);
+ ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_LINEBREAK, bLineBreak ), bSkipPoolDefs );
+
+ // vertical alignment
+ ScfTools::PutItem( rItemSet, SvxVerJustifyItem( GetScVerAlign(), ATTR_VER_JUSTIFY ), bSkipPoolDefs );
+ ScfTools::PutItem( rItemSet, SvxJustifyMethodItem( GetScVerJustifyMethod(), ATTR_VER_JUSTIFY_METHOD ), bSkipPoolDefs );
+
+ // indent
+ sal_uInt16 nScIndent = mnIndent * 200; // 1 Excel unit == 10 pt == 200 twips
+ ScfTools::PutItem( rItemSet, SfxUInt16Item( ATTR_INDENT, nScIndent ), bSkipPoolDefs );
+
+ // shrink to fit
+ ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_SHRINKTOFIT, mbShrink ), bSkipPoolDefs );
+
+ // text orientation/rotation (BIFF2-BIFF7 sets mnOrient)
+ sal_uInt8 nXclRot = (mnOrient == EXC_ORIENT_NONE) ? mnRotation : XclTools::GetXclRotFromOrient( mnOrient );
+ bool bStacked = (nXclRot == EXC_ROT_STACKED);
+ ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_STACKED, bStacked ), bSkipPoolDefs );
+ // set an angle in the range from -90 to 90 degrees
+ sal_Int32 nAngle = XclTools::GetScRotation( nXclRot, 0 );
+ ScfTools::PutItem( rItemSet, SfxInt32Item( ATTR_ROTATE_VALUE, nAngle ), bSkipPoolDefs );
+ // set "Use asian vertical layout", if cell is stacked and font contains CKJ characters
+ bool bAsianVert = bStacked && pFont && pFont->HasAsianChars();
+ ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_VERTICAL_ASIAN, bAsianVert ), bSkipPoolDefs );
+
+ // CTL text direction
+ ScfTools::PutItem( rItemSet, SvxFrameDirectionItem( GetScFrameDir(), ATTR_WRITINGDIR ), bSkipPoolDefs );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpCellBorder::XclImpCellBorder()
+{
+ SetUsedFlags( false, false );
+}
+
+void XclImpCellBorder::SetUsedFlags( bool bOuterUsed, bool bDiagUsed )
+{
+ mbLeftUsed = mbRightUsed = mbTopUsed = mbBottomUsed = bOuterUsed;
+ mbDiagUsed = bDiagUsed;
+}
+
+void XclImpCellBorder::FillFromXF2( sal_uInt8 nFlags )
+{
+ mnLeftLine = ::get_flagvalue( nFlags, EXC_XF2_LEFTLINE, EXC_LINE_THIN, EXC_LINE_NONE );
+ mnRightLine = ::get_flagvalue( nFlags, EXC_XF2_RIGHTLINE, EXC_LINE_THIN, EXC_LINE_NONE );
+ mnTopLine = ::get_flagvalue( nFlags, EXC_XF2_TOPLINE, EXC_LINE_THIN, EXC_LINE_NONE );
+ mnBottomLine = ::get_flagvalue( nFlags, EXC_XF2_BOTTOMLINE, EXC_LINE_THIN, EXC_LINE_NONE );
+ mnLeftColor = mnRightColor = mnTopColor = mnBottomColor = EXC_COLOR_BIFF2_BLACK;
+ SetUsedFlags( true, false );
+}
+
+void XclImpCellBorder::FillFromXF3( sal_uInt32 nBorder )
+{
+ mnTopLine = ::extract_value< sal_uInt8 >( nBorder, 0, 3 );
+ mnLeftLine = ::extract_value< sal_uInt8 >( nBorder, 8, 3 );
+ mnBottomLine = ::extract_value< sal_uInt8 >( nBorder, 16, 3 );
+ mnRightLine = ::extract_value< sal_uInt8 >( nBorder, 24, 3 );
+ mnTopColor = ::extract_value< sal_uInt16 >( nBorder, 3, 5 );
+ mnLeftColor = ::extract_value< sal_uInt16 >( nBorder, 11, 5 );
+ mnBottomColor = ::extract_value< sal_uInt16 >( nBorder, 19, 5 );
+ mnRightColor = ::extract_value< sal_uInt16 >( nBorder, 27, 5 );
+ SetUsedFlags( true, false );
+}
+
+void XclImpCellBorder::FillFromXF5( sal_uInt32 nBorder, sal_uInt32 nArea )
+{
+ mnTopLine = ::extract_value< sal_uInt8 >( nBorder, 0, 3 );
+ mnLeftLine = ::extract_value< sal_uInt8 >( nBorder, 3, 3 );
+ mnBottomLine = ::extract_value< sal_uInt8 >( nArea, 22, 3 );
+ mnRightLine = ::extract_value< sal_uInt8 >( nBorder, 6, 3 );
+ mnTopColor = ::extract_value< sal_uInt16 >( nBorder, 9, 7 );
+ mnLeftColor = ::extract_value< sal_uInt16 >( nBorder, 16, 7 );
+ mnBottomColor = ::extract_value< sal_uInt16 >( nArea, 25, 7 );
+ mnRightColor = ::extract_value< sal_uInt16 >( nBorder, 23, 7 );
+ SetUsedFlags( true, false );
+}
+
+void XclImpCellBorder::FillFromXF8( sal_uInt32 nBorder1, sal_uInt32 nBorder2 )
+{
+ mnLeftLine = ::extract_value< sal_uInt8 >( nBorder1, 0, 4 );
+ mnRightLine = ::extract_value< sal_uInt8 >( nBorder1, 4, 4 );
+ mnTopLine = ::extract_value< sal_uInt8 >( nBorder1, 8, 4 );
+ mnBottomLine = ::extract_value< sal_uInt8 >( nBorder1, 12, 4 );
+ mnLeftColor = ::extract_value< sal_uInt16 >( nBorder1, 16, 7 );
+ mnRightColor = ::extract_value< sal_uInt16 >( nBorder1, 23, 7 );
+ mnTopColor = ::extract_value< sal_uInt16 >( nBorder2, 0, 7 );
+ mnBottomColor = ::extract_value< sal_uInt16 >( nBorder2, 7, 7 );
+ mbDiagTLtoBR = ::get_flag( nBorder1, EXC_XF_DIAGONAL_TL_TO_BR );
+ mbDiagBLtoTR = ::get_flag( nBorder1, EXC_XF_DIAGONAL_BL_TO_TR );
+ if( mbDiagTLtoBR || mbDiagBLtoTR )
+ {
+ mnDiagLine = ::extract_value< sal_uInt8 >( nBorder2, 21, 4 );
+ mnDiagColor = ::extract_value< sal_uInt16 >( nBorder2, 14, 7 );
+ }
+ SetUsedFlags( true, true );
+}
+
+void XclImpCellBorder::FillFromCF8( sal_uInt16 nLineStyle, sal_uInt32 nLineColor, sal_uInt32 nFlags )
+{
+ mnLeftLine = ::extract_value< sal_uInt8 >( nLineStyle, 0, 4 );
+ mnRightLine = ::extract_value< sal_uInt8 >( nLineStyle, 4, 4 );
+ mnTopLine = ::extract_value< sal_uInt8 >( nLineStyle, 8, 4 );
+ mnBottomLine = ::extract_value< sal_uInt8 >( nLineStyle, 12, 4 );
+ mnLeftColor = ::extract_value< sal_uInt16 >( nLineColor, 0, 7 );
+ mnRightColor = ::extract_value< sal_uInt16 >( nLineColor, 7, 7 );
+ mnTopColor = ::extract_value< sal_uInt16 >( nLineColor, 16, 7 );
+ mnBottomColor = ::extract_value< sal_uInt16 >( nLineColor, 23, 7 );
+ mbLeftUsed = !::get_flag( nFlags, EXC_CF_BORDER_LEFT );
+ mbRightUsed = !::get_flag( nFlags, EXC_CF_BORDER_RIGHT );
+ mbTopUsed = !::get_flag( nFlags, EXC_CF_BORDER_TOP );
+ mbBottomUsed = !::get_flag( nFlags, EXC_CF_BORDER_BOTTOM );
+ mbDiagUsed = false;
+}
+
+bool XclImpCellBorder::HasAnyOuterBorder() const
+{
+ return
+ (mbLeftUsed && (mnLeftLine != EXC_LINE_NONE)) ||
+ (mbRightUsed && (mnRightLine != EXC_LINE_NONE)) ||
+ (mbTopUsed && (mnTopLine != EXC_LINE_NONE)) ||
+ (mbBottomUsed && (mnBottomLine != EXC_LINE_NONE));
+}
+
+namespace {
+
+// TODO: These values are approximate; we should probably tweak these values
+// further to better match Excel's border thickness.
+#define XLS_LINE_WIDTH_HAIR 1
+#define XLS_LINE_WIDTH_THIN 6
+#define XLS_LINE_WIDTH_MEDIUM 18
+#define XLS_LINE_WIDTH_THICK 24
+
+/** Converts the passed line style to a ::editeng::SvxBorderLine, or returns false, if style is "no line". */
+bool lclConvertBorderLine( ::editeng::SvxBorderLine& rLine, const XclImpPalette& rPalette, sal_uInt8 nXclLine, sal_uInt16 nXclColor )
+{
+ static const sal_uInt16 ppnLineParam[][ 4 ] =
+ {
+ // outer width, type
+ { 0, ::editeng::SOLID }, // 0 = none
+ { XLS_LINE_WIDTH_THIN, ::editeng::SOLID }, // 1 = thin
+ { XLS_LINE_WIDTH_MEDIUM, ::editeng::SOLID }, // 2 = medium
+ { XLS_LINE_WIDTH_THIN, ::editeng::DASHED }, // 3 = dashed
+ { XLS_LINE_WIDTH_THIN, ::editeng::DOTTED }, // 4 = dotted
+ { XLS_LINE_WIDTH_THICK, ::editeng::SOLID }, // 5 = thick
+ { XLS_LINE_WIDTH_THIN, ::editeng::DOUBLE }, // 6 = double
+ { XLS_LINE_WIDTH_HAIR, ::editeng::SOLID }, // 7 = hair
+ { XLS_LINE_WIDTH_MEDIUM, ::editeng::DASHED }, // 8 = med dash
+ { XLS_LINE_WIDTH_THIN, ::editeng::SOLID }, // 9 = thin dashdot
+ { XLS_LINE_WIDTH_MEDIUM, ::editeng::SOLID }, // A = med dashdot
+ { XLS_LINE_WIDTH_THIN, ::editeng::SOLID }, // B = thin dashdotdot
+ { XLS_LINE_WIDTH_MEDIUM, ::editeng::SOLID }, // C = med dashdotdot
+ { XLS_LINE_WIDTH_MEDIUM, ::editeng::SOLID } // D = med slant dashdot
+ };
+
+ if( nXclLine == EXC_LINE_NONE )
+ return false;
+ if( nXclLine >= SAL_N_ELEMENTS( ppnLineParam ) )
+ nXclLine = EXC_LINE_THIN;
+
+ rLine.SetColor( rPalette.GetColor( nXclColor ) );
+ rLine.SetWidth( ppnLineParam[ nXclLine ][ 0 ] );
+ rLine.SetStyle( (::editeng::SvxBorderStyle)ppnLineParam[ nXclLine ][ 1 ] );
+ return true;
+}
+
+} // namespace
+
+void XclImpCellBorder::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
+{
+ if( mbLeftUsed || mbRightUsed || mbTopUsed || mbBottomUsed )
+ {
+ SvxBoxItem aBoxItem( ATTR_BORDER );
+ ::editeng::SvxBorderLine aLine;
+ if( mbLeftUsed && lclConvertBorderLine( aLine, rPalette, mnLeftLine, mnLeftColor ) )
+ aBoxItem.SetLine( &aLine, BOX_LINE_LEFT );
+ if( mbRightUsed && lclConvertBorderLine( aLine, rPalette, mnRightLine, mnRightColor ) )
+ aBoxItem.SetLine( &aLine, BOX_LINE_RIGHT );
+ if( mbTopUsed && lclConvertBorderLine( aLine, rPalette, mnTopLine, mnTopColor ) )
+ aBoxItem.SetLine( &aLine, BOX_LINE_TOP );
+ if( mbBottomUsed && lclConvertBorderLine( aLine, rPalette, mnBottomLine, mnBottomColor ) )
+ aBoxItem.SetLine( &aLine, BOX_LINE_BOTTOM );
+ ScfTools::PutItem( rItemSet, aBoxItem, bSkipPoolDefs );
+ }
+ if( mbDiagUsed )
+ {
+ SvxLineItem aTLBRItem( ATTR_BORDER_TLBR );
+ SvxLineItem aBLTRItem( ATTR_BORDER_BLTR );
+ ::editeng::SvxBorderLine aLine;
+ if( lclConvertBorderLine( aLine, rPalette, mnDiagLine, mnDiagColor ) )
+ {
+ if( mbDiagTLtoBR )
+ aTLBRItem.SetLine( &aLine );
+ if( mbDiagBLtoTR )
+ aBLTRItem.SetLine( &aLine );
+ }
+ ScfTools::PutItem( rItemSet, aTLBRItem, bSkipPoolDefs );
+ ScfTools::PutItem( rItemSet, aBLTRItem, bSkipPoolDefs );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpCellArea::XclImpCellArea()
+{
+ SetUsedFlags( false );
+}
+
+void XclImpCellArea::SetUsedFlags( bool bUsed )
+{
+ mbForeUsed = mbBackUsed = mbPattUsed = bUsed;
+}
+
+void XclImpCellArea::FillFromXF2( sal_uInt8 nFlags )
+{
+ mnPattern = ::get_flagvalue( nFlags, EXC_XF2_BACKGROUND, EXC_PATT_12_5_PERC, EXC_PATT_NONE );
+ mnForeColor = EXC_COLOR_BIFF2_BLACK;
+ mnBackColor = EXC_COLOR_BIFF2_WHITE;
+ SetUsedFlags( true );
+}
+
+void XclImpCellArea::FillFromXF3( sal_uInt16 nArea )
+{
+ mnPattern = ::extract_value< sal_uInt8 >( nArea, 0, 6 );
+ mnForeColor = ::extract_value< sal_uInt16 >( nArea, 6, 5 );
+ mnBackColor = ::extract_value< sal_uInt16 >( nArea, 11, 5 );
+ SetUsedFlags( true );
+}
+
+void XclImpCellArea::FillFromXF5( sal_uInt32 nArea )
+{
+ mnPattern = ::extract_value< sal_uInt8 >( nArea, 16, 6 );
+ mnForeColor = ::extract_value< sal_uInt16 >( nArea, 0, 7 );
+ mnBackColor = ::extract_value< sal_uInt16 >( nArea, 7, 7 );
+ SetUsedFlags( true );
+}
+
+void XclImpCellArea::FillFromXF8( sal_uInt32 nBorder2, sal_uInt16 nArea )
+{
+ mnPattern = ::extract_value< sal_uInt8 >( nBorder2, 26, 6 );
+ mnForeColor = ::extract_value< sal_uInt16 >( nArea, 0, 7 );
+ mnBackColor = ::extract_value< sal_uInt16 >( nArea, 7, 7 );
+ SetUsedFlags( true );
+}
+
+void XclImpCellArea::FillFromCF8( sal_uInt16 nPattern, sal_uInt16 nColor, sal_uInt32 nFlags )
+{
+ mnForeColor = ::extract_value< sal_uInt16 >( nColor, 0, 7 );
+ mnBackColor = ::extract_value< sal_uInt16 >( nColor, 7, 7 );
+ mnPattern = ::extract_value< sal_uInt8 >( nPattern, 10, 6 );
+ mbForeUsed = !::get_flag( nFlags, EXC_CF_AREA_FGCOLOR );
+ mbBackUsed = !::get_flag( nFlags, EXC_CF_AREA_BGCOLOR );
+ mbPattUsed = !::get_flag( nFlags, EXC_CF_AREA_PATTERN );
+
+ if( mbBackUsed && (!mbPattUsed || (mnPattern == EXC_PATT_SOLID)) )
+ {
+ mnForeColor = mnBackColor;
+ mnPattern = EXC_PATT_SOLID;
+ mbForeUsed = mbPattUsed = true;
+ }
+ else if( !mbBackUsed && mbPattUsed && (mnPattern == EXC_PATT_SOLID) )
+ {
+ mbPattUsed = false;
+ }
+}
+
+void XclImpCellArea::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
+{
+ if( mbPattUsed ) // colors may be both unused in cond. formats
+ {
+ SvxBrushItem aBrushItem( ATTR_BACKGROUND );
+
+ // do not use IsTransparent() - old Calc filter writes tranparency with different color indexes
+ if( mnPattern == EXC_PATT_NONE )
+ {
+ aBrushItem.SetColor( Color( COL_TRANSPARENT ) );
+ }
+ else
+ {
+ Color aFore( rPalette.GetColor( mbForeUsed ? mnForeColor : EXC_COLOR_WINDOWTEXT ) );
+ Color aBack( rPalette.GetColor( mbBackUsed ? mnBackColor : EXC_COLOR_WINDOWBACK ) );
+ aBrushItem.SetColor( XclTools::GetPatternColor( aFore, aBack, mnPattern ) );
+ }
+
+ ScfTools::PutItem( rItemSet, aBrushItem, bSkipPoolDefs );
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+
+XclImpXF::XclImpXF( const XclImpRoot& rRoot ) :
+ XclXFBase( true ), // default is cell XF
+ XclImpRoot( rRoot ),
+ mpStyleSheet( 0 ),
+ mnXclNumFmt( 0 ),
+ mnXclFont( 0 )
+{
+}
+
+XclImpXF::~XclImpXF()
+{
+}
+
+void XclImpXF::ReadXF2( XclImpStream& rStrm )
+{
+ sal_uInt8 nReadFont, nReadNumFmt, nFlags;
+ rStrm >> nReadFont;
+ rStrm.Ignore( 1 );
+ rStrm >> nReadNumFmt >> nFlags;
+
+ // XF type always cell, no parent, used flags always true
+ SetAllUsedFlags( true );
+
+ // attributes
+ maProtection.FillFromXF2( nReadNumFmt );
+ mnXclFont = nReadFont;
+ mnXclNumFmt = nReadNumFmt & EXC_XF2_VALFMT_MASK;
+ maAlignment.FillFromXF2( nFlags );
+ maBorder.FillFromXF2( nFlags );
+ maArea.FillFromXF2( nFlags );
+}
+
+void XclImpXF::ReadXF3( XclImpStream& rStrm )
+{
+ sal_uInt32 nBorder;
+ sal_uInt16 nTypeProt, nAlign, nArea;
+ sal_uInt8 nReadFont, nReadNumFmt;
+ rStrm >> nReadFont >> nReadNumFmt >> nTypeProt >> nAlign >> nArea >> nBorder;
+
+ // XF type/parent, attribute used flags
+ mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE ); // new in BIFF3
+ mnParent = ::extract_value< sal_uInt16 >( nAlign, 4, 12 ); // new in BIFF3
+ SetUsedFlags( ::extract_value< sal_uInt8 >( nTypeProt, 10, 6 ) );
+
+ // attributes
+ maProtection.FillFromXF3( nTypeProt );
+ mnXclFont = nReadFont;
+ mnXclNumFmt = nReadNumFmt;
+ maAlignment.FillFromXF3( nAlign );
+ maBorder.FillFromXF3( nBorder );
+ maArea.FillFromXF3( nArea ); // new in BIFF3
+}
+
+void XclImpXF::ReadXF4( XclImpStream& rStrm )
+{
+ sal_uInt32 nBorder;
+ sal_uInt16 nTypeProt, nAlign, nArea;
+ sal_uInt8 nReadFont, nReadNumFmt;
+ rStrm >> nReadFont >> nReadNumFmt >> nTypeProt >> nAlign >> nArea >> nBorder;
+
+ // XF type/parent, attribute used flags
+ mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
+ mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
+ SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) );
+
+ // attributes
+ maProtection.FillFromXF3( nTypeProt );
+ mnXclFont = nReadFont;
+ mnXclNumFmt = nReadNumFmt;
+ maAlignment.FillFromXF4( nAlign );
+ maBorder.FillFromXF3( nBorder );
+ maArea.FillFromXF3( nArea );
+}
+
+void XclImpXF::ReadXF5( XclImpStream& rStrm )
+{
+ sal_uInt32 nArea, nBorder;
+ sal_uInt16 nTypeProt, nAlign;
+ rStrm >> mnXclFont >> mnXclNumFmt >> nTypeProt >> nAlign >> nArea >> nBorder;
+
+ // XF type/parent, attribute used flags
+ mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
+ mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
+ SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) );
+
+ // attributes
+ maProtection.FillFromXF3( nTypeProt );
+ maAlignment.FillFromXF5( nAlign );
+ maBorder.FillFromXF5( nBorder, nArea );
+ maArea.FillFromXF5( nArea );
+}
+
+void XclImpXF::ReadXF8( XclImpStream& rStrm )
+{
+ sal_uInt32 nBorder1, nBorder2;
+ sal_uInt16 nTypeProt, nAlign, nMiscAttrib, nArea;
+ rStrm >> mnXclFont >> mnXclNumFmt >> nTypeProt >> nAlign >> nMiscAttrib >> nBorder1 >> nBorder2 >> nArea;
+
+ // XF type/parent, attribute used flags
+ mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
+ mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
+ SetUsedFlags( ::extract_value< sal_uInt8 >( nMiscAttrib, 10, 6 ) );
+
+ // attributes
+ maProtection.FillFromXF3( nTypeProt );
+ maAlignment.FillFromXF8( nAlign, nMiscAttrib );
+ maBorder.FillFromXF8( nBorder1, nBorder2 );
+ maArea.FillFromXF8( nBorder2, nArea );
+}
+
+void XclImpXF::ReadXF( XclImpStream& rStrm )
+{
+ switch( GetBiff() )
+ {
+ case EXC_BIFF2: ReadXF2( rStrm ); break;
+ case EXC_BIFF3: ReadXF3( rStrm ); break;
+ case EXC_BIFF4: ReadXF4( rStrm ); break;
+ case EXC_BIFF5: ReadXF5( rStrm ); break;
+ case EXC_BIFF8: ReadXF8( rStrm ); break;
+ default: DBG_ERROR_BIFF();
+ }
+}
+
+const ScPatternAttr& XclImpXF::CreatePattern( bool bSkipPoolDefs )
+{
+ if( mpPattern.get() )
+ return *mpPattern;
+
+ // create new pattern attribute set
+ mpPattern.reset( new ScPatternAttr( GetDoc().GetPool() ) );
+ SfxItemSet& rItemSet = mpPattern->GetItemSet();
+ XclImpXF* pParentXF = IsCellXF() ? GetXFBuffer().GetXF( mnParent ) : 0;
+
+ // parent cell style
+ if( IsCellXF() && !mpStyleSheet )
+ {
+ mpStyleSheet = GetXFBuffer().CreateStyleSheet( mnParent );
+
+ /* Enables mb***Used flags, if the formatting attributes differ from
+ the passed XF record. In cell XFs Excel uses the cell attributes,
+ if they differ from the parent style XF.
+ ...or if the respective flag is not set in parent style XF. */
+ if( pParentXF )
+ {
+ if( !mbProtUsed )
+ mbProtUsed = !pParentXF->mbProtUsed || !(maProtection == pParentXF->maProtection);
+ if( !mbFontUsed )
+ mbFontUsed = !pParentXF->mbFontUsed || (mnXclFont != pParentXF->mnXclFont);
+ if( !mbFmtUsed )
+ mbFmtUsed = !pParentXF->mbFmtUsed || (mnXclNumFmt != pParentXF->mnXclNumFmt);
+ if( !mbAlignUsed )
+ mbAlignUsed = !pParentXF->mbAlignUsed || !(maAlignment == pParentXF->maAlignment);
+ if( !mbBorderUsed )
+ mbBorderUsed = !pParentXF->mbBorderUsed || !(maBorder == pParentXF->maBorder);
+ if( !mbAreaUsed )
+ mbAreaUsed = !pParentXF->mbAreaUsed || !(maArea == pParentXF->maArea);
+ }
+ }
+
+ // cell protection
+ if( mbProtUsed )
+ maProtection.FillToItemSet( rItemSet, bSkipPoolDefs );
+
+ // font
+ if( mbFontUsed )
+ GetFontBuffer().FillToItemSet( rItemSet, EXC_FONTITEM_CELL, mnXclFont, bSkipPoolDefs );
+
+ // value format
+ if( mbFmtUsed )
+ {
+ GetNumFmtBuffer().FillToItemSet( rItemSet, mnXclNumFmt, bSkipPoolDefs );
+ // Trace occurrences of Windows date formats
+ GetTracer().TraceDates( mnXclNumFmt );
+ }
+
+ // alignment
+ if( mbAlignUsed )
+ maAlignment.FillToItemSet( rItemSet, GetFontBuffer().GetFont( mnXclFont ), bSkipPoolDefs );
+
+ // border
+ if( mbBorderUsed )
+ {
+ maBorder.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs );
+ GetTracer().TraceBorderLineStyle(maBorder.mnLeftLine > EXC_LINE_HAIR ||
+ maBorder.mnRightLine > EXC_LINE_HAIR || maBorder.mnTopLine > EXC_LINE_HAIR ||
+ maBorder.mnBottomLine > EXC_LINE_HAIR );
+ }
+
+ // area
+ if( mbAreaUsed )
+ {
+ maArea.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs );
+ GetTracer().TraceFillPattern(maArea.mnPattern != EXC_PATT_NONE &&
+ maArea.mnPattern != EXC_PATT_SOLID);
+ }
+
+ /* #i38709# Decide which rotation reference mode to use. If any outer
+ border line of the cell is set (either explicitly or via cell style),
+ and the cell contents are rotated, set rotation reference to bottom of
+ cell. This causes the borders to be painted rotated with the text. */
+ if( mbAlignUsed || mbBorderUsed )
+ {
+ SvxRotateMode eRotateMode = SVX_ROTATE_MODE_STANDARD;
+ const XclImpCellAlign* pAlign = mbAlignUsed ? &maAlignment : (pParentXF ? &pParentXF->maAlignment : 0);
+ const XclImpCellBorder* pBorder = mbBorderUsed ? &maBorder : (pParentXF ? &pParentXF->maBorder : 0);
+ if( pAlign && pBorder && (0 < pAlign->mnRotation) && (pAlign->mnRotation <= 180) && pBorder->HasAnyOuterBorder() )
+ eRotateMode = SVX_ROTATE_MODE_BOTTOM;
+ ScfTools::PutItem( rItemSet, SvxRotateModeItem( eRotateMode, ATTR_ROTATE_MODE ), bSkipPoolDefs );
+ }
+
+ // Excel's cell margins are different from Calc's default margins.
+ SvxMarginItem aItem(40, 40, 40, 40, ATTR_MARGIN);
+ ScfTools::PutItem(rItemSet, aItem, bSkipPoolDefs);
+
+ return *mpPattern;
+}
+
+void XclImpXF::ApplyPatternToAttrList(
+ list<ScAttrEntry>& rAttrs, SCROW nRow1, SCROW nRow2, sal_uInt32 nForceScNumFmt)
+{
+ // force creation of cell style and hard formatting, do it here to have mpStyleSheet
+ const ScPatternAttr& rOrigPat = CreatePattern();
+ ScPatternAttr aNewPat = rOrigPat;
+ const ScPatternAttr* pPat = NULL;
+
+ // insert into document
+ ScDocument& rDoc = GetDoc();
+
+ if (IsCellXF() && mpStyleSheet)
+ {
+ // Style sheet exists. Create a copy of the original pattern.
+ aNewPat.SetStyleSheet(mpStyleSheet);
+ pPat = &aNewPat;
+ }
+
+ if (HasUsedFlags())
+ {
+ if (!pPat)
+ pPat = &aNewPat;
+
+ SfxItemPoolCache aCache(rDoc.GetPool(), &rOrigPat.GetItemSet());
+ pPat = static_cast<const ScPatternAttr*>(&aCache.ApplyTo(*pPat, true));
+ }
+
+ if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ if (!pPat)
+ pPat = &aNewPat;
+
+ ScPatternAttr aNumPat(GetDoc().GetPool());
+ GetNumFmtBuffer().FillScFmtToItemSet(aNumPat.GetItemSet(), nForceScNumFmt);
+ SfxItemPoolCache aCache(rDoc.GetPool(), &aNumPat.GetItemSet());
+ pPat = static_cast<const ScPatternAttr*>(&aCache.ApplyTo(*pPat, true));
+ }
+
+ // Make sure we skip unnamed styles.
+ if (pPat && pPat->GetStyleName())
+ {
+ // Check for a gap between the last entry and this one.
+ bool bHasGap = false;
+ if (rAttrs.empty() && nRow1 > 0)
+ // First attribute range doesn't start at row 0.
+ bHasGap = true;
+
+ if (!rAttrs.empty() && rAttrs.back().nRow + 1 < nRow1)
+ bHasGap = true;
+
+ if (bHasGap)
+ {
+ // Fill this gap with the default pattern.
+ ScAttrEntry aEntry;
+ aEntry.nRow = nRow1 - 1;
+ aEntry.pPattern = rDoc.GetDefPattern();
+ rAttrs.push_back(aEntry);
+ }
+
+ ScAttrEntry aEntry;
+ aEntry.nRow = nRow2;
+ aEntry.pPattern = static_cast<const ScPatternAttr*>(&rDoc.GetPool()->Put(*pPat));
+ rAttrs.push_back(aEntry);
+ }
+}
+
+void XclImpXF::SetUsedFlags( sal_uInt8 nUsedFlags )
+{
+ /* Notes about finding the mb***Used flags:
+ - In cell XFs a *set* bit means a used attribute.
+ - In style XFs a *cleared* bit means a used attribute.
+ The mb***Used members always store true, if the attribute is used.
+ The "mbCellXF == ::get_flag(...)" construct evaluates to true in
+ both mentioned cases: cell XF and set bit; or style XF and cleared bit.
+ */
+ mbProtUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_PROT ));
+ mbFontUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_FONT ));
+ mbFmtUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_VALFMT ));
+ mbAlignUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_ALIGN ));
+ mbBorderUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_BORDER ));
+ mbAreaUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_AREA ));
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpStyle::XclImpStyle( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ mnXfId( EXC_XF_NOTFOUND ),
+ mnBuiltinId( EXC_STYLE_USERDEF ),
+ mnLevel( EXC_STYLE_NOLEVEL ),
+ mbBuiltin( false ),
+ mbCustom( false ),
+ mbHidden( false ),
+ mpStyleSheet( 0 )
+{
+}
+
+void XclImpStyle::ReadStyle( XclImpStream& rStrm )
+{
+ DBG_ASSERT_BIFF( GetBiff() >= EXC_BIFF3 );
+
+ sal_uInt16 nXFIndex;
+ rStrm >> nXFIndex;
+ mnXfId = nXFIndex & EXC_STYLE_XFMASK;
+ mbBuiltin = ::get_flag( nXFIndex, EXC_STYLE_BUILTIN );
+
+ if( mbBuiltin )
+ {
+ rStrm >> mnBuiltinId >> mnLevel;
+ }
+ else
+ {
+ maName = (GetBiff() <= EXC_BIFF5) ? rStrm.ReadByteString( false ) : rStrm.ReadUniString();
+ // #i103281# check if this is a new built-in style introduced in XL2007
+ if( (GetBiff() == EXC_BIFF8) && (rStrm.GetNextRecId() == EXC_ID_STYLEEXT) && rStrm.StartNextRecord() )
+ {
+ sal_uInt8 nExtFlags;
+ rStrm.Ignore( 12 );
+ rStrm >> nExtFlags;
+ mbBuiltin = ::get_flag( nExtFlags, EXC_STYLEEXT_BUILTIN );
+ mbCustom = ::get_flag( nExtFlags, EXC_STYLEEXT_CUSTOM );
+ mbHidden = ::get_flag( nExtFlags, EXC_STYLEEXT_HIDDEN );
+ if( mbBuiltin )
+ {
+ rStrm.Ignore( 1 ); // category
+ rStrm >> mnBuiltinId >> mnLevel;
+ }
+ }
+ }
+}
+
+ScStyleSheet* XclImpStyle::CreateStyleSheet()
+{
+ // #i1624# #i1768# ignore unnamed user styles
+ if( !mpStyleSheet && (maFinalName.Len() > 0) )
+ {
+ bool bCreatePattern = false;
+ XclImpXF* pXF = GetXFBuffer().GetXF( mnXfId );
+
+ bool bDefStyle = mbBuiltin && (mnBuiltinId == EXC_STYLE_NORMAL);
+ if( bDefStyle )
+ {
+ // set all flags to true to get all items in XclImpXF::CreatePattern()
+ if( pXF ) pXF->SetAllUsedFlags( true );
+ // use existing "Default" style sheet
+ mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find(
+ ScGlobal::GetRscString( STR_STYLENAME_STANDARD ), SFX_STYLE_FAMILY_PARA ) );
+ DBG_ASSERT( mpStyleSheet, "XclImpStyle::CreateStyleSheet - Default style not found" );
+ bCreatePattern = true;
+ }
+ else
+ {
+ /* #i103281# do not create another style sheet of the same name,
+ if it exists already. This is needed to prevent that styles
+ pasted from clipboard get duplicated over and over. */
+ mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find( maFinalName, SFX_STYLE_FAMILY_PARA ) );
+ if( !mpStyleSheet )
+ {
+ mpStyleSheet = &static_cast< ScStyleSheet& >( GetStyleSheetPool().Make( maFinalName, SFX_STYLE_FAMILY_PARA, SFXSTYLEBIT_USERDEF ) );
+ bCreatePattern = true;
+ }
+ }
+
+ // bDefStyle==true omits default pool items in CreatePattern()
+ if( bCreatePattern && mpStyleSheet && pXF )
+ mpStyleSheet->GetItemSet().Put( pXF->CreatePattern( bDefStyle ).GetItemSet() );
+ }
+ return mpStyleSheet;
+}
+
+void XclImpStyle::CreateUserStyle( const String& rFinalName )
+{
+ maFinalName = rFinalName;
+ if( !IsBuiltin() || mbCustom )
+ CreateStyleSheet();
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpXFBuffer::XclImpXFBuffer( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpXFBuffer::Initialize()
+{
+ maXFList.clear();
+ maBuiltinStyles.clear();
+ maUserStyles.clear();
+ maStylesByXf.clear();
+}
+
+void XclImpXFBuffer::ReadXF( XclImpStream& rStrm )
+{
+ XclImpXF* pXF = new XclImpXF( GetRoot() );
+ pXF->ReadXF( rStrm );
+ maXFList.push_back( pXF );
+}
+
+void XclImpXFBuffer::ReadStyle( XclImpStream& rStrm )
+{
+ XclImpStyle* pStyle = new XclImpStyle( GetRoot() );
+ pStyle->ReadStyle( rStrm );
+ (pStyle->IsBuiltin() ? maBuiltinStyles : maUserStyles).push_back( pStyle );
+ DBG_ASSERT( maStylesByXf.count( pStyle->GetXfId() ) == 0, "XclImpXFBuffer::ReadStyle - multiple styles with equal XF identifier" );
+ maStylesByXf[ pStyle->GetXfId() ] = pStyle;
+}
+
+sal_uInt16 XclImpXFBuffer::GetFontIndex( sal_uInt16 nXFIndex ) const
+{
+ const XclImpXF* pXF = GetXF( nXFIndex );
+ return pXF ? pXF->GetFontIndex() : EXC_FONT_NOTFOUND;
+}
+
+const XclImpFont* XclImpXFBuffer::GetFont( sal_uInt16 nXFIndex ) const
+{
+ return GetFontBuffer().GetFont( GetFontIndex( nXFIndex ) );
+}
+
+namespace {
+
+/** Functor for case-insensitive string comparison, usable in maps etc. */
+struct IgnoreCaseCompare
+{
+ inline bool operator()( const String& rName1, const String& rName2 ) const
+ { return rName1.CompareIgnoreCaseToAscii( rName2 ) == COMPARE_LESS; }
+};
+
+} // namespace
+
+void XclImpXFBuffer::CreateUserStyles()
+{
+ // calculate final names of all styles
+ typedef ::std::map< String, XclImpStyle*, IgnoreCaseCompare > CellStyleNameMap;
+ typedef ::std::vector< XclImpStyle* > XclImpStyleVector;
+
+ CellStyleNameMap aCellStyles;
+ XclImpStyleVector aConflictNameStyles;
+
+ /* First, reserve style names that are built-in in Calc. This causes that
+ imported cell styles get different unused names and thus do not try to
+ overwrite these built-in styles. For BIFF4 workbooks (which contain a
+ separate list of cell styles per sheet), reserve all existing styles if
+ current sheet is not the first sheet (this styles buffer will be
+ initialized again for every new sheet). This will create unique names
+ for styles in different sheets with the same name. Assuming that the
+ BIFF4W import filter is never used to import from clipboard... */
+ bool bReserveAll = (GetBiff() == EXC_BIFF4) && (GetCurrScTab() > 0);
+ SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SFX_STYLE_FAMILY_PARA );
+ String aStandardName = ScGlobal::GetRscString( STR_STYLENAME_STANDARD );
+ for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
+ if( (pStyleSheet->GetName() != aStandardName) && (bReserveAll || !pStyleSheet->IsUserDefined()) )
+ if( aCellStyles.count( pStyleSheet->GetName() ) == 0 )
+ aCellStyles[ pStyleSheet->GetName() ] = 0;
+
+ /* Calculate names of built-in styles. Store styles with reserved names
+ in the aConflictNameStyles list. */
+ for( XclImpStyleList::iterator itStyle = maBuiltinStyles.begin(); itStyle != maBuiltinStyles.end(); ++itStyle )
+ {
+ String aStyleName = XclTools::GetBuiltInStyleName( itStyle->GetBuiltinId(), itStyle->GetName(), itStyle->GetLevel() );
+ DBG_ASSERT( bReserveAll || (aCellStyles.count( aStyleName ) == 0),
+ "XclImpXFBuffer::CreateUserStyles - multiple styles with equal built-in identifier" );
+ if( aCellStyles.count( aStyleName ) > 0 )
+ aConflictNameStyles.push_back( &(*itStyle) );
+ else
+ aCellStyles[ aStyleName ] = &(*itStyle);
+ }
+
+ /* Calculate names of user defined styles. Store styles with reserved
+ names in the aConflictNameStyles list. */
+ for( XclImpStyleList::iterator itStyle = maUserStyles.begin(); itStyle != maUserStyles.end(); ++itStyle )
+ {
+ // #i1624# #i1768# ignore unnamed user styles
+ if( itStyle->GetName().Len() > 0 )
+ {
+ if( aCellStyles.count( itStyle->GetName() ) > 0 )
+ aConflictNameStyles.push_back( &(*itStyle) );
+ else
+ aCellStyles[ itStyle->GetName() ] = &(*itStyle);
+ }
+ }
+
+ // find unused names for all styles with conflicting names
+ for( XclImpStyleVector::iterator aIt = aConflictNameStyles.begin(), aEnd = aConflictNameStyles.end(); aIt != aEnd; ++aIt )
+ {
+ XclImpStyle* pStyle = *aIt;
+ String aUnusedName;
+ sal_Int32 nIndex = 0;
+ do
+ {
+ aUnusedName.Assign( pStyle->GetName() ).Append( ' ' ).Append( String::CreateFromInt32( ++nIndex ) );
+ }
+ while( aCellStyles.count( aUnusedName ) > 0 );
+ aCellStyles[ aUnusedName ] = pStyle;
+ }
+
+ // set final names and create user-defined and modified built-in cell styles
+ for( CellStyleNameMap::iterator aIt = aCellStyles.begin(), aEnd = aCellStyles.end(); aIt != aEnd; ++aIt )
+ if( aIt->second )
+ aIt->second->CreateUserStyle( aIt->first );
+}
+
+ScStyleSheet* XclImpXFBuffer::CreateStyleSheet( sal_uInt16 nXFIndex )
+{
+ XclImpStyleMap::iterator aIt = maStylesByXf.find( nXFIndex );
+ return (aIt == maStylesByXf.end()) ? 0 : aIt->second->CreateStyleSheet();
+}
+
+// Buffer for XF indexes in cells =============================================
+
+IMPL_FIXEDMEMPOOL_NEWDEL( XclImpXFRange, 100, 500 )
+
+bool XclImpXFRange::Expand( SCROW nScRow, const XclImpXFIndex& rXFIndex )
+{
+ if( maXFIndex != rXFIndex )
+ return false;
+
+ if( mnScRow2 + 1 == nScRow )
+ {
+ ++mnScRow2;
+ return true;
+ }
+ if( mnScRow1 > 0 && (mnScRow1 - 1 == nScRow) )
+ {
+ --mnScRow1;
+ return true;
+ }
+
+ return false;
+}
+
+bool XclImpXFRange::Expand( const XclImpXFRange& rNextRange )
+{
+ DBG_ASSERT( mnScRow2 < rNextRange.mnScRow1, "XclImpXFRange::Expand - rows out of order" );
+ if( (maXFIndex == rNextRange.maXFIndex) && (mnScRow2 + 1 == rNextRange.mnScRow1) )
+ {
+ mnScRow2 = rNextRange.mnScRow2;
+ return true;
+ }
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpXFRangeColumn::SetDefaultXF( const XclImpXFIndex& rXFIndex )
+{
+ // List should be empty when inserting the default column format.
+ // Later explicit SetXF() calls will break up this range.
+ DBG_ASSERT( maIndexList.empty(), "XclImpXFRangeColumn::SetDefaultXF - Setting Default Column XF is not empty" );
+
+ // insert a complete row range with one insert.
+ maIndexList.push_back( new XclImpXFRange( 0, MAXROW, rXFIndex ) );
+}
+
+// ----------------------------------------------------------------------------
+
+void XclImpXFRangeColumn::SetXF( SCROW nScRow, const XclImpXFIndex& rXFIndex )
+{
+ XclImpXFRange* pPrevRange;
+ XclImpXFRange* pNextRange;
+ sal_uLong nNextIndex;
+
+ Find( pPrevRange, pNextRange, nNextIndex, nScRow );
+
+ // previous range:
+ // try to overwrite XF (if row is contained in) or try to expand range
+ if( pPrevRange )
+ {
+ if( pPrevRange->Contains( nScRow ) ) // overwrite old XF
+ {
+ if( rXFIndex == pPrevRange->maXFIndex )
+ return;
+
+ SCROW nFirstScRow = pPrevRange->mnScRow1;
+ SCROW nLastScRow = pPrevRange->mnScRow2;
+ sal_uLong nIndex = nNextIndex - 1;
+ XclImpXFRange* pThisRange = pPrevRange;
+ pPrevRange = (nIndex > 0 && nIndex <= maIndexList.size()) ? &(maIndexList[ nIndex - 1 ]) : 0;
+
+ if( nFirstScRow == nLastScRow ) // replace solely XF
+ {
+ pThisRange->maXFIndex = rXFIndex;
+ TryConcatPrev( nNextIndex ); // try to concat. next with this
+ TryConcatPrev( nIndex ); // try to concat. this with previous
+ }
+ else if( nFirstScRow == nScRow ) // replace first XF
+ {
+ ++(pThisRange->mnScRow1);
+ // try to concatenate with previous of this
+ if( !pPrevRange || !pPrevRange->Expand( nScRow, rXFIndex ) )
+ Insert( new XclImpXFRange( nScRow, rXFIndex ), nIndex );
+ }
+ else if( nLastScRow == nScRow ) // replace last XF
+ {
+ --(pThisRange->mnScRow2);
+ if( !pNextRange || !pNextRange->Expand( nScRow, rXFIndex ) )
+ Insert( new XclImpXFRange( nScRow, rXFIndex ), nNextIndex );
+ }
+ else // insert in the middle of the range
+ {
+ pThisRange->mnScRow1 = nScRow + 1;
+ // List::Insert() moves entries towards end of list, so insert twice at nIndex
+ Insert( new XclImpXFRange( nScRow, rXFIndex ), nIndex );
+ Insert( new XclImpXFRange( nFirstScRow, nScRow - 1, pThisRange->maXFIndex ), nIndex );
+ }
+ return;
+ }
+ else if( pPrevRange->Expand( nScRow, rXFIndex ) ) // try to expand
+ {
+ TryConcatPrev( nNextIndex ); // try to concatenate next with expanded
+ return;
+ }
+ }
+
+ // try to expand next range
+ if( pNextRange && pNextRange->Expand( nScRow, rXFIndex ) )
+ return;
+
+ // create new range
+ Insert( new XclImpXFRange( nScRow, rXFIndex ), nNextIndex );
+}
+
+void XclImpXFRangeColumn::Insert(XclImpXFRange* pXFRange, sal_uLong nIndex)
+{
+ maIndexList.insert( maIndexList.begin() + nIndex, pXFRange );
+}
+
+void XclImpXFRangeColumn::Find(
+ XclImpXFRange*& rpPrevRange, XclImpXFRange*& rpNextRange,
+ sal_uLong& rnNextIndex, SCROW nScRow )
+{
+
+ // test whether list is empty
+ if( maIndexList.empty() )
+ {
+ rpPrevRange = rpNextRange = 0;
+ rnNextIndex = 0;
+ return;
+ }
+
+ rpPrevRange = &maIndexList.front();
+ rpNextRange = &maIndexList.back();
+
+ // test whether row is at end of list (contained in or behind last range)
+ // rpPrevRange will contain a possible existing row
+ if( rpNextRange->mnScRow1 <= nScRow )
+ {
+ rpPrevRange = rpNextRange;
+ rpNextRange = 0;
+ rnNextIndex = maIndexList.size();
+ return;
+ }
+
+ // test whether row is at beginning of list (really before first range)
+ if( nScRow < rpPrevRange->mnScRow1 )
+ {
+ rpNextRange = rpPrevRange;
+ rpPrevRange = 0;
+ rnNextIndex = 0;
+ return;
+ }
+
+ // loop: find range entries before and after new row
+ // break the loop if there is no more range between first and last -or-
+ // if rpPrevRange contains nScRow (rpNextRange will never contain nScRow)
+ sal_uLong nPrevIndex = 0;
+ sal_uLong nMidIndex;
+ rnNextIndex = maIndexList.size() - 1;
+ XclImpXFRange* pMidRange;
+ while( ((rnNextIndex - nPrevIndex) > 1) && (rpPrevRange->mnScRow2 < nScRow) )
+ {
+ nMidIndex = (nPrevIndex + rnNextIndex) / 2;
+ pMidRange = &maIndexList[nMidIndex];
+ DBG_ASSERT( pMidRange, "XclImpXFRangeColumn::Find - missing XF index range" );
+ if( nScRow < pMidRange->mnScRow1 ) // row is really before pMidRange
+ {
+ rpNextRange = pMidRange;
+ rnNextIndex = nMidIndex;
+ }
+ else // row is in or after pMidRange
+ {
+ rpPrevRange = pMidRange;
+ nPrevIndex = nMidIndex;
+ }
+ }
+
+ // find next rpNextRange if rpPrevRange contains nScRow
+ if( nScRow <= rpPrevRange->mnScRow2 )
+ {
+ rnNextIndex = nPrevIndex + 1;
+ rpNextRange = &maIndexList[rnNextIndex];
+ }
+}
+
+void XclImpXFRangeColumn::TryConcatPrev( sal_uLong nIndex )
+{
+ if( !nIndex || nIndex >= maIndexList.size() )
+ return;
+
+ XclImpXFRange& prevRange = maIndexList[ nIndex - 1 ];
+ XclImpXFRange& nextRange = maIndexList[ nIndex ];
+
+ if( prevRange.Expand( nextRange ) )
+ maIndexList.erase( maIndexList.begin() + nIndex );
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpXFRangeBuffer::XclImpXFRangeBuffer( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+XclImpXFRangeBuffer::~XclImpXFRangeBuffer()
+{
+}
+
+void XclImpXFRangeBuffer::Initialize()
+{
+ maColumns.clear();
+ maHyperlinks.clear();
+ maMergeList.RemoveAll();
+}
+
+void XclImpXFRangeBuffer::SetXF( const ScAddress& rScPos, sal_uInt16 nXFIndex, XclImpXFInsertMode eMode )
+{
+ SCCOL nScCol = rScPos.Col();
+ SCROW nScRow = rScPos.Row();
+
+ // set cell XF's
+ size_t nIndex = static_cast< size_t >( nScCol );
+ if( maColumns.size() <= nIndex )
+ maColumns.resize( nIndex + 1 );
+ if( !maColumns[ nIndex ] )
+ maColumns[ nIndex ].reset( new XclImpXFRangeColumn );
+ // remember all Boolean cells, they will get 'Standard' number format
+ maColumns[ nIndex ]->SetXF( nScRow, XclImpXFIndex( nXFIndex, eMode == xlXFModeBoolCell ) );
+
+ // set "center across selection" and "fill" attribute for all following empty cells
+ // ignore it on row default XFs
+ if( eMode != xlXFModeRow )
+ {
+ const XclImpXF* pXF = GetXFBuffer().GetXF( nXFIndex );
+ if( pXF && ((pXF->GetHorAlign() == EXC_XF_HOR_CENTER_AS) || (pXF->GetHorAlign() == EXC_XF_HOR_FILL)) )
+ {
+ // expand last merged range if this attribute is set repeatedly
+ if ( !maMergeList.empty() )
+ {
+ ScRange* pRange = maMergeList.back();
+ if( (pRange->aEnd.Row() == nScRow)
+ && (pRange->aEnd.Col() + 1 == nScCol)
+ && (eMode == xlXFModeBlank)
+ )
+ pRange->aEnd.IncCol();
+ }
+ else if( eMode != xlXFModeBlank ) // do not merge empty cells
+ SetMerge( nScCol, nScRow );
+ }
+ }
+}
+
+void XclImpXFRangeBuffer::SetXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
+{
+ SetXF( rScPos, nXFIndex, xlXFModeCell );
+}
+
+void XclImpXFRangeBuffer::SetBlankXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
+{
+ SetXF( rScPos, nXFIndex, xlXFModeBlank );
+}
+
+void XclImpXFRangeBuffer::SetBoolXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
+{
+ SetXF( rScPos, nXFIndex, xlXFModeBoolCell );
+}
+
+void XclImpXFRangeBuffer::SetRowDefXF( SCROW nScRow, sal_uInt16 nXFIndex )
+{
+ for( SCCOL nScCol = 0; nScCol <= MAXCOL; ++nScCol )
+ SetXF( ScAddress( nScCol, nScRow, 0 ), nXFIndex, xlXFModeRow );
+}
+
+void XclImpXFRangeBuffer::SetColumnDefXF( SCCOL nScCol, sal_uInt16 nXFIndex )
+{
+ // our array should not have values when creating the default column format.
+ size_t nIndex = static_cast< size_t >( nScCol );
+ if( maColumns.size() <= nIndex )
+ maColumns.resize( nIndex + 1 );
+ DBG_ASSERT( !maColumns[ nIndex ], "XclImpXFRangeBuffer::SetColumnDefXF - default column of XFs already has values" );
+ maColumns[ nIndex ].reset( new XclImpXFRangeColumn );
+ maColumns[ nIndex ]->SetDefaultXF( XclImpXFIndex( nXFIndex ) );
+}
+
+void XclImpXFRangeBuffer::SetBorderLine( const ScRange& rRange, SCTAB nScTab, sal_uInt16 nLine )
+{
+ SCCOL nFromScCol = (nLine == BOX_LINE_RIGHT) ? rRange.aEnd.Col() : rRange.aStart.Col();
+ SCROW nFromScRow = (nLine == BOX_LINE_BOTTOM) ? rRange.aEnd.Row() : rRange.aStart.Row();
+ ScDocument& rDoc = GetDoc();
+
+ const SvxBoxItem* pFromItem = static_cast< const SvxBoxItem* >(
+ rDoc.GetAttr( nFromScCol, nFromScRow, nScTab, ATTR_BORDER ) );
+ const SvxBoxItem* pToItem = static_cast< const SvxBoxItem* >(
+ rDoc.GetAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, ATTR_BORDER ) );
+
+ SvxBoxItem aNewItem( *pToItem );
+ aNewItem.SetLine( pFromItem->GetLine( nLine ), nLine );
+ rDoc.ApplyAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, aNewItem );
+}
+
+void XclImpXFRangeBuffer::SetHyperlink( const XclRange& rXclRange, const String& rUrl )
+{
+ maHyperlinks.push_back( XclImpHyperlinkRange( rXclRange, rUrl ) );
+}
+
+void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol, SCROW nScRow )
+{
+ maMergeList.Append( ScRange( nScCol, nScRow, 0 ) );
+}
+
+void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2 )
+{
+ if( (nScCol1 < nScCol2) || (nScRow1 < nScRow2) )
+ maMergeList.Append( ScRange( nScCol1, nScRow1, 0, nScCol2, nScRow2, 0 ) );
+}
+
+void XclImpXFRangeBuffer::Finalize()
+{
+ ScDocument& rDoc = GetDoc();
+ SCTAB nScTab = GetCurrScTab();
+
+ // apply patterns
+ XclImpXFBuffer& rXFBuffer = GetXFBuffer();
+ for( XclImpXFRangeColumnVec::const_iterator aVBeg = maColumns.begin(), aVEnd = maColumns.end(), aVIt = aVBeg; aVIt != aVEnd; ++aVIt )
+ {
+ // apply all cell styles of an existing column
+ if( aVIt->get() )
+ {
+ XclImpXFRangeColumn& rColumn = **aVIt;
+ SCCOL nScCol = static_cast< SCCOL >( aVIt - aVBeg );
+ list<ScAttrEntry> aAttrs;
+
+ for (XclImpXFRangeColumn::IndexList::iterator itr = rColumn.begin(), itrEnd = rColumn.end();
+ itr != itrEnd; ++itr)
+ {
+ XclImpXFRange& rStyle = *itr;
+ const XclImpXFIndex& rXFIndex = rStyle.maXFIndex;
+ XclImpXF* pXF = rXFBuffer.GetXF( rXFIndex.GetXFIndex() );
+ if (!pXF)
+ continue;
+
+ sal_uInt32 nForceScNumFmt = rXFIndex.IsBoolCell() ?
+ GetNumFmtBuffer().GetStdScNumFmt() : NUMBERFORMAT_ENTRY_NOT_FOUND;
+
+ pXF->ApplyPatternToAttrList(aAttrs, rStyle.mnScRow1, rStyle.mnScRow2, nForceScNumFmt);
+ }
+
+ if (aAttrs.empty() || aAttrs.back().nRow != MAXROW)
+ {
+ ScAttrEntry aEntry;
+ aEntry.nRow = MAXROW;
+ aEntry.pPattern = rDoc.GetDefPattern();
+ aAttrs.push_back(aEntry);
+ }
+
+ size_t nAttrSize = aAttrs.size();
+ ScAttrEntry* pData = new ScAttrEntry[nAttrSize];
+ list<ScAttrEntry>::const_iterator itr = aAttrs.begin(), itrEnd = aAttrs.end();
+ for (size_t i = 0; itr != itrEnd; ++itr, ++i)
+ pData[i] = *itr;
+
+ rDoc.SetAttrEntries(nScCol, nScTab, pData, static_cast<SCSIZE>(nAttrSize));
+ }
+ }
+
+ // insert hyperlink cells
+ for( XclImpHyperlinkList::const_iterator aLIt = maHyperlinks.begin(), aLEnd = maHyperlinks.end(); aLIt != aLEnd; ++aLIt )
+ XclImpHyperlink::InsertUrl( GetRoot(), aLIt->first, aLIt->second );
+
+ // apply cell merging
+ for ( size_t i = 0, nRange = maMergeList.size(); i < nRange; ++i )
+ {
+ const ScRange* pRange = maMergeList[ i ];
+ const ScAddress& rStart = pRange->aStart;
+ const ScAddress& rEnd = pRange->aEnd;
+ bool bMultiCol = rStart.Col() != rEnd.Col();
+ bool bMultiRow = rStart.Row() != rEnd.Row();
+ // set correct right border
+ if( bMultiCol )
+ SetBorderLine( *pRange, nScTab, BOX_LINE_RIGHT );
+ // set correct lower border
+ if( bMultiRow )
+ SetBorderLine( *pRange, nScTab, BOX_LINE_BOTTOM );
+ // do merge
+ if( bMultiCol || bMultiRow )
+ rDoc.DoMerge( nScTab, rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row() );
+ // #i93609# merged range in a single row: test if manual row height is needed
+ if( !bMultiRow )
+ {
+ bool bTextWrap = static_cast< const SfxBoolItem* >( rDoc.GetAttr( rStart.Col(), rStart.Row(), rStart.Tab(), ATTR_LINEBREAK ) )->GetValue();
+ if( !bTextWrap && (rDoc.GetCellType( rStart ) == CELLTYPE_EDIT) )
+ if( const EditTextObject* pEditObj = static_cast< const ScEditCell* >( rDoc.GetCell( rStart ) )->GetData() )
+ bTextWrap = pEditObj->GetParagraphCount() > 1;
+ if( bTextWrap )
+ GetOldRoot().pColRowBuff->SetManualRowHeight( rStart.Row() );
+ }
+ }
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xiview.cxx b/sc/source/filter/excel/xiview.cxx
new file mode 100644
index 000000000000..85abb6589f03
--- /dev/null
+++ b/sc/source/filter/excel/xiview.cxx
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xiview.hxx"
+#include "document.hxx"
+#include "scextopt.hxx"
+#include "viewopti.hxx"
+#include "xistream.hxx"
+#include "xihelper.hxx"
+#include "xistyle.hxx"
+
+// Document view settings =====================================================
+
+XclImpDocViewSettings::XclImpDocViewSettings( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpDocViewSettings::ReadWindow1( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnWinX
+ >> maData.mnWinY
+ >> maData.mnWinWidth
+ >> maData.mnWinHeight
+ >> maData.mnFlags;
+ if( GetBiff() >= EXC_BIFF5 )
+ {
+ rStrm >> maData.mnDisplXclTab
+ >> maData.mnFirstVisXclTab
+ >> maData.mnXclSelectCnt
+ >> maData.mnTabBarWidth;
+ }
+}
+
+SCTAB XclImpDocViewSettings::GetDisplScTab() const
+{
+ /* Simply cast Excel index to Calc index.
+ TODO: This may fail if the document contains scenarios. */
+ sal_uInt16 nMaxXclTab = static_cast< sal_uInt16 >( GetMaxPos().Tab() );
+ return static_cast< SCTAB >( (maData.mnDisplXclTab <= nMaxXclTab) ? maData.mnDisplXclTab : 0 );
+}
+
+void XclImpDocViewSettings::Finalize()
+{
+ ScViewOptions aViewOpt( GetDoc().GetViewOptions() );
+ aViewOpt.SetOption( VOPT_HSCROLL, ::get_flag( maData.mnFlags, EXC_WIN1_HOR_SCROLLBAR ) );
+ aViewOpt.SetOption( VOPT_VSCROLL, ::get_flag( maData.mnFlags, EXC_WIN1_VER_SCROLLBAR ) );
+ aViewOpt.SetOption( VOPT_TABCONTROLS, ::get_flag( maData.mnFlags, EXC_WIN1_TABBAR ) );
+ GetDoc().SetViewOptions( aViewOpt );
+
+ // displayed sheet
+ GetExtDocOptions().GetDocSettings().mnDisplTab = GetDisplScTab();
+
+ // width of the tabbar with sheet names
+ if( maData.mnTabBarWidth <= 1000 )
+ GetExtDocOptions().GetDocSettings().mfTabBarWidth = static_cast< double >( maData.mnTabBarWidth ) / 1000.0;
+}
+
+// Sheet view settings ========================================================
+
+namespace {
+
+long lclGetScZoom( sal_uInt16 nXclZoom, sal_uInt16 nDefZoom )
+{
+ return static_cast< long >( nXclZoom ? nXclZoom : nDefZoom );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclImpTabViewSettings::XclImpTabViewSettings( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+ Initialize();
+}
+
+void XclImpTabViewSettings::Initialize()
+{
+ maData.SetDefaults();
+}
+
+void XclImpTabViewSettings::ReadTabBgColor( XclImpStream& rStrm, XclImpPalette& rPal )
+{
+ DBG_ASSERT_BIFF( GetBiff() >= EXC_BIFF8 );
+ if( GetBiff() < EXC_BIFF8 )
+ return;
+
+ sal_uInt8 ColorIndex;
+ Color TabBgColor;
+
+ rStrm.Ignore( 16 );
+ ColorIndex = rStrm.ReaduInt8() & EXC_SHEETEXT_TABCOLOR; //0x7F
+ if ( ColorIndex >= 8 && ColorIndex <= 63 ) //only accept valid index values
+ {
+ TabBgColor = rPal.GetColor( ColorIndex );
+ maData.maTabBgColor = TabBgColor;
+ }
+}
+
+void XclImpTabViewSettings::ReadWindow2( XclImpStream& rStrm, bool bChart )
+{
+ if( GetBiff() == EXC_BIFF2 )
+ {
+ maData.mbShowFormulas = rStrm.ReaduInt8() != 0;
+ maData.mbShowGrid = rStrm.ReaduInt8() != 0;
+ maData.mbShowHeadings = rStrm.ReaduInt8() != 0;
+ maData.mbFrozenPanes = rStrm.ReaduInt8() != 0;
+ maData.mbShowZeros = rStrm.ReaduInt8() != 0;
+ rStrm >> maData.maFirstXclPos;
+ maData.mbDefGridColor = rStrm.ReaduInt8() != 0;
+ rStrm >> maData.maGridColor;
+ }
+ else
+ {
+ sal_uInt16 nFlags;
+ rStrm >> nFlags >> maData.maFirstXclPos;
+
+ // #i59590# real life: Excel ignores some view settings in chart sheets
+ maData.mbSelected = ::get_flag( nFlags, EXC_WIN2_SELECTED );
+ maData.mbDisplayed = ::get_flag( nFlags, EXC_WIN2_DISPLAYED );
+ maData.mbMirrored = !bChart && ::get_flag( nFlags, EXC_WIN2_MIRRORED );
+ maData.mbFrozenPanes = !bChart && ::get_flag( nFlags, EXC_WIN2_FROZEN );
+ maData.mbPageMode = !bChart && ::get_flag( nFlags, EXC_WIN2_PAGEBREAKMODE );
+ maData.mbDefGridColor = bChart || ::get_flag( nFlags, EXC_WIN2_DEFGRIDCOLOR );
+ maData.mbShowFormulas = !bChart && ::get_flag( nFlags, EXC_WIN2_SHOWFORMULAS );
+ maData.mbShowGrid = bChart || ::get_flag( nFlags, EXC_WIN2_SHOWGRID );
+ maData.mbShowHeadings = bChart || ::get_flag( nFlags, EXC_WIN2_SHOWHEADINGS );
+ maData.mbShowZeros = bChart || ::get_flag( nFlags, EXC_WIN2_SHOWZEROS );
+ maData.mbShowOutline = bChart || ::get_flag( nFlags, EXC_WIN2_SHOWOUTLINE );
+
+ switch( GetBiff() )
+ {
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ case EXC_BIFF5:
+ rStrm >> maData.maGridColor;
+ break;
+ case EXC_BIFF8:
+ {
+ sal_uInt16 nGridColorIdx;
+ rStrm >> nGridColorIdx;
+ // zoom data not included in chart sheets
+ if( rStrm.GetRecLeft() >= 6 )
+ {
+ rStrm.Ignore( 2 );
+ rStrm >> maData.mnPageZoom >> maData.mnNormalZoom;
+ }
+
+ if( !maData.mbDefGridColor )
+ maData.maGridColor = GetPalette().GetColor( nGridColorIdx );
+ }
+ break;
+ default: DBG_ERROR_BIFF();
+ }
+ }
+
+ // do not scroll chart sheets
+ if( bChart )
+ maData.maFirstXclPos.Set( 0, 0 );
+}
+
+void XclImpTabViewSettings::ReadScl( XclImpStream& rStrm )
+{
+ sal_uInt16 nNum, nDenom;
+ rStrm >> nNum >> nDenom;
+ DBG_ASSERT( nDenom > 0, "XclImpPageSettings::ReadScl - invalid denominator" );
+ if( nDenom > 0 )
+ maData.mnCurrentZoom = limit_cast< sal_uInt16 >( (nNum * 100) / nDenom );
+}
+
+void XclImpTabViewSettings::ReadPane( XclImpStream& rStrm )
+{
+ rStrm >> maData.mnSplitX;
+ maData.mnSplitY = rStrm.ReaduInt16();
+
+ rStrm >> maData.maSecondXclPos
+ >> maData.mnActivePane;
+}
+
+void XclImpTabViewSettings::ReadSelection( XclImpStream& rStrm )
+{
+ // pane of this selection
+ sal_uInt8 nPane;
+ rStrm >> nPane;
+ XclSelectionData& rSelData = maData.CreateSelectionData( nPane );
+ // cursor position and selection
+ rStrm >> rSelData.maXclCursor >> rSelData.mnCursorIdx;
+ rSelData.maXclSelection.Read( rStrm, false );
+}
+
+void XclImpTabViewSettings::Finalize()
+{
+ SCTAB nScTab = GetCurrScTab();
+ ScDocument& rDoc = GetDoc();
+ XclImpAddressConverter& rAddrConv = GetAddressConverter();
+ ScExtTabSettings& rTabSett = GetExtDocOptions().GetOrCreateTabSettings( nScTab );
+ bool bDisplayed = GetDocViewSettings().GetDisplScTab() == nScTab;
+
+ // *** sheet options: cursor, selection, splits, zoom ***
+
+ // sheet flags
+ if( maData.mbMirrored )
+ // do not call this function with sal_False, it would mirror away all drawing objects
+ rDoc.SetLayoutRTL( nScTab, sal_True );
+ rTabSett.mbSelected = maData.mbSelected || bDisplayed;
+
+ // first visible cell in top-left pane and in additional pane(s)
+ rTabSett.maFirstVis = rAddrConv.CreateValidAddress( maData.maFirstXclPos, nScTab, false );
+ rTabSett.maSecondVis = rAddrConv.CreateValidAddress( maData.maSecondXclPos, nScTab, false );
+
+ // cursor position and selection
+ if( const XclSelectionData* pSelData = maData.GetSelectionData( maData.mnActivePane ) )
+ {
+ rTabSett.maCursor = rAddrConv.CreateValidAddress( pSelData->maXclCursor, nScTab, false );
+ rAddrConv.ConvertRangeList( rTabSett.maSelection, pSelData->maXclSelection, nScTab, false );
+ }
+
+ // active pane
+ switch( maData.mnActivePane )
+ {
+ case EXC_PANE_TOPLEFT: rTabSett.meActivePane = SCEXT_PANE_TOPLEFT; break;
+ case EXC_PANE_TOPRIGHT: rTabSett.meActivePane = SCEXT_PANE_TOPRIGHT; break;
+ case EXC_PANE_BOTTOMLEFT: rTabSett.meActivePane = SCEXT_PANE_BOTTOMLEFT; break;
+ case EXC_PANE_BOTTOMRIGHT: rTabSett.meActivePane = SCEXT_PANE_BOTTOMRIGHT; break;
+ }
+
+ // freeze/split position
+ rTabSett.mbFrozenPanes = maData.mbFrozenPanes;
+ if( maData.mbFrozenPanes )
+ {
+ /* Frozen panes: handle split position as row/column positions.
+ #i35812# Excel uses number of visible rows/columns, Calc uses position of freeze. */
+ if( (maData.mnSplitX > 0) && (maData.maFirstXclPos.mnCol + maData.mnSplitX <= GetScMaxPos().Col()) )
+ rTabSett.maFreezePos.SetCol( static_cast< SCCOL >( maData.maFirstXclPos.mnCol + maData.mnSplitX ) );
+ if( (maData.mnSplitY > 0) && (maData.maFirstXclPos.mnRow + maData.mnSplitY <= static_cast<unsigned>(GetScMaxPos().Row())) )
+ rTabSett.maFreezePos.SetRow( static_cast< SCROW >( maData.maFirstXclPos.mnRow + maData.mnSplitY ) );
+ }
+ else
+ {
+ // split window: position is in twips
+ rTabSett.maSplitPos.X() = static_cast< long >( maData.mnSplitX );
+ rTabSett.maSplitPos.Y() = static_cast< long >( maData.mnSplitY );
+ }
+
+ // grid color
+ if( maData.mbDefGridColor )
+ rTabSett.maGridColor.SetColor( COL_AUTO );
+ else
+ rTabSett.maGridColor = maData.maGridColor;
+
+ // show grid option
+ rTabSett.mbShowGrid = maData.mbShowGrid;
+
+ // view mode and zoom
+ if( maData.mnCurrentZoom != 0 )
+ (maData.mbPageMode ? maData.mnPageZoom : maData.mnNormalZoom) = maData.mnCurrentZoom;
+ rTabSett.mbPageMode = maData.mbPageMode;
+ rTabSett.mnNormalZoom = lclGetScZoom( maData.mnNormalZoom, EXC_WIN2_NORMALZOOM_DEF );
+ rTabSett.mnPageZoom = lclGetScZoom( maData.mnPageZoom, EXC_WIN2_PAGEZOOM_DEF );
+
+ // *** additional handling for displayed sheet ***
+
+ if( bDisplayed )
+ {
+ // set Excel sheet settings globally at Calc document, take settings from displayed sheet
+ ScViewOptions aViewOpt( rDoc.GetViewOptions() );
+ aViewOpt.SetOption( VOPT_FORMULAS, maData.mbShowFormulas );
+ aViewOpt.SetOption( VOPT_HEADER, maData.mbShowHeadings );
+ aViewOpt.SetOption( VOPT_NULLVALS, maData.mbShowZeros );
+ aViewOpt.SetOption( VOPT_OUTLINER, maData.mbShowOutline );
+ rDoc.SetViewOptions( aViewOpt );
+ }
+
+ // *** set tab bg color
+ if ( !maData.IsDefaultTabBgColor() )
+ rDoc.SetTabBgColor(nScTab, maData.maTabBgColor);
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xladdress.cxx b/sc/source/filter/excel/xladdress.cxx
new file mode 100644
index 000000000000..e66251b33bde
--- /dev/null
+++ b/sc/source/filter/excel/xladdress.cxx
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xladdress.hxx"
+#include "xestream.hxx"
+#include "xltracer.hxx"
+#include "xistream.hxx"
+
+// ============================================================================
+
+void XclAddress::Read( XclImpStream& rStrm, bool bCol16Bit )
+{
+ mnRow = rStrm.ReaduInt16();
+ if( bCol16Bit )
+ rStrm >> mnCol;
+ else
+ mnCol = rStrm.ReaduInt8();
+}
+
+void XclAddress::Write( XclExpStream& rStrm, bool bCol16Bit ) const
+{
+ rStrm << static_cast<sal_uInt16> (mnRow);
+ if( bCol16Bit )
+ rStrm << mnCol;
+ else
+ rStrm << static_cast< sal_uInt8 >( mnCol );
+}
+
+// ----------------------------------------------------------------------------
+
+bool XclRange::Contains( const XclAddress& rPos ) const
+{
+ return (maFirst.mnCol <= rPos.mnCol) && (rPos.mnCol <= maLast.mnCol) &&
+ (maFirst.mnRow <= rPos.mnRow) && (rPos.mnRow <= maLast.mnRow);
+}
+
+void XclRange::Read( XclImpStream& rStrm, bool bCol16Bit )
+{
+ maFirst.mnRow = rStrm.ReaduInt16();
+ maLast.mnRow = rStrm.ReaduInt16();
+
+ if( bCol16Bit )
+ rStrm >> maFirst.mnCol >> maLast.mnCol;
+ else
+ {
+ maFirst.mnCol = rStrm.ReaduInt8();
+ maLast.mnCol = rStrm.ReaduInt8();
+ }
+}
+
+void XclRange::Write( XclExpStream& rStrm, bool bCol16Bit ) const
+{
+ rStrm << static_cast<sal_uInt16>(maFirst.mnRow) << static_cast<sal_uInt16>(maLast.mnRow);
+ if( bCol16Bit )
+ rStrm << maFirst.mnCol << maLast.mnCol;
+ else
+ rStrm << static_cast< sal_uInt8 >( maFirst.mnCol ) << static_cast< sal_uInt8 >( maLast.mnCol );
+}
+
+// ----------------------------------------------------------------------------
+
+XclRange XclRangeList::GetEnclosingRange() const
+{
+ XclRange aXclRange;
+ if( !empty() )
+ {
+ const_iterator aIt = begin(), aEnd = end();
+ aXclRange = *aIt;
+ for( ++aIt; aIt != aEnd; ++aIt )
+ {
+ aXclRange.maFirst.mnCol = ::std::min( aXclRange.maFirst.mnCol, aIt->maFirst.mnCol );
+ aXclRange.maFirst.mnRow = ::std::min( aXclRange.maFirst.mnRow, aIt->maFirst.mnRow );
+ aXclRange.maLast.mnCol = ::std::max( aXclRange.maLast.mnCol, aIt->maLast.mnCol );
+ aXclRange.maLast.mnRow = ::std::max( aXclRange.maLast.mnRow, aIt->maLast.mnRow );
+ }
+ }
+ return aXclRange;
+}
+
+void XclRangeList::Read( XclImpStream& rStrm, bool bCol16Bit )
+{
+ sal_uInt16 nCount;
+ rStrm >> nCount;
+ size_t nOldSize = size();
+ resize( nOldSize + nCount );
+ for( iterator aIt = begin() + nOldSize; rStrm.IsValid() && (nCount > 0); --nCount, ++aIt )
+ aIt->Read( rStrm, bCol16Bit );
+}
+
+void XclRangeList::Write( XclExpStream& rStrm, bool bCol16Bit ) const
+{
+ WriteSubList( rStrm, 0, size(), bCol16Bit );
+}
+
+void XclRangeList::WriteSubList( XclExpStream& rStrm, size_t nBegin, size_t nCount, bool bCol16Bit ) const
+{
+ DBG_ASSERT( nBegin <= size(), "XclRangeList::WriteSubList - invalid start position" );
+ size_t nEnd = ::std::min< size_t >( nBegin + nCount, size() );
+ sal_uInt16 nXclCount = ulimit_cast< sal_uInt16 >( nEnd - nBegin );
+ rStrm << nXclCount;
+ rStrm.SetSliceSize( bCol16Bit ? 8 : 6 );
+ for( const_iterator aIt = begin() + nBegin, aEnd = begin() + nEnd; aIt != aEnd; ++aIt )
+ aIt->Write( rStrm, bCol16Bit );
+}
+
+// ============================================================================
+
+XclAddressConverterBase::XclAddressConverterBase( XclTracer& rTracer, const ScAddress& rMaxPos ) :
+ mrTracer( rTracer ),
+ maMaxPos( rMaxPos ),
+ mnMaxCol( static_cast< sal_uInt16 >( rMaxPos.Col() ) ),
+ mnMaxRow( static_cast< sal_uInt16 >( rMaxPos.Row() ) ),
+ mbColTrunc( false ),
+ mbRowTrunc( false ),
+ mbTabTrunc( false )
+{
+ DBG_ASSERT( static_cast< size_t >( rMaxPos.Col() ) <= SAL_MAX_UINT16, "XclAddressConverterBase::XclAddressConverterBase - invalid max column" );
+ DBG_ASSERT( static_cast< size_t >( rMaxPos.Row() ) <= SAL_MAX_UINT32, "XclAddressConverterBase::XclAddressConverterBase - invalid max row" );
+}
+
+XclAddressConverterBase::~XclAddressConverterBase()
+{
+}
+
+bool XclAddressConverterBase::CheckScTab( SCTAB nScTab, bool bWarn )
+{
+ bool bValid = (0 <= nScTab) && (nScTab <= maMaxPos.Tab());
+ if( !bValid && bWarn )
+ {
+ mbTabTrunc |= (nScTab > maMaxPos.Tab()); // do not warn for deleted refs
+ mrTracer.TraceInvalidTab( nScTab, maMaxPos.Tab() );
+ }
+ return bValid;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xlchart.cxx b/sc/source/filter/excel/xlchart.cxx
new file mode 100644
index 000000000000..033468998ea5
--- /dev/null
+++ b/sc/source/filter/excel/xlchart.cxx
@@ -0,0 +1,1351 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "xlchart.hxx"
+
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/drawing/Hatch.hpp>
+#include <com/sun/star/drawing/LineDash.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/BitmapMode.hpp>
+#include <com/sun/star/chart/DataLabelPlacement.hpp>
+#include <com/sun/star/chart/XAxisXSupplier.hpp>
+#include <com/sun/star/chart/XAxisYSupplier.hpp>
+#include <com/sun/star/chart/XAxisZSupplier.hpp>
+#include <com/sun/star/chart/XChartDocument.hpp>
+#include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp>
+#include <com/sun/star/chart2/Symbol.hpp>
+
+#include <sal/macros.h>
+#include <rtl/math.hxx>
+#include <svl/itemset.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/unomid.hxx>
+#include <filter/msfilter/escherex.hxx>
+#include <editeng/memberids.hrc>
+#include "global.hxx"
+#include "xlroot.hxx"
+#include "xlstyle.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::chart2::XChartDocument;
+using ::com::sun::star::drawing::XShape;
+
+namespace cssc = ::com::sun::star::chart;
+
+// Common =====================================================================
+
+XclChRectangle::XclChRectangle() :
+ mnX( 0 ),
+ mnY( 0 ),
+ mnWidth( 0 ),
+ mnHeight( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChDataPointPos::XclChDataPointPos( sal_uInt16 nSeriesIdx, sal_uInt16 nPointIdx ) :
+ mnSeriesIdx( nSeriesIdx ),
+ mnPointIdx( nPointIdx )
+{
+}
+
+bool operator<( const XclChDataPointPos& rL, const XclChDataPointPos& rR )
+{
+ return (rL.mnSeriesIdx < rR.mnSeriesIdx) ||
+ ((rL.mnSeriesIdx == rR.mnSeriesIdx) && (rL.mnPointIdx < rR.mnPointIdx));
+}
+
+// ----------------------------------------------------------------------------
+
+XclChFrBlock::XclChFrBlock( sal_uInt16 nType ) :
+ mnType( nType ),
+ mnContext( 0 ),
+ mnValue1( 0 ),
+ mnValue2( 0 )
+{
+}
+
+// Frame formatting ===========================================================
+
+XclChFramePos::XclChFramePos() :
+ mnTLMode( EXC_CHFRAMEPOS_PARENT ),
+ mnBRMode( EXC_CHFRAMEPOS_PARENT )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChLineFormat::XclChLineFormat() :
+ maColor( COL_BLACK ),
+ mnPattern( EXC_CHLINEFORMAT_SOLID ),
+ mnWeight( EXC_CHLINEFORMAT_SINGLE ),
+ mnFlags( EXC_CHLINEFORMAT_AUTO )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChAreaFormat::XclChAreaFormat() :
+ maPattColor( COL_WHITE ),
+ maBackColor( COL_BLACK ),
+ mnPattern( EXC_PATT_SOLID ),
+ mnFlags( EXC_CHAREAFORMAT_AUTO )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChEscherFormat::XclChEscherFormat()
+{
+}
+
+XclChEscherFormat::~XclChEscherFormat()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChPicFormat::XclChPicFormat() :
+ mnBmpMode( EXC_CHPICFORMAT_NONE ),
+ mnFormat( EXC_CHPICFORMAT_DEFAULT ),
+ mnFlags( EXC_CHPICFORMAT_DEFAULTFLAGS ),
+ mfScale( 0.5 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChFrame::XclChFrame() :
+ mnFormat( EXC_CHFRAME_STANDARD ),
+ mnFlags( EXC_CHFRAME_AUTOSIZE | EXC_CHFRAME_AUTOPOS )
+{
+}
+
+// Source links ===============================================================
+
+XclChSourceLink::XclChSourceLink() :
+ mnDestType( EXC_CHSRCLINK_TITLE ),
+ mnLinkType( EXC_CHSRCLINK_DEFAULT ),
+ mnFlags( 0 ),
+ mnNumFmtIdx( 0 )
+{
+}
+
+// Text =======================================================================
+
+XclChObjectLink::XclChObjectLink() :
+ mnTarget( EXC_CHOBJLINK_NONE )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChFrLabelProps::XclChFrLabelProps() :
+ mnFlags( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChText::XclChText() :
+ maTextColor( COL_BLACK ),
+ mnHAlign( EXC_CHTEXT_ALIGN_CENTER ),
+ mnVAlign( EXC_CHTEXT_ALIGN_CENTER ),
+ mnBackMode( EXC_CHTEXT_TRANSPARENT ),
+ mnFlags( EXC_CHTEXT_AUTOCOLOR | EXC_CHTEXT_AUTOFILL ),
+ mnFlags2( EXC_CHTEXT_POS_DEFAULT ),
+ mnRotation( EXC_ROT_NONE )
+{
+}
+
+// Data series ================================================================
+
+XclChMarkerFormat::XclChMarkerFormat() :
+ maLineColor( COL_BLACK ),
+ maFillColor( COL_WHITE ),
+ mnMarkerSize( EXC_CHMARKERFORMAT_SINGLESIZE ),
+ mnMarkerType( EXC_CHMARKERFORMAT_NOSYMBOL ),
+ mnFlags( EXC_CHMARKERFORMAT_AUTO )
+{
+};
+
+// ----------------------------------------------------------------------------
+
+XclCh3dDataFormat::XclCh3dDataFormat() :
+ mnBase( EXC_CH3DDATAFORMAT_RECT ),
+ mnTop( EXC_CH3DDATAFORMAT_STRAIGHT )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChDataFormat::XclChDataFormat() :
+ mnFormatIdx( EXC_CHDATAFORMAT_DEFAULT ),
+ mnFlags( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChSerTrendLine::XclChSerTrendLine() :
+ mfForecastFor( 0.0 ),
+ mfForecastBack( 0.0 ),
+ mnLineType( EXC_CHSERTREND_POLYNOMIAL ),
+ mnOrder( 1 ),
+ mnShowEquation( 0 ),
+ mnShowRSquared( 0 )
+{
+ /* Set all bits in mfIntercept to 1 (that is -1.#NAN) to indicate that
+ there is no interception point. Cannot use ::rtl::math::setNan() here
+ cause it misses the sign bit. */
+ sal_math_Double* pDouble = reinterpret_cast< sal_math_Double* >( &mfIntercept );
+ pDouble->w32_parts.msw = pDouble->w32_parts.lsw = 0xFFFFFFFF;
+}
+
+// ----------------------------------------------------------------------------
+
+XclChSerErrorBar::XclChSerErrorBar() :
+ mfValue( 0.0 ),
+ mnValueCount( 1 ),
+ mnBarType( EXC_CHSERERR_NONE ),
+ mnSourceType( EXC_CHSERERR_FIXED ),
+ mnLineEnd( EXC_CHSERERR_END_TSHAPE )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChSeries::XclChSeries() :
+ mnCategType( EXC_CHSERIES_NUMERIC ),
+ mnValueType( EXC_CHSERIES_NUMERIC ),
+ mnBubbleType( EXC_CHSERIES_NUMERIC ),
+ mnCategCount( 0 ),
+ mnValueCount( 0 ),
+ mnBubbleCount( 0 )
+{
+}
+
+// Chart type groups ==========================================================
+
+XclChType::XclChType() :
+ mnOverlap( 0 ),
+ mnGap( 150 ),
+ mnRotation( 0 ),
+ mnPieHole( 0 ),
+ mnBubbleSize( 100 ),
+ mnBubbleType( EXC_CHSCATTER_AREA ),
+ mnFlags( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChChart3d::XclChChart3d() :
+ mnRotation( 20 ),
+ mnElevation( 15 ),
+ mnEyeDist( 30 ),
+ mnRelHeight( 100 ),
+ mnRelDepth( 100 ),
+ mnDepthGap( 150 ),
+ mnFlags( EXC_CHCHART3D_AUTOHEIGHT )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChLegend::XclChLegend() :
+ mnDockMode( EXC_CHLEGEND_RIGHT ),
+ mnSpacing( EXC_CHLEGEND_MEDIUM ),
+ mnFlags( EXC_CHLEGEND_DOCKED | EXC_CHLEGEND_AUTOSERIES |
+ EXC_CHLEGEND_AUTOPOSX | EXC_CHLEGEND_AUTOPOSY | EXC_CHLEGEND_STACKED )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChTypeGroup::XclChTypeGroup() :
+ mnFlags( 0 ),
+ mnGroupIdx( EXC_CHSERGROUP_NONE )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChProperties::XclChProperties() :
+ mnFlags( 0 ),
+ mnEmptyMode( EXC_CHPROPS_EMPTY_SKIP )
+{
+}
+
+// Axes =======================================================================
+
+XclChLabelRange::XclChLabelRange() :
+ mnCross( 1 ),
+ mnLabelFreq( 1 ),
+ mnTickFreq( 1 ),
+ mnFlags( 0 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChDateRange::XclChDateRange() :
+ mnMinDate( 0 ),
+ mnMaxDate( 0 ),
+ mnMajorStep( 0 ),
+ mnMajorUnit( EXC_CHDATERANGE_DAYS ),
+ mnMinorStep( 0 ),
+ mnMinorUnit( EXC_CHDATERANGE_DAYS ),
+ mnBaseUnit( EXC_CHDATERANGE_DAYS ),
+ mnCross( 0 ),
+ mnFlags( EXC_CHDATERANGE_AUTOMIN | EXC_CHDATERANGE_AUTOMAX |
+ EXC_CHDATERANGE_AUTOMAJOR | EXC_CHDATERANGE_AUTOMINOR |
+ EXC_CHDATERANGE_AUTOBASE | EXC_CHDATERANGE_AUTOCROSS |
+ EXC_CHDATERANGE_AUTODATE )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChValueRange::XclChValueRange() :
+ mfMin( 0.0 ),
+ mfMax( 0.0 ),
+ mfMajorStep( 0.0 ),
+ mfMinorStep( 0.0 ),
+ mfCross( 0.0 ),
+ mnFlags( EXC_CHVALUERANGE_AUTOMIN | EXC_CHVALUERANGE_AUTOMAX |
+ EXC_CHVALUERANGE_AUTOMAJOR | EXC_CHVALUERANGE_AUTOMINOR |
+ EXC_CHVALUERANGE_AUTOCROSS | EXC_CHVALUERANGE_BIT8 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChTick::XclChTick() :
+ maTextColor( COL_BLACK ),
+ mnMajor( EXC_CHTICK_INSIDE | EXC_CHTICK_OUTSIDE ),
+ mnMinor( 0 ),
+ mnLabelPos( EXC_CHTICK_NEXT ),
+ mnBackMode( EXC_CHTICK_TRANSPARENT ),
+ mnFlags( EXC_CHTICK_AUTOCOLOR | EXC_CHTICK_AUTOROT ),
+ mnRotation( EXC_ROT_NONE )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclChAxis::XclChAxis() :
+ mnType( EXC_CHAXIS_NONE )
+{
+}
+
+sal_Int32 XclChAxis::GetApiAxisDimension() const
+{
+ sal_Int32 nApiAxisDim = EXC_CHART_AXIS_NONE;
+ switch( mnType )
+ {
+ case EXC_CHAXIS_X: nApiAxisDim = EXC_CHART_AXIS_X; break;
+ case EXC_CHAXIS_Y: nApiAxisDim = EXC_CHART_AXIS_Y; break;
+ case EXC_CHAXIS_Z: nApiAxisDim = EXC_CHART_AXIS_Z; break;
+ }
+ return nApiAxisDim;
+}
+
+// ----------------------------------------------------------------------------
+
+XclChAxesSet::XclChAxesSet() :
+ mnAxesSetId( EXC_CHAXESSET_PRIMARY )
+{
+}
+
+sal_Int32 XclChAxesSet::GetApiAxesSetIndex() const
+{
+ sal_Int32 nApiAxesSetIdx = EXC_CHART_AXESSET_NONE;
+ switch( mnAxesSetId )
+ {
+ case EXC_CHAXESSET_PRIMARY: nApiAxesSetIdx = EXC_CHART_AXESSET_PRIMARY; break;
+ case EXC_CHAXESSET_SECONDARY: nApiAxesSetIdx = EXC_CHART_AXESSET_SECONDARY; break;
+ }
+ return nApiAxesSetIdx;
+}
+
+// Static helper functions ====================================================
+
+sal_uInt16 XclChartHelper::GetSeriesLineAutoColorIdx( sal_uInt16 nFormatIdx )
+{
+ static const sal_uInt16 spnLineColors[] =
+ {
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 63
+ };
+ return spnLineColors[ nFormatIdx % SAL_N_ELEMENTS( spnLineColors ) ];
+}
+
+sal_uInt16 XclChartHelper::GetSeriesFillAutoColorIdx( sal_uInt16 nFormatIdx )
+{
+ static const sal_uInt16 spnFillColors[] =
+ {
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23
+ };
+ return spnFillColors[ nFormatIdx % SAL_N_ELEMENTS( spnFillColors ) ];
+}
+
+sal_uInt8 XclChartHelper::GetSeriesFillAutoTransp( sal_uInt16 nFormatIdx )
+{
+ static const sal_uInt8 spnTrans[] = { 0x00, 0x40, 0x20, 0x60, 0x70 };
+ return spnTrans[ (nFormatIdx / 56) % SAL_N_ELEMENTS( spnTrans ) ];
+}
+
+sal_uInt16 XclChartHelper::GetAutoMarkerType( sal_uInt16 nFormatIdx )
+{
+ static const sal_uInt16 spnSymbols[] = {
+ EXC_CHMARKERFORMAT_DIAMOND, EXC_CHMARKERFORMAT_SQUARE, EXC_CHMARKERFORMAT_TRIANGLE,
+ EXC_CHMARKERFORMAT_CROSS, EXC_CHMARKERFORMAT_STAR, EXC_CHMARKERFORMAT_CIRCLE,
+ EXC_CHMARKERFORMAT_PLUS, EXC_CHMARKERFORMAT_DOWJ, EXC_CHMARKERFORMAT_STDDEV };
+ return spnSymbols[ nFormatIdx % SAL_N_ELEMENTS( spnSymbols ) ];
+}
+
+bool XclChartHelper::HasMarkerFillColor( sal_uInt16 nMarkerType )
+{
+ static const bool spbFilled[] = {
+ false, true, true, true, false, false, false, false, true, false };
+ return (nMarkerType < SAL_N_ELEMENTS( spbFilled )) && spbFilled[ nMarkerType ];
+}
+
+OUString XclChartHelper::GetErrorBarValuesRole( sal_uInt8 nBarType )
+{
+ switch( nBarType )
+ {
+ case EXC_CHSERERR_XPLUS: return EXC_CHPROP_ROLE_ERRORBARS_POSX;
+ case EXC_CHSERERR_XMINUS: return EXC_CHPROP_ROLE_ERRORBARS_NEGX;
+ case EXC_CHSERERR_YPLUS: return EXC_CHPROP_ROLE_ERRORBARS_POSY;
+ case EXC_CHSERERR_YMINUS: return EXC_CHPROP_ROLE_ERRORBARS_NEGY;
+ default: DBG_ERRORFILE( "XclChartHelper::GetErrorBarValuesRole - unknown bar type" );
+ }
+ return OUString();
+}
+
+// Chart formatting info provider =============================================
+
+namespace {
+
+static const XclChFormatInfo spFmtInfos[] =
+{
+ // object type property mode auto line color auto line weight auto pattern color missing frame type create delete isframe
+ { EXC_CHOBJTYPE_BACKGROUND, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_INVISIBLE, true, true, true },
+ { EXC_CHOBJTYPE_PLOTFRAME, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_INVISIBLE, true, true, true },
+ { EXC_CHOBJTYPE_WALL3D, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_AUTO, true, false, true },
+ { EXC_CHOBJTYPE_FLOOR3D, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, 23, EXC_CHFRAMETYPE_AUTO, true, false, true },
+ { EXC_CHOBJTYPE_TEXT, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_INVISIBLE, false, true, true },
+ { EXC_CHOBJTYPE_LEGEND, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_AUTO, true, true, true },
+ { EXC_CHOBJTYPE_LINEARSERIES, EXC_CHPROPMODE_LINEARSERIES, 0xFFFF, EXC_CHLINEFORMAT_SINGLE, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_AUTO, false, false, false },
+ { EXC_CHOBJTYPE_FILLEDSERIES, EXC_CHPROPMODE_FILLEDSERIES, EXC_COLOR_CHBORDERAUTO, EXC_CHLINEFORMAT_SINGLE, 0xFFFF, EXC_CHFRAMETYPE_AUTO, false, false, true },
+ { EXC_CHOBJTYPE_AXISLINE, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_AUTO, false, false, false },
+ { EXC_CHOBJTYPE_GRIDLINE, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_INVISIBLE, false, true, false },
+ { EXC_CHOBJTYPE_TRENDLINE, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_DOUBLE, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_INVISIBLE, false, false, false },
+ { EXC_CHOBJTYPE_ERRORBAR, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_SINGLE, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_INVISIBLE, false, false, false },
+ { EXC_CHOBJTYPE_CONNECTLINE, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_INVISIBLE, false, false, false },
+ { EXC_CHOBJTYPE_HILOLINE, EXC_CHPROPMODE_LINEARSERIES, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_INVISIBLE, false, false, false },
+ { EXC_CHOBJTYPE_WHITEDROPBAR, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWBACK, EXC_CHFRAMETYPE_INVISIBLE, false, false, true },
+ { EXC_CHOBJTYPE_BLACKDROPBAR, EXC_CHPROPMODE_COMMON, EXC_COLOR_CHWINDOWTEXT, EXC_CHLINEFORMAT_HAIR, EXC_COLOR_CHWINDOWTEXT, EXC_CHFRAMETYPE_INVISIBLE, false, false, true }
+};
+
+}
+
+// ----------------------------------------------------------------------------
+
+XclChFormatInfoProvider::XclChFormatInfoProvider()
+{
+ const XclChFormatInfo* pEnd = STATIC_TABLE_END( spFmtInfos );
+ for( const XclChFormatInfo* pIt = spFmtInfos; pIt != pEnd; ++pIt )
+ maInfoMap[ pIt->meObjType ] = pIt;
+}
+
+const XclChFormatInfo& XclChFormatInfoProvider::GetFormatInfo( XclChObjectType eObjType ) const
+{
+ XclFmtInfoMap::const_iterator aIt = maInfoMap.find( eObjType );
+ DBG_ASSERT( aIt != maInfoMap.end(), "XclChFormatInfoProvider::GetFormatInfo - unknown object type" );
+ return (aIt == maInfoMap.end()) ? *spFmtInfos : *aIt->second;
+}
+
+// Chart type info provider ===================================================
+
+namespace {
+
+// chart type service names
+const sal_Char SERVICE_CHART2_AREA[] = "com.sun.star.chart2.AreaChartType";
+const sal_Char SERVICE_CHART2_CANDLE[] = "com.sun.star.chart2.CandleStickChartType";
+const sal_Char SERVICE_CHART2_COLUMN[] = "com.sun.star.chart2.ColumnChartType";
+const sal_Char SERVICE_CHART2_LINE[] = "com.sun.star.chart2.LineChartType";
+const sal_Char SERVICE_CHART2_NET[] = "com.sun.star.chart2.NetChartType";
+const sal_Char SERVICE_CHART2_FILLEDNET[] = "com.sun.star.chart2.FilledNetChartType";
+const sal_Char SERVICE_CHART2_PIE[] = "com.sun.star.chart2.PieChartType";
+const sal_Char SERVICE_CHART2_SCATTER[] = "com.sun.star.chart2.ScatterChartType";
+const sal_Char SERVICE_CHART2_BUBBLE[] = "com.sun.star.chart2.BubbleChartType";
+const sal_Char SERVICE_CHART2_SURFACE[] = "com.sun.star.chart2.ColumnChartType"; // Todo
+
+namespace csscd = cssc::DataLabelPlacement;
+
+static const XclChTypeInfo spTypeInfos[] =
+{
+ // chart type chart type category record id service varied point color def label pos comb2d 3d polar area2d area3d 1stvis xcateg swap stack revers betw
+ { EXC_CHTYPEID_BAR, EXC_CHTYPECATEG_BAR, EXC_ID_CHBAR, SERVICE_CHART2_COLUMN, EXC_CHVARPOINT_SINGLE, csscd::OUTSIDE, true, true, false, true, true, false, true, false, true, false, true },
+ { EXC_CHTYPEID_HORBAR, EXC_CHTYPECATEG_BAR, EXC_ID_CHBAR, SERVICE_CHART2_COLUMN, EXC_CHVARPOINT_SINGLE, csscd::OUTSIDE, false, true, false, true, true, false, true, true, true, false, true },
+ { EXC_CHTYPEID_LINE, EXC_CHTYPECATEG_LINE, EXC_ID_CHLINE, SERVICE_CHART2_LINE, EXC_CHVARPOINT_SINGLE, csscd::RIGHT, true, true, false, false, true, false, true, false, true, false, false },
+ { EXC_CHTYPEID_AREA, EXC_CHTYPECATEG_LINE, EXC_ID_CHAREA, SERVICE_CHART2_AREA, EXC_CHVARPOINT_NONE, csscd::CENTER, true, true, false, true, true, false, true, false, true, true, false },
+ { EXC_CHTYPEID_STOCK, EXC_CHTYPECATEG_LINE, EXC_ID_CHLINE, SERVICE_CHART2_CANDLE, EXC_CHVARPOINT_NONE, csscd::RIGHT, true, false, false, false, false, false, true, false, true, false, false },
+ { EXC_CHTYPEID_RADARLINE, EXC_CHTYPECATEG_RADAR, EXC_ID_CHRADARLINE, SERVICE_CHART2_NET, EXC_CHVARPOINT_SINGLE, csscd::TOP, false, false, true, false, true, false, true, false, false, false, false },
+ { EXC_CHTYPEID_RADARAREA, EXC_CHTYPECATEG_RADAR, EXC_ID_CHRADARAREA, SERVICE_CHART2_FILLEDNET, EXC_CHVARPOINT_NONE, csscd::TOP, false, false, true, true, true, false, true, false, false, true, false },
+ { EXC_CHTYPEID_PIE, EXC_CHTYPECATEG_PIE, EXC_ID_CHPIE, SERVICE_CHART2_PIE, EXC_CHVARPOINT_MULTI, csscd::AVOID_OVERLAP, false, true, true, true, true, true, true, false, false, false, false },
+ { EXC_CHTYPEID_DONUT, EXC_CHTYPECATEG_PIE, EXC_ID_CHPIE, SERVICE_CHART2_PIE, EXC_CHVARPOINT_MULTI, csscd::AVOID_OVERLAP, false, true, true, true, true, false, true, false, false, true, false },
+ { EXC_CHTYPEID_PIEEXT, EXC_CHTYPECATEG_PIE, EXC_ID_CHPIEEXT, SERVICE_CHART2_PIE, EXC_CHVARPOINT_MULTI, csscd::AVOID_OVERLAP, false, false, true, true, true, true, true, false, false, false, false },
+ { EXC_CHTYPEID_SCATTER, EXC_CHTYPECATEG_SCATTER, EXC_ID_CHSCATTER, SERVICE_CHART2_SCATTER, EXC_CHVARPOINT_SINGLE, csscd::RIGHT, true, false, false, false, true, false, false, false, false, false, false },
+ { EXC_CHTYPEID_BUBBLES, EXC_CHTYPECATEG_SCATTER, EXC_ID_CHSCATTER, SERVICE_CHART2_BUBBLE, EXC_CHVARPOINT_SINGLE, csscd::RIGHT, false, false, false, true, true, false, false, false, false, false, false },
+ { EXC_CHTYPEID_SURFACE, EXC_CHTYPECATEG_SURFACE, EXC_ID_CHSURFACE, SERVICE_CHART2_SURFACE, EXC_CHVARPOINT_NONE, csscd::RIGHT, false, true, false, true, true, false, true, false, false, false, false },
+ { EXC_CHTYPEID_UNKNOWN, EXC_CHTYPECATEG_BAR, EXC_ID_CHBAR, SERVICE_CHART2_COLUMN, EXC_CHVARPOINT_SINGLE, csscd::OUTSIDE, true, true, false, true, true, false, true, false, true, false, true }
+};
+
+} // namespace
+
+XclChExtTypeInfo::XclChExtTypeInfo( const XclChTypeInfo& rTypeInfo ) :
+ XclChTypeInfo( rTypeInfo ),
+ mb3dChart( false ),
+ mbSpline( false )
+{
+}
+
+void XclChExtTypeInfo::Set( const XclChTypeInfo& rTypeInfo, bool b3dChart, bool bSpline )
+{
+ static_cast< XclChTypeInfo& >( *this ) = rTypeInfo;
+ mb3dChart = mbSupports3d && b3dChart;
+ mbSpline = bSpline;
+}
+
+// ----------------------------------------------------------------------------
+
+XclChTypeInfoProvider::XclChTypeInfoProvider()
+{
+ const XclChTypeInfo* pEnd = STATIC_TABLE_END( spTypeInfos );
+ for( const XclChTypeInfo* pIt = spTypeInfos; pIt != pEnd; ++pIt )
+ maInfoMap[ pIt->meTypeId ] = pIt;
+}
+
+const XclChTypeInfo& XclChTypeInfoProvider::GetTypeInfo( XclChTypeId eTypeId ) const
+{
+ XclChTypeInfoMap::const_iterator aIt = maInfoMap.find( eTypeId );
+ DBG_ASSERT( aIt != maInfoMap.end(), "XclChTypeInfoProvider::GetTypeInfo - unknown chart type" );
+ return (aIt == maInfoMap.end()) ? *maInfoMap.rbegin()->second : *aIt->second;
+}
+
+const XclChTypeInfo& XclChTypeInfoProvider::GetTypeInfoFromRecId( sal_uInt16 nRecId ) const
+{
+ const XclChTypeInfo* pEnd = STATIC_TABLE_END( spTypeInfos );
+ for( const XclChTypeInfo* pIt = spTypeInfos; pIt != pEnd; ++pIt )
+ if( pIt->mnRecId == nRecId )
+ return *pIt;
+ DBG_ERRORFILE( "XclChTypeInfoProvider::GetTypeInfoFromRecId - unknown record id" );
+ return GetTypeInfo( EXC_CHTYPEID_UNKNOWN );
+}
+
+const XclChTypeInfo& XclChTypeInfoProvider::GetTypeInfoFromService( const OUString& rServiceName ) const
+{
+ const XclChTypeInfo* pEnd = STATIC_TABLE_END( spTypeInfos );
+ for( const XclChTypeInfo* pIt = spTypeInfos; pIt != pEnd; ++pIt )
+ if( rServiceName.equalsAscii( pIt->mpcServiceName ) )
+ return *pIt;
+ DBG_ERRORFILE( "XclChTypeInfoProvider::GetTypeInfoFromService - unknown service name" );
+ return GetTypeInfo( EXC_CHTYPEID_UNKNOWN );
+}
+
+// Property helpers ===========================================================
+
+XclChObjectTable::XclChObjectTable( Reference< XMultiServiceFactory > xFactory,
+ const OUString& rServiceName, const OUString& rObjNameBase ) :
+ mxFactory( xFactory ),
+ maServiceName( rServiceName ),
+ maObjNameBase( rObjNameBase ),
+ mnIndex( 0 )
+{
+}
+
+Any XclChObjectTable::GetObject( const OUString& rObjName )
+{
+ // get object table
+ if( !mxContainer.is() )
+ mxContainer.set( ScfApiHelper::CreateInstance( mxFactory, maServiceName ), UNO_QUERY );
+ DBG_ASSERT( mxContainer.is(), "XclChObjectTable::GetObject - container not found" );
+
+ Any aObj;
+ if( mxContainer.is() )
+ {
+ // get object from container
+ try
+ {
+ aObj = mxContainer->getByName( rObjName );
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "XclChObjectTable::GetObject - object not found" );
+ }
+ }
+ return aObj;
+}
+
+OUString XclChObjectTable::InsertObject( const Any& rObj )
+{
+
+ // create object table
+ if( !mxContainer.is() )
+ mxContainer.set( ScfApiHelper::CreateInstance( mxFactory, maServiceName ), UNO_QUERY );
+ DBG_ASSERT( mxContainer.is(), "XclChObjectTable::InsertObject - container not found" );
+
+ OUString aObjName;
+ if( mxContainer.is() )
+ {
+ // create new unused identifier
+ do
+ {
+ aObjName = maObjNameBase + OUString::valueOf( ++mnIndex );
+ }
+ while( mxContainer->hasByName( aObjName ) );
+
+ // insert object
+ try
+ {
+ mxContainer->insertByName( aObjName, rObj );
+ }
+ catch( Exception& )
+ {
+ DBG_ERRORFILE( "XclChObjectTable::InsertObject - cannot insert object" );
+ aObjName = OUString();
+ }
+ }
+ return aObjName;
+}
+
+// Property names -------------------------------------------------------------
+
+namespace {
+
+/** Property names for line style in common objects. */
+const sal_Char* const sppcLineNamesCommon[] =
+ { "LineStyle", "LineWidth", "LineColor", "LineTransparence", "LineDashName", 0 };
+/** Property names for line style in linear series objects. */
+const sal_Char* const sppcLineNamesLinear[] =
+ { "LineStyle", "LineWidth", "Color", "Transparency", "LineDashName", 0 };
+/** Property names for line style in filled series objects. */
+const sal_Char* const sppcLineNamesFilled[] =
+ { "BorderStyle", "BorderWidth", "BorderColor", "BorderTransparency", "BorderDashName", 0 };
+
+/** Property names for solid area style in common objects. */
+const sal_Char* const sppcAreaNamesCommon[] = { "FillStyle", "FillColor", "FillTransparence", 0 };
+/** Property names for solid area style in filled series objects. */
+const sal_Char* const sppcAreaNamesFilled[] = { "FillStyle", "Color", "Transparency", 0 };
+/** Property names for gradient area style in common objects. */
+const sal_Char* const sppcGradNamesCommon[] = { "FillStyle", "FillGradientName", 0 };
+/** Property names for gradient area style in filled series objects. */
+const sal_Char* const sppcGradNamesFilled[] = { "FillStyle", "GradientName", 0 };
+/** Property names for hatch area style in common objects. */
+const sal_Char* const sppcHatchNamesCommon[] = { "FillStyle", "FillHatchName", "FillColor", "FillBackground", 0 };
+/** Property names for hatch area style in filled series objects. */
+const sal_Char* const sppcHatchNamesFilled[] = { "FillStyle", "HatchName", "Color", "FillBackground", 0 };
+/** Property names for bitmap area style. */
+const sal_Char* const sppcBitmapNames[] = { "FillStyle", "FillBitmapName", "FillBitmapMode", 0 };
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclChPropSetHelper::XclChPropSetHelper() :
+ maLineHlpCommon( sppcLineNamesCommon ),
+ maLineHlpLinear( sppcLineNamesLinear ),
+ maLineHlpFilled( sppcLineNamesFilled ),
+ maAreaHlpCommon( sppcAreaNamesCommon ),
+ maAreaHlpFilled( sppcAreaNamesFilled ),
+ maGradHlpCommon( sppcGradNamesCommon ),
+ maGradHlpFilled( sppcGradNamesFilled ),
+ maHatchHlpCommon( sppcHatchNamesCommon ),
+ maHatchHlpFilled( sppcHatchNamesFilled ),
+ maBitmapHlp( sppcBitmapNames )
+{
+}
+
+// read properties ------------------------------------------------------------
+
+void XclChPropSetHelper::ReadLineProperties(
+ XclChLineFormat& rLineFmt, XclChObjectTable& rDashTable,
+ const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode )
+{
+ namespace cssd = ::com::sun::star::drawing;
+
+ // read properties from property set
+ cssd::LineStyle eApiStyle = cssd::LineStyle_NONE;
+ sal_Int32 nApiWidth = 0;
+ sal_Int16 nApiTrans = 0;
+ Any aDashNameAny;
+
+ ScfPropSetHelper& rLineHlp = GetLineHelper( ePropMode );
+ rLineHlp.ReadFromPropertySet( rPropSet );
+ rLineHlp >> eApiStyle >> nApiWidth >> rLineFmt.maColor >> nApiTrans >> aDashNameAny;
+
+ // clear automatic flag
+ ::set_flag( rLineFmt.mnFlags, EXC_CHLINEFORMAT_AUTO, false );
+
+ // line width
+ if( nApiWidth <= 0 ) rLineFmt.mnWeight = EXC_CHLINEFORMAT_HAIR;
+ else if( nApiWidth <= 35 ) rLineFmt.mnWeight = EXC_CHLINEFORMAT_SINGLE;
+ else if( nApiWidth <= 70 ) rLineFmt.mnWeight = EXC_CHLINEFORMAT_DOUBLE;
+ else rLineFmt.mnWeight = EXC_CHLINEFORMAT_TRIPLE;
+
+ // line style
+ switch( eApiStyle )
+ {
+ case cssd::LineStyle_NONE:
+ rLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE;
+ break;
+ case cssd::LineStyle_SOLID:
+ {
+ if( nApiTrans < 13 ) rLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
+ else if( nApiTrans < 38 ) rLineFmt.mnPattern = EXC_CHLINEFORMAT_DARKTRANS;
+ else if( nApiTrans < 63 ) rLineFmt.mnPattern = EXC_CHLINEFORMAT_MEDTRANS;
+ else if( nApiTrans < 100 ) rLineFmt.mnPattern = EXC_CHLINEFORMAT_LIGHTTRANS;
+ else rLineFmt.mnPattern = EXC_CHLINEFORMAT_NONE;
+ }
+ break;
+ case cssd::LineStyle_DASH:
+ {
+ rLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
+ OUString aDashName;
+ cssd::LineDash aApiDash;
+ if( (aDashNameAny >>= aDashName) && (rDashTable.GetObject( aDashName ) >>= aApiDash) )
+ {
+ // reorder dashes that are shorter than dots
+ if( (aApiDash.Dashes == 0) || (aApiDash.DashLen < aApiDash.DotLen) )
+ {
+ ::std::swap( aApiDash.Dashes, aApiDash.Dots );
+ ::std::swap( aApiDash.DashLen, aApiDash.DotLen );
+ }
+ // ignore dots that are nearly equal to dashes
+ if( aApiDash.DotLen * 3 > aApiDash.DashLen * 2 )
+ aApiDash.Dots = 0;
+
+ // convert line dash to predefined Excel dash types
+ if( (aApiDash.Dashes == 1) && (aApiDash.Dots >= 1) )
+ // one dash and one or more dots
+ rLineFmt.mnPattern = (aApiDash.Dots == 1) ?
+ EXC_CHLINEFORMAT_DASHDOT : EXC_CHLINEFORMAT_DASHDOTDOT;
+ else if( aApiDash.Dashes >= 1 )
+ // one or more dashes and no dots (also: dash-dash-dot)
+ rLineFmt.mnPattern = (aApiDash.DashLen < 250) ?
+ EXC_CHLINEFORMAT_DOT : EXC_CHLINEFORMAT_DASH;
+ }
+ }
+ break;
+ default:
+ DBG_ERRORFILE( "XclChPropSetHelper::ReadLineProperties - unknown line style" );
+ rLineFmt.mnPattern = EXC_CHLINEFORMAT_SOLID;
+ }
+}
+
+bool XclChPropSetHelper::ReadAreaProperties( XclChAreaFormat& rAreaFmt,
+ const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode )
+{
+ namespace cssd = ::com::sun::star::drawing;
+
+ // read properties from property set
+ cssd::FillStyle eApiStyle = cssd::FillStyle_NONE;
+ sal_Int16 nTransparency = 0;
+
+ ScfPropSetHelper& rAreaHlp = GetAreaHelper( ePropMode );
+ rAreaHlp.ReadFromPropertySet( rPropSet );
+ rAreaHlp >> eApiStyle >> rAreaFmt.maPattColor >> nTransparency;
+
+ // clear automatic flag
+ ::set_flag( rAreaFmt.mnFlags, EXC_CHAREAFORMAT_AUTO, false );
+
+ // set fill style transparent or solid (set solid for anything but transparent)
+ rAreaFmt.mnPattern = (eApiStyle == cssd::FillStyle_NONE) ? EXC_PATT_NONE : EXC_PATT_SOLID;
+
+ // return true to indicate complex fill (gradient, bitmap, solid transparency)
+ return (eApiStyle != cssd::FillStyle_NONE) && ((eApiStyle != cssd::FillStyle_SOLID) || (nTransparency > 0));
+}
+
+void XclChPropSetHelper::ReadEscherProperties(
+ XclChEscherFormat& rEscherFmt, XclChPicFormat& rPicFmt,
+ XclChObjectTable& rGradientTable, XclChObjectTable& rHatchTable, XclChObjectTable& rBitmapTable,
+ const ScfPropertySet& rPropSet, XclChPropertyMode ePropMode )
+{
+ namespace cssd = ::com::sun::star::drawing;
+ namespace cssa = ::com::sun::star::awt;
+
+ // read style and transparency properties from property set
+ cssd::FillStyle eApiStyle = cssd::FillStyle_NONE;
+ Color aColor;
+ sal_Int16 nTransparency = 0;
+
+ ScfPropSetHelper& rAreaHlp = GetAreaHelper( ePropMode );
+ rAreaHlp.ReadFromPropertySet( rPropSet );
+ rAreaHlp >> eApiStyle >> aColor >> nTransparency;
+
+ switch( eApiStyle )
+ {
+ case cssd::FillStyle_SOLID:
+ {
+ DBG_ASSERT( nTransparency > 0, "XclChPropSetHelper::ReadEscherProperties - unexpected solid area without transparency" );
+ if( (0 < nTransparency) && (nTransparency <= 100) )
+ {
+ // convert to Escher properties
+ sal_uInt32 nEscherColor = 0x02000000;
+ ::insert_value( nEscherColor, aColor.GetBlue(), 16, 8 );
+ ::insert_value( nEscherColor, aColor.GetGreen(), 8, 8 );
+ ::insert_value( nEscherColor, aColor.GetRed(), 0, 8 );
+ sal_uInt32 nEscherOpacity = static_cast< sal_uInt32 >( (100 - nTransparency) * 655.36 );
+ rEscherFmt.mxEscherSet.reset( new EscherPropertyContainer );
+ rEscherFmt.mxEscherSet->AddOpt( ESCHER_Prop_fillType, ESCHER_FillSolid );
+ rEscherFmt.mxEscherSet->AddOpt( ESCHER_Prop_fillColor, nEscherColor );
+ rEscherFmt.mxEscherSet->AddOpt( ESCHER_Prop_fillOpacity, nEscherOpacity );
+ rEscherFmt.mxEscherSet->AddOpt( ESCHER_Prop_fillBackColor, 0x02FFFFFF );
+ rEscherFmt.mxEscherSet->AddOpt( ESCHER_Prop_fillBackOpacity, 0x00010000 );
+ rEscherFmt.mxEscherSet->AddOpt( ESCHER_Prop_fNoFillHitTest, 0x001F001C );
+ }
+ }
+ break;
+ case cssd::FillStyle_GRADIENT:
+ {
+ // extract gradient from global gradient table
+ OUString aGradientName;
+ ScfPropSetHelper& rGradHlp = GetGradientHelper( ePropMode );
+ rGradHlp.ReadFromPropertySet( rPropSet );
+ rGradHlp >> eApiStyle >> aGradientName;
+ cssa::Gradient aGradient;
+ if( rGradientTable.GetObject( aGradientName ) >>= aGradient )
+ {
+ // convert to Escher properties
+ rEscherFmt.mxEscherSet.reset( new EscherPropertyContainer );
+ rEscherFmt.mxEscherSet->CreateGradientProperties( aGradient );
+ }
+ }
+ break;
+ case cssd::FillStyle_HATCH:
+ {
+ // extract hatch from global hatch table
+ OUString aHatchName;
+ bool bFillBackground;
+ ScfPropSetHelper& rHatchHlp = GetHatchHelper( ePropMode );
+ rHatchHlp.ReadFromPropertySet( rPropSet );
+ rHatchHlp >> eApiStyle >> aHatchName >> aColor >> bFillBackground;
+ cssd::Hatch aHatch;
+ if( rHatchTable.GetObject( aHatchName ) >>= aHatch )
+ {
+ // convert to Escher properties
+ rEscherFmt.mxEscherSet.reset( new EscherPropertyContainer );
+ rEscherFmt.mxEscherSet->CreateEmbeddedHatchProperties( aHatch, aColor, bFillBackground );
+ rPicFmt.mnBmpMode = EXC_CHPICFORMAT_STACK;
+ }
+ }
+ break;
+ case cssd::FillStyle_BITMAP:
+ {
+ // extract bitmap URL from global bitmap table
+ OUString aBitmapName;
+ cssd::BitmapMode eApiBmpMode;
+ maBitmapHlp.ReadFromPropertySet( rPropSet );
+ maBitmapHlp >> eApiStyle >> aBitmapName >> eApiBmpMode;
+ OUString aBitmapUrl;
+ if( rBitmapTable.GetObject( aBitmapName ) >>= aBitmapUrl )
+ {
+ // convert to Escher properties
+ rEscherFmt.mxEscherSet.reset( new EscherPropertyContainer );
+ rEscherFmt.mxEscherSet->CreateEmbeddedBitmapProperties( aBitmapUrl, eApiBmpMode );
+ rPicFmt.mnBmpMode = (eApiBmpMode == cssd::BitmapMode_REPEAT) ?
+ EXC_CHPICFORMAT_STACK : EXC_CHPICFORMAT_STRETCH;
+ }
+ }
+ break;
+ default:
+ DBG_ERRORFILE( "XclChPropSetHelper::ReadEscherProperties - unknown fill style" );
+ }
+}
+
+void XclChPropSetHelper::ReadMarkerProperties(
+ XclChMarkerFormat& rMarkerFmt, const ScfPropertySet& rPropSet, sal_uInt16 nFormatIdx )
+{
+ namespace cssc = ::com::sun::star::chart2;
+ namespace cssa = ::com::sun::star::awt;
+ cssc::Symbol aApiSymbol;
+ if( rPropSet.GetProperty( aApiSymbol, EXC_CHPROP_SYMBOL ) )
+ {
+ // clear automatic flag
+ ::set_flag( rMarkerFmt.mnFlags, EXC_CHMARKERFORMAT_AUTO, false );
+
+ // symbol style
+ switch( aApiSymbol.Style )
+ {
+ case cssc::SymbolStyle_NONE:
+ rMarkerFmt.mnMarkerType = EXC_CHMARKERFORMAT_NOSYMBOL;
+ break;
+ case cssc::SymbolStyle_STANDARD:
+ switch( aApiSymbol.StandardSymbol )
+ {
+ case 0: rMarkerFmt.mnMarkerType = EXC_CHMARKERFORMAT_SQUARE; break; // square
+ case 1: rMarkerFmt.mnMarkerType = EXC_CHMARKERFORMAT_DIAMOND; break; // diamond
+ case 2: rMarkerFmt.mnMarkerType = EXC_CHMARKERFORMAT_STDDEV; break; // arrow down
+ case 3: rMarkerFmt.mnMarkerType = EXC_CHMARKERFORMAT_TRIANGLE; break; // arrow up
+ case 4: rMarkerFmt.mnMarkerType = EXC_CHMARKERFORMAT_CIRCLE; break; // arrow right
+ case 5: rMarkerFmt.mnMarkerType = EXC_CHMARKERFORMAT_PLUS; break; // arrow left
+ case 6: rMarkerFmt.mnMarkerType = EXC_CHMARKERFORMAT_CROSS; break; // bow tie
+ case 7: rMarkerFmt.mnMarkerType = EXC_CHMARKERFORMAT_STAR; break; // sand glass
+ default: rMarkerFmt.mnMarkerType = XclChartHelper::GetAutoMarkerType( nFormatIdx );
+ }
+ break;
+ default:
+ rMarkerFmt.mnMarkerType = XclChartHelper::GetAutoMarkerType( nFormatIdx );
+ }
+ bool bHasFillColor = XclChartHelper::HasMarkerFillColor( rMarkerFmt.mnMarkerType );
+ ::set_flag( rMarkerFmt.mnFlags, EXC_CHMARKERFORMAT_NOFILL, !bHasFillColor );
+
+ // symbol size
+ sal_Int32 nApiSize = (aApiSymbol.Size.Width + aApiSymbol.Size.Height + 1) / 2;
+ rMarkerFmt.mnMarkerSize = XclTools::GetTwipsFromHmm( nApiSize );
+
+ // symbol colors
+ rMarkerFmt.maLineColor = ScfApiHelper::ConvertFromApiColor( aApiSymbol.BorderColor );
+ rMarkerFmt.maFillColor = ScfApiHelper::ConvertFromApiColor( aApiSymbol.FillColor );
+ }
+}
+
+sal_uInt16 XclChPropSetHelper::ReadRotationProperties( const ScfPropertySet& rPropSet, bool bSupportsStacked )
+{
+ // chart2 handles rotation as double in the range [0,360)
+ double fAngle = 0.0;
+ rPropSet.GetProperty( fAngle, EXC_CHPROP_TEXTROTATION );
+ bool bStacked = bSupportsStacked && rPropSet.GetBoolProperty( EXC_CHPROP_STACKCHARACTERS );
+ return bStacked ? EXC_ROT_STACKED :
+ XclTools::GetXclRotation( static_cast< sal_Int32 >( fAngle * 100.0 + 0.5 ) );
+}
+
+// write properties -----------------------------------------------------------
+
+void XclChPropSetHelper::WriteLineProperties(
+ ScfPropertySet& rPropSet, XclChObjectTable& rDashTable,
+ const XclChLineFormat& rLineFmt, XclChPropertyMode ePropMode )
+{
+ namespace cssd = ::com::sun::star::drawing;
+
+ // line width
+ sal_Int32 nApiWidth = 0; // 0 is the width of a hair line
+ switch( rLineFmt.mnWeight )
+ {
+ case EXC_CHLINEFORMAT_SINGLE: nApiWidth = 35; break;
+ case EXC_CHLINEFORMAT_DOUBLE: nApiWidth = 70; break;
+ case EXC_CHLINEFORMAT_TRIPLE: nApiWidth = 105; break;
+ }
+
+ // line style
+ cssd::LineStyle eApiStyle = cssd::LineStyle_NONE;
+ sal_Int16 nApiTrans = 0;
+ sal_Int32 nDotLen = ::std::min< sal_Int32 >( rLineFmt.mnWeight + 105, 210 );
+ cssd::LineDash aApiDash( cssd::DashStyle_RECT, 0, nDotLen, 0, 4 * nDotLen, nDotLen );
+
+ switch( rLineFmt.mnPattern )
+ {
+ case EXC_CHLINEFORMAT_SOLID:
+ eApiStyle = cssd::LineStyle_SOLID;
+ break;
+ case EXC_CHLINEFORMAT_DARKTRANS:
+ eApiStyle = cssd::LineStyle_SOLID; nApiTrans = 25;
+ break;
+ case EXC_CHLINEFORMAT_MEDTRANS:
+ eApiStyle = cssd::LineStyle_SOLID; nApiTrans = 50;
+ break;
+ case EXC_CHLINEFORMAT_LIGHTTRANS:
+ eApiStyle = cssd::LineStyle_SOLID; nApiTrans = 75;
+ break;
+ case EXC_CHLINEFORMAT_DASH:
+ eApiStyle = cssd::LineStyle_DASH; aApiDash.Dashes = 1;
+ break;
+ case EXC_CHLINEFORMAT_DOT:
+ eApiStyle = cssd::LineStyle_DASH; aApiDash.Dots = 1;
+ break;
+ case EXC_CHLINEFORMAT_DASHDOT:
+ eApiStyle = cssd::LineStyle_DASH; aApiDash.Dashes = aApiDash.Dots = 1;
+ break;
+ case EXC_CHLINEFORMAT_DASHDOTDOT:
+ eApiStyle = cssd::LineStyle_DASH; aApiDash.Dashes = 1; aApiDash.Dots = 2;
+ break;
+ }
+
+ // line color
+ sal_Int32 nApiColor = ScfApiHelper::ConvertToApiColor( rLineFmt.maColor );
+
+ // try to insert the dash style and receive its name
+ Any aDashNameAny;
+ if( eApiStyle == cssd::LineStyle_DASH )
+ {
+ OUString aDashName = rDashTable.InsertObject( ::com::sun::star::uno::makeAny( aApiDash ) );
+ if( aDashName.getLength() )
+ aDashNameAny <<= aDashName;
+ }
+
+ // write the properties
+ ScfPropSetHelper& rLineHlp = GetLineHelper( ePropMode );
+ rLineHlp.InitializeWrite();
+ rLineHlp << eApiStyle << nApiWidth << nApiColor << nApiTrans << aDashNameAny;
+ rLineHlp.WriteToPropertySet( rPropSet );
+}
+
+void XclChPropSetHelper::WriteAreaProperties( ScfPropertySet& rPropSet,
+ const XclChAreaFormat& rAreaFmt, XclChPropertyMode ePropMode )
+{
+ namespace cssd = ::com::sun::star::drawing;
+ cssd::FillStyle eFillStyle = cssd::FillStyle_NONE;
+ Color aColor;
+ sal_Int16 nTransparency = 0;
+
+ // fill color
+ if( rAreaFmt.mnPattern != EXC_PATT_NONE )
+ {
+ eFillStyle = cssd::FillStyle_SOLID;
+ aColor = XclTools::GetPatternColor( rAreaFmt.maPattColor, rAreaFmt.maBackColor, rAreaFmt.mnPattern );
+ }
+
+ // write the properties
+ ScfPropSetHelper& rAreaHlp = GetAreaHelper( ePropMode );
+ rAreaHlp.InitializeWrite();
+ rAreaHlp << eFillStyle << aColor << nTransparency;
+ rAreaHlp.WriteToPropertySet( rPropSet );
+}
+
+void XclChPropSetHelper::WriteEscherProperties( ScfPropertySet& rPropSet,
+ XclChObjectTable& rGradientTable, XclChObjectTable& /*rHatchTable*/, XclChObjectTable& rBitmapTable,
+ const XclChEscherFormat& rEscherFmt, const XclChPicFormat& rPicFmt,
+ XclChPropertyMode ePropMode )
+{
+ if( rEscherFmt.mxItemSet )
+ {
+ if( const XFillStyleItem* pStyleItem = static_cast< const XFillStyleItem* >( rEscherFmt.mxItemSet->GetItem( XATTR_FILLSTYLE, false ) ) )
+ {
+ switch( pStyleItem->GetValue() )
+ {
+ case XFILL_SOLID:
+ // #i84812# Excel 2007 writes Escher properties for solid fill
+ if( const XFillColorItem* pColorItem = static_cast< const XFillColorItem* >( rEscherFmt.mxItemSet->GetItem( XATTR_FILLCOLOR, false ) ) )
+ {
+ namespace cssd = ::com::sun::star::drawing;
+ // get solid transparence too
+ const XFillTransparenceItem* pTranspItem = static_cast< const XFillTransparenceItem* >( rEscherFmt.mxItemSet->GetItem( XATTR_FILLTRANSPARENCE, false ) );
+ sal_uInt16 nTransp = pTranspItem ? pTranspItem->GetValue() : 0;
+ ScfPropSetHelper& rAreaHlp = GetAreaHelper( ePropMode );
+ rAreaHlp.InitializeWrite();
+ rAreaHlp << cssd::FillStyle_SOLID << pColorItem->GetColorValue() << static_cast< sal_Int16 >( nTransp );
+ rAreaHlp.WriteToPropertySet( rPropSet );
+ }
+ break;
+ case XFILL_GRADIENT:
+ if( const XFillGradientItem* pGradItem = static_cast< const XFillGradientItem* >( rEscherFmt.mxItemSet->GetItem( XATTR_FILLGRADIENT, false ) ) )
+ {
+ Any aGradientAny;
+ if( pGradItem->QueryValue( aGradientAny, MID_FILLGRADIENT ) )
+ {
+ OUString aGradName = rGradientTable.InsertObject( aGradientAny );
+ if( aGradName.getLength() )
+ {
+ namespace cssd = ::com::sun::star::drawing;
+ ScfPropSetHelper& rGradHlp = GetGradientHelper( ePropMode );
+ rGradHlp.InitializeWrite();
+ rGradHlp << cssd::FillStyle_GRADIENT << aGradName;
+ rGradHlp.WriteToPropertySet( rPropSet );
+ }
+ }
+ }
+ break;
+ case XFILL_BITMAP:
+ if( const XFillBitmapItem* pBmpItem = static_cast< const XFillBitmapItem* >( rEscherFmt.mxItemSet->GetItem( XATTR_FILLBITMAP, false ) ) )
+ {
+ Any aBitmapAny;
+ if( pBmpItem->QueryValue( aBitmapAny, MID_GRAFURL ) )
+ {
+ OUString aBmpName = rBitmapTable.InsertObject( aBitmapAny );
+ if( aBmpName.getLength() )
+ {
+ namespace cssd = ::com::sun::star::drawing;
+ cssd::BitmapMode eApiBmpMode = (rPicFmt.mnBmpMode == EXC_CHPICFORMAT_STRETCH) ?
+ cssd::BitmapMode_STRETCH : cssd::BitmapMode_REPEAT;
+ maBitmapHlp.InitializeWrite();
+ maBitmapHlp << cssd::FillStyle_BITMAP << aBmpName << eApiBmpMode;
+ maBitmapHlp.WriteToPropertySet( rPropSet );
+ }
+ }
+ }
+ break;
+ default:
+ DBG_ERRORFILE( "XclChPropSetHelper::WriteEscherProperties - unknown fill mode" );
+ }
+ }
+ }
+}
+
+void XclChPropSetHelper::WriteMarkerProperties(
+ ScfPropertySet& rPropSet, const XclChMarkerFormat& rMarkerFmt )
+{
+ namespace cssc = ::com::sun::star::chart2;
+ namespace cssa = ::com::sun::star::awt;
+
+ // symbol style
+ cssc::Symbol aApiSymbol;
+ aApiSymbol.Style = cssc::SymbolStyle_STANDARD;
+ switch( rMarkerFmt.mnMarkerType )
+ {
+ case EXC_CHMARKERFORMAT_NOSYMBOL: aApiSymbol.Style = cssc::SymbolStyle_NONE; break;
+ case EXC_CHMARKERFORMAT_SQUARE: aApiSymbol.StandardSymbol = 0; break; // square
+ case EXC_CHMARKERFORMAT_DIAMOND: aApiSymbol.StandardSymbol = 1; break; // diamond
+ case EXC_CHMARKERFORMAT_TRIANGLE: aApiSymbol.StandardSymbol = 3; break; // arrow up
+ case EXC_CHMARKERFORMAT_CROSS: aApiSymbol.StandardSymbol = 6; break; // bow tie
+ case EXC_CHMARKERFORMAT_STAR: aApiSymbol.StandardSymbol = 7; break; // sand glass
+ case EXC_CHMARKERFORMAT_DOWJ: aApiSymbol.StandardSymbol = 4; break; // arrow right
+ case EXC_CHMARKERFORMAT_STDDEV: aApiSymbol.StandardSymbol = 2; break; // arrow down
+ case EXC_CHMARKERFORMAT_CIRCLE: aApiSymbol.StandardSymbol = 4; break; // arrow right
+ case EXC_CHMARKERFORMAT_PLUS: aApiSymbol.StandardSymbol = 5; break; // arrow left
+ }
+
+ // symbol size
+ sal_Int32 nApiSize = XclTools::GetHmmFromTwips( rMarkerFmt.mnMarkerSize );
+ aApiSymbol.Size = cssa::Size( nApiSize, nApiSize );
+
+ // symbol colors
+ aApiSymbol.FillColor = ScfApiHelper::ConvertToApiColor( rMarkerFmt.maFillColor );
+ aApiSymbol.BorderColor = ::get_flag( rMarkerFmt.mnFlags, EXC_CHMARKERFORMAT_NOLINE ) ?
+ aApiSymbol.FillColor : ScfApiHelper::ConvertToApiColor( rMarkerFmt.maLineColor );
+
+ // set the property
+ rPropSet.SetProperty( EXC_CHPROP_SYMBOL, aApiSymbol );
+}
+
+void XclChPropSetHelper::WriteRotationProperties(
+ ScfPropertySet& rPropSet, sal_uInt16 nRotation, bool bSupportsStacked )
+{
+ if( nRotation != EXC_CHART_AUTOROTATION )
+ {
+ // chart2 handles rotation as double in the range [0,360)
+ double fAngle = XclTools::GetScRotation( nRotation, 0 ) / 100.0;
+ rPropSet.SetProperty( EXC_CHPROP_TEXTROTATION, fAngle );
+ if( bSupportsStacked )
+ rPropSet.SetProperty( EXC_CHPROP_STACKCHARACTERS, nRotation == EXC_ROT_STACKED );
+ }
+}
+
+// private --------------------------------------------------------------------
+
+ScfPropSetHelper& XclChPropSetHelper::GetLineHelper( XclChPropertyMode ePropMode )
+{
+ switch( ePropMode )
+ {
+ case EXC_CHPROPMODE_COMMON: return maLineHlpCommon;
+ case EXC_CHPROPMODE_LINEARSERIES: return maLineHlpLinear;
+ case EXC_CHPROPMODE_FILLEDSERIES: return maLineHlpFilled;
+ default: DBG_ERRORFILE( "XclChPropSetHelper::GetLineHelper - unknown property mode" );
+ }
+ return maLineHlpCommon;
+}
+
+ScfPropSetHelper& XclChPropSetHelper::GetAreaHelper( XclChPropertyMode ePropMode )
+{
+ switch( ePropMode )
+ {
+ case EXC_CHPROPMODE_COMMON: return maAreaHlpCommon;
+ case EXC_CHPROPMODE_FILLEDSERIES: return maAreaHlpFilled;
+ default: DBG_ERRORFILE( "XclChPropSetHelper::GetAreaHelper - unknown property mode" );
+ }
+ return maAreaHlpCommon;
+}
+
+ScfPropSetHelper& XclChPropSetHelper::GetGradientHelper( XclChPropertyMode ePropMode )
+{
+ switch( ePropMode )
+ {
+ case EXC_CHPROPMODE_COMMON: return maGradHlpCommon;
+ case EXC_CHPROPMODE_FILLEDSERIES: return maGradHlpFilled;
+ default: DBG_ERRORFILE( "XclChPropSetHelper::GetGradientHelper - unknown property mode" );
+ }
+ return maGradHlpCommon;
+}
+
+ScfPropSetHelper& XclChPropSetHelper::GetHatchHelper( XclChPropertyMode ePropMode )
+{
+ switch( ePropMode )
+ {
+ case EXC_CHPROPMODE_COMMON: return maHatchHlpCommon;
+ case EXC_CHPROPMODE_FILLEDSERIES: return maHatchHlpFilled;
+ default: DBG_ERRORFILE( "XclChPropSetHelper::GetHatchHelper - unknown property mode" );
+ }
+ return maHatchHlpCommon;
+}
+
+// ============================================================================
+
+namespace {
+
+/* The following local functions implement getting the XShape interface of all
+ supported title objects (chart and axes). This needs some effort due to the
+ design of the old Chart1 API used to access these objects. */
+
+/** A code fragment that returns a shape object from the passed shape supplier
+ using the specified interface function. Checks a boolean property first. */
+#define EXC_FRAGMENT_GETTITLESHAPE( shape_supplier, supplier_func, property_name ) \
+ ScfPropertySet aPropSet( shape_supplier ); \
+ if( shape_supplier.is() && aPropSet.GetBoolProperty( CREATE_OUSTRING( #property_name ) ) ) \
+ return shape_supplier->supplier_func(); \
+ return Reference< XShape >(); \
+
+/** Implements a function returning the drawing shape of an axis title, if
+ existing, using the specified API interface and its function. */
+#define EXC_DEFINEFUNC_GETAXISTITLESHAPE( func_name, interface_type, supplier_func, property_name ) \
+Reference< XShape > func_name( const Reference< cssc::XChartDocument >& rxChart1Doc ) \
+{ \
+ Reference< cssc::interface_type > xAxisSupp( rxChart1Doc->getDiagram(), UNO_QUERY ); \
+ EXC_FRAGMENT_GETTITLESHAPE( xAxisSupp, supplier_func, property_name ) \
+}
+
+/** Returns the drawing shape of the main title, if existing. */
+Reference< XShape > lclGetMainTitleShape( const Reference< cssc::XChartDocument >& rxChart1Doc )
+{
+ EXC_FRAGMENT_GETTITLESHAPE( rxChart1Doc, getTitle, HasMainTitle )
+}
+
+EXC_DEFINEFUNC_GETAXISTITLESHAPE( lclGetXAxisTitleShape, XAxisXSupplier, getXAxisTitle, HasXAxisTitle )
+EXC_DEFINEFUNC_GETAXISTITLESHAPE( lclGetYAxisTitleShape, XAxisYSupplier, getYAxisTitle, HasYAxisTitle )
+EXC_DEFINEFUNC_GETAXISTITLESHAPE( lclGetZAxisTitleShape, XAxisZSupplier, getZAxisTitle, HasZAxisTitle )
+EXC_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecXAxisTitleShape, XSecondAxisTitleSupplier, getSecondXAxisTitle, HasSecondaryXAxisTitle )
+EXC_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecYAxisTitleShape, XSecondAxisTitleSupplier, getSecondYAxisTitle, HasSecondaryYAxisTitle )
+
+#undef EXC_DEFINEFUNC_GETAXISTITLESHAPE
+#undef EXC_IMPLEMENT_GETTITLESHAPE
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclChRootData::XclChRootData() :
+ mxTypeInfoProv( new XclChTypeInfoProvider ),
+ mxFmtInfoProv( new XclChFormatInfoProvider ),
+ mnBorderGapX( 0 ),
+ mnBorderGapY( 0 )
+{
+ // remember some title shape getter functions
+ maGetShapeFuncs[ XclChTextKey( EXC_CHTEXTTYPE_TITLE ) ] = lclGetMainTitleShape;
+ maGetShapeFuncs[ XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, EXC_CHAXESSET_PRIMARY, EXC_CHAXIS_X ) ] = lclGetXAxisTitleShape;
+ maGetShapeFuncs[ XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, EXC_CHAXESSET_PRIMARY, EXC_CHAXIS_Y ) ] = lclGetYAxisTitleShape;
+ maGetShapeFuncs[ XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, EXC_CHAXESSET_PRIMARY, EXC_CHAXIS_Z ) ] = lclGetZAxisTitleShape;
+ maGetShapeFuncs[ XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, EXC_CHAXESSET_SECONDARY, EXC_CHAXIS_X ) ] = lclGetSecXAxisTitleShape;
+ maGetShapeFuncs[ XclChTextKey( EXC_CHTEXTTYPE_AXISTITLE, EXC_CHAXESSET_SECONDARY, EXC_CHAXIS_Y ) ] = lclGetSecYAxisTitleShape;
+}
+
+XclChRootData::~XclChRootData()
+{
+}
+
+void XclChRootData::InitConversion( const XclRoot& rRoot, const Reference< XChartDocument >& rxChartDoc, const Rectangle& rChartRect )
+{
+ // remember chart document reference and chart shape position/size
+ DBG_ASSERT( rxChartDoc.is(), "XclChRootData::InitConversion - missing chart document" );
+ mxChartDoc = rxChartDoc;
+ maChartRect = rChartRect;
+
+ // Excel excludes a border of 5 pixels in each direction from chart area
+ mnBorderGapX = rRoot.GetHmmFromPixelX( 5.0 );
+ mnBorderGapY = rRoot.GetHmmFromPixelY( 5.0 );
+
+ // size of a chart unit in 1/100 mm
+ mfUnitSizeX = ::std::max< double >( maChartRect.GetWidth() - 2 * mnBorderGapX, mnBorderGapX ) / EXC_CHART_TOTALUNITS;
+ mfUnitSizeY = ::std::max< double >( maChartRect.GetHeight() - 2 * mnBorderGapY, mnBorderGapY ) / EXC_CHART_TOTALUNITS;
+
+ // create object tables
+ Reference< XMultiServiceFactory > xFactory( mxChartDoc, UNO_QUERY );
+ mxLineDashTable.reset( new XclChObjectTable(
+ xFactory, SERVICE_DRAWING_DASHTABLE, CREATE_OUSTRING( "Excel line dash " ) ) );
+ mxGradientTable.reset( new XclChObjectTable(
+ xFactory, SERVICE_DRAWING_GRADIENTTABLE, CREATE_OUSTRING( "Excel gradient " ) ) );
+ mxHatchTable.reset( new XclChObjectTable(
+ xFactory, SERVICE_DRAWING_HATCHTABLE, CREATE_OUSTRING( "Excel hatch " ) ) );
+ mxBitmapTable.reset( new XclChObjectTable(
+ xFactory, SERVICE_DRAWING_BITMAPTABLE, CREATE_OUSTRING( "Excel bitmap " ) ) );
+}
+
+void XclChRootData::FinishConversion()
+{
+ // forget formatting object tables
+ mxBitmapTable.reset();
+ mxHatchTable.reset();
+ mxGradientTable.reset();
+ mxLineDashTable.reset();
+ // forget chart document reference
+ mxChartDoc.clear();
+}
+
+Reference< XShape > XclChRootData::GetTitleShape( const XclChTextKey& rTitleKey ) const
+{
+ XclChGetShapeFuncMap::const_iterator aIt = maGetShapeFuncs.find( rTitleKey );
+ OSL_ENSURE( aIt != maGetShapeFuncs.end(), "XclChRootData::GetTitleShape - invalid title key" );
+ Reference< cssc::XChartDocument > xChart1Doc( mxChartDoc, UNO_QUERY );
+ Reference< XShape > xTitleShape;
+ if( xChart1Doc.is() && (aIt != maGetShapeFuncs.end()) )
+ xTitleShape = (aIt->second)( xChart1Doc );
+ return xTitleShape;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xlescher.cxx b/sc/source/filter/excel/xlescher.cxx
new file mode 100644
index 000000000000..7c531a64d018
--- /dev/null
+++ b/sc/source/filter/excel/xlescher.cxx
@@ -0,0 +1,382 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "xlescher.hxx"
+
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <svx/unoapi.hxx>
+#include "document.hxx"
+#include "xestream.hxx"
+#include "xistream.hxx"
+#include "xlroot.hxx"
+#include "xltools.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::drawing::XControlShape;
+using ::com::sun::star::awt::XControlModel;
+using ::com::sun::star::script::ScriptEventDescriptor;
+
+// Structs and classes ========================================================
+
+XclObjId::XclObjId() :
+ mnScTab( SCTAB_INVALID ),
+ mnObjId( EXC_OBJ_INVALID_ID )
+{
+}
+
+XclObjId::XclObjId( SCTAB nScTab, sal_uInt16 nObjId ) :
+ mnScTab( nScTab ),
+ mnObjId( nObjId )
+{
+}
+
+bool operator==( const XclObjId& rL, const XclObjId& rR )
+{
+ return (rL.mnScTab == rR.mnScTab) && (rL.mnObjId == rR.mnObjId);
+}
+
+bool operator<( const XclObjId& rL, const XclObjId& rR )
+{
+ return (rL.mnScTab < rR.mnScTab) || ((rL.mnScTab == rR.mnScTab) && (rL.mnObjId < rR.mnObjId));
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+/** Returns the scaling factor to calculate coordinates from twips. */
+double lclGetTwipsScale( MapUnit eMapUnit )
+{
+ /* We cannot use OutputDevice::LogicToLogic() or the XclTools
+ conversion functions to calculate drawing layer coordinates due to
+ Calc's strange definition of a point (1 inch == 72.27 points, instead
+ of 72 points). */
+ double fScale = 1.0;
+ switch( eMapUnit )
+ {
+ case MAP_TWIP: fScale = 72 / POINTS_PER_INCH; break; // Calc twips <-> real twips
+ case MAP_100TH_MM: fScale = HMM_PER_TWIPS; break; // Calc twips <-> 1/100mm
+ default: DBG_ERRORFILE( "lclGetTwipsScale - map unit not implemented" );
+ }
+ return fScale;
+}
+
+/** Calculates a drawing layer X position (in twips) from an object column position. */
+long lclGetXFromCol( ScDocument& rDoc, SCTAB nScTab, sal_uInt16 nXclCol, sal_uInt16 nOffset, double fScale )
+{
+ SCCOL nScCol = static_cast< SCCOL >( nXclCol );
+ return static_cast< long >( fScale * (rDoc.GetColOffset( nScCol, nScTab ) +
+ ::std::min( nOffset / 1024.0, 1.0 ) * rDoc.GetColWidth( nScCol, nScTab )) + 0.5 );
+}
+
+/** Calculates a drawing layer Y position (in twips) from an object row position. */
+long lclGetYFromRow( ScDocument& rDoc, SCTAB nScTab, sal_uInt16 nXclRow, sal_uInt16 nOffset, double fScale )
+{
+ SCROW nScRow = static_cast< SCROW >( nXclRow );
+ return static_cast< long >( fScale * (rDoc.GetRowOffset( nScRow, nScTab ) +
+ ::std::min( nOffset / 256.0, 1.0 ) * rDoc.GetRowHeight( nScRow, nScTab )) + 0.5 );
+}
+
+/** Calculates an object column position from a drawing layer X position (in twips). */
+void lclGetColFromX(
+ ScDocument& rDoc, SCTAB nScTab, sal_uInt16& rnXclCol,
+ sal_uInt16& rnOffset, sal_uInt16 nXclStartCol, sal_uInt16 nXclMaxCol,
+ long& rnStartW, long nX, double fScale )
+{
+ // rnStartW in conjunction with nXclStartCol is used as buffer for previously calculated width
+ long nTwipsX = static_cast< long >( nX / fScale + 0.5 );
+ long nColW = 0;
+ for( rnXclCol = nXclStartCol; rnXclCol <= nXclMaxCol; ++rnXclCol )
+ {
+ nColW = rDoc.GetColWidth( static_cast< SCCOL >( rnXclCol ), nScTab );
+ if( rnStartW + nColW > nTwipsX )
+ break;
+ rnStartW += nColW;
+ }
+ rnOffset = nColW ? static_cast< sal_uInt16 >( (nTwipsX - rnStartW) * 1024.0 / nColW + 0.5 ) : 0;
+}
+
+/** Calculates an object row position from a drawing layer Y position (in twips). */
+void lclGetRowFromY(
+ ScDocument& rDoc, SCTAB nScTab, sal_uInt32& rnXclRow,
+ sal_uInt32& rnOffset, sal_uInt32 nXclStartRow, sal_uInt32 nXclMaxRow,
+ long& rnStartH, long nY, double fScale )
+{
+ // rnStartH in conjunction with nXclStartRow is used as buffer for previously calculated height
+ long nTwipsY = static_cast< long >( nY / fScale + 0.5 );
+ long nRowH = 0;
+ bool bFound = false;
+ for( SCROW nRow = static_cast< SCROW >( nXclStartRow ); static_cast<unsigned>(nRow) <= nXclMaxRow; ++nRow )
+ {
+ nRowH = rDoc.GetRowHeight( nRow, nScTab );
+ if( rnStartH + nRowH > nTwipsY )
+ {
+ rnXclRow = static_cast< sal_uInt32 >( nRow );
+ bFound = true;
+ break;
+ }
+ rnStartH += nRowH;
+ }
+ if( !bFound )
+ rnXclRow = nXclMaxRow;
+ rnOffset = static_cast< sal_uInt32 >( nRowH ? ((nTwipsY - rnStartH) * 256.0 / nRowH + 0.5) : 0 );
+}
+
+/** Mirrors a rectangle (from LTR to RTL layout or vice versa). */
+void lclMirrorRectangle( Rectangle& rRect )
+{
+ long nLeft = rRect.Left();
+ rRect.Left() = -rRect.Right();
+ rRect.Right() = -nLeft;
+}
+
+sal_uInt16 lclGetEmbeddedScale( long nPageSize, sal_Int32 nPageScale, long nPos, double fPosScale )
+{
+ return static_cast< sal_uInt16 >( nPos * fPosScale / nPageSize * nPageScale + 0.5 );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclObjAnchor::XclObjAnchor() :
+ mnLX( 0 ),
+ mnTY( 0 ),
+ mnRX( 0 ),
+ mnBY( 0 )
+{
+}
+
+Rectangle XclObjAnchor::GetRect( const XclRoot& rRoot, SCTAB nScTab, MapUnit eMapUnit ) const
+{
+ ScDocument& rDoc = rRoot.GetDoc();
+ double fScale = lclGetTwipsScale( eMapUnit );
+ Rectangle aRect(
+ lclGetXFromCol( rDoc, nScTab, maFirst.mnCol, mnLX, fScale ),
+ lclGetYFromRow( rDoc, nScTab, maFirst.mnRow, mnTY, fScale ),
+ lclGetXFromCol( rDoc, nScTab, maLast.mnCol, mnRX + 1, fScale ),
+ lclGetYFromRow( rDoc, nScTab, maLast.mnRow, mnBY, fScale ) );
+
+ // adjust coordinates in mirrored sheets
+ if( rDoc.IsLayoutRTL( nScTab ) )
+ lclMirrorRectangle( aRect );
+ return aRect;
+}
+
+void XclObjAnchor::SetRect( const XclRoot& rRoot, SCTAB nScTab, const Rectangle& rRect, MapUnit eMapUnit )
+{
+ ScDocument& rDoc = rRoot.GetDoc();
+ sal_uInt16 nXclMaxCol = rRoot.GetXclMaxPos().Col();
+ sal_uInt16 nXclMaxRow = static_cast<sal_uInt16>( rRoot.GetXclMaxPos().Row());
+
+ // adjust coordinates in mirrored sheets
+ Rectangle aRect( rRect );
+ if( rDoc.IsLayoutRTL( nScTab ) )
+ lclMirrorRectangle( aRect );
+
+ double fScale = lclGetTwipsScale( eMapUnit );
+ long nDummy = 0;
+ lclGetColFromX( rDoc, nScTab, maFirst.mnCol, mnLX, 0, nXclMaxCol, nDummy, aRect.Left(), fScale );
+ lclGetColFromX( rDoc, nScTab, maLast.mnCol, mnRX, maFirst.mnCol, nXclMaxCol, nDummy, aRect.Right(), fScale );
+ nDummy = 0;
+ lclGetRowFromY( rDoc, nScTab, maFirst.mnRow, mnTY, 0, nXclMaxRow, nDummy, aRect.Top(), fScale );
+ lclGetRowFromY( rDoc, nScTab, maLast.mnRow, mnBY, maFirst.mnRow, nXclMaxRow, nDummy, aRect.Bottom(), fScale );
+}
+
+void XclObjAnchor::SetRect( const Size& rPageSize, sal_Int32 nScaleX, sal_Int32 nScaleY,
+ const Rectangle& rRect, MapUnit eMapUnit, bool bDffAnchor )
+{
+ double fScale = 1.0;
+ switch( eMapUnit )
+ {
+ case MAP_TWIP: fScale = HMM_PER_TWIPS; break; // Calc twips -> 1/100mm
+ case MAP_100TH_MM: fScale = 1.0; break; // Calc 1/100mm -> 1/100mm
+ default: DBG_ERRORFILE( "XclObjAnchor::SetRect - map unit not implemented" );
+ }
+
+ /* In objects with DFF client anchor, the position of the shape is stored
+ in the cell address components of the client anchor. In old BIFF3-BIFF5
+ objects, the position is stored in the offset components of the anchor. */
+ (bDffAnchor ? maFirst.mnCol : mnLX) = lclGetEmbeddedScale( rPageSize.Width(), nScaleX, rRect.Left(), fScale );
+ (bDffAnchor ? maFirst.mnRow : mnTY) = lclGetEmbeddedScale( rPageSize.Height(), nScaleY, rRect.Top(), fScale );
+ (bDffAnchor ? maLast.mnCol : mnRX) = lclGetEmbeddedScale( rPageSize.Width(), nScaleX, rRect.Right(), fScale );
+ (bDffAnchor ? maLast.mnRow : mnBY) = lclGetEmbeddedScale( rPageSize.Height(), nScaleY, rRect.Bottom(), fScale );
+
+ // for safety, clear the other members
+ if( bDffAnchor )
+ mnLX = mnTY = mnRX = mnBY = 0;
+ else
+ Set( 0, 0, 0, 0 );
+}
+
+// ----------------------------------------------------------------------------
+
+XclObjLineData::XclObjLineData() :
+ mnColorIdx( EXC_OBJ_LINE_AUTOCOLOR ),
+ mnStyle( EXC_OBJ_LINE_SOLID ),
+ mnWidth( EXC_OBJ_LINE_HAIR ),
+ mnAuto( EXC_OBJ_LINE_AUTO )
+{
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclObjLineData& rLineData )
+{
+ return rStrm
+ >> rLineData.mnColorIdx
+ >> rLineData.mnStyle
+ >> rLineData.mnWidth
+ >> rLineData.mnAuto;
+}
+
+// ----------------------------------------------------------------------------
+
+XclObjFillData::XclObjFillData() :
+ mnBackColorIdx( EXC_OBJ_LINE_AUTOCOLOR ),
+ mnPattColorIdx( EXC_OBJ_FILL_AUTOCOLOR ),
+ mnPattern( EXC_PATT_SOLID ),
+ mnAuto( EXC_OBJ_FILL_AUTO )
+{
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclObjFillData& rFillData )
+{
+ return rStrm
+ >> rFillData.mnBackColorIdx
+ >> rFillData.mnPattColorIdx
+ >> rFillData.mnPattern
+ >> rFillData.mnAuto;
+}
+
+// ----------------------------------------------------------------------------
+
+XclObjTextData::XclObjTextData() :
+ mnTextLen( 0 ),
+ mnFormatSize( 0 ),
+ mnLinkSize( 0 ),
+ mnDefFontIdx( EXC_FONT_APP ),
+ mnFlags( 0 ),
+ mnOrient( EXC_OBJ_ORIENT_NONE ),
+ mnButtonFlags( 0 ),
+ mnShortcut( 0 ),
+ mnShortcutEA( 0 )
+{
+}
+
+void XclObjTextData::ReadObj3( XclImpStream& rStrm )
+{
+ rStrm >> mnTextLen;
+ rStrm.Ignore( 2 );
+ rStrm >> mnFormatSize >> mnDefFontIdx;
+ rStrm.Ignore( 2 );
+ rStrm >> mnFlags >> mnOrient;
+ rStrm.Ignore( 8 );
+}
+
+void XclObjTextData::ReadObj5( XclImpStream& rStrm )
+{
+ rStrm >> mnTextLen;
+ rStrm.Ignore( 2 );
+ rStrm >> mnFormatSize >> mnDefFontIdx;
+ rStrm.Ignore( 2 );
+ rStrm >> mnFlags >> mnOrient;
+ rStrm.Ignore( 2 );
+ rStrm >> mnLinkSize;
+ rStrm.Ignore( 2 );
+ rStrm >> mnButtonFlags >> mnShortcut >> mnShortcutEA;
+}
+
+void XclObjTextData::ReadTxo8( XclImpStream& rStrm )
+{
+ rStrm >> mnFlags >> mnOrient >> mnButtonFlags >> mnShortcut >> mnShortcutEA >> mnTextLen >> mnFormatSize;
+}
+
+// ============================================================================
+
+Reference< XControlModel > XclControlHelper::GetControlModel( Reference< XShape > xShape )
+{
+ Reference< XControlModel > xCtrlModel;
+ Reference< XControlShape > xCtrlShape( xShape, UNO_QUERY );
+ if( xCtrlShape.is() )
+ xCtrlModel = xCtrlShape->getControl();
+ return xCtrlModel;
+}
+
+namespace {
+
+static const struct
+{
+ const sal_Char* mpcListenerType;
+ const sal_Char* mpcEventMethod;
+}
+spTbxListenerData[] =
+{
+ // Attention: MUST be in order of the XclTbxEventType enum!
+ /*EXC_TBX_EVENT_ACTION*/ { "XActionListener", "actionPerformed" },
+ /*EXC_TBX_EVENT_MOUSE*/ { "XMouseListener", "mouseReleased" },
+ /*EXC_TBX_EVENT_TEXT*/ { "XTextListener", "textChanged" },
+ /*EXC_TBX_EVENT_VALUE*/ { "XAdjustmentListener", "adjustmentValueChanged" },
+ /*EXC_TBX_EVENT_CHANGE*/ { "XChangeListener", "changed" }
+};
+
+} // namespace
+
+bool XclControlHelper::FillMacroDescriptor( ScriptEventDescriptor& rDescriptor,
+ XclTbxEventType eEventType, const String& rXclMacroName, SfxObjectShell* pDocShell )
+{
+ if( rXclMacroName.Len() > 0 )
+ {
+ rDescriptor.ListenerType = OUString::createFromAscii( spTbxListenerData[ eEventType ].mpcListenerType );
+ rDescriptor.EventMethod = OUString::createFromAscii( spTbxListenerData[ eEventType ].mpcEventMethod );
+ rDescriptor.ScriptType = CREATE_OUSTRING( "Script" );
+ rDescriptor.ScriptCode = XclTools::GetSbMacroUrl( rXclMacroName, pDocShell );
+ return true;
+ }
+ return false;
+}
+
+String XclControlHelper::ExtractFromMacroDescriptor(
+ const ScriptEventDescriptor& rDescriptor, XclTbxEventType eEventType, SfxObjectShell* /*pShell*/ )
+{
+ if( (rDescriptor.ScriptCode.getLength() > 0) &&
+ rDescriptor.ScriptType.equalsIgnoreAsciiCaseAscii( "Script" ) &&
+ rDescriptor.ListenerType.equalsAscii( spTbxListenerData[ eEventType ].mpcListenerType ) &&
+ rDescriptor.EventMethod.equalsAscii( spTbxListenerData[ eEventType ].mpcEventMethod ) )
+ return XclTools::GetXclMacroName( rDescriptor.ScriptCode );
+ return String::EmptyString();
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xlformula.cxx b/sc/source/filter/excel/xlformula.cxx
new file mode 100644
index 000000000000..336de4ded284
--- /dev/null
+++ b/sc/source/filter/excel/xlformula.cxx
@@ -0,0 +1,788 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xlformula.hxx"
+
+#include "compiler.hxx"
+#include "rangenam.hxx"
+#include "token.hxx"
+#include "tokenarray.hxx"
+#include "xestream.hxx"
+#include "xistream.hxx"
+#include "xlroot.hxx"
+
+using namespace ::formula;
+
+// Function data ==============================================================
+
+String XclFunctionInfo::GetMacroFuncName() const
+{
+ if( IsMacroFunc() )
+ return String( mpcMacroName, RTL_TEXTENCODING_UTF8 );
+ return EMPTY_STRING;
+}
+
+// abbreviations for function return token class
+const sal_uInt8 R = EXC_TOKCLASS_REF;
+const sal_uInt8 V = EXC_TOKCLASS_VAL;
+const sal_uInt8 A = EXC_TOKCLASS_ARR;
+
+// abbreviations for parameter infos
+#define RO { EXC_PARAM_REGULAR, EXC_PARAMCONV_ORG, false }
+#define RV { EXC_PARAM_REGULAR, EXC_PARAMCONV_VAL, false }
+#define RA { EXC_PARAM_REGULAR, EXC_PARAMCONV_ARR, false }
+#define RR { EXC_PARAM_REGULAR, EXC_PARAMCONV_RPT, false }
+#define RX { EXC_PARAM_REGULAR, EXC_PARAMCONV_RPX, false }
+#define VO { EXC_PARAM_REGULAR, EXC_PARAMCONV_ORG, true }
+#define VV { EXC_PARAM_REGULAR, EXC_PARAMCONV_VAL, true }
+#define VA { EXC_PARAM_REGULAR, EXC_PARAMCONV_ARR, true }
+#define VR { EXC_PARAM_REGULAR, EXC_PARAMCONV_RPT, true }
+#define VX { EXC_PARAM_REGULAR, EXC_PARAMCONV_RPX, true }
+#define RO_E { EXC_PARAM_EXCELONLY, EXC_PARAMCONV_ORG, false }
+#define VR_E { EXC_PARAM_EXCELONLY, EXC_PARAMCONV_RPT, true }
+#define C { EXC_PARAM_CALCONLY, EXC_PARAMCONV_ORG, false }
+
+const sal_uInt16 NOID = SAL_MAX_UINT16; /// No BIFF/OOBIN function identifier available.
+const sal_uInt8 MX = 30; /// Maximum parameter count.
+
+#define EXC_FUNCNAME( ascii ) "_xlfn." ascii
+#define EXC_FUNCNAME_ODF( ascii ) "_xlfnodf." ascii
+
+/** Functions new in BIFF2. */
+static const XclFunctionInfo saFuncTable_2[] =
+{
+ { ocCount, 0, 0, MX, V, { RX }, 0, 0 },
+ { ocIf, 1, 2, 3, R, { VO, RO }, 0, 0 },
+ { ocIsNA, 2, 1, 1, V, { VR }, 0, 0 },
+ { ocIsError, 3, 1, 1, V, { VR }, 0, 0 },
+ { ocSum, 4, 0, MX, V, { RX }, 0, 0 },
+ { ocAverage, 5, 1, MX, V, { RX }, 0, 0 },
+ { ocMin, 6, 1, MX, V, { RX }, 0, 0 },
+ { ocMax, 7, 1, MX, V, { RX }, 0, 0 },
+ { ocRow, 8, 0, 1, V, { RO }, 0, 0 },
+ { ocColumn, 9, 0, 1, V, { RO }, 0, 0 },
+ { ocNotAvail, 10, 0, 0, V, {}, 0, 0 },
+ { ocNPV, 11, 2, MX, V, { VR, RX }, 0, 0 },
+ { ocStDev, 12, 1, MX, V, { RX }, 0, 0 },
+ { ocCurrency, 13, 1, 2, V, { VR }, 0, 0 },
+ { ocFixed, 14, 1, 2, V, { VR, VR, C }, 0, 0 },
+ { ocSin, 15, 1, 1, V, { VR }, 0, 0 },
+ { ocCos, 16, 1, 1, V, { VR }, 0, 0 },
+ { ocTan, 17, 1, 1, V, { VR }, 0, 0 },
+ { ocCot, 17, 1, 1, V, { VR }, EXC_FUNCFLAG_EXPORTONLY, 0 },
+ { ocArcTan, 18, 1, 1, V, { VR }, 0, 0 },
+ { ocArcCot, 18, 1, 1, V, { VR }, EXC_FUNCFLAG_EXPORTONLY, 0 },
+ { ocPi, 19, 0, 0, V, {}, 0, 0 },
+ { ocSqrt, 20, 1, 1, V, { VR }, 0, 0 },
+ { ocExp, 21, 1, 1, V, { VR }, 0, 0 },
+ { ocLn, 22, 1, 1, V, { VR }, 0, 0 },
+ { ocLog10, 23, 1, 1, V, { VR }, 0, 0 },
+ { ocAbs, 24, 1, 1, V, { VR }, 0, 0 },
+ { ocInt, 25, 1, 1, V, { VR }, 0, 0 },
+ { ocPlusMinus, 26, 1, 1, V, { VR }, 0, 0 },
+ { ocRound, 27, 2, 2, V, { VR }, 0, 0 },
+ { ocLookup, 28, 2, 3, V, { VR, RA }, 0, 0 },
+ { ocIndex, 29, 2, 4, R, { RA, VV }, 0, 0 },
+ { ocRept, 30, 2, 2, V, { VR }, 0, 0 },
+ { ocMid, 31, 3, 3, V, { VR }, 0, 0 },
+ { ocLen, 32, 1, 1, V, { VR }, 0, 0 },
+ { ocValue, 33, 1, 1, V, { VR }, 0, 0 },
+ { ocTrue, 34, 0, 0, V, {}, 0, 0 },
+ { ocFalse, 35, 0, 0, V, {}, 0, 0 },
+ { ocAnd, 36, 1, MX, V, { RX }, 0, 0 },
+ { ocOr, 37, 1, MX, V, { RX }, 0, 0 },
+ { ocNot, 38, 1, 1, V, { VR }, 0, 0 },
+ { ocMod, 39, 2, 2, V, { VR }, 0, 0 },
+ { ocDBCount, 40, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocDBSum, 41, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocDBAverage, 42, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocDBMin, 43, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocDBMax, 44, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocDBStdDev, 45, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocVar, 46, 1, MX, V, { RX }, 0, 0 },
+ { ocDBVar, 47, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocText, 48, 2, 2, V, { VR }, 0, 0 },
+ { ocRGP, 49, 1, 2, A, { RA, RA, C, C }, 0, 0 },
+ { ocTrend, 50, 1, 3, A, { RA, RA, RA, C }, 0, 0 },
+ { ocRKP, 51, 1, 2, A, { RA, RA, C, C }, 0, 0 },
+ { ocGrowth, 52, 1, 3, A, { RA, RA, RA, C }, 0, 0 },
+ { ocBW, 56, 3, 5, V, { VR }, 0, 0 },
+ { ocZW, 57, 3, 5, V, { VR }, 0, 0 },
+ { ocZZR, 58, 3, 5, V, { VR }, 0, 0 },
+ { ocRMZ, 59, 3, 5, V, { VR }, 0, 0 },
+ { ocZins, 60, 3, 6, V, { VR }, 0, 0 },
+ { ocMIRR, 61, 3, 3, V, { RA, VR }, 0, 0 },
+ { ocIRR, 62, 1, 2, V, { RA, VR }, 0, 0 },
+ { ocRandom, 63, 0, 0, V, {}, EXC_FUNCFLAG_VOLATILE, 0 },
+ { ocMatch, 64, 2, 3, V, { VR, RX, RR }, 0, 0 },
+ { ocGetDate, 65, 3, 3, V, { VR }, 0, 0 },
+ { ocGetTime, 66, 3, 3, V, { VR }, 0, 0 },
+ { ocGetDay, 67, 1, 1, V, { VR }, 0, 0 },
+ { ocGetMonth, 68, 1, 1, V, { VR }, 0, 0 },
+ { ocGetYear, 69, 1, 1, V, { VR }, 0, 0 },
+ { ocGetDayOfWeek, 70, 1, 1, V, { VR, C }, 0, 0 },
+ { ocGetHour, 71, 1, 1, V, { VR }, 0, 0 },
+ { ocGetMin, 72, 1, 1, V, { VR }, 0, 0 },
+ { ocGetSec, 73, 1, 1, V, { VR }, 0, 0 },
+ { ocGetActTime, 74, 0, 0, V, {}, EXC_FUNCFLAG_VOLATILE, 0 },
+ { ocAreas, 75, 1, 1, V, { RO }, 0, 0 },
+ { ocRows, 76, 1, 1, V, { RO }, 0, 0 },
+ { ocColumns, 77, 1, 1, V, { RO }, 0, 0 },
+ { ocOffset, 78, 3, 5, R, { RO, VR }, EXC_FUNCFLAG_VOLATILE, 0 },
+ { ocSearch, 82, 2, 3, V, { VR }, 0, 0 },
+ { ocMatTrans, 83, 1, 1, A, { VO }, 0, 0 },
+ { ocType, 86, 1, 1, V, { VX }, 0, 0 },
+ { ocArcTan2, 97, 2, 2, V, { VR }, 0, 0 },
+ { ocArcSin, 98, 1, 1, V, { VR }, 0, 0 },
+ { ocArcCos, 99, 1, 1, V, { VR }, 0, 0 },
+ { ocChose, 100, 2, MX, R, { VO, RO }, 0, 0 },
+ { ocHLookup, 101, 3, 3, V, { VV, RO, RO, C }, 0, 0 },
+ { ocVLookup, 102, 3, 3, V, { VV, RO, RO, C }, 0, 0 },
+ { ocIsRef, 105, 1, 1, V, { RX }, 0, 0 },
+ { ocLog, 109, 1, 2, V, { VR }, 0, 0 },
+ { ocChar, 111, 1, 1, V, { VR }, 0, 0 },
+ { ocLower, 112, 1, 1, V, { VR }, 0, 0 },
+ { ocUpper, 113, 1, 1, V, { VR }, 0, 0 },
+ { ocPropper, 114, 1, 1, V, { VR }, 0, 0 },
+ { ocLeft, 115, 1, 2, V, { VR }, 0, 0 },
+ { ocRight, 116, 1, 2, V, { VR }, 0, 0 },
+ { ocExact, 117, 2, 2, V, { VR }, 0, 0 },
+ { ocTrim, 118, 1, 1, V, { VR }, 0, 0 },
+ { ocReplace, 119, 4, 4, V, { VR }, 0, 0 },
+ { ocSubstitute, 120, 3, 4, V, { VR }, 0, 0 },
+ { ocCode, 121, 1, 1, V, { VR }, 0, 0 },
+ { ocFind, 124, 2, 3, V, { VR }, 0, 0 },
+ { ocCell, 125, 1, 2, V, { VV, RO }, EXC_FUNCFLAG_VOLATILE, 0 },
+ { ocIsErr, 126, 1, 1, V, { VR }, 0, 0 },
+ { ocIsString, 127, 1, 1, V, { VR }, 0, 0 },
+ { ocIsValue, 128, 1, 1, V, { VR }, 0, 0 },
+ { ocIsEmpty, 129, 1, 1, V, { VR }, 0, 0 },
+ { ocT, 130, 1, 1, V, { RO }, 0, 0 },
+ { ocN, 131, 1, 1, V, { RO }, 0, 0 },
+ { ocGetDateValue, 140, 1, 1, V, { VR }, 0, 0 },
+ { ocGetTimeValue, 141, 1, 1, V, { VR }, 0, 0 },
+ { ocLIA, 142, 3, 3, V, { VR }, 0, 0 },
+ { ocDIA, 143, 4, 4, V, { VR }, 0, 0 },
+ { ocGDA, 144, 4, 5, V, { VR }, 0, 0 },
+ { ocIndirect, 148, 1, 2, R, { VR }, EXC_FUNCFLAG_VOLATILE, 0 },
+ { ocClean, 162, 1, 1, V, { VR }, 0, 0 },
+ { ocMatDet, 163, 1, 1, V, { VA }, 0, 0 },
+ { ocMatInv, 164, 1, 1, A, { VA }, 0, 0 },
+ { ocMatMult, 165, 2, 2, A, { VA }, 0, 0 },
+ { ocZinsZ, 167, 4, 6, V, { VR }, 0, 0 },
+ { ocKapz, 168, 4, 6, V, { VR }, 0, 0 },
+ { ocCount2, 169, 0, MX, V, { RX }, 0, 0 },
+ { ocProduct, 183, 0, MX, V, { RX }, 0, 0 },
+ { ocFact, 184, 1, 1, V, { VR }, 0, 0 },
+ { ocDBProduct, 189, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocIsNonString, 190, 1, 1, V, { VR }, 0, 0 },
+ { ocStDevP, 193, 1, MX, V, { RX }, 0, 0 },
+ { ocVarP, 194, 1, MX, V, { RX }, 0, 0 },
+ { ocDBStdDevP, 195, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocDBVarP, 196, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocTrunc, 197, 1, 1, V, { VR, C }, 0, 0 },
+ { ocIsLogical, 198, 1, 1, V, { VR }, 0, 0 },
+ { ocDBCount2, 199, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocCurrency, 204, 1, 2, V, { VR }, EXC_FUNCFLAG_IMPORTONLY, 0 },
+ { ocRoundUp, 212, 2, 2, V, { VR }, 0, 0 },
+ { ocRoundDown, 213, 2, 2, V, { VR }, 0, 0 },
+ { ocExternal, 255, 1, MX, R, { RO_E, RO }, EXC_FUNCFLAG_IMPORTONLY, 0 }
+};
+
+/** Functions new in BIFF3. */
+static const XclFunctionInfo saFuncTable_3[] =
+{
+ { ocRGP, 49, 1, 4, A, { RA, RA, VV }, 0, 0 }, // BIFF2: 1-2, BIFF3: 1-4
+ { ocTrend, 50, 1, 4, A, { RA, RA, RA, VV }, 0, 0 }, // BIFF2: 1-3, BIFF3: 1-4
+ { ocRKP, 51, 1, 4, A, { RA, RA, VV }, 0, 0 }, // BIFF2: 1-2, BIFF3: 1-4
+ { ocGrowth, 52, 1, 4, A, { RA, RA, RA, VV }, 0, 0 }, // BIFF2: 1-3, BIFF3: 1-4
+ { ocTrunc, 197, 1, 2, V, { VR }, 0, 0 }, // BIFF2: 1, BIFF3: 1-2
+ { ocAddress, 219, 2, 5, V, { VR }, 0, 0 },
+ { ocGetDiffDate360, 220, 2, 2, V, { VR, VR, C }, 0, 0 },
+ { ocGetActDate, 221, 0, 0, V, {}, EXC_FUNCFLAG_VOLATILE, 0 },
+ { ocVBD, 222, 5, 7, V, { VR }, 0, 0 },
+ { ocMedian, 227, 1, MX, V, { RX }, 0, 0 },
+ { ocSumProduct, 228, 1, MX, V, { VA }, 0, 0 },
+ { ocSinHyp, 229, 1, 1, V, { VR }, 0, 0 },
+ { ocCosHyp, 230, 1, 1, V, { VR }, 0, 0 },
+ { ocTanHyp, 231, 1, 1, V, { VR }, 0, 0 },
+ { ocCotHyp, 231, 1, 1, V, { VR }, EXC_FUNCFLAG_EXPORTONLY, 0 },
+ { ocArcSinHyp, 232, 1, 1, V, { VR }, 0, 0 },
+ { ocArcCosHyp, 233, 1, 1, V, { VR }, 0, 0 },
+ { ocArcTanHyp, 234, 1, 1, V, { VR }, 0, 0 },
+ { ocArcCotHyp, 234, 1, 1, V, { VR }, EXC_FUNCFLAG_EXPORTONLY, 0 },
+ { ocDBGet, 235, 3, 3, V, { RO, RR }, 0, 0 },
+ { ocInfo, 244, 1, 1, V, { VR }, EXC_FUNCFLAG_VOLATILE, 0 }
+};
+
+/** Functions new in BIFF4. */
+static const XclFunctionInfo saFuncTable_4[] =
+{
+ { ocFixed, 14, 1, 3, V, { VR }, 0, 0 }, // BIFF2-3: 1-2, BIFF4: 1-3
+ { ocAsc, 214, 1, 1, V, { VR }, 0, 0 },
+ { ocJis, 215, 1, 1, V, { VR }, 0, 0 },
+ { ocRank, 216, 2, 3, V, { VR, RO, VR }, 0, 0 },
+ { ocGDA2, 247, 4, 5, V, { VR }, 0, 0 },
+ { ocFrequency, 252, 2, 2, A, { RA }, 0, 0 },
+ { ocErrorType, 261, 1, 1, V, { VR }, 0, 0 },
+ { ocAveDev, 269, 1, MX, V, { RX }, 0, 0 },
+ { ocBetaDist, 270, 3, 5, V, { VR }, 0, 0 },
+ { ocGammaLn, 271, 1, 1, V, { VR }, 0, 0 },
+ { ocBetaInv, 272, 3, 5, V, { VR }, 0, 0 },
+ { ocBinomDist, 273, 4, 4, V, { VR }, 0, 0 },
+ { ocChiDist, 274, 2, 2, V, { VR }, 0, 0 },
+ { ocChiInv, 275, 2, 2, V, { VR }, 0, 0 },
+ { ocKombin, 276, 2, 2, V, { VR }, 0, 0 },
+ { ocConfidence, 277, 3, 3, V, { VR }, 0, 0 },
+ { ocKritBinom, 278, 3, 3, V, { VR }, 0, 0 },
+ { ocEven, 279, 1, 1, V, { VR }, 0, 0 },
+ { ocExpDist, 280, 3, 3, V, { VR }, 0, 0 },
+ { ocFDist, 281, 3, 3, V, { VR }, 0, 0 },
+ { ocFInv, 282, 3, 3, V, { VR }, 0, 0 },
+ { ocFisher, 283, 1, 1, V, { VR }, 0, 0 },
+ { ocFisherInv, 284, 1, 1, V, { VR }, 0, 0 },
+ { ocFloor, 285, 2, 2, V, { VR, VR, C }, 0, 0 },
+ { ocGammaDist, 286, 4, 4, V, { VR }, 0, 0 },
+ { ocGammaInv, 287, 3, 3, V, { VR }, 0, 0 },
+ { ocCeil, 288, 2, 2, V, { VR, VR, C }, 0, 0 },
+ { ocHypGeomDist, 289, 4, 4, V, { VR }, 0, 0 },
+ { ocLogNormDist, 290, 3, 3, V, { VR }, 0, 0 },
+ { ocLogInv, 291, 3, 3, V, { VR }, 0, 0 },
+ { ocNegBinomVert, 292, 3, 3, V, { VR }, 0, 0 },
+ { ocNormDist, 293, 4, 4, V, { VR }, 0, 0 },
+ { ocStdNormDist, 294, 1, 1, V, { VR }, 0, 0 },
+ { ocNormInv, 295, 3, 3, V, { VR }, 0, 0 },
+ { ocSNormInv, 296, 1, 1, V, { VR }, 0, 0 },
+ { ocStandard, 297, 3, 3, V, { VR }, 0, 0 },
+ { ocOdd, 298, 1, 1, V, { VR }, 0, 0 },
+ { ocVariationen, 299, 2, 2, V, { VR }, 0, 0 },
+ { ocPoissonDist, 300, 3, 3, V, { VR }, 0, 0 },
+ { ocTDist, 301, 3, 3, V, { VR }, 0, 0 },
+ { ocWeibull, 302, 4, 4, V, { VR }, 0, 0 },
+ { ocSumXMY2, 303, 2, 2, V, { VA }, 0, 0 },
+ { ocSumX2MY2, 304, 2, 2, V, { VA }, 0, 0 },
+ { ocSumX2DY2, 305, 2, 2, V, { VA }, 0, 0 },
+ { ocChiTest, 306, 2, 2, V, { VA }, 0, 0 },
+ { ocCorrel, 307, 2, 2, V, { VA }, 0, 0 },
+ { ocCovar, 308, 2, 2, V, { VA }, 0, 0 },
+ { ocForecast, 309, 3, 3, V, { VR, VA }, 0, 0 },
+ { ocFTest, 310, 2, 2, V, { VA }, 0, 0 },
+ { ocIntercept, 311, 2, 2, V, { VA }, 0, 0 },
+ { ocPearson, 312, 2, 2, V, { VA }, 0, 0 },
+ { ocRSQ, 313, 2, 2, V, { VA }, 0, 0 },
+ { ocSTEYX, 314, 2, 2, V, { VA }, 0, 0 },
+ { ocSlope, 315, 2, 2, V, { VA }, 0, 0 },
+ { ocTTest, 316, 4, 4, V, { VA, VA, VR }, 0, 0 },
+ { ocProb, 317, 3, 4, V, { VA, VA, VR }, 0, 0 },
+ { ocDevSq, 318, 1, MX, V, { RX }, 0, 0 },
+ { ocGeoMean, 319, 1, MX, V, { RX }, 0, 0 },
+ { ocHarMean, 320, 1, MX, V, { RX }, 0, 0 },
+ { ocSumSQ, 321, 0, MX, V, { RX }, 0, 0 },
+ { ocKurt, 322, 1, MX, V, { RX }, 0, 0 },
+ { ocSchiefe, 323, 1, MX, V, { RX }, 0, 0 },
+ { ocZTest, 324, 2, 3, V, { RX, VR }, 0, 0 },
+ { ocLarge, 325, 2, 2, V, { RX, VR }, 0, 0 },
+ { ocSmall, 326, 2, 2, V, { RX, VR }, 0, 0 },
+ { ocQuartile, 327, 2, 2, V, { RX, VR }, 0, 0 },
+ { ocPercentile, 328, 2, 2, V, { RX, VR }, 0, 0 },
+ { ocPercentrank, 329, 2, 3, V, { RX, VR, VR_E }, 0, 0 },
+ { ocModalValue, 330, 1, MX, V, { VA }, 0, 0 },
+ { ocTrimMean, 331, 2, 2, V, { RX, VR }, 0, 0 },
+ { ocTInv, 332, 2, 2, V, { VR }, 0, 0 }
+};
+
+/** Functions new in BIFF5/BIFF7. Unsupported functions: DATEDIF, DATESTRING, NUMBERSTRING. */
+static const XclFunctionInfo saFuncTable_5[] =
+{
+ { ocGetDayOfWeek, 70, 1, 2, V, { VR }, 0, 0 }, // BIFF2-4: 1, BIFF5: 1-2
+ { ocHLookup, 101, 3, 4, V, { VV, RO, RO, VV }, 0, 0 }, // BIFF2-4: 3, BIFF5: 3-4
+ { ocVLookup, 102, 3, 4, V, { VV, RO, RO, VV }, 0, 0 }, // BIFF2-4: 3, BIFF5: 3-4
+ { ocGetDiffDate360, 220, 2, 3, V, { VR }, 0, 0 }, // BIFF3-4: 2, BIFF5: 2-3
+ { ocMacro, 255, 1, MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY, 0 },
+ { ocExternal, 255, 1, MX, R, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY, 0 },
+ { ocConcat, 336, 0, MX, V, { VR }, 0, 0 },
+ { ocPower, 337, 2, 2, V, { VR }, 0, 0 },
+ { ocRad, 342, 1, 1, V, { VR }, 0, 0 },
+ { ocDeg, 343, 1, 1, V, { VR }, 0, 0 },
+ { ocSubTotal, 344, 2, MX, V, { VR, RO }, 0, 0 },
+ { ocSumIf, 345, 2, 3, V, { RO, VR, RO }, 0, 0 },
+ { ocCountIf, 346, 2, 2, V, { RO, VR }, 0, 0 },
+ { ocCountEmptyCells, 347, 1, 1, V, { RO }, 0, 0 },
+ { ocISPMT, 350, 4, 4, V, { VR }, 0, 0 },
+ { ocNoName, 351, 3, 3, V, { VR }, EXC_FUNCFLAG_IMPORTONLY, 0 }, // DATEDIF
+ { ocNoName, 352, 1, 1, V, { VR }, EXC_FUNCFLAG_IMPORTONLY, 0 }, // DATESTRING
+ { ocNoName, 353, 2, 2, V, { VR }, EXC_FUNCFLAG_IMPORTONLY, 0 }, // NUMBERSTRING
+ { ocRoman, 354, 1, 2, V, { VR }, 0, 0 }
+};
+
+/** Functions new in BIFF8. Unsupported functions: PHONETIC. */
+static const XclFunctionInfo saFuncTable_8[] =
+{
+ { ocGetPivotData, 358, 2, MX, V, { RR, RR, VR }, 0, 0 },
+ { ocHyperLink, 359, 1, 2, V, { VV, VO }, 0, 0 },
+ { ocNoName, 360, 1, 1, V, { RO }, EXC_FUNCFLAG_IMPORTONLY, 0 }, // PHONETIC
+ { ocAverageA, 361, 1, MX, V, { RX }, 0, 0 },
+ { ocMaxA, 362, 1, MX, V, { RX }, 0, 0 },
+ { ocMinA, 363, 1, MX, V, { RX }, 0, 0 },
+ { ocStDevPA, 364, 1, MX, V, { RX }, 0, 0 },
+ { ocVarPA, 365, 1, MX, V, { RX }, 0, 0 },
+ { ocStDevA, 366, 1, MX, V, { RX }, 0, 0 },
+ { ocVarA, 367, 1, MX, V, { RX }, 0, 0 },
+ { ocBahtText, 368, 1, 1, V, { VR }, EXC_FUNCFLAG_IMPORTONLY, EXC_FUNCNAME( "BAHTTEXT" ) },
+ { ocBahtText, 255, 2, 2, V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY, EXC_FUNCNAME( "BAHTTEXT" ) },
+ { ocEuroConvert, 255, 4, 6, V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY, "EUROCONVERT" }
+};
+
+#define EXC_FUNCENTRY_ODF( opcode, minparam, maxparam, flags, asciiname ) \
+ { opcode, NOID, minparam, maxparam, V, { VR }, EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME_ODF( asciiname ) }, \
+ { opcode, 255, (minparam)+1, (maxparam)+1, V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME_ODF( asciiname ) }
+
+/** Functions defined by OpenFormula, but not supported by Calc (ocNoName) or by Excel (defined op-code). */
+static const XclFunctionInfo saFuncTable_Odf[] =
+{
+ EXC_FUNCENTRY_ODF( ocArabic, 1, 1, 0, "ARABIC" ),
+ EXC_FUNCENTRY_ODF( ocB, 3, 4, 0, "B" ),
+ EXC_FUNCENTRY_ODF( ocBase, 2, 3, 0, "BASE" ),
+ EXC_FUNCENTRY_ODF( ocNoName, 2, 2, 0, "BITAND" ),
+ EXC_FUNCENTRY_ODF( ocNoName, 2, 2, 0, "BITLSHIFT" ),
+ EXC_FUNCENTRY_ODF( ocNoName, 2, 2, 0, "BITOR" ),
+ EXC_FUNCENTRY_ODF( ocNoName, 2, 2, 0, "BITRSHIFT" ),
+ EXC_FUNCENTRY_ODF( ocNoName, 2, 2, 0, "BITXOR" ),
+ EXC_FUNCENTRY_ODF( ocChiSqDist, 2, 3, 0, "CHISQDIST" ),
+ EXC_FUNCENTRY_ODF( ocChiSqInv, 2, 2, 0, "CHISQINV" ),
+ EXC_FUNCENTRY_ODF( ocKombin2, 2, 2, 0, "COMBINA" ),
+ EXC_FUNCENTRY_ODF( ocGetDiffDate, 2, 2, 0, "DAYS" ),
+ EXC_FUNCENTRY_ODF( ocDecimal, 2, 2, 0, "DECIMAL" ),
+ EXC_FUNCENTRY_ODF( ocFDist, 3, 4, 0, "FDIST" ),
+ EXC_FUNCENTRY_ODF( ocFInv, 3, 3, 0, "FINV" ),
+ EXC_FUNCENTRY_ODF( ocFormula, 1, 1, 0, "FORMULA" ),
+ EXC_FUNCENTRY_ODF( ocGamma, 1, 1, 0, "GAMMA" ),
+ EXC_FUNCENTRY_ODF( ocGauss, 1, 1, 0, "GAUSS" ),
+ EXC_FUNCENTRY_ODF( ocNoName, 2, 2, 0, "IFNA" ),
+ EXC_FUNCENTRY_ODF( ocIsFormula, 1, 1, 0, "ISFORMULA" ),
+ EXC_FUNCENTRY_ODF( ocWeek, 1, 2, 0, "ISOWEEKNUM" ),
+ EXC_FUNCENTRY_ODF( ocMatrixUnit, 1, 1, 0, "MUNIT" ),
+ EXC_FUNCENTRY_ODF( ocNumberValue, 2, 2, 0, "NUMBERVALUE" ),
+ EXC_FUNCENTRY_ODF( ocLaufz, 3, 3, 0, "PDURATION" ),
+ EXC_FUNCENTRY_ODF( ocVariationen2, 2, 2, 0, "PERMUTATIONA" ),
+ EXC_FUNCENTRY_ODF( ocPhi, 1, 1, 0, "PHI" ),
+ EXC_FUNCENTRY_ODF( ocZGZ, 3, 3, 0, "RRI" ),
+ EXC_FUNCENTRY_ODF( ocTable, 0, 1, 0, "SHEET" ),
+ EXC_FUNCENTRY_ODF( ocTables, 0, 1, 0, "SHEETS" ),
+ EXC_FUNCENTRY_ODF( ocNoName, 1, MX, 0, "SKEWP" ),
+ EXC_FUNCENTRY_ODF( ocUnichar, 1, 1, 0, "UNICHAR" ),
+ EXC_FUNCENTRY_ODF( ocUnicode, 1, 1, 0, "UNICODE" ),
+ EXC_FUNCENTRY_ODF( ocNoName, 1, MX, 0, "XOR" )
+};
+
+#undef EXC_FUNCENTRY_ODF
+
+// ----------------------------------------------------------------------------
+
+XclFunctionProvider::XclFunctionProvider( const XclRoot& rRoot )
+{
+ void (XclFunctionProvider::*pFillFunc)( const XclFunctionInfo*, const XclFunctionInfo* ) =
+ rRoot.IsImport() ? &XclFunctionProvider::FillXclFuncMap : &XclFunctionProvider::FillScFuncMap;
+
+ /* Only read/write functions supported in the current BIFF version.
+ Function tables from later BIFF versions may overwrite single functions
+ from earlier tables. */
+ XclBiff eBiff = rRoot.GetBiff();
+ if( eBiff >= EXC_BIFF2 )
+ (this->*pFillFunc)( saFuncTable_2, STATIC_TABLE_END( saFuncTable_2 ) );
+ if( eBiff >= EXC_BIFF3 )
+ (this->*pFillFunc)( saFuncTable_3, STATIC_TABLE_END( saFuncTable_3 ) );
+ if( eBiff >= EXC_BIFF4 )
+ (this->*pFillFunc)( saFuncTable_4, STATIC_TABLE_END( saFuncTable_4 ) );
+ if( eBiff >= EXC_BIFF5 )
+ (this->*pFillFunc)( saFuncTable_5, STATIC_TABLE_END( saFuncTable_5 ) );
+ if( eBiff >= EXC_BIFF8 )
+ (this->*pFillFunc)( saFuncTable_8, STATIC_TABLE_END( saFuncTable_8 ) );
+ (this->*pFillFunc)( saFuncTable_Odf, STATIC_TABLE_END( saFuncTable_Odf ) );
+}
+
+const XclFunctionInfo* XclFunctionProvider::GetFuncInfoFromXclFunc( sal_uInt16 nXclFunc ) const
+{
+ // only in import filter allowed
+ DBG_ASSERT( !maXclFuncMap.empty(), "XclFunctionProvider::GetFuncInfoFromXclFunc - wrong filter" );
+ XclFuncMap::const_iterator aIt = maXclFuncMap.find( nXclFunc );
+ return (aIt == maXclFuncMap.end()) ? 0 : aIt->second;
+}
+
+const XclFunctionInfo* XclFunctionProvider::GetFuncInfoFromXclMacroName( const String& rXclMacroName ) const
+{
+ // only in import filter allowed, but do not test maXclMacroNameMap, it may be empty for old BIFF versions
+ DBG_ASSERT( !maXclFuncMap.empty(), "XclFunctionProvider::GetFuncInfoFromXclMacroName - wrong filter" );
+ XclMacroNameMap::const_iterator aIt = maXclMacroNameMap.find( rXclMacroName );
+ return (aIt == maXclMacroNameMap.end()) ? 0 : aIt->second;
+}
+
+const XclFunctionInfo* XclFunctionProvider::GetFuncInfoFromOpCode( OpCode eOpCode ) const
+{
+ // only in export filter allowed
+ DBG_ASSERT( !maScFuncMap.empty(), "XclFunctionProvider::GetFuncInfoFromOpCode - wrong filter" );
+ ScFuncMap::const_iterator aIt = maScFuncMap.find( eOpCode );
+ return (aIt == maScFuncMap.end()) ? 0 : aIt->second;
+}
+
+void XclFunctionProvider::FillXclFuncMap( const XclFunctionInfo* pBeg, const XclFunctionInfo* pEnd )
+{
+ for( const XclFunctionInfo* pIt = pBeg; pIt != pEnd; ++pIt )
+ {
+ if( !::get_flag( pIt->mnFlags, EXC_FUNCFLAG_EXPORTONLY ) )
+ {
+ maXclFuncMap[ pIt->mnXclFunc ] = pIt;
+ if( pIt->IsMacroFunc() )
+ maXclMacroNameMap[ pIt->GetMacroFuncName() ] = pIt;
+ }
+ }
+}
+
+void XclFunctionProvider::FillScFuncMap( const XclFunctionInfo* pBeg, const XclFunctionInfo* pEnd )
+{
+ for( const XclFunctionInfo* pIt = pBeg; pIt != pEnd; ++pIt )
+ if( !::get_flag( pIt->mnFlags, EXC_FUNCFLAG_IMPORTONLY ) )
+ maScFuncMap[ pIt->meOpCode ] = pIt;
+}
+
+// Token array ================================================================
+
+XclTokenArray::XclTokenArray( bool bVolatile ) :
+ mbVolatile( bVolatile )
+{
+}
+
+XclTokenArray::XclTokenArray( ScfUInt8Vec& rTokVec, bool bVolatile ) :
+ mbVolatile( bVolatile )
+{
+ maTokVec.swap( rTokVec );
+}
+
+XclTokenArray::XclTokenArray( ScfUInt8Vec& rTokVec, ScfUInt8Vec& rExtDataVec, bool bVolatile ) :
+ mbVolatile( bVolatile )
+{
+ maTokVec.swap( rTokVec );
+ maExtDataVec.swap( rExtDataVec );
+}
+
+sal_uInt16 XclTokenArray::GetSize() const
+{
+ DBG_ASSERT( maTokVec.size() <= 0xFFFF, "XclTokenArray::GetSize - array too long" );
+ return limit_cast< sal_uInt16 >( maTokVec.size() );
+}
+
+void XclTokenArray::ReadSize( XclImpStream& rStrm )
+{
+ sal_uInt16 nSize;
+ rStrm >> nSize;
+ maTokVec.resize( nSize );
+}
+
+void XclTokenArray::ReadArray( XclImpStream& rStrm )
+{
+ if( !maTokVec.empty() )
+ rStrm.Read( &maTokVec.front(), GetSize() );
+}
+
+void XclTokenArray::Read( XclImpStream& rStrm )
+{
+ ReadSize( rStrm );
+ ReadArray( rStrm );
+}
+
+void XclTokenArray::WriteSize( XclExpStream& rStrm ) const
+{
+ rStrm << GetSize();
+}
+
+void XclTokenArray::WriteArray( XclExpStream& rStrm ) const
+{
+ if( !maTokVec.empty() )
+ rStrm.Write( &maTokVec.front(), GetSize() );
+ if( !maExtDataVec.empty() )
+ rStrm.Write( &maExtDataVec.front(), maExtDataVec.size() );
+}
+
+void XclTokenArray::Write( XclExpStream& rStrm ) const
+{
+ WriteSize( rStrm );
+ WriteArray( rStrm );
+}
+
+bool XclTokenArray::operator==( const XclTokenArray& rTokArr ) const
+{
+ return (mbVolatile == rTokArr.mbVolatile) && (maTokVec == rTokArr.maTokVec) && (maExtDataVec == rTokArr.maExtDataVec);
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclTokenArray& rTokArr )
+{
+ rTokArr.Read( rStrm );
+ return rStrm;
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclTokenArrayRef& rxTokArr )
+{
+ if( !rxTokArr )
+ rxTokArr.reset( new XclTokenArray );
+ rxTokArr->Read( rStrm );
+ return rStrm;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclTokenArray& rTokArr )
+{
+ rTokArr.Write( rStrm );
+ return rStrm;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclTokenArrayRef& rxTokArr )
+{
+ if( rxTokArr )
+ rxTokArr->Write( rStrm );
+ else
+ rStrm << sal_uInt16( 0 );
+ return rStrm;
+}
+
+// ----------------------------------------------------------------------------
+
+XclTokenArrayIterator::XclTokenArrayIterator() :
+ mppScTokenBeg( 0 ),
+ mppScTokenEnd( 0 ),
+ mppScToken( 0 ),
+ mbSkipSpaces( false )
+{
+}
+
+XclTokenArrayIterator::XclTokenArrayIterator( const ScTokenArray& rScTokArr, bool bSkipSpaces )
+{
+ Init( rScTokArr, bSkipSpaces );
+}
+
+XclTokenArrayIterator::XclTokenArrayIterator( const XclTokenArrayIterator& rTokArrIt, bool bSkipSpaces ) :
+ mppScTokenBeg( rTokArrIt.mppScTokenBeg ),
+ mppScTokenEnd( rTokArrIt.mppScTokenEnd ),
+ mppScToken( rTokArrIt.mppScToken ),
+ mbSkipSpaces( bSkipSpaces )
+{
+ SkipSpaces();
+}
+
+void XclTokenArrayIterator::Init()
+{
+ mppScTokenBeg = mppScTokenEnd = mppScToken = 0;
+}
+
+void XclTokenArrayIterator::Init( const ScTokenArray& rScTokArr, bool bSkipSpaces )
+{
+ sal_uInt16 nTokArrLen = rScTokArr.GetLen();
+ mppScTokenBeg = static_cast< const FormulaToken* const* >( nTokArrLen ? rScTokArr.GetArray() : 0 );
+ mppScTokenEnd = mppScTokenBeg ? (mppScTokenBeg + nTokArrLen) : 0;
+ mppScToken = (mppScTokenBeg != mppScTokenEnd) ? mppScTokenBeg : 0;
+ mbSkipSpaces = bSkipSpaces;
+ SkipSpaces();
+}
+
+XclTokenArrayIterator& XclTokenArrayIterator::operator++()
+{
+ NextRawToken();
+ SkipSpaces();
+ return *this;
+}
+
+void XclTokenArrayIterator::NextRawToken()
+{
+ if( mppScToken )
+ if( (++mppScToken == mppScTokenEnd) || !*mppScToken )
+ mppScToken = 0;
+}
+
+void XclTokenArrayIterator::SkipSpaces()
+{
+ if( mbSkipSpaces )
+ while( Is() && ((*this)->GetOpCode() == ocSpaces) )
+ NextRawToken();
+}
+
+// strings and string lists ---------------------------------------------------
+
+bool XclTokenArrayHelper::GetTokenString( String& rString, const FormulaToken& rScToken )
+{
+ bool bIsStr = (rScToken.GetType() == svString) && (rScToken.GetOpCode() == ocPush);
+ if( bIsStr ) rString = rScToken.GetString();
+ return bIsStr;
+}
+
+bool XclTokenArrayHelper::GetString( String& rString, const ScTokenArray& rScTokArr )
+{
+ XclTokenArrayIterator aIt( rScTokArr, true );
+ // something is following the string token -> error
+ return aIt.Is() && GetTokenString( rString, *aIt ) && !++aIt;
+}
+
+bool XclTokenArrayHelper::GetStringList( String& rStringList, const ScTokenArray& rScTokArr, sal_Unicode cSep )
+{
+ bool bRet = true;
+ String aString;
+ XclTokenArrayIterator aIt( rScTokArr, true );
+ enum { STATE_START, STATE_STR, STATE_SEP, STATE_END } eState = STATE_START;
+ while( eState != STATE_END ) switch( eState )
+ {
+ case STATE_START:
+ eState = aIt.Is() ? STATE_STR : STATE_END;
+ break;
+ case STATE_STR:
+ bRet = GetTokenString( aString, *aIt );
+ if( bRet ) rStringList.Append( aString );
+ eState = (bRet && (++aIt).Is()) ? STATE_SEP : STATE_END;
+ break;
+ case STATE_SEP:
+ bRet = aIt->GetOpCode() == ocSep;
+ if( bRet ) rStringList.Append( cSep );
+ eState = (bRet && (++aIt).Is()) ? STATE_STR : STATE_END;
+ break;
+ default:;
+ }
+ return bRet;
+}
+
+void XclTokenArrayHelper::ConvertStringToList( ScTokenArray& rScTokArr, sal_Unicode cStringSep, bool bTrimLeadingSpaces )
+{
+ String aString;
+ if( GetString( aString, rScTokArr ) )
+ {
+ rScTokArr.Clear();
+ xub_StrLen nTokenCnt = aString.GetTokenCount( cStringSep );
+ xub_StrLen nStringIx = 0;
+ for( xub_StrLen nToken = 0; nToken < nTokenCnt; ++nToken )
+ {
+ String aToken( aString.GetToken( 0, cStringSep, nStringIx ) );
+ if( bTrimLeadingSpaces )
+ aToken.EraseLeadingChars( ' ' );
+ if( nToken > 0 )
+ rScTokArr.AddOpCode( ocSep );
+ rScTokArr.AddString( aToken );
+ }
+ }
+}
+
+// shared formulas ------------------------------------------------------------
+
+const ScTokenArray* XclTokenArrayHelper::GetSharedFormula( const XclRoot& rRoot, const ScTokenArray& rScTokArr )
+{
+ if( rScTokArr.GetLen() == 1 )
+ if( const FormulaToken* pScToken = rScTokArr.GetArray()[ 0 ] )
+ if( pScToken->GetOpCode() == ocName )
+ if( ScRangeData* pData = rRoot.GetNamedRanges().findByIndex( pScToken->GetIndex() ) )
+ if( pData->HasType( RT_SHARED ) )
+ return pData->GetCode();
+ return 0;
+}
+
+// multiple operations --------------------------------------------------------
+
+namespace {
+
+inline bool lclGetAddress( ScAddress& rAddress, const FormulaToken& rToken )
+{
+ OpCode eOpCode = rToken.GetOpCode();
+ bool bIsSingleRef = (eOpCode == ocPush) && (rToken.GetType() == svSingleRef);
+ if( bIsSingleRef )
+ {
+ const ScSingleRefData& rRef = static_cast<const ScToken&>(rToken).GetSingleRef();
+ rAddress.Set( rRef.nCol, rRef.nRow, rRef.nTab );
+ bIsSingleRef = !rRef.IsDeleted();
+ }
+ return bIsSingleRef;
+}
+
+} // namespace
+
+bool XclTokenArrayHelper::GetMultipleOpRefs( XclMultipleOpRefs& rRefs, const ScTokenArray& rScTokArr )
+{
+ rRefs.mbDblRefMode = false;
+ enum
+ {
+ stBegin, stTableOp, stOpen, stFormula, stFormulaSep,
+ stColFirst, stColFirstSep, stColRel, stColRelSep,
+ stRowFirst, stRowFirstSep, stRowRel, stClose, stError
+ } eState = stBegin; // last read token
+ for( XclTokenArrayIterator aIt( rScTokArr, true ); aIt.Is() && (eState != stError); ++aIt )
+ {
+ OpCode eOpCode = aIt->GetOpCode();
+ bool bIsSep = eOpCode == ocSep;
+ switch( eState )
+ {
+ case stBegin:
+ eState = (eOpCode == ocTableOp) ? stTableOp : stError;
+ break;
+ case stTableOp:
+ eState = (eOpCode == ocOpen) ? stOpen : stError;
+ break;
+ case stOpen:
+ eState = lclGetAddress( rRefs.maFmlaScPos, *aIt ) ? stFormula : stError;
+ break;
+ case stFormula:
+ eState = bIsSep ? stFormulaSep : stError;
+ break;
+ case stFormulaSep:
+ eState = lclGetAddress( rRefs.maColFirstScPos, *aIt ) ? stColFirst : stError;
+ break;
+ case stColFirst:
+ eState = bIsSep ? stColFirstSep : stError;
+ break;
+ case stColFirstSep:
+ eState = lclGetAddress( rRefs.maColRelScPos, *aIt ) ? stColRel : stError;
+ break;
+ case stColRel:
+ eState = bIsSep ? stColRelSep : ((eOpCode == ocClose) ? stClose : stError);
+ break;
+ case stColRelSep:
+ eState = lclGetAddress( rRefs.maRowFirstScPos, *aIt ) ? stRowFirst : stError;
+ rRefs.mbDblRefMode = true;
+ break;
+ case stRowFirst:
+ eState = bIsSep ? stRowFirstSep : stError;
+ break;
+ case stRowFirstSep:
+ eState = lclGetAddress( rRefs.maRowRelScPos, *aIt ) ? stRowRel : stError;
+ break;
+ case stRowRel:
+ eState = (eOpCode == ocClose) ? stClose : stError;
+ break;
+ default:
+ eState = stError;
+ }
+ }
+ return eState == stClose;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xlpage.cxx b/sc/source/filter/excel/xlpage.cxx
new file mode 100644
index 000000000000..1fd4d155f5c4
--- /dev/null
+++ b/sc/source/filter/excel/xlpage.cxx
@@ -0,0 +1,277 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xlpage.hxx"
+#include <sfx2/printer.hxx>
+#include <editeng/svxenum.hxx>
+#include <editeng/paperinf.hxx>
+#include <vcl/svapp.hxx>
+#include <sal/macros.h>
+#include "scitems.hxx"
+#include <editeng/brshitem.hxx>
+#include "global.hxx"
+#include "xlconst.hxx"
+#include <oox/core/xmlfilterbase.hxx>
+
+// Paper size =================================================================
+
+struct XclPaperSize
+{
+ Paper mePaper; /// SVX paper size identifier.
+ long mnWidth; /// Paper width in twips.
+ long mnHeight; /// Paper height in twips.
+};
+
+#define IN2TWIPS( v ) ((long)((v) * EXC_TWIPS_PER_INCH + 0.5))
+#define MM2TWIPS( v ) ((long)((v) * EXC_TWIPS_PER_INCH / CM_PER_INCH / 10.0 + 0.5))
+#define TWIPS2MM( v ) ((long)((v - 0.5) / EXC_TWIPS_PER_INCH * CM_PER_INCH * 10.0))
+
+
+static const XclPaperSize pPaperSizeTable[] =
+{
+/* 0*/ { PAPER_USER, 0, 0 }, // undefined
+ { PAPER_LETTER, IN2TWIPS( 8.5 ), IN2TWIPS( 11 ) }, // Letter
+ { PAPER_USER, IN2TWIPS( 8.5 ), IN2TWIPS( 11 ) }, // Letter Small
+ { PAPER_TABLOID, IN2TWIPS( 11 ), IN2TWIPS( 17 ) }, // Tabloid
+ { PAPER_LEDGER, IN2TWIPS( 17 ), IN2TWIPS( 11 ) }, // Ledger
+/* 5*/ { PAPER_LEGAL, IN2TWIPS( 8.5 ), IN2TWIPS( 14 ) }, // Legal
+ { PAPER_STATEMENT, IN2TWIPS( 5.5 ), IN2TWIPS( 8.5 ) }, // Statement
+ { PAPER_EXECUTIVE, IN2TWIPS( 7.25 ), IN2TWIPS( 10.5 ) }, // Executive
+ { PAPER_A3, MM2TWIPS( 297 ), MM2TWIPS( 420 ) }, // A3
+ { PAPER_A4, MM2TWIPS( 210 ), MM2TWIPS( 297 ) }, // A4
+/* 10*/ { PAPER_USER, MM2TWIPS( 210 ), MM2TWIPS( 297 ) }, // A4 Small
+ { PAPER_A5, MM2TWIPS( 148 ), MM2TWIPS( 210 ) }, // A5
+ //See: http://wiki.services.openoffice.org/wiki/DefaultPaperSize comments
+ //near DMPAPER_B4 in vcl
+ //i.e.
+ //http://msdn.microsoft.com/en-us/library/bb241398.aspx makes the claim:
+ //xlPaperB4 12 B4 (250 mm x 354 mm)
+ //xlPaperB5 13 A5 (148 mm x 210 mm)
+ //but, a paper enum called B5 is surely not actually "A5", and furthermore
+ //the XlPaperSize enumeration otherwise follows the DMPAPER values
+ //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx
+ //which has
+ //DMPAPER_B4 12 B4 (JIS) 250 x 354
+ //DMPAPER_B5 13 B5 (JIS) 182 x 257 mm
+ //which claim them to be the JIS sizes. Though that document then gives
+ //"B4 (JIS)" an *ISO* B4 size in the text, but
+ //http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf
+ //claims that the MS DMPAPER_B4 and DMPAPER_B5 truly are the JIS sizes
+ //which at least makes some sort of sense. (cmc)
+ { PAPER_B4_JIS, MM2TWIPS( 257 ), MM2TWIPS( 364 ) }, // B4 (JIS)
+ { PAPER_B5_JIS, MM2TWIPS( 182 ), MM2TWIPS( 257 ) }, // B5 (JIS)
+ { PAPER_USER, IN2TWIPS( 8.5 ), IN2TWIPS( 13 ) }, // Folio
+/* 15*/ { PAPER_QUARTO, MM2TWIPS( 215 ), MM2TWIPS( 275 ) }, // Quarto
+ { PAPER_10x14, IN2TWIPS( 10 ), IN2TWIPS( 14 ) }, // 10x14
+ { PAPER_USER, IN2TWIPS( 11 ), IN2TWIPS( 17 ) }, // 11x17
+ { PAPER_USER, IN2TWIPS( 8.5 ), IN2TWIPS( 11 ) }, // Note
+ { PAPER_ENV_9, IN2TWIPS( 3.875 ), IN2TWIPS( 8.875 ) }, // Envelope #9
+/* 20*/ { PAPER_ENV_10, IN2TWIPS( 4.125 ), IN2TWIPS( 9.5 ) }, // Envelope #10
+ { PAPER_ENV_11, IN2TWIPS( 4.5 ), IN2TWIPS( 10.375 ) }, // Envelope #11
+ { PAPER_ENV_12, IN2TWIPS( 4.75 ), IN2TWIPS( 11 ) }, // Envelope #12
+ { PAPER_ENV_14, IN2TWIPS( 5 ), IN2TWIPS( 11.5 ) }, // Envelope #14
+ { PAPER_C, IN2TWIPS( 17 ), IN2TWIPS( 22 ) }, // ANSI-C
+/* 25*/ { PAPER_D, IN2TWIPS( 22 ), IN2TWIPS( 34 ) }, // ANSI-D
+ { PAPER_E, IN2TWIPS( 34 ), IN2TWIPS( 44 ) }, // ANSI-E
+ { PAPER_ENV_DL, MM2TWIPS( 110 ), MM2TWIPS( 220 ) }, // Envelope DL
+ { PAPER_ENV_C5, MM2TWIPS( 162 ), MM2TWIPS( 229 ) }, // Envelope C5
+ { PAPER_ENV_C3, MM2TWIPS( 324 ), MM2TWIPS( 458 ) }, // Envelope C3
+/* 30*/ { PAPER_ENV_C4, MM2TWIPS( 229 ), MM2TWIPS( 324 ) }, // Envelope C4
+ { PAPER_ENV_C6, MM2TWIPS( 114 ), MM2TWIPS( 162 ) }, // Envelope C6
+ { PAPER_ENV_C65, MM2TWIPS( 114 ), MM2TWIPS( 229 ) }, // Envelope C65
+ { PAPER_B4_ISO, MM2TWIPS( 250 ), MM2TWIPS( 353 ) }, // B4 (ISO)
+ { PAPER_B5_ISO, MM2TWIPS( 176 ), MM2TWIPS( 250 ) }, // B5 (ISO)
+/* 35*/ { PAPER_B6_ISO, MM2TWIPS( 125 ), MM2TWIPS( 176 ) }, // B6 (ISO)
+ { PAPER_ENV_ITALY, MM2TWIPS( 110 ), MM2TWIPS( 230 ) }, // Envelope Italy
+ { PAPER_ENV_MONARCH, IN2TWIPS( 3.875 ), IN2TWIPS( 7.5 ) }, // Envelope Monarch
+ { PAPER_ENV_PERSONAL, IN2TWIPS( 3.625 ), IN2TWIPS( 6.5 ) }, // 6 3/4 Envelope
+ { PAPER_FANFOLD_US, IN2TWIPS( 14.875 ), IN2TWIPS( 11 ) }, // US Std Fanfold
+/* 40*/ { PAPER_FANFOLD_DE, IN2TWIPS( 8.5 ), IN2TWIPS( 12 ) }, // German Std Fanfold
+ { PAPER_FANFOLD_LEGAL_DE, IN2TWIPS( 8.5 ), IN2TWIPS( 13 ) }, // German Legal Fanfold
+ { PAPER_B4_ISO, MM2TWIPS( 250 ), MM2TWIPS( 353 ) }, // B4 (ISO)
+ { PAPER_POSTCARD_JP,MM2TWIPS( 100 ), MM2TWIPS( 148 ) }, // Japanese Postcard
+ { PAPER_9x11, IN2TWIPS( 9 ), IN2TWIPS( 11 ) }, // 9x11
+/* 45*/ { PAPER_10x11, IN2TWIPS( 10 ), IN2TWIPS( 11 ) }, // 10x11
+ { PAPER_15x11, IN2TWIPS( 15 ), IN2TWIPS( 11 ) }, // 15x11
+ { PAPER_ENV_INVITE, MM2TWIPS( 220 ), MM2TWIPS( 220 ) }, // Envelope Invite
+ { PAPER_USER, 0, 0 }, // undefined
+ { PAPER_USER, 0, 0 }, // undefined
+/* 50*/ { PAPER_USER, IN2TWIPS( 9.5 ), IN2TWIPS( 12 ) }, // Letter Extra
+ { PAPER_USER, IN2TWIPS( 9.5 ), IN2TWIPS( 15 ) }, // Legal Extra
+ { PAPER_USER, IN2TWIPS( 11.69 ), IN2TWIPS( 18 ) }, // Tabloid Extra
+ { PAPER_USER, MM2TWIPS( 235 ), MM2TWIPS( 322 ) }, // A4 Extra
+ { PAPER_USER, IN2TWIPS( 8.5 ), IN2TWIPS( 11 ) }, // Letter Transverse
+/* 55*/ { PAPER_USER, MM2TWIPS( 210 ), MM2TWIPS( 297 ) }, // A4 Transverse
+ { PAPER_USER, IN2TWIPS( 9.5 ), IN2TWIPS( 12 ) }, // Letter Extra Transverse
+ { PAPER_A_PLUS, MM2TWIPS( 227 ), MM2TWIPS( 356 ) }, // Super A/A4
+ { PAPER_B_PLUS, MM2TWIPS( 305 ), MM2TWIPS( 487 ) }, // Super B/A3
+ { PAPER_LETTER_PLUS,IN2TWIPS( 8.5 ), IN2TWIPS( 12.69 ) }, // Letter Plus
+/* 60*/ { PAPER_A4_PLUS, MM2TWIPS( 210 ), MM2TWIPS( 330 ) }, // A4 Plus
+ { PAPER_USER, MM2TWIPS( 148 ), MM2TWIPS( 210 ) }, // A5 Transverse
+ { PAPER_USER, MM2TWIPS( 182 ), MM2TWIPS( 257 ) }, // B5 (JIS) Transverse
+ { PAPER_USER, MM2TWIPS( 322 ), MM2TWIPS( 445 ) }, // A3 Extra
+ { PAPER_USER, MM2TWIPS( 174 ), MM2TWIPS( 235 ) }, // A5 Extra
+/* 65*/ { PAPER_USER, MM2TWIPS( 201 ), MM2TWIPS( 276 ) }, // B5 (ISO) Extra
+ { PAPER_A2, MM2TWIPS( 420 ), MM2TWIPS( 594 ) }, // A2
+ { PAPER_USER, MM2TWIPS( 297 ), MM2TWIPS( 420 ) }, // A3 Transverse
+ { PAPER_USER, MM2TWIPS( 322 ), MM2TWIPS( 445 ) }, // A3 Extra Transverse
+ { PAPER_DOUBLEPOSTCARD_JP, MM2TWIPS( 200 ), MM2TWIPS( 148 ) }, // Double Japanese Postcard
+/* 70*/ { PAPER_A6, MM2TWIPS( 105 ), MM2TWIPS( 148 ) }, // A6
+ { PAPER_USER, 0, 0 }, // undefined
+ { PAPER_USER, 0, 0 }, // undefined
+ { PAPER_USER, 0, 0 }, // undefined
+ { PAPER_USER, 0, 0 }, // undefined
+/* 75*/ { PAPER_USER, IN2TWIPS( 11 ), IN2TWIPS( 8.5 ) }, // Letter Rotated
+ { PAPER_USER, MM2TWIPS( 420 ), MM2TWIPS( 297 ) }, // A3 Rotated
+ { PAPER_USER, MM2TWIPS( 297 ), MM2TWIPS( 210 ) }, // A4 Rotated
+ { PAPER_USER, MM2TWIPS( 210 ), MM2TWIPS( 148 ) }, // A5 Rotated
+ { PAPER_USER, MM2TWIPS( 364 ), MM2TWIPS( 257 ) }, // B4 (JIS) Rotated
+/* 80*/ { PAPER_USER, MM2TWIPS( 257 ), MM2TWIPS( 182 ) }, // B5 (JIS) Rotated
+ { PAPER_USER, MM2TWIPS( 148 ), MM2TWIPS( 100 ) }, // Japanese Postcard Rotated
+ { PAPER_USER, MM2TWIPS( 148 ), MM2TWIPS( 200 ) }, // Double Japanese Postcard Rotated
+ { PAPER_USER, MM2TWIPS( 148 ), MM2TWIPS( 105 ) }, // A6 Rotated
+ { PAPER_USER, 0, 0 }, // undefined
+/* 85*/ { PAPER_USER, 0, 0 }, // undefined
+ { PAPER_USER, 0, 0 }, // undefined
+ { PAPER_USER, 0, 0 }, // undefined
+ { PAPER_B6_JIS, MM2TWIPS( 128 ), MM2TWIPS( 182 ) }, // B6 (JIS)
+ { PAPER_USER, MM2TWIPS( 182 ), MM2TWIPS( 128 ) }, // B6 (JIS) Rotated
+/* 90*/ { PAPER_12x11, IN2TWIPS( 12 ), IN2TWIPS( 11 ) } // 12x11
+};
+
+#undef IN2TWIPS
+#undef MM2TWIPS
+
+// Page settings ==============================================================
+
+XclPageData::XclPageData()
+{
+ SetDefaults();
+}
+
+XclPageData::~XclPageData()
+{
+ // SvxBrushItem incomplete in header
+}
+
+void XclPageData::SetDefaults()
+{
+ maHorPageBreaks.clear();
+ maVerPageBreaks.clear();
+ mxBrushItem.reset();
+ maHeader.Erase();
+ maFooter.Erase();
+ mfLeftMargin = mfRightMargin = XclTools::GetInchFromHmm( EXC_MARGIN_DEFAULT_LR );
+ mfTopMargin = mfBottomMargin = XclTools::GetInchFromHmm( EXC_MARGIN_DEFAULT_TB );
+ mfHeaderMargin = mfFooterMargin = XclTools::GetInchFromHmm( EXC_MARGIN_DEFAULT_HF );
+ mfHdrLeftMargin = mfHdrRightMargin = XclTools::GetInchFromHmm( EXC_MARGIN_DEFAULT_HLR );
+ mfFtrLeftMargin = mfFtrRightMargin = XclTools::GetInchFromHmm( EXC_MARGIN_DEFAULT_FLR );
+ mnPaperSize = EXC_PAPERSIZE_DEFAULT;
+ mnPaperWidth = 0;
+ mnPaperHeight = 0;
+ mnCopies = 1;
+ mnStartPage = 0;
+ mnScaling = 100;
+ mnFitToWidth = mnFitToHeight = 1;
+ mnHorPrintRes = mnVerPrintRes = 300;
+ mbValid = false;
+ mbPortrait = true;
+ mbPrintInRows = mbBlackWhite = mbDraftQuality = mbPrintNotes = mbManualStart = mbFitToPages = false;
+ mbHorCenter = mbVerCenter = mbPrintHeadings = mbPrintGrid = false;
+}
+
+Size XclPageData::GetScPaperSize() const
+{
+ const XclPaperSize* pEntry = pPaperSizeTable;
+ if( mnPaperSize < SAL_N_ELEMENTS( pPaperSizeTable ) )
+ pEntry += mnPaperSize;
+
+ Size aSize;
+ if( pEntry->mePaper == PAPER_USER )
+ aSize = Size( pEntry->mnWidth, pEntry->mnHeight );
+ else
+ aSize = SvxPaperInfo::GetPaperSize( pEntry->mePaper );
+
+ // invalid size -> back to default
+ if( !aSize.Width() || !aSize.Height() )
+ aSize = SvxPaperInfo::GetDefaultPaperSize();
+
+ if( !mbPortrait )
+ ::std::swap( aSize.Width(), aSize.Height() );
+
+ return aSize;
+}
+
+void XclPageData::SetScPaperSize( const Size& rSize, bool bPortrait, bool bStrictSize )
+{
+ mbPortrait = bPortrait;
+ mnPaperSize = 0;
+ long nWidth = bPortrait ? rSize.Width() : rSize.Height();
+ long nHeight = bPortrait ? rSize.Height() : rSize.Width();
+ long nMaxWDiff = 80;
+ long nMaxHDiff = 50;
+
+ mnPaperWidth = TWIPS2MM( nWidth );
+ mnPaperHeight = TWIPS2MM( nHeight );
+ if( bStrictSize )
+ {
+ nMaxWDiff = 5;
+ nMaxHDiff = 5;
+ mnStrictPaperSize = EXC_PAPERSIZE_USER;
+ }
+ else
+ {
+ mnPaperSize = 0;
+ }
+
+ for( const XclPaperSize* pEntry = pPaperSizeTable; pEntry != STATIC_TABLE_END( pPaperSizeTable ); ++pEntry )
+ {
+ long nWDiff = Abs( pEntry->mnWidth - nWidth );
+ long nHDiff = Abs( pEntry->mnHeight - nHeight );
+ if( ((nWDiff <= nMaxWDiff) && (nHDiff < nMaxHDiff)) ||
+ ((nWDiff < nMaxWDiff) && (nHDiff <= nMaxHDiff)) )
+ {
+ sal_uInt16 nIndex = static_cast< sal_uInt16 >( pEntry - pPaperSizeTable );
+ if( !bStrictSize )
+ mnPaperSize = nIndex;
+ else
+ mnStrictPaperSize = mnPaperSize = nIndex;
+
+ nMaxWDiff = nWDiff;
+ nMaxHDiff = nHDiff;
+ }
+ }
+ if( !bStrictSize )
+ SetScPaperSize( rSize, bPortrait, sal_True );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xlpivot.cxx b/sc/source/filter/excel/xlpivot.cxx
new file mode 100644
index 000000000000..fb0a7bbb64fe
--- /dev/null
+++ b/sc/source/filter/excel/xlpivot.cxx
@@ -0,0 +1,1028 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "dpgroup.hxx"
+#include "dpsave.hxx"
+#include "xestream.hxx"
+#include "xistream.hxx"
+#include "xestring.hxx"
+#include "xlpivot.hxx"
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+
+using ::com::sun::star::sheet::GeneralFunction;
+using ::com::sun::star::sheet::DataPilotFieldOrientation;
+
+namespace ScDPSortMode = ::com::sun::star::sheet::DataPilotFieldSortMode;
+namespace ScDPShowItemsMode = ::com::sun::star::sheet::DataPilotFieldShowItemsMode;
+namespace ScDPLayoutMode = ::com::sun::star::sheet::DataPilotFieldLayoutMode;
+namespace ScDPRefItemType = ::com::sun::star::sheet::DataPilotFieldReferenceItemType;
+namespace ScDPGroupBy = ::com::sun::star::sheet::DataPilotFieldGroupBy;
+
+// ============================================================================
+// Pivot cache
+// ============================================================================
+
+XclPCItem::XclPCItem() :
+ meType( EXC_PCITEM_INVALID )
+{
+}
+
+XclPCItem::~XclPCItem()
+{
+}
+
+void XclPCItem::SetEmpty()
+{
+ meType = EXC_PCITEM_EMPTY;
+ maText.Erase();
+}
+
+void XclPCItem::SetText( const String& rText )
+{
+ meType = EXC_PCITEM_TEXT;
+ maText = rText;
+}
+
+void XclPCItem::SetDouble( double fValue )
+{
+ meType = EXC_PCITEM_DOUBLE;
+ //! TODO convert double to string
+ maText.Erase();
+ mfValue = fValue;
+}
+
+void XclPCItem::SetDateTime( const DateTime& rDateTime )
+{
+ meType = EXC_PCITEM_DATETIME;
+ //! TODO convert date to string
+ maText.Erase();
+ maDateTime = rDateTime;
+}
+
+void XclPCItem::SetInteger( sal_Int16 nValue )
+{
+ meType = EXC_PCITEM_INTEGER;
+ maText = String::CreateFromInt32( nValue );
+ mnValue = nValue;
+}
+
+void XclPCItem::SetError( sal_uInt16 nError )
+{
+ meType = EXC_PCITEM_ERROR;
+ //! TODO convert error to string
+ maText.Erase();
+ mnError = nError;
+}
+
+void XclPCItem::SetBool( bool bValue )
+{
+ meType = EXC_PCITEM_BOOL;
+ //! TODO convert boolean to string
+ maText.Erase();
+ mbValue = bValue;
+}
+
+// ----------------------------------------------------------------------------
+
+bool XclPCItem::IsEqual( const XclPCItem& rItem ) const
+{
+ if( meType == rItem.meType ) switch( meType )
+ {
+ case EXC_PCITEM_INVALID: return true;
+ case EXC_PCITEM_EMPTY: return true;
+ case EXC_PCITEM_TEXT: return maText == rItem.maText;
+ case EXC_PCITEM_DOUBLE: return mfValue == rItem.mfValue;
+ case EXC_PCITEM_DATETIME: return maDateTime == rItem.maDateTime;
+ case EXC_PCITEM_INTEGER: return mnValue == rItem.mnValue;
+ case EXC_PCITEM_BOOL: return mbValue == rItem.mbValue;
+ case EXC_PCITEM_ERROR: return mnError == rItem.mnError;
+ default: DBG_ERRORFILE( "XclPCItem::IsEqual - unknown pivot cache item type" );
+ }
+ return false;
+}
+
+bool XclPCItem::IsEmpty() const
+{
+ return meType == EXC_PCITEM_EMPTY;
+}
+
+const String* XclPCItem::GetText() const
+{
+ return (meType == EXC_PCITEM_TEXT) ? &maText : 0;
+}
+
+const double* XclPCItem::GetDouble() const
+{
+ return (meType == EXC_PCITEM_DOUBLE) ? &mfValue : 0;
+}
+
+const DateTime* XclPCItem::GetDateTime() const
+{
+ return (meType == EXC_PCITEM_DATETIME) ? &maDateTime : 0;
+}
+
+const sal_Int16* XclPCItem::GetInteger() const
+{
+ return (meType == EXC_PCITEM_INTEGER) ? &mnValue : 0;
+}
+
+const sal_uInt16* XclPCItem::GetError() const
+{
+ return (meType == EXC_PCITEM_ERROR) ? &mnError : 0;
+}
+
+const bool* XclPCItem::GetBool() const
+{
+ return (meType == EXC_PCITEM_BOOL) ? &mbValue : 0;
+}
+
+// Field settings =============================================================
+
+XclPCFieldInfo::XclPCFieldInfo() :
+ mnFlags( 0 ),
+ mnGroupChild( 0 ),
+ mnGroupBase( 0 ),
+ mnVisItems( 0 ),
+ mnGroupItems( 0 ),
+ mnBaseItems( 0 ),
+ mnOrigItems( 0 )
+{
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPCFieldInfo& rInfo )
+{
+ rStrm >> rInfo.mnFlags
+ >> rInfo.mnGroupChild
+ >> rInfo.mnGroupBase
+ >> rInfo.mnVisItems
+ >> rInfo.mnGroupItems
+ >> rInfo.mnBaseItems
+ >> rInfo.mnOrigItems;
+ if( rStrm.GetRecLeft() >= 3 )
+ rInfo.maName = rStrm.ReadUniString();
+ else
+ rInfo.maName.Erase();
+ return rStrm;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPCFieldInfo& rInfo )
+{
+ return rStrm
+ << rInfo.mnFlags
+ << rInfo.mnGroupChild
+ << rInfo.mnGroupBase
+ << rInfo.mnVisItems
+ << rInfo.mnGroupItems
+ << rInfo.mnBaseItems
+ << rInfo.mnOrigItems
+ << XclExpString( rInfo.maName );
+}
+
+// Numeric grouping field settings ============================================
+
+XclPCNumGroupInfo::XclPCNumGroupInfo() :
+ mnFlags( EXC_SXNUMGROUP_AUTOMIN | EXC_SXNUMGROUP_AUTOMAX )
+{
+ SetNumType();
+}
+
+void XclPCNumGroupInfo::SetNumType()
+{
+ SetXclDataType( EXC_SXNUMGROUP_TYPE_NUM );
+}
+
+sal_Int32 XclPCNumGroupInfo::GetScDateType() const
+{
+ sal_Int32 nScType = 0;
+ switch( GetXclDataType() )
+ {
+ case EXC_SXNUMGROUP_TYPE_SEC: nScType = ScDPGroupBy::SECONDS; break;
+ case EXC_SXNUMGROUP_TYPE_MIN: nScType = ScDPGroupBy::MINUTES; break;
+ case EXC_SXNUMGROUP_TYPE_HOUR: nScType = ScDPGroupBy::HOURS; break;
+ case EXC_SXNUMGROUP_TYPE_DAY: nScType = ScDPGroupBy::DAYS; break;
+ case EXC_SXNUMGROUP_TYPE_MONTH: nScType = ScDPGroupBy::MONTHS; break;
+ case EXC_SXNUMGROUP_TYPE_QUART: nScType = ScDPGroupBy::QUARTERS; break;
+ case EXC_SXNUMGROUP_TYPE_YEAR: nScType = ScDPGroupBy::YEARS; break;
+ default: OSL_TRACE( "XclPCNumGroupInfo::GetScDateType - unexpected date type %d", GetXclDataType() );
+ }
+ return nScType;
+}
+
+void XclPCNumGroupInfo::SetScDateType( sal_Int32 nScType )
+{
+ sal_uInt16 nXclType = EXC_SXNUMGROUP_TYPE_NUM;
+ switch( nScType )
+ {
+ case ScDPGroupBy::SECONDS: nXclType = EXC_SXNUMGROUP_TYPE_SEC; break;
+ case ScDPGroupBy::MINUTES: nXclType = EXC_SXNUMGROUP_TYPE_MIN; break;
+ case ScDPGroupBy::HOURS: nXclType = EXC_SXNUMGROUP_TYPE_HOUR; break;
+ case ScDPGroupBy::DAYS: nXclType = EXC_SXNUMGROUP_TYPE_DAY; break;
+ case ScDPGroupBy::MONTHS: nXclType = EXC_SXNUMGROUP_TYPE_MONTH; break;
+ case ScDPGroupBy::QUARTERS: nXclType = EXC_SXNUMGROUP_TYPE_QUART; break;
+ case ScDPGroupBy::YEARS: nXclType = EXC_SXNUMGROUP_TYPE_YEAR; break;
+ default: OSL_TRACE( "XclPCNumGroupInfo::SetScDateType - unexpected date type %d", nScType );
+ }
+ SetXclDataType( nXclType );
+}
+
+sal_uInt16 XclPCNumGroupInfo::GetXclDataType() const
+{
+ return ::extract_value< sal_uInt16 >( mnFlags, 2, 4 );
+}
+
+void XclPCNumGroupInfo::SetXclDataType( sal_uInt16 nXclType )
+{
+ ::insert_value( mnFlags, nXclType, 2, 4 );
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPCNumGroupInfo& rInfo )
+{
+ return rStrm >> rInfo.mnFlags;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPCNumGroupInfo& rInfo )
+{
+ return rStrm << rInfo.mnFlags;
+}
+
+// Base class for pivot cache fields ==========================================
+
+XclPCField::XclPCField( XclPCFieldType eFieldType, sal_uInt16 nFieldIdx ) :
+ meFieldType( eFieldType ),
+ mnFieldIdx( nFieldIdx )
+{
+}
+
+XclPCField::~XclPCField()
+{
+}
+
+bool XclPCField::IsSupportedField() const
+{
+ return (meFieldType != EXC_PCFIELD_CALCED) && (meFieldType != EXC_PCFIELD_UNKNOWN);
+}
+
+bool XclPCField::IsStandardField() const
+{
+ return meFieldType == EXC_PCFIELD_STANDARD;
+}
+
+bool XclPCField::IsStdGroupField() const
+{
+ return meFieldType == EXC_PCFIELD_STDGROUP;
+}
+
+bool XclPCField::IsNumGroupField() const
+{
+ return meFieldType == EXC_PCFIELD_NUMGROUP;
+}
+
+bool XclPCField::IsDateGroupField() const
+{
+ return (meFieldType == EXC_PCFIELD_DATEGROUP) || (meFieldType == EXC_PCFIELD_DATECHILD);
+}
+
+bool XclPCField::IsGroupField() const
+{
+ return IsStdGroupField() || IsNumGroupField() || IsDateGroupField();
+}
+
+bool XclPCField::IsGroupBaseField() const
+{
+ return ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_HASCHILD );
+}
+
+bool XclPCField::IsGroupChildField() const
+{
+ return (meFieldType == EXC_PCFIELD_STDGROUP) || (meFieldType == EXC_PCFIELD_DATECHILD);
+}
+
+sal_uInt16 XclPCField::GetBaseFieldIndex() const
+{
+ return IsGroupChildField() ? maFieldInfo.mnGroupBase : mnFieldIdx;
+}
+
+bool XclPCField::HasOrigItems() const
+{
+ return IsSupportedField() && ((maFieldInfo.mnOrigItems > 0) || HasPostponedItems());
+}
+
+bool XclPCField::HasInlineItems() const
+{
+ return (IsStandardField() || IsGroupField()) && ((maFieldInfo.mnGroupItems > 0) || (maFieldInfo.mnOrigItems > 0));
+}
+
+bool XclPCField::HasPostponedItems() const
+{
+ return IsStandardField() && ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_POSTPONE );
+}
+
+bool XclPCField::Has16BitIndexes() const
+{
+ return IsStandardField() && ::get_flag( maFieldInfo.mnFlags, EXC_SXFIELD_16BIT );
+}
+
+// Pivot cache settings =======================================================
+
+/** Contains data for a pivot cache (SXDB record). */
+XclPCInfo::XclPCInfo() :
+ mnSrcRecs( 0 ),
+ mnStrmId( 0xFFFF ),
+ mnFlags( EXC_SXDB_DEFAULTFLAGS ),
+ mnBlockRecs( EXC_SXDB_BLOCKRECS ),
+ mnStdFields( 0 ),
+ mnTotalFields( 0 ),
+ mnSrcType( EXC_SXDB_SRC_SHEET )
+{
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPCInfo& rInfo )
+{
+ rStrm >> rInfo.mnSrcRecs
+ >> rInfo.mnStrmId
+ >> rInfo.mnFlags
+ >> rInfo.mnBlockRecs
+ >> rInfo.mnStdFields
+ >> rInfo.mnTotalFields;
+ rStrm.Ignore( 2 );
+ rStrm >> rInfo.mnSrcType;
+ rInfo.maUserName = rStrm.ReadUniString();
+ return rStrm;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPCInfo& rInfo )
+{
+ return rStrm
+ << rInfo.mnSrcRecs
+ << rInfo.mnStrmId
+ << rInfo.mnFlags
+ << rInfo.mnBlockRecs
+ << rInfo.mnStdFields
+ << rInfo.mnTotalFields
+ << sal_uInt16( 0 )
+ << rInfo.mnSrcType
+ << XclExpString( rInfo.maUserName );
+}
+
+// ============================================================================
+// Pivot table
+// ============================================================================
+
+// cached name ================================================================
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPTCachedName& rCachedName )
+{
+ sal_uInt16 nStrLen;
+ rStrm >> nStrLen;
+ rCachedName.mbUseCache = nStrLen == EXC_PT_NOSTRING;
+ if( rCachedName.mbUseCache )
+ rCachedName.maName.Erase();
+ else
+ rCachedName.maName = rStrm.ReadUniString( nStrLen );
+ return rStrm;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPTCachedName& rCachedName )
+{
+ if( rCachedName.mbUseCache )
+ rStrm << EXC_PT_NOSTRING;
+ else
+ rStrm << XclExpString( rCachedName.maName, EXC_STR_DEFAULT, EXC_PT_MAXSTRLEN );
+ return rStrm;
+}
+
+// ----------------------------------------------------------------------------
+
+const String* XclPTVisNameInfo::GetVisName() const
+{
+ return HasVisName() ? &maVisName.maName : 0;
+}
+
+void XclPTVisNameInfo::SetVisName( const String& rName )
+{
+ maVisName.maName = rName;
+ maVisName.mbUseCache = rName.Len() == 0;
+}
+
+// Field item settings ========================================================
+
+XclPTItemInfo::XclPTItemInfo() :
+ mnType( EXC_SXVI_TYPE_DATA ),
+ mnFlags( EXC_SXVI_DEFAULTFLAGS ),
+ mnCacheIdx( EXC_SXVI_DEFAULT_CACHE )
+{
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPTItemInfo& rInfo )
+{
+ return rStrm
+ >> rInfo.mnType
+ >> rInfo.mnFlags
+ >> rInfo.mnCacheIdx
+ >> rInfo.maVisName;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPTItemInfo& rInfo )
+{
+ return rStrm
+ << rInfo.mnType
+ << rInfo.mnFlags
+ << rInfo.mnCacheIdx
+ << rInfo.maVisName;
+}
+
+// General field settings =====================================================
+
+XclPTFieldInfo::XclPTFieldInfo() :
+ mnAxes( EXC_SXVD_AXIS_NONE ),
+ mnSubtCount( 1 ),
+ mnSubtotals( EXC_SXVD_SUBT_DEFAULT ),
+ mnItemCount( 0 ),
+ mnCacheIdx( EXC_SXVD_DEFAULT_CACHE )
+{
+}
+
+DataPilotFieldOrientation XclPTFieldInfo::GetApiOrient( sal_uInt16 nMask ) const
+{
+ using namespace ::com::sun::star::sheet;
+ DataPilotFieldOrientation eOrient = DataPilotFieldOrientation_HIDDEN;
+ sal_uInt16 nUsedAxes = mnAxes & nMask;
+ if( nUsedAxes & EXC_SXVD_AXIS_ROW )
+ eOrient = DataPilotFieldOrientation_ROW;
+ else if( nUsedAxes & EXC_SXVD_AXIS_COL )
+ eOrient = DataPilotFieldOrientation_COLUMN;
+ else if( nUsedAxes & EXC_SXVD_AXIS_PAGE )
+ eOrient = DataPilotFieldOrientation_PAGE;
+ else if( nUsedAxes & EXC_SXVD_AXIS_DATA )
+ eOrient = DataPilotFieldOrientation_DATA;
+ return eOrient;
+}
+
+void XclPTFieldInfo::AddApiOrient( DataPilotFieldOrientation eOrient )
+{
+ using namespace ::com::sun::star::sheet;
+ switch( eOrient )
+ {
+ case DataPilotFieldOrientation_ROW: mnAxes |= EXC_SXVD_AXIS_ROW; break;
+ case DataPilotFieldOrientation_COLUMN: mnAxes |= EXC_SXVD_AXIS_COL; break;
+ case DataPilotFieldOrientation_PAGE: mnAxes |= EXC_SXVD_AXIS_PAGE; break;
+ case DataPilotFieldOrientation_DATA: mnAxes |= EXC_SXVD_AXIS_DATA; break;
+ default:;
+ }
+}
+
+//! TODO: should be a Sequence<GeneralFunction> in ScDPSaveData
+void XclPTFieldInfo::GetSubtotals( XclPTSubtotalVec& rSubtotals ) const
+{
+ rSubtotals.clear();
+ rSubtotals.reserve( 16 );
+
+ using namespace ::com::sun::star::sheet;
+ if( mnSubtotals & EXC_SXVD_SUBT_DEFAULT ) rSubtotals.push_back( GeneralFunction_AUTO );
+ if( mnSubtotals & EXC_SXVD_SUBT_SUM ) rSubtotals.push_back( GeneralFunction_SUM );
+ if( mnSubtotals & EXC_SXVD_SUBT_COUNT ) rSubtotals.push_back( GeneralFunction_COUNT );
+ if( mnSubtotals & EXC_SXVD_SUBT_AVERAGE ) rSubtotals.push_back( GeneralFunction_AVERAGE );
+ if( mnSubtotals & EXC_SXVD_SUBT_MAX ) rSubtotals.push_back( GeneralFunction_MAX );
+ if( mnSubtotals & EXC_SXVD_SUBT_MIN ) rSubtotals.push_back( GeneralFunction_MIN );
+ if( mnSubtotals & EXC_SXVD_SUBT_PROD ) rSubtotals.push_back( GeneralFunction_PRODUCT );
+ if( mnSubtotals & EXC_SXVD_SUBT_COUNTNUM ) rSubtotals.push_back( GeneralFunction_COUNTNUMS );
+ if( mnSubtotals & EXC_SXVD_SUBT_STDDEV ) rSubtotals.push_back( GeneralFunction_STDEV );
+ if( mnSubtotals & EXC_SXVD_SUBT_STDDEVP ) rSubtotals.push_back( GeneralFunction_STDEVP );
+ if( mnSubtotals & EXC_SXVD_SUBT_VAR ) rSubtotals.push_back( GeneralFunction_VAR );
+ if( mnSubtotals & EXC_SXVD_SUBT_VARP ) rSubtotals.push_back( GeneralFunction_VARP );
+}
+
+void XclPTFieldInfo::SetSubtotals( const XclPTSubtotalVec& rSubtotals )
+{
+ mnSubtotals = EXC_SXVD_SUBT_NONE;
+ using namespace ::com::sun::star::sheet;
+ for( XclPTSubtotalVec::const_iterator aIt = rSubtotals.begin(), aEnd = rSubtotals.end(); aIt != aEnd; ++aIt )
+ {
+ switch( *aIt )
+ {
+ case GeneralFunction_AUTO: mnSubtotals |= EXC_SXVD_SUBT_DEFAULT; break;
+ case GeneralFunction_SUM: mnSubtotals |= EXC_SXVD_SUBT_SUM; break;
+ case GeneralFunction_COUNT: mnSubtotals |= EXC_SXVD_SUBT_COUNT; break;
+ case GeneralFunction_AVERAGE: mnSubtotals |= EXC_SXVD_SUBT_AVERAGE; break;
+ case GeneralFunction_MAX: mnSubtotals |= EXC_SXVD_SUBT_MAX; break;
+ case GeneralFunction_MIN: mnSubtotals |= EXC_SXVD_SUBT_MIN; break;
+ case GeneralFunction_PRODUCT: mnSubtotals |= EXC_SXVD_SUBT_PROD; break;
+ case GeneralFunction_COUNTNUMS: mnSubtotals |= EXC_SXVD_SUBT_COUNTNUM; break;
+ case GeneralFunction_STDEV: mnSubtotals |= EXC_SXVD_SUBT_STDDEV; break;
+ case GeneralFunction_STDEVP: mnSubtotals |= EXC_SXVD_SUBT_STDDEVP; break;
+ case GeneralFunction_VAR: mnSubtotals |= EXC_SXVD_SUBT_VAR; break;
+ case GeneralFunction_VARP: mnSubtotals |= EXC_SXVD_SUBT_VARP; break;
+ }
+ }
+
+ mnSubtCount = 0;
+ for( sal_uInt16 nMask = 0x8000; nMask; nMask >>= 1 )
+ if( mnSubtotals & nMask )
+ ++mnSubtCount;
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPTFieldInfo& rInfo )
+{
+ // rInfo.mnCacheIdx is not part of the SXVD record
+ return rStrm
+ >> rInfo.mnAxes
+ >> rInfo.mnSubtCount
+ >> rInfo.mnSubtotals
+ >> rInfo.mnItemCount
+ >> rInfo.maVisName;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPTFieldInfo& rInfo )
+{
+ // rInfo.mnCacheIdx is not part of the SXVD record
+ return rStrm
+ << rInfo.mnAxes
+ << rInfo.mnSubtCount
+ << rInfo.mnSubtotals
+ << rInfo.mnItemCount
+ << rInfo.maVisName;
+}
+
+// Extended field settings ====================================================
+
+XclPTFieldExtInfo::XclPTFieldExtInfo() :
+ mnFlags( EXC_SXVDEX_DEFAULTFLAGS ),
+ mnSortField( EXC_SXVDEX_SORT_OWN ),
+ mnShowField( EXC_SXVDEX_SHOW_NONE ),
+ mnNumFmt(0),
+ mpFieldTotalName(NULL)
+{
+}
+
+sal_Int32 XclPTFieldExtInfo::GetApiSortMode() const
+{
+ sal_Int32 nSortMode = ScDPSortMode::MANUAL;
+ if( ::get_flag( mnFlags, EXC_SXVDEX_SORT ) )
+ nSortMode = (mnSortField == EXC_SXVDEX_SORT_OWN) ? ScDPSortMode::NAME : ScDPSortMode::DATA;
+ return nSortMode;
+}
+
+void XclPTFieldExtInfo::SetApiSortMode( sal_Int32 nSortMode )
+{
+ bool bSort = (nSortMode == ScDPSortMode::NAME) || (nSortMode == ScDPSortMode::DATA);
+ ::set_flag( mnFlags, EXC_SXVDEX_SORT, bSort );
+ if( nSortMode == ScDPSortMode::NAME )
+ mnSortField = EXC_SXVDEX_SORT_OWN; // otherwise sort field has to be set by caller
+}
+
+sal_Int32 XclPTFieldExtInfo::GetApiAutoShowMode() const
+{
+ return ::get_flagvalue( mnFlags, EXC_SXVDEX_AUTOSHOW_ASC,
+ ScDPShowItemsMode::FROM_TOP, ScDPShowItemsMode::FROM_BOTTOM );
+}
+
+void XclPTFieldExtInfo::SetApiAutoShowMode( sal_Int32 nShowMode )
+{
+ ::set_flag( mnFlags, EXC_SXVDEX_AUTOSHOW_ASC, nShowMode == ScDPShowItemsMode::FROM_TOP );
+}
+
+sal_Int32 XclPTFieldExtInfo::GetApiAutoShowCount() const
+{
+ return ::extract_value< sal_Int32 >( mnFlags, 24, 8 );
+}
+
+void XclPTFieldExtInfo::SetApiAutoShowCount( sal_Int32 nShowCount )
+{
+ ::insert_value( mnFlags, limit_cast< sal_uInt8 >( nShowCount ), 24, 8 );
+}
+
+sal_Int32 XclPTFieldExtInfo::GetApiLayoutMode() const
+{
+ sal_Int32 nLayoutMode = ScDPLayoutMode::TABULAR_LAYOUT;
+ if( ::get_flag( mnFlags, EXC_SXVDEX_LAYOUT_REPORT ) )
+ nLayoutMode = ::get_flag( mnFlags, EXC_SXVDEX_LAYOUT_TOP ) ?
+ ScDPLayoutMode::OUTLINE_SUBTOTALS_TOP : ScDPLayoutMode::OUTLINE_SUBTOTALS_BOTTOM;
+ return nLayoutMode;
+}
+
+void XclPTFieldExtInfo::SetApiLayoutMode( sal_Int32 nLayoutMode )
+{
+ ::set_flag( mnFlags, EXC_SXVDEX_LAYOUT_REPORT, nLayoutMode != ScDPLayoutMode::TABULAR_LAYOUT );
+ ::set_flag( mnFlags, EXC_SXVDEX_LAYOUT_TOP, nLayoutMode == ScDPLayoutMode::OUTLINE_SUBTOTALS_TOP );
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPTFieldExtInfo& rInfo )
+{
+ sal_uInt8 nNameLen = 0;
+ rStrm >> rInfo.mnFlags
+ >> rInfo.mnSortField
+ >> rInfo.mnShowField
+ >> rInfo.mnNumFmt
+ >> nNameLen;
+
+ rStrm.Ignore(10);
+ if (nNameLen != 0xFF)
+ // Custom field total name is used. Pick it up.
+ rInfo.mpFieldTotalName.reset(new rtl::OUString(rStrm.ReadUniString(nNameLen, 0)));
+
+ return rStrm;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPTFieldExtInfo& rInfo )
+{
+ rStrm << rInfo.mnFlags
+ << rInfo.mnSortField
+ << rInfo.mnShowField
+ << EXC_SXVDEX_FORMAT_NONE;
+
+ if (rInfo.mpFieldTotalName.get() && rInfo.mpFieldTotalName->getLength() > 0)
+ {
+ rtl::OUString aFinalName = *rInfo.mpFieldTotalName;
+ if (aFinalName.getLength() >= 254)
+ aFinalName = aFinalName.copy(0, 254);
+ sal_uInt8 nNameLen = static_cast<sal_uInt8>(aFinalName.getLength());
+ rStrm << nNameLen;
+ rStrm.WriteZeroBytes(10);
+ rStrm << XclExpString(aFinalName, EXC_STR_NOHEADER);
+ }
+ else
+ {
+ rStrm << sal_uInt16(0xFFFF);
+ rStrm.WriteZeroBytes(8);
+ }
+ return rStrm;
+}
+
+// Page field settings ========================================================
+
+XclPTPageFieldInfo::XclPTPageFieldInfo() :
+ mnField( 0 ),
+ mnSelItem( EXC_SXPI_ALLITEMS ),
+ mnObjId( 0xFFFF )
+{
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPTPageFieldInfo& rInfo )
+{
+ return rStrm
+ >> rInfo.mnField
+ >> rInfo.mnSelItem
+ >> rInfo.mnObjId;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPTPageFieldInfo& rInfo )
+{
+ return rStrm
+ << rInfo.mnField
+ << rInfo.mnSelItem
+ << rInfo.mnObjId;
+}
+
+// Data field settings ========================================================
+
+XclPTDataFieldInfo::XclPTDataFieldInfo() :
+ mnField( 0 ),
+ mnAggFunc( EXC_SXDI_FUNC_SUM ),
+ mnRefType( EXC_SXDI_REF_NORMAL ),
+ mnRefField( 0 ),
+ mnRefItem( 0 ),
+ mnNumFmt( 0 )
+{
+}
+
+GeneralFunction XclPTDataFieldInfo::GetApiAggFunc() const
+{
+ using namespace ::com::sun::star::sheet;
+ GeneralFunction eAggFunc;
+ switch( mnAggFunc )
+ {
+ case EXC_SXDI_FUNC_SUM: eAggFunc = GeneralFunction_SUM; break;
+ case EXC_SXDI_FUNC_COUNT: eAggFunc = GeneralFunction_COUNT; break;
+ case EXC_SXDI_FUNC_AVERAGE: eAggFunc = GeneralFunction_AVERAGE; break;
+ case EXC_SXDI_FUNC_MAX: eAggFunc = GeneralFunction_MAX; break;
+ case EXC_SXDI_FUNC_MIN: eAggFunc = GeneralFunction_MIN; break;
+ case EXC_SXDI_FUNC_PRODUCT: eAggFunc = GeneralFunction_PRODUCT; break;
+ case EXC_SXDI_FUNC_COUNTNUM: eAggFunc = GeneralFunction_COUNTNUMS; break;
+ case EXC_SXDI_FUNC_STDDEV: eAggFunc = GeneralFunction_STDEV; break;
+ case EXC_SXDI_FUNC_STDDEVP: eAggFunc = GeneralFunction_STDEVP; break;
+ case EXC_SXDI_FUNC_VAR: eAggFunc = GeneralFunction_VAR; break;
+ case EXC_SXDI_FUNC_VARP: eAggFunc = GeneralFunction_VARP; break;
+ default: eAggFunc = GeneralFunction_SUM;
+ }
+ return eAggFunc;
+}
+
+void XclPTDataFieldInfo::SetApiAggFunc( GeneralFunction eAggFunc )
+{
+ using namespace ::com::sun::star::sheet;
+ switch( eAggFunc )
+ {
+ case GeneralFunction_SUM: mnAggFunc = EXC_SXDI_FUNC_SUM; break;
+ case GeneralFunction_COUNT: mnAggFunc = EXC_SXDI_FUNC_COUNT; break;
+ case GeneralFunction_AVERAGE: mnAggFunc = EXC_SXDI_FUNC_AVERAGE; break;
+ case GeneralFunction_MAX: mnAggFunc = EXC_SXDI_FUNC_MAX; break;
+ case GeneralFunction_MIN: mnAggFunc = EXC_SXDI_FUNC_MIN; break;
+ case GeneralFunction_PRODUCT: mnAggFunc = EXC_SXDI_FUNC_PRODUCT; break;
+ case GeneralFunction_COUNTNUMS: mnAggFunc = EXC_SXDI_FUNC_COUNTNUM; break;
+ case GeneralFunction_STDEV: mnAggFunc = EXC_SXDI_FUNC_STDDEV; break;
+ case GeneralFunction_STDEVP: mnAggFunc = EXC_SXDI_FUNC_STDDEVP; break;
+ case GeneralFunction_VAR: mnAggFunc = EXC_SXDI_FUNC_VAR; break;
+ case GeneralFunction_VARP: mnAggFunc = EXC_SXDI_FUNC_VARP; break;
+ default: mnAggFunc = EXC_SXDI_FUNC_SUM;
+ }
+}
+
+sal_Int32 XclPTDataFieldInfo::GetApiRefType() const
+{
+ namespace ScDPRefType = ::com::sun::star::sheet::DataPilotFieldReferenceType;
+ sal_Int32 nRefType;
+ switch( mnRefType )
+ {
+ case EXC_SXDI_REF_DIFF: nRefType = ScDPRefType::ITEM_DIFFERENCE; break;
+ case EXC_SXDI_REF_PERC: nRefType = ScDPRefType::ITEM_PERCENTAGE; break;
+ case EXC_SXDI_REF_PERC_DIFF: nRefType = ScDPRefType::ITEM_PERCENTAGE_DIFFERENCE; break;
+ case EXC_SXDI_REF_RUN_TOTAL: nRefType = ScDPRefType::RUNNING_TOTAL; break;
+ case EXC_SXDI_REF_PERC_ROW: nRefType = ScDPRefType::ROW_PERCENTAGE; break;
+ case EXC_SXDI_REF_PERC_COL: nRefType = ScDPRefType::COLUMN_PERCENTAGE; break;
+ case EXC_SXDI_REF_PERC_TOTAL: nRefType = ScDPRefType::TOTAL_PERCENTAGE; break;
+ case EXC_SXDI_REF_INDEX: nRefType = ScDPRefType::INDEX; break;
+ default: nRefType = ScDPRefType::NONE;
+ }
+ return nRefType;
+}
+
+void XclPTDataFieldInfo::SetApiRefType( sal_Int32 nRefType )
+{
+ namespace ScDPRefType = ::com::sun::star::sheet::DataPilotFieldReferenceType;
+ switch( nRefType )
+ {
+ case ScDPRefType::ITEM_DIFFERENCE: mnRefType = EXC_SXDI_REF_DIFF; break;
+ case ScDPRefType::ITEM_PERCENTAGE: mnRefType = EXC_SXDI_REF_PERC; break;
+ case ScDPRefType::ITEM_PERCENTAGE_DIFFERENCE: mnRefType = EXC_SXDI_REF_PERC_DIFF; break;
+ case ScDPRefType::RUNNING_TOTAL: mnRefType = EXC_SXDI_REF_RUN_TOTAL; break;
+ case ScDPRefType::ROW_PERCENTAGE: mnRefType = EXC_SXDI_REF_PERC_ROW; break;
+ case ScDPRefType::COLUMN_PERCENTAGE: mnRefType = EXC_SXDI_REF_PERC_COL; break;
+ case ScDPRefType::TOTAL_PERCENTAGE: mnRefType = EXC_SXDI_REF_PERC_TOTAL;break;
+ case ScDPRefType::INDEX: mnRefType = EXC_SXDI_REF_INDEX; break;
+ default: mnRefType = EXC_SXDI_REF_NORMAL;
+ }
+}
+
+sal_Int32 XclPTDataFieldInfo::GetApiRefItemType() const
+{
+ sal_Int32 nRefItemType;
+ switch( mnRefItem )
+ {
+ case EXC_SXDI_PREVITEM: nRefItemType = ScDPRefItemType::PREVIOUS; break;
+ case EXC_SXDI_NEXTITEM: nRefItemType = ScDPRefItemType::NEXT; break;
+ default: nRefItemType = ScDPRefItemType::NAMED;
+ }
+ return nRefItemType;
+}
+
+void XclPTDataFieldInfo::SetApiRefItemType( sal_Int32 nRefItemType )
+{
+ switch( nRefItemType )
+ {
+ case ScDPRefItemType::PREVIOUS: mnRefItem = EXC_SXDI_PREVITEM; break;
+ case ScDPRefItemType::NEXT: mnRefItem = EXC_SXDI_NEXTITEM; break;
+ // nothing for named item reference
+ }
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPTDataFieldInfo& rInfo )
+{
+ return rStrm
+ >> rInfo.mnField
+ >> rInfo.mnAggFunc
+ >> rInfo.mnRefType
+ >> rInfo.mnRefField
+ >> rInfo.mnRefItem
+ >> rInfo.mnNumFmt
+ >> rInfo.maVisName;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPTDataFieldInfo& rInfo )
+{
+ return rStrm
+ << rInfo.mnField
+ << rInfo.mnAggFunc
+ << rInfo.mnRefType
+ << rInfo.mnRefField
+ << rInfo.mnRefItem
+ << rInfo.mnNumFmt
+ << rInfo.maVisName;
+}
+
+// Pivot table settings =======================================================
+
+XclPTInfo::XclPTInfo() :
+ mnFirstHeadRow( 0 ),
+ mnCacheIdx( 0xFFFF ),
+ mnDataAxis( EXC_SXVD_AXIS_NONE ),
+ mnDataPos( EXC_SXVIEW_DATALAST ),
+ mnFields( 0 ),
+ mnRowFields( 0 ),
+ mnColFields( 0 ),
+ mnPageFields( 0 ),
+ mnDataFields( 0 ),
+ mnDataRows( 0 ),
+ mnDataCols( 0 ),
+ mnFlags( EXC_SXVIEW_DEFAULTFLAGS ),
+ mnAutoFmtIdx( EXC_SXVIEW_AUTOFMT )
+{
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPTInfo& rInfo )
+{
+ sal_uInt16 nTabLen, nDataLen;
+
+ rStrm >> rInfo.maOutXclRange
+ >> rInfo.mnFirstHeadRow
+ >> rInfo.maDataXclPos
+ >> rInfo.mnCacheIdx;
+ rStrm.Ignore( 2 );
+ rStrm >> rInfo.mnDataAxis >> rInfo.mnDataPos
+ >> rInfo.mnFields
+ >> rInfo.mnRowFields >> rInfo.mnColFields
+ >> rInfo.mnPageFields >> rInfo.mnDataFields
+ >> rInfo.mnDataRows >> rInfo.mnDataCols
+ >> rInfo.mnFlags
+ >> rInfo.mnAutoFmtIdx
+ >> nTabLen >> nDataLen;
+ rInfo.maTableName = rStrm.ReadUniString( nTabLen );
+ rInfo.maDataName = rStrm.ReadUniString( nDataLen );
+ return rStrm;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPTInfo& rInfo )
+{
+ XclExpString aXclTableName( rInfo.maTableName );
+ XclExpString aXclDataName( rInfo.maDataName );
+
+ rStrm << rInfo.maOutXclRange
+ << rInfo.mnFirstHeadRow
+ << rInfo.maDataXclPos
+ << rInfo.mnCacheIdx
+ << sal_uInt16( 0 )
+ << rInfo.mnDataAxis << rInfo.mnDataPos
+ << rInfo.mnFields
+ << rInfo.mnRowFields << rInfo.mnColFields
+ << rInfo.mnPageFields << rInfo.mnDataFields
+ << rInfo.mnDataRows << rInfo.mnDataCols
+ << rInfo.mnFlags
+ << rInfo.mnAutoFmtIdx
+ << aXclTableName.Len() << aXclDataName.Len();
+ aXclTableName.WriteFlagField( rStrm );
+ aXclTableName.WriteBuffer( rStrm );
+ aXclDataName.WriteFlagField( rStrm );
+ aXclDataName.WriteBuffer( rStrm );
+ return rStrm;
+}
+
+// Extended pivot table settings ==============================================
+
+XclPTExtInfo::XclPTExtInfo() :
+ mnSxformulaRecs( 0 ),
+ mnSxselectRecs( 0 ),
+ mnPagePerRow( 0 ),
+ mnPagePerCol( 0 ),
+ mnFlags( EXC_SXEX_DEFAULTFLAGS )
+{
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPTExtInfo& rInfo )
+{
+ rStrm >> rInfo.mnSxformulaRecs;
+ rStrm.Ignore( 6 );
+ return rStrm
+ >> rInfo.mnSxselectRecs
+ >> rInfo.mnPagePerRow
+ >> rInfo.mnPagePerCol
+ >> rInfo.mnFlags;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPTExtInfo& rInfo )
+{
+ return rStrm
+ << rInfo.mnSxformulaRecs
+ << EXC_PT_NOSTRING // length of alt. error text
+ << EXC_PT_NOSTRING // length of alt. empty text
+ << EXC_PT_NOSTRING // length of tag
+ << rInfo.mnSxselectRecs
+ << rInfo.mnPagePerRow
+ << rInfo.mnPagePerCol
+ << rInfo.mnFlags
+ << EXC_PT_NOSTRING // length of page field style name
+ << EXC_PT_NOSTRING // length of table style name
+ << EXC_PT_NOSTRING; // length of vacate style name
+}
+
+// ============================================================================
+
+// Pivot table autoformat settings ============================================
+
+/**
+classic : 10 08 00 00 00 00 00 00 20 00 00 00 01 00 00 00 00
+default : 10 08 00 00 00 00 00 00 20 00 00 00 01 00 00 00 00
+report01 : 10 08 02 00 00 00 00 00 20 00 00 00 00 10 00 00 00
+report02 : 10 08 02 00 00 00 00 00 20 00 00 00 01 10 00 00 00
+report03 : 10 08 02 00 00 00 00 00 20 00 00 00 02 10 00 00 00
+report04 : 10 08 02 00 00 00 00 00 20 00 00 00 03 10 00 00 00
+report05 : 10 08 02 00 00 00 00 00 20 00 00 00 04 10 00 00 00
+report06 : 10 08 02 00 00 00 00 00 20 00 00 00 05 10 00 00 00
+report07 : 10 08 02 00 00 00 00 00 20 00 00 00 06 10 00 00 00
+report08 : 10 08 02 00 00 00 00 00 20 00 00 00 07 10 00 00 00
+report09 : 10 08 02 00 00 00 00 00 20 00 00 00 08 10 00 00 00
+report10 : 10 08 02 00 00 00 00 00 20 00 00 00 09 10 00 00 00
+table01 : 10 08 00 00 00 00 00 00 20 00 00 00 0a 10 00 00 00
+table02 : 10 08 00 00 00 00 00 00 20 00 00 00 0b 10 00 00 00
+table03 : 10 08 00 00 00 00 00 00 20 00 00 00 0c 10 00 00 00
+table04 : 10 08 00 00 00 00 00 00 20 00 00 00 0d 10 00 00 00
+table05 : 10 08 00 00 00 00 00 00 20 00 00 00 0e 10 00 00 00
+table06 : 10 08 00 00 00 00 00 00 20 00 00 00 0f 10 00 00 00
+table07 : 10 08 00 00 00 00 00 00 20 00 00 00 10 10 00 00 00
+table08 : 10 08 00 00 00 00 00 00 20 00 00 00 11 10 00 00 00
+table09 : 10 08 00 00 00 00 00 00 20 00 00 00 12 10 00 00 00
+table10 : 10 08 00 00 00 00 00 00 20 00 00 00 13 10 00 00 00
+none : 10 08 00 00 00 00 00 00 20 00 00 00 15 10 00 00 00
+**/
+
+XclPTViewEx9Info::XclPTViewEx9Info() :
+ mbReport( 0 ),
+ mnAutoFormat( 0 ),
+ mnGridLayout( 0x10 )
+{
+}
+
+void XclPTViewEx9Info::Init( const ScDPObject& rDPObj )
+{
+ if( rDPObj.GetHeaderLayout() )
+ {
+ mbReport = 0;
+ mnAutoFormat = 1;
+ mnGridLayout = 0;
+ }
+ else
+ {
+ // Report1 for now
+ // TODO : sync with autoformat indicies
+ mbReport = 2;
+ mnAutoFormat = 1;
+ mnGridLayout = 0x10;
+ }
+
+ const ScDPSaveData* pData = rDPObj.GetSaveData();
+ if (pData)
+ {
+ const rtl::OUString* pGrandTotal = pData->GetGrandTotalName();
+ if (pGrandTotal)
+ maGrandTotalName = *pGrandTotal;
+ }
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclPTViewEx9Info& rInfo )
+{
+ rStrm.Ignore( 2 );
+ rStrm >> rInfo.mbReport; /// 2 for report* fmts ?
+ rStrm.Ignore( 6 );
+ rStrm >> rInfo.mnAutoFormat >> rInfo.mnGridLayout;
+ rInfo.maGrandTotalName = rStrm.ReadUniString();
+ return rStrm;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclPTViewEx9Info& rInfo )
+{
+ return rStrm
+ << EXC_PT_AUTOFMT_HEADER
+ << rInfo.mbReport
+ << EXC_PT_AUTOFMT_ZERO
+ << EXC_PT_AUTOFMT_FLAGS
+ << rInfo.mnAutoFormat
+ << rInfo.mnGridLayout
+ << XclExpString(rInfo.maGrandTotalName, EXC_STR_DEFAULT, EXC_PT_MAXSTRLEN);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xlroot.cxx b/sc/source/filter/excel/xlroot.cxx
new file mode 100644
index 000000000000..3dc0fda96dc0
--- /dev/null
+++ b/sc/source/filter/excel/xlroot.cxx
@@ -0,0 +1,440 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xlroot.hxx"
+#include <com/sun/star/awt/XDevice.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XFramesSupplier.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <comphelper/processfactory.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/stritem.hxx>
+#include <svl/languageoptions.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/docfile.hxx>
+#include <vcl/font.hxx>
+#include <editeng/editstat.hxx>
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+#include "document.hxx"
+#include "docpool.hxx"
+#include "docuno.hxx"
+#include "editutil.hxx"
+#include "drwlayer.hxx"
+#include "scextopt.hxx"
+#include "patattr.hxx"
+#include "fapihelper.hxx"
+#include "xlconst.hxx"
+#include "xlstyle.hxx"
+#include "xlchart.hxx"
+#include "xltracer.hxx"
+#include <unotools/useroptions.hxx>
+#include "root.hxx"
+
+namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::UNO_SET_THROW;
+using ::com::sun::star::awt::XDevice;
+using ::com::sun::star::awt::DeviceInfo;
+using ::com::sun::star::frame::XFrame;
+using ::com::sun::star::frame::XFramesSupplier;
+using ::com::sun::star::lang::XMultiServiceFactory;
+
+using namespace ::com::sun::star;
+
+// Global data ================================================================
+
+#ifdef DBG_UTIL
+XclDebugObjCounter::~XclDebugObjCounter()
+{
+ DBG_ASSERT( mnObjCnt == 0, "XclDebugObjCounter::~XclDebugObjCounter - wrong root object count" );
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+XclRootData::XclRootData( XclBiff eBiff, SfxMedium& rMedium,
+ SotStorageRef xRootStrg, ScDocument& rDoc, rtl_TextEncoding eTextEnc, bool bExport ) :
+ meBiff( eBiff ),
+ meOutput( EXC_OUTPUT_BINARY ),
+ mrMedium( rMedium ),
+ mxRootStrg( xRootStrg ),
+ mrDoc( rDoc ),
+ maDefPassword( CREATE_STRING( "VelvetSweatshop" ) ),
+ meTextEnc( eTextEnc ),
+ meSysLang( Application::GetSettings().GetLanguage() ),
+ meDocLang( Application::GetSettings().GetLanguage() ),
+ meUILang( Application::GetSettings().GetUILanguage() ),
+ mnDefApiScript( ApiScriptType::LATIN ),
+ maScMaxPos( MAXCOL, MAXROW, MAXTAB ),
+ maXclMaxPos( EXC_MAXCOL2, EXC_MAXROW2, EXC_MAXTAB2 ),
+ maMaxPos( EXC_MAXCOL2, EXC_MAXROW2, EXC_MAXTAB2 ),
+ mxFontPropSetHlp( new XclFontPropSetHelper ),
+ mxChPropSetHlp( new XclChPropSetHelper ),
+ mxRD( new RootData ),//!
+ mfScreenPixelX( 50.0 ),
+ mfScreenPixelY( 50.0 ),
+ mnCharWidth( 110 ),
+ mnScTab( 0 ),
+ mbExport( bExport )
+{
+ maUserName = SvtUserOptions().GetLastName();
+ if( maUserName.Len() == 0 )
+ maUserName = CREATE_STRING( "Calc" );
+
+ switch( ScGlobal::GetDefaultScriptType() )
+ {
+ case SCRIPTTYPE_LATIN: mnDefApiScript = ApiScriptType::LATIN; break;
+ case SCRIPTTYPE_ASIAN: mnDefApiScript = ApiScriptType::ASIAN; break;
+ case SCRIPTTYPE_COMPLEX: mnDefApiScript = ApiScriptType::COMPLEX; break;
+ default: DBG_ERRORFILE( "XclRootData::XclRootData - unknown script type" );
+ }
+
+ // maximum cell position
+ switch( meBiff )
+ {
+ case EXC_BIFF2: maXclMaxPos.Set( EXC_MAXCOL2, EXC_MAXROW2, EXC_MAXTAB2 ); break;
+ case EXC_BIFF3: maXclMaxPos.Set( EXC_MAXCOL3, EXC_MAXROW3, EXC_MAXTAB3 ); break;
+ case EXC_BIFF4: maXclMaxPos.Set( EXC_MAXCOL4, EXC_MAXROW4, EXC_MAXTAB4 ); break;
+ case EXC_BIFF5: maXclMaxPos.Set( EXC_MAXCOL5, EXC_MAXROW5, EXC_MAXTAB5 ); break;
+ case EXC_BIFF8: maXclMaxPos.Set( EXC_MAXCOL8, EXC_MAXROW8, EXC_MAXTAB8 ); break;
+ default: DBG_ERROR_BIFF();
+ }
+ maMaxPos.SetCol( ::std::min( maScMaxPos.Col(), maXclMaxPos.Col() ) );
+ maMaxPos.SetRow( ::std::min( maScMaxPos.Row(), maXclMaxPos.Row() ) );
+ maMaxPos.SetTab( ::std::min( maScMaxPos.Tab(), maXclMaxPos.Tab() ) );
+
+ // document URL and path
+ if( const SfxItemSet* pItemSet = mrMedium.GetItemSet() )
+ if( const SfxStringItem* pItem = static_cast< const SfxStringItem* >( pItemSet->GetItem( SID_FILE_NAME ) ) )
+ maDocUrl = pItem->GetValue();
+ maBasePath = maDocUrl.Copy( 0, maDocUrl.SearchBackward( '/' ) + 1 );
+
+ // extended document options - always own object, try to copy existing data from document
+ if( const ScExtDocOptions* pOldDocOpt = mrDoc.GetExtDocOptions() )
+ mxExtDocOpt.reset( new ScExtDocOptions( *pOldDocOpt ) );
+ else
+ mxExtDocOpt.reset( new ScExtDocOptions );
+
+ // screen pixel size
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), UNO_SET_THROW );
+ Reference< XFramesSupplier > xFramesSupp( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.frame.Desktop" ) ), UNO_QUERY_THROW );
+ Reference< XFrame > xFrame( xFramesSupp->getActiveFrame(), UNO_SET_THROW );
+ Reference< XDevice > xDevice( xFrame->getContainerWindow(), UNO_QUERY_THROW );
+ DeviceInfo aDeviceInfo = xDevice->getInfo();
+ mfScreenPixelX = (aDeviceInfo.PixelPerMeterX > 0) ? (100000.0 / aDeviceInfo.PixelPerMeterX) : 50.0;
+ mfScreenPixelY = (aDeviceInfo.PixelPerMeterY > 0) ? (100000.0 / aDeviceInfo.PixelPerMeterY) : 50.0;
+ }
+ catch( Exception& )
+ {
+ OSL_FAIL( "XclRootData::XclRootData - cannot get output device info" );
+ }
+}
+
+XclRootData::~XclRootData()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclRoot::XclRoot( XclRootData& rRootData ) :
+ mrData( rRootData )
+{
+#ifdef DBG_UTIL
+ ++mrData.mnObjCnt;
+#endif
+
+ // filter tracer
+ // do not use CREATE_OUSTRING for conditional expression
+ mrData.mxTracer.reset( new XclTracer( GetDocUrl(), IsExport() ?
+ OUString(RTL_CONSTASCII_USTRINGPARAM("Office.Tracing/Export/Excel"))
+ : OUString(RTL_CONSTASCII_USTRINGPARAM("Office.Tracing/Import/Excel" )) ) );
+}
+
+XclRoot::XclRoot( const XclRoot& rRoot ) :
+ mrData( rRoot.mrData )
+{
+#ifdef DBG_UTIL
+ ++mrData.mnObjCnt;
+#endif
+}
+
+XclRoot::~XclRoot()
+{
+#ifdef DBG_UTIL
+ --mrData.mnObjCnt;
+#endif
+}
+
+XclRoot& XclRoot::operator=( const XclRoot& rRoot )
+{
+ (void)rRoot; // avoid compiler warning
+ // allowed for assignment in derived classes - but test if the same root data is used
+ DBG_ASSERT( &mrData == &rRoot.mrData, "XclRoot::operator= - incompatible root data" );
+ return *this;
+}
+
+void XclRoot::SetTextEncoding( rtl_TextEncoding eTextEnc )
+{
+ if( eTextEnc != RTL_TEXTENCODING_DONTKNOW )
+ mrData.meTextEnc = eTextEnc;
+}
+
+void XclRoot::SetCharWidth( const XclFontData& rFontData )
+{
+ mrData.mnCharWidth = 0;
+ if( OutputDevice* pPrinter = GetPrinter() )
+ {
+ Font aFont( rFontData.maName, Size( 0, rFontData.mnHeight ) );
+ aFont.SetFamily( rFontData.GetScFamily( GetTextEncoding() ) );
+ aFont.SetCharSet( rFontData.GetFontEncoding() );
+ aFont.SetWeight( rFontData.GetScWeight() );
+ pPrinter->SetFont( aFont );
+ mrData.mnCharWidth = pPrinter->GetTextWidth( String( '0' ) );
+ }
+ if( mrData.mnCharWidth <= 0 )
+ {
+ // #i48717# Win98 with HP LaserJet returns 0
+ DBG_ERRORFILE( "XclRoot::SetCharWidth - invalid character width (no printer?)" );
+ mrData.mnCharWidth = 11 * rFontData.mnHeight / 20;
+ }
+}
+
+sal_Int32 XclRoot::GetHmmFromPixelX( double fPixelX ) const
+{
+ return static_cast< sal_Int32 >( fPixelX * mrData.mfScreenPixelX + 0.5 );
+}
+
+sal_Int32 XclRoot::GetHmmFromPixelY( double fPixelY ) const
+{
+ return static_cast< sal_Int32 >( fPixelY * mrData.mfScreenPixelY + 0.5 );
+}
+
+double XclRoot::GetPixelXFromHmm( sal_Int32 nX ) const
+{
+ return static_cast< double >( (nX - 0.5) / mrData.mfScreenPixelX );
+}
+
+double XclRoot::GetPixelYFromHmm( sal_Int32 nY ) const
+{
+ return static_cast< double >( (nY - 0.5) / mrData.mfScreenPixelY );
+}
+
+uno::Sequence< beans::NamedValue > XclRoot::RequestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier ) const
+{
+ ::std::vector< OUString > aDefaultPasswords;
+ aDefaultPasswords.push_back( mrData.maDefPassword );
+ return ScfApiHelper::QueryEncryptionDataForMedium( mrData.mrMedium, rVerifier, &aDefaultPasswords );
+}
+
+bool XclRoot::HasVbaStorage() const
+{
+ SotStorageRef xRootStrg = GetRootStorage();
+ return xRootStrg.Is() && xRootStrg->IsContained( EXC_STORAGE_VBA_PROJECT );
+}
+
+SotStorageRef XclRoot::OpenStorage( SotStorageRef xStrg, const String& rStrgName ) const
+{
+ return mrData.mbExport ?
+ ScfTools::OpenStorageWrite( xStrg, rStrgName ) :
+ ScfTools::OpenStorageRead( xStrg, rStrgName );
+}
+
+SotStorageRef XclRoot::OpenStorage( const String& rStrgName ) const
+{
+ return OpenStorage( GetRootStorage(), rStrgName );
+}
+
+SotStorageStreamRef XclRoot::OpenStream( SotStorageRef xStrg, const String& rStrmName ) const
+{
+ return mrData.mbExport ?
+ ScfTools::OpenStorageStreamWrite( xStrg, rStrmName ) :
+ ScfTools::OpenStorageStreamRead( xStrg, rStrmName );
+}
+
+SotStorageStreamRef XclRoot::OpenStream( const String& rStrmName ) const
+{
+ return OpenStream( GetRootStorage(), rStrmName );
+}
+
+SfxObjectShell* XclRoot::GetDocShell() const
+{
+ return GetDoc().GetDocumentShell();
+}
+
+ScModelObj* XclRoot::GetDocModelObj() const
+{
+ SfxObjectShell* pDocShell = GetDocShell();
+ return pDocShell ? ScModelObj::getImplementation( pDocShell->GetModel() ) : 0;
+}
+
+OutputDevice* XclRoot::GetPrinter() const
+{
+ return GetDoc().GetRefDevice();
+}
+
+ScStyleSheetPool& XclRoot::GetStyleSheetPool() const
+{
+ return *GetDoc().GetStyleSheetPool();
+}
+
+ScRangeName& XclRoot::GetNamedRanges() const
+{
+ return *GetDoc().GetRangeName();
+}
+
+ScDBCollection& XclRoot::GetDatabaseRanges() const
+{
+ return *GetDoc().GetDBCollection();
+}
+
+SdrPage* XclRoot::GetSdrPage( SCTAB nScTab ) const
+{
+ return ((nScTab >= 0) && GetDoc().GetDrawLayer()) ?
+ GetDoc().GetDrawLayer()->GetPage( static_cast< sal_uInt16 >( nScTab ) ) : 0;
+}
+
+SvNumberFormatter& XclRoot::GetFormatter() const
+{
+ return *GetDoc().GetFormatTable();
+}
+
+DateTime XclRoot::GetNullDate() const
+{
+ return *GetFormatter().GetNullDate();
+}
+
+sal_uInt16 XclRoot::GetBaseYear() const
+{
+ // return 1904 for 1904-01-01, and 1900 for 1899-12-30
+ return (GetNullDate().GetYear() == 1904) ? 1904 : 1900;
+}
+
+double XclRoot::GetDoubleFromDateTime( const DateTime& rDateTime ) const
+{
+ double fValue = rDateTime - GetNullDate();
+ // adjust dates before 1900-03-01 to get correct time values in the range [0.0,1.0)
+ if( rDateTime < DateTime( Date( 1, 3, 1900 ) ) )
+ fValue -= 1.0;
+ return fValue;
+}
+
+DateTime XclRoot::GetDateTimeFromDouble( double fValue ) const
+{
+ DateTime aDateTime = GetNullDate() + fValue;
+ // adjust dates before 1900-03-01 to get correct time values
+ if( aDateTime < DateTime( Date( 1, 3, 1900 ) ) )
+ aDateTime += 1L;
+ return aDateTime;
+}
+
+ScEditEngineDefaulter& XclRoot::GetEditEngine() const
+{
+ if( !mrData.mxEditEngine.get() )
+ {
+ mrData.mxEditEngine.reset( new ScEditEngineDefaulter( GetDoc().GetEnginePool() ) );
+ ScEditEngineDefaulter& rEE = *mrData.mxEditEngine;
+ rEE.SetRefMapMode( MAP_100TH_MM );
+ rEE.SetEditTextObjectPool( GetDoc().GetEditPool() );
+ rEE.SetUpdateMode( false );
+ rEE.EnableUndo( false );
+ rEE.SetControlWord( rEE.GetControlWord() & ~EE_CNTRL_ALLOWBIGOBJS );
+ }
+ return *mrData.mxEditEngine;
+}
+
+ScHeaderEditEngine& XclRoot::GetHFEditEngine() const
+{
+ if( !mrData.mxHFEditEngine.get() )
+ {
+ mrData.mxHFEditEngine.reset( new ScHeaderEditEngine( EditEngine::CreatePool(), sal_True ) );
+ ScHeaderEditEngine& rEE = *mrData.mxHFEditEngine;
+ rEE.SetRefMapMode( MAP_TWIP ); // headers/footers use twips as default metric
+ rEE.SetUpdateMode( false );
+ rEE.EnableUndo( false );
+ rEE.SetControlWord( rEE.GetControlWord() & ~EE_CNTRL_ALLOWBIGOBJS );
+
+ // set Calc header/footer defaults
+ SfxItemSet* pEditSet = new SfxItemSet( rEE.GetEmptyItemSet() );
+ SfxItemSet aItemSet( *GetDoc().GetPool(), ATTR_PATTERN_START, ATTR_PATTERN_END );
+ ScPatternAttr::FillToEditItemSet( *pEditSet, aItemSet );
+ // FillToEditItemSet() adjusts font height to 1/100th mm, we need twips
+ pEditSet->Put( aItemSet.Get( ATTR_FONT_HEIGHT ), EE_CHAR_FONTHEIGHT );
+ pEditSet->Put( aItemSet.Get( ATTR_CJK_FONT_HEIGHT ), EE_CHAR_FONTHEIGHT_CJK );
+ pEditSet->Put( aItemSet.Get( ATTR_CTL_FONT_HEIGHT ), EE_CHAR_FONTHEIGHT_CTL );
+ rEE.SetDefaults( pEditSet ); // takes ownership
+ }
+ return *mrData.mxHFEditEngine;
+}
+
+EditEngine& XclRoot::GetDrawEditEngine() const
+{
+ if( !mrData.mxDrawEditEng.get() )
+ {
+ mrData.mxDrawEditEng.reset( new EditEngine( &GetDoc().GetDrawLayer()->GetItemPool() ) );
+ EditEngine& rEE = *mrData.mxDrawEditEng;
+ rEE.SetRefMapMode( MAP_100TH_MM );
+ rEE.SetUpdateMode( false );
+ rEE.EnableUndo( false );
+ rEE.SetControlWord( rEE.GetControlWord() & ~EE_CNTRL_ALLOWBIGOBJS );
+ }
+ return *mrData.mxDrawEditEng;
+}
+
+XclFontPropSetHelper& XclRoot::GetFontPropSetHelper() const
+{
+ return *mrData.mxFontPropSetHlp;
+}
+
+XclChPropSetHelper& XclRoot::GetChartPropSetHelper() const
+{
+ return *mrData.mxChPropSetHlp;
+}
+
+ScExtDocOptions& XclRoot::GetExtDocOptions() const
+{
+ return *mrData.mxExtDocOpt;
+}
+
+XclTracer& XclRoot::GetTracer() const
+{
+ return *mrData.mxTracer;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xlstyle.cxx b/sc/source/filter/excel/xlstyle.cxx
new file mode 100644
index 000000000000..85537d32e547
--- /dev/null
+++ b/sc/source/filter/excel/xlstyle.cxx
@@ -0,0 +1,1772 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include "xlstyle.hxx"
+#include <com/sun/star/awt/FontFamily.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <vcl/svapp.hxx>
+#include <vcl/font.hxx>
+#include <sal/macros.h>
+#include <rtl/tencinfo.h>
+#include <toolkit/unohlp.hxx>
+#include <editeng/svxfont.hxx>
+#include "global.hxx"
+#include "xlroot.hxx"
+
+// Color data =================================================================
+
+/** Standard EGA colors, bright. */
+#define EXC_PALETTE_EGA_COLORS_LIGHT \
+ 0x000000, 0xFFFFFF, 0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF
+/** Standard EGA colors, dark. */
+#define EXC_PALETTE_EGA_COLORS_DARK \
+ 0x800000, 0x008000, 0x000080, 0x808000, 0x800080, 0x008080, 0xC0C0C0, 0x808080
+
+/** Default color table for BIFF2. */
+static const ColorData spnDefColorTable2[] =
+{
+/* 0 */ EXC_PALETTE_EGA_COLORS_LIGHT
+};
+
+/** Default color table for BIFF3/BIFF4. */
+static const ColorData spnDefColorTable3[] =
+{
+/* 0 */ EXC_PALETTE_EGA_COLORS_LIGHT,
+/* 8 */ EXC_PALETTE_EGA_COLORS_LIGHT,
+/* 16 */ EXC_PALETTE_EGA_COLORS_DARK
+};
+
+/** Default color table for BIFF5/BIFF7. */
+static const ColorData spnDefColorTable5[] =
+{
+/* 0 */ EXC_PALETTE_EGA_COLORS_LIGHT,
+/* 8 */ EXC_PALETTE_EGA_COLORS_LIGHT,
+/* 16 */ EXC_PALETTE_EGA_COLORS_DARK,
+/* 24 */ 0x8080FF, 0x802060, 0xFFFFC0, 0xA0E0E0, 0x600080, 0xFF8080, 0x0080C0, 0xC0C0FF,
+/* 32 */ 0x000080, 0xFF00FF, 0xFFFF00, 0x00FFFF, 0x800080, 0x800000, 0x008080, 0x0000FF,
+/* 40 */ 0x00CFFF, 0x69FFFF, 0xE0FFE0, 0xFFFF80, 0xA6CAF0, 0xDD9CB3, 0xB38FEE, 0xE3E3E3,
+/* 48 */ 0x2A6FF9, 0x3FB8CD, 0x488436, 0x958C41, 0x8E5E42, 0xA0627A, 0x624FAC, 0x969696,
+/* 56 */ 0x1D2FBE, 0x286676, 0x004500, 0x453E01, 0x6A2813, 0x85396A, 0x4A3285, 0x424242
+};
+
+/** Default color table for BIFF8. */
+static const ColorData spnDefColorTable8[] =
+{
+/* 0 */ EXC_PALETTE_EGA_COLORS_LIGHT,
+/* 8 */ EXC_PALETTE_EGA_COLORS_LIGHT,
+/* 16 */ EXC_PALETTE_EGA_COLORS_DARK,
+/* 24 */ 0x9999FF, 0x993366, 0xFFFFCC, 0xCCFFFF, 0x660066, 0xFF8080, 0x0066CC, 0xCCCCFF,
+/* 32 */ 0x000080, 0xFF00FF, 0xFFFF00, 0x00FFFF, 0x800080, 0x800000, 0x008080, 0x0000FF,
+/* 40 */ 0x00CCFF, 0xCCFFFF, 0xCCFFCC, 0xFFFF99, 0x99CCFF, 0xFF99CC, 0xCC99FF, 0xFFCC99,
+/* 48 */ 0x3366FF, 0x33CCCC, 0x99CC00, 0xFFCC00, 0xFF9900, 0xFF6600, 0x666699, 0x969696,
+/* 56 */ 0x003366, 0x339966, 0x003300, 0x333300, 0x993300, 0x993366, 0x333399, 0x333333
+};
+
+#undef EXC_PALETTE_EGA_COLORS_LIGHT
+#undef EXC_PALETTE_EGA_COLORS_DARK
+
+// ----------------------------------------------------------------------------
+
+XclDefaultPalette::XclDefaultPalette( const XclRoot& rRoot ) :
+ mpnColorTable( 0 ),
+ mnTableSize( 0 )
+{
+ const StyleSettings& rSett = Application::GetSettings().GetStyleSettings();
+ mnWindowText = rSett.GetWindowTextColor().GetColor();
+ mnWindowBack = rSett.GetWindowColor().GetColor();
+ mnFaceColor = rSett.GetFaceColor().GetColor();
+ mnNoteText = rSett.GetHelpTextColor().GetColor();
+ mnNoteBack = rSett.GetHelpColor().GetColor();
+
+ // default colors
+ switch( rRoot.GetBiff() )
+ {
+ case EXC_BIFF2:
+ mpnColorTable = spnDefColorTable2;
+ mnTableSize = SAL_N_ELEMENTS( spnDefColorTable2 );
+ break;
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ mpnColorTable = spnDefColorTable3;
+ mnTableSize = SAL_N_ELEMENTS( spnDefColorTable3 );
+ break;
+ case EXC_BIFF5:
+ mpnColorTable = spnDefColorTable5;
+ mnTableSize = SAL_N_ELEMENTS( spnDefColorTable5 );
+ break;
+ case EXC_BIFF8:
+ mpnColorTable = spnDefColorTable8;
+ mnTableSize = SAL_N_ELEMENTS( spnDefColorTable8 );
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+}
+
+ColorData XclDefaultPalette::GetDefColorData( sal_uInt16 nXclIndex ) const
+{
+ ColorData nColor;
+ if( nXclIndex < mnTableSize )
+ nColor = mpnColorTable[ nXclIndex ];
+ else switch( nXclIndex )
+ {
+ case EXC_COLOR_WINDOWTEXT3:
+ case EXC_COLOR_WINDOWTEXT:
+ case EXC_COLOR_CHWINDOWTEXT: nColor = mnWindowText; break;
+ case EXC_COLOR_WINDOWBACK3:
+ case EXC_COLOR_WINDOWBACK:
+ case EXC_COLOR_CHWINDOWBACK: nColor = mnWindowBack; break;
+ case EXC_COLOR_BUTTONBACK: nColor = mnFaceColor; break;
+ case EXC_COLOR_CHBORDERAUTO: nColor = COL_BLACK; break; // TODO: really always black?
+ case EXC_COLOR_NOTEBACK: nColor = mnNoteBack; break;
+ case EXC_COLOR_NOTETEXT: nColor = mnNoteText; break;
+ case EXC_COLOR_FONTAUTO: nColor = COL_AUTO; break;
+ default:
+ OSL_TRACE( "XclDefaultPalette::GetDefColorData - unknown default color index: %d", nXclIndex );
+ nColor = COL_AUTO;
+ }
+ return nColor;
+}
+
+// Font Data ==================================================================
+
+namespace Awt = ::com::sun::star::awt;
+namespace AwtFontFamily = Awt::FontFamily;
+namespace AwtFontUnderline = Awt::FontUnderline;
+namespace AwtFontStrikeout = Awt::FontStrikeout;
+
+// ----------------------------------------------------------------------------
+
+XclFontData::XclFontData()
+{
+ Clear();
+}
+
+XclFontData::XclFontData( const Font& rFont )
+{
+ Clear();
+ FillFromVclFont( rFont );
+}
+
+XclFontData::XclFontData( const SvxFont& rFont )
+{
+ FillFromSvxFont( rFont );
+}
+
+void XclFontData::Clear()
+{
+ maName.Erase();
+ maStyle.Erase();
+ maColor.SetColor( COL_AUTO );
+ mnHeight = 0;
+ mnWeight = EXC_FONTWGHT_DONTKNOW;
+ mnEscapem = EXC_FONTESC_NONE;
+ mnFamily = EXC_FONTFAM_SYSTEM;
+ mnCharSet = EXC_FONTCSET_ANSI_LATIN;
+ mnUnderline = EXC_FONTUNDERL_NONE;
+ mbItalic = mbStrikeout = mbOutline = mbShadow = false;
+}
+
+void XclFontData::FillFromVclFont( const Font& rFont )
+{
+ maName = XclTools::GetXclFontName( rFont.GetName() ); // substitute with MS fonts
+ maStyle.Erase();
+ maColor = rFont.GetColor();
+ SetScUnderline( rFont.GetUnderline() );
+ mnEscapem = EXC_FONTESC_NONE;
+ SetScHeight( rFont.GetSize().Height() );
+ SetScWeight( rFont.GetWeight() );
+ SetScFamily( rFont.GetFamily() );
+ SetFontEncoding( rFont.GetCharSet() );
+ SetScPosture( rFont.GetItalic() );
+ SetScStrikeout( rFont.GetStrikeout() );
+ mbOutline = rFont.IsOutline();
+ mbShadow = rFont.IsShadow();
+}
+
+void XclFontData::FillFromSvxFont( const SvxFont& rFont )
+{
+ FillFromVclFont( rFont );
+ SetScEscapement( rFont.GetEscapement() );
+}
+
+// *** conversion of VCL/SVX constants *** ------------------------------------
+
+FontFamily XclFontData::GetScFamily( rtl_TextEncoding eDefTextEnc ) const
+{
+ FontFamily eScFamily;
+ // ! format differs from Windows documentation: family is in lower nibble, pitch unknown
+ switch( mnFamily & 0x0F )
+ {
+ case EXC_FONTFAM_ROMAN: eScFamily = FAMILY_ROMAN; break;
+ case EXC_FONTFAM_SWISS: eScFamily = FAMILY_SWISS; break;
+ case EXC_FONTFAM_MODERN: eScFamily = FAMILY_MODERN; break;
+ case EXC_FONTFAM_SCRIPT: eScFamily = FAMILY_SCRIPT; break;
+ case EXC_FONTFAM_DECORATIVE: eScFamily = FAMILY_DECORATIVE; break;
+ default:
+ eScFamily =
+ ((eDefTextEnc == RTL_TEXTENCODING_APPLE_ROMAN) &&
+ (maName.EqualsIgnoreCaseAscii( "Geneva" ) || maName.EqualsIgnoreCaseAscii( "Chicago" ))) ?
+ FAMILY_SWISS : FAMILY_DONTKNOW;
+ }
+ return eScFamily;
+}
+
+rtl_TextEncoding XclFontData::GetFontEncoding() const
+{
+ // convert Windows character set to text encoding identifier
+ return rtl_getTextEncodingFromWindowsCharset( mnCharSet );
+}
+
+FontItalic XclFontData::GetScPosture() const
+{
+ return mbItalic ? ITALIC_NORMAL : ITALIC_NONE;
+}
+
+FontWeight XclFontData::GetScWeight() const
+{
+ FontWeight eScWeight;
+
+ if( !mnWeight ) eScWeight = WEIGHT_DONTKNOW;
+ else if( mnWeight < 150 ) eScWeight = WEIGHT_THIN;
+ else if( mnWeight < 250 ) eScWeight = WEIGHT_ULTRALIGHT;
+ else if( mnWeight < 325 ) eScWeight = WEIGHT_LIGHT;
+ else if( mnWeight < 375 ) eScWeight = WEIGHT_SEMILIGHT;
+ else if( mnWeight < 450 ) eScWeight = WEIGHT_NORMAL;
+ else if( mnWeight < 550 ) eScWeight = WEIGHT_MEDIUM;
+ else if( mnWeight < 650 ) eScWeight = WEIGHT_SEMIBOLD;
+ else if( mnWeight < 750 ) eScWeight = WEIGHT_BOLD;
+ else if( mnWeight < 850 ) eScWeight = WEIGHT_ULTRABOLD;
+ else eScWeight = WEIGHT_BLACK;
+
+ return eScWeight;
+}
+
+FontUnderline XclFontData::GetScUnderline() const
+{
+ FontUnderline eScUnderl = UNDERLINE_NONE;
+ switch( mnUnderline )
+ {
+ case EXC_FONTUNDERL_SINGLE:
+ case EXC_FONTUNDERL_SINGLE_ACC: eScUnderl = UNDERLINE_SINGLE; break;
+ case EXC_FONTUNDERL_DOUBLE:
+ case EXC_FONTUNDERL_DOUBLE_ACC: eScUnderl = UNDERLINE_DOUBLE; break;
+ }
+ return eScUnderl;
+}
+
+SvxEscapement XclFontData::GetScEscapement() const
+{
+ SvxEscapement eScEscapem = SVX_ESCAPEMENT_OFF;
+ switch( mnEscapem )
+ {
+ case EXC_FONTESC_SUPER: eScEscapem = SVX_ESCAPEMENT_SUPERSCRIPT; break;
+ case EXC_FONTESC_SUB: eScEscapem = SVX_ESCAPEMENT_SUBSCRIPT; break;
+ }
+ return eScEscapem;
+}
+
+FontStrikeout XclFontData::GetScStrikeout() const
+{
+ return mbStrikeout ? STRIKEOUT_SINGLE : STRIKEOUT_NONE;
+}
+
+void XclFontData::SetScHeight( sal_Int32 nTwips )
+{
+ mnHeight = static_cast< sal_uInt16 >( ::std::min( nTwips, static_cast<sal_Int32>(0x7FFFL) ) );
+}
+
+void XclFontData::SetScFamily( FontFamily eScFamily )
+{
+ switch( eScFamily )
+ {
+ case FAMILY_DONTKNOW: mnFamily = EXC_FONTFAM_DONTKNOW; break;
+ case FAMILY_DECORATIVE: mnFamily = EXC_FONTFAM_DECORATIVE; break;
+ case FAMILY_MODERN: mnFamily = EXC_FONTFAM_MODERN; break;
+ case FAMILY_ROMAN: mnFamily = EXC_FONTFAM_ROMAN; break;
+ case FAMILY_SCRIPT: mnFamily = EXC_FONTFAM_SCRIPT; break;
+ case FAMILY_SWISS: mnFamily = EXC_FONTFAM_SWISS; break;
+ case FAMILY_SYSTEM: mnFamily = EXC_FONTFAM_SYSTEM; break;
+ default:
+ DBG_ERRORFILE( "XclFontData::SetScFamily - unknown font family" );
+ mnFamily = EXC_FONTFAM_DONTKNOW;
+ }
+}
+
+void XclFontData::SetFontEncoding( rtl_TextEncoding eFontEnc )
+{
+ // convert text encoding identifier to Windows character set
+ mnCharSet = rtl_getBestWindowsCharsetFromTextEncoding( eFontEnc );
+}
+
+
+void XclFontData::SetScPosture( FontItalic eScPosture )
+{
+ mbItalic = (eScPosture == ITALIC_OBLIQUE) || (eScPosture == ITALIC_NORMAL);
+}
+
+void XclFontData::SetScWeight( FontWeight eScWeight )
+{
+ switch( eScWeight )
+ {
+ case WEIGHT_DONTKNOW: mnWeight = EXC_FONTWGHT_DONTKNOW; break;
+ case WEIGHT_THIN: mnWeight = EXC_FONTWGHT_THIN; break;
+ case WEIGHT_ULTRALIGHT: mnWeight = EXC_FONTWGHT_ULTRALIGHT; break;
+ case WEIGHT_LIGHT: mnWeight = EXC_FONTWGHT_LIGHT; break;
+ case WEIGHT_SEMILIGHT: mnWeight = EXC_FONTWGHT_SEMILIGHT; break;
+ case WEIGHT_NORMAL: mnWeight = EXC_FONTWGHT_NORMAL; break;
+ case WEIGHT_MEDIUM: mnWeight = EXC_FONTWGHT_MEDIUM; break;
+ case WEIGHT_SEMIBOLD: mnWeight = EXC_FONTWGHT_SEMIBOLD; break;
+ case WEIGHT_BOLD: mnWeight = EXC_FONTWGHT_BOLD; break;
+ case WEIGHT_ULTRABOLD: mnWeight = EXC_FONTWGHT_ULTRABOLD; break;
+ case WEIGHT_BLACK: mnWeight = EXC_FONTWGHT_BLACK; break;
+ default: mnWeight = EXC_FONTWGHT_NORMAL;
+ }
+}
+
+void XclFontData::SetScUnderline( FontUnderline eScUnderl )
+{
+ switch( eScUnderl )
+ {
+ case UNDERLINE_NONE:
+ case UNDERLINE_DONTKNOW: mnUnderline = EXC_FONTUNDERL_NONE; break;
+ case UNDERLINE_DOUBLE:
+ case UNDERLINE_DOUBLEWAVE: mnUnderline = EXC_FONTUNDERL_DOUBLE; break;
+ default: mnUnderline = EXC_FONTUNDERL_SINGLE;
+ }
+}
+
+void XclFontData::SetScEscapement( short nScEscapem )
+{
+ if( nScEscapem > 0 )
+ mnEscapem = EXC_FONTESC_SUPER;
+ else if( nScEscapem < 0 )
+ mnEscapem = EXC_FONTESC_SUB;
+ else
+ mnEscapem = EXC_FONTESC_NONE;
+}
+
+void XclFontData::SetScStrikeout( FontStrikeout eScStrikeout )
+{
+ mbStrikeout =
+ (eScStrikeout == STRIKEOUT_SINGLE) || (eScStrikeout == STRIKEOUT_DOUBLE) ||
+ (eScStrikeout == STRIKEOUT_BOLD) || (eScStrikeout == STRIKEOUT_SLASH) ||
+ (eScStrikeout == STRIKEOUT_X);
+}
+
+// *** conversion of API constants *** ----------------------------------------
+
+float XclFontData::GetApiHeight() const
+{
+ return static_cast< float >( mnHeight / TWIPS_PER_POINT );
+}
+
+sal_Int16 XclFontData::GetApiFamily() const
+{
+ sal_Int16 nApiFamily = AwtFontFamily::DONTKNOW;
+ switch( mnFamily )
+ {
+ case FAMILY_DECORATIVE: nApiFamily = AwtFontFamily::DECORATIVE; break;
+ case FAMILY_MODERN: nApiFamily = AwtFontFamily::MODERN; break;
+ case FAMILY_ROMAN: nApiFamily = AwtFontFamily::ROMAN; break;
+ case FAMILY_SCRIPT: nApiFamily = AwtFontFamily::SCRIPT; break;
+ case FAMILY_SWISS: nApiFamily = AwtFontFamily::SWISS; break;
+ case FAMILY_SYSTEM: nApiFamily = AwtFontFamily::SYSTEM; break;
+ }
+ return nApiFamily;
+}
+
+sal_Int16 XclFontData::GetApiFontEncoding() const
+{
+ // API constants are equal to rtl_TextEncoding constants
+ return static_cast< sal_Int16 >( GetFontEncoding() );
+}
+
+Awt::FontSlant XclFontData::GetApiPosture() const
+{
+ return mbItalic ? Awt::FontSlant_ITALIC : Awt::FontSlant_NONE;
+}
+
+float XclFontData::GetApiWeight() const
+{
+ return VCLUnoHelper::ConvertFontWeight( GetScWeight() );
+}
+
+sal_Int16 XclFontData::GetApiUnderline() const
+{
+ sal_Int16 nApiUnderl = AwtFontUnderline::NONE;
+ switch( mnUnderline )
+ {
+ case EXC_FONTUNDERL_SINGLE:
+ case EXC_FONTUNDERL_SINGLE_ACC: nApiUnderl = AwtFontUnderline::SINGLE; break;
+ case EXC_FONTUNDERL_DOUBLE:
+ case EXC_FONTUNDERL_DOUBLE_ACC: nApiUnderl = AwtFontUnderline::DOUBLE; break;
+ }
+ return nApiUnderl;
+}
+
+sal_Int16 XclFontData::GetApiEscapement() const
+{
+ sal_Int16 nApiEscapem = 0;
+ switch( mnEscapem )
+ {
+ case EXC_FONTESC_SUPER: nApiEscapem = 33; break;
+ case EXC_FONTESC_SUB: nApiEscapem = -33; break;
+ }
+ return nApiEscapem;
+}
+
+sal_Int16 XclFontData::GetApiStrikeout() const
+{
+ return mbStrikeout ? AwtFontStrikeout::SINGLE : AwtFontStrikeout::NONE;
+}
+
+void XclFontData::SetApiHeight( float fPoint )
+{
+ mnHeight = static_cast< sal_uInt16 >( ::std::min( fPoint * TWIPS_PER_POINT + 0.5, 32767.0 ) );
+}
+
+void XclFontData::SetApiFamily( sal_Int16 nApiFamily )
+{
+ switch( nApiFamily )
+ {
+ case AwtFontFamily::DECORATIVE: mnFamily = FAMILY_DECORATIVE; break;
+ case AwtFontFamily::MODERN: mnFamily = FAMILY_MODERN; break;
+ case AwtFontFamily::ROMAN: mnFamily = FAMILY_ROMAN; break;
+ case AwtFontFamily::SCRIPT: mnFamily = FAMILY_SCRIPT; break;
+ case AwtFontFamily::SWISS: mnFamily = FAMILY_SWISS; break;
+ case AwtFontFamily::SYSTEM: mnFamily = FAMILY_SYSTEM; break;
+ default: mnFamily = FAMILY_DONTKNOW;
+ }
+}
+
+void XclFontData::SetApiPosture( Awt::FontSlant eApiPosture )
+{
+ mbItalic =
+ (eApiPosture == Awt::FontSlant_OBLIQUE) ||
+ (eApiPosture == Awt::FontSlant_ITALIC) ||
+ (eApiPosture == Awt::FontSlant_REVERSE_OBLIQUE) ||
+ (eApiPosture == Awt::FontSlant_REVERSE_ITALIC);
+}
+
+void XclFontData::SetApiWeight( float fApiWeight )
+{
+ SetScWeight( VCLUnoHelper::ConvertFontWeight( fApiWeight ) );
+}
+
+void XclFontData::SetApiUnderline( sal_Int16 nApiUnderl )
+{
+ switch( nApiUnderl )
+ {
+ case AwtFontUnderline::NONE:
+ case AwtFontUnderline::DONTKNOW: mnUnderline = EXC_FONTUNDERL_NONE; break;
+ case AwtFontUnderline::DOUBLE:
+ case AwtFontUnderline::DOUBLEWAVE: mnUnderline = EXC_FONTUNDERL_DOUBLE; break;
+ default: mnUnderline = EXC_FONTUNDERL_SINGLE;
+ }
+}
+
+void XclFontData::SetApiEscapement( sal_Int16 nApiEscapem )
+{
+ if( nApiEscapem > 0 )
+ mnEscapem = EXC_FONTESC_SUPER;
+ else if( nApiEscapem < 0 )
+ mnEscapem = EXC_FONTESC_SUB;
+ else
+ mnEscapem = EXC_FONTESC_NONE;
+}
+
+void XclFontData::SetApiStrikeout( sal_Int16 nApiStrikeout )
+{
+ mbStrikeout =
+ (nApiStrikeout != AwtFontStrikeout::NONE) &&
+ (nApiStrikeout != AwtFontStrikeout::DONTKNOW);
+}
+
+// ----------------------------------------------------------------------------
+
+bool operator==( const XclFontData& rLeft, const XclFontData& rRight )
+{
+ return
+ (rLeft.mnHeight == rRight.mnHeight) &&
+ (rLeft.mnWeight == rRight.mnWeight) &&
+ (rLeft.mnUnderline == rRight.mnUnderline) &&
+ (rLeft.maColor == rRight.maColor) &&
+ (rLeft.mnEscapem == rRight.mnEscapem) &&
+ (rLeft.mnFamily == rRight.mnFamily) &&
+ (rLeft.mnCharSet == rRight.mnCharSet) &&
+ (rLeft.mbItalic == rRight.mbItalic) &&
+ (rLeft.mbStrikeout == rRight.mbStrikeout) &&
+ (rLeft.mbOutline == rRight.mbOutline) &&
+ (rLeft.mbShadow == rRight.mbShadow) &&
+ (rLeft.maName == rRight.maName);
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+/** Property names for common font settings. */
+const sal_Char *const sppcPropNamesChCommon[] =
+{
+ "CharUnderline", "CharStrikeout", "CharColor", "CharContoured", "CharShadowed", 0
+};
+/** Property names for Western font settings. */
+const sal_Char *const sppcPropNamesChWstrn[] =
+{
+ "CharFontName", "CharHeight", "CharPosture", "CharWeight", 0
+};
+/** Property names for Asian font settings. */
+const sal_Char *const sppcPropNamesChAsian[] =
+{
+ "CharFontNameAsian", "CharHeightAsian", "CharPostureAsian", "CharWeightAsian", 0
+};
+/** Property names for Complex font settings. */
+const sal_Char *const sppcPropNamesChCmplx[] =
+{
+ "CharFontNameComplex", "CharHeightComplex", "CharPostureComplex", "CharWeightComplex", 0
+};
+/** Property names for escapement. */
+const sal_Char *const sppcPropNamesChEscapement[] =
+{
+ "CharEscapement", "CharEscapementHeight", 0
+};
+const sal_Int8 EXC_API_ESC_HEIGHT = 58; /// Default escapement font height.
+
+/** Property names for Western font settings without font name. */
+const sal_Char *const *const sppcPropNamesChWstrnNoName = sppcPropNamesChWstrn + 1;
+/** Property names for Asian font settings without font name. */
+const sal_Char *const *const sppcPropNamesChAsianNoName = sppcPropNamesChAsian + 1;
+/** Property names for Complex font settings without font name. */
+const sal_Char *const *const sppcPropNamesChCmplxNoName = sppcPropNamesChCmplx + 1;
+
+/** Property names for font settings in form controls. */
+const sal_Char *const sppcPropNamesControl[] =
+{
+ "FontName", "FontFamily", "FontCharset", "FontHeight", "FontSlant",
+ "FontWeight", "FontUnderline", "FontStrikeout", "TextColor", 0
+};
+
+/** Inserts all passed API font settings into the font data object. */
+void lclSetApiFontSettings( XclFontData& rFontData,
+ const String& rApiFontName, float fApiHeight, float fApiWeight,
+ Awt::FontSlant eApiPosture, sal_Int16 nApiUnderl, sal_Int16 nApiStrikeout )
+{
+ rFontData.maName = XclTools::GetXclFontName( rApiFontName );
+ rFontData.SetApiHeight( fApiHeight );
+ rFontData.SetApiWeight( fApiWeight );
+ rFontData.SetApiPosture( eApiPosture );
+ rFontData.SetApiUnderline( nApiUnderl );
+ rFontData.SetApiStrikeout( nApiStrikeout );
+}
+
+/** Writes script dependent properties to a font property set helper. */
+void lclWriteChartFont( ScfPropertySet& rPropSet,
+ ScfPropSetHelper& rHlpName, ScfPropSetHelper& rHlpNoName,
+ const XclFontData& rFontData, bool bHasFontName )
+{
+ // select the font helper
+ ScfPropSetHelper& rPropSetHlp = bHasFontName ? rHlpName : rHlpNoName;
+ // initialize the font helper (must be called before writing any properties)
+ rPropSetHlp.InitializeWrite();
+ // write font name
+ if( bHasFontName )
+ rPropSetHlp << rFontData.maName;
+ // write remaining properties
+ rPropSetHlp << rFontData.GetApiHeight() << rFontData.GetApiPosture() << rFontData.GetApiWeight();
+ // write properties to property set
+ rPropSetHlp.WriteToPropertySet( rPropSet );
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+XclFontPropSetHelper::XclFontPropSetHelper() :
+ maHlpChCommon( sppcPropNamesChCommon ),
+ maHlpChWstrn( sppcPropNamesChWstrn ),
+ maHlpChAsian( sppcPropNamesChAsian ),
+ maHlpChCmplx( sppcPropNamesChCmplx ),
+ maHlpChWstrnNoName( sppcPropNamesChWstrnNoName ),
+ maHlpChAsianNoName( sppcPropNamesChAsianNoName ),
+ maHlpChCmplxNoName( sppcPropNamesChCmplxNoName ),
+ maHlpChEscapement( sppcPropNamesChEscapement ),
+ maHlpControl( sppcPropNamesControl )
+{
+}
+
+void XclFontPropSetHelper::ReadFontProperties( XclFontData& rFontData,
+ const ScfPropertySet& rPropSet, XclFontPropSetType eType, sal_Int16 nScript )
+{
+ switch( eType )
+ {
+ case EXC_FONTPROPSET_CHART:
+ {
+ String aApiFontName;
+ float fApiHeight, fApiWeight;
+ sal_Int16 nApiUnderl = 0, nApiStrikeout = 0;
+ Awt::FontSlant eApiPosture;
+
+ // read script type dependent properties
+ ScfPropSetHelper& rPropSetHlp = GetChartHelper( nScript );
+ rPropSetHlp.ReadFromPropertySet( rPropSet );
+ rPropSetHlp >> aApiFontName >> fApiHeight >> eApiPosture >> fApiWeight;
+ // read common properties
+ maHlpChCommon.ReadFromPropertySet( rPropSet );
+ maHlpChCommon >> nApiUnderl
+ >> nApiStrikeout
+ >> rFontData.maColor
+ >> rFontData.mbOutline
+ >> rFontData.mbShadow;
+
+ // convert API property values to Excel settings
+ lclSetApiFontSettings( rFontData, aApiFontName,
+ fApiHeight, fApiWeight, eApiPosture, nApiUnderl, nApiStrikeout );
+
+ // font escapement
+ sal_Int16 nApiEscapement = 0;
+ sal_Int8 nApiEscHeight = 0;
+ maHlpChEscapement.ReadFromPropertySet( rPropSet );
+ maHlpChEscapement.ReadFromPropertySet( rPropSet );
+ maHlpChEscapement.ReadFromPropertySet( rPropSet );
+ maHlpChEscapement >> nApiEscapement >> nApiEscHeight;
+ rFontData.SetApiEscapement( nApiEscapement );
+ }
+ break;
+
+ case EXC_FONTPROPSET_CONTROL:
+ {
+ String aApiFontName;
+ float fApiHeight, fApiWeight;
+ sal_Int16 nApiFamily, nApiCharSet, nApiPosture, nApiUnderl, nApiStrikeout;
+
+ // read font properties
+ maHlpControl.ReadFromPropertySet( rPropSet );
+ maHlpControl >> aApiFontName
+ >> nApiFamily
+ >> nApiCharSet
+ >> fApiHeight
+ >> nApiPosture
+ >> fApiWeight
+ >> nApiUnderl
+ >> nApiStrikeout
+ >> rFontData.maColor;
+
+ // convert API property values to Excel settings
+ Awt::FontSlant eApiPosture = static_cast< Awt::FontSlant >( nApiPosture );
+ lclSetApiFontSettings( rFontData, aApiFontName,
+ fApiHeight, fApiWeight, eApiPosture, nApiUnderl, nApiStrikeout );
+ rFontData.SetApiFamily( nApiFamily );
+ rFontData.SetFontEncoding( nApiCharSet );
+ }
+ break;
+ }
+}
+
+void XclFontPropSetHelper::WriteFontProperties(
+ ScfPropertySet& rPropSet, XclFontPropSetType eType,
+ const XclFontData& rFontData, bool bHasWstrn, bool bHasAsian, bool bHasCmplx,
+ const Color* pFontColor )
+{
+ switch( eType )
+ {
+ case EXC_FONTPROPSET_CHART:
+ {
+ // write common properties
+ maHlpChCommon.InitializeWrite();
+ const Color& rColor = pFontColor ? *pFontColor : rFontData.maColor;
+ maHlpChCommon << rFontData.GetApiUnderline()
+ << rFontData.GetApiStrikeout()
+ << rColor
+ << rFontData.mbOutline
+ << rFontData.mbShadow;
+ maHlpChCommon.WriteToPropertySet( rPropSet );
+
+ // write script type dependent properties
+ lclWriteChartFont( rPropSet, maHlpChWstrn, maHlpChWstrnNoName, rFontData, bHasWstrn );
+ lclWriteChartFont( rPropSet, maHlpChAsian, maHlpChAsianNoName, rFontData, bHasAsian );
+ lclWriteChartFont( rPropSet, maHlpChCmplx, maHlpChCmplxNoName, rFontData, bHasCmplx );
+
+ // font escapement
+ if( rFontData.GetScEscapement() != SVX_ESCAPEMENT_OFF )
+ {
+ maHlpChEscapement.InitializeWrite();
+ maHlpChEscapement << rFontData.GetApiEscapement() << EXC_API_ESC_HEIGHT;
+ maHlpChEscapement.WriteToPropertySet( rPropSet );
+ }
+ }
+ break;
+
+ case EXC_FONTPROPSET_CONTROL:
+ {
+ maHlpControl.InitializeWrite();
+ maHlpControl << rFontData.maName
+ << rFontData.GetApiFamily()
+ << rFontData.GetApiFontEncoding()
+ << static_cast< sal_Int16 >( rFontData.GetApiHeight() + 0.5 )
+ << rFontData.GetApiPosture()
+ << rFontData.GetApiWeight()
+ << rFontData.GetApiUnderline()
+ << rFontData.GetApiStrikeout()
+ << rFontData.maColor;
+ maHlpControl.WriteToPropertySet( rPropSet );
+ }
+ break;
+ }
+}
+
+ScfPropSetHelper& XclFontPropSetHelper::GetChartHelper( sal_Int16 nScript )
+{
+ namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
+ switch( nScript )
+ {
+ case ApiScriptType::LATIN: return maHlpChWstrn;
+ case ApiScriptType::ASIAN: return maHlpChAsian;
+ case ApiScriptType::COMPLEX: return maHlpChCmplx;
+ default: DBG_ERRORFILE( "XclFontPropSetHelper::GetChartHelper - unknown script type" );
+ }
+ return maHlpChWstrn;
+}
+
+// Number formats =============================================================
+
+namespace {
+
+// ----------------------------------------------------------------------------
+
+/** Special number format index describing a reused format. */
+const NfIndexTableOffset PRV_NF_INDEX_REUSE = NF_INDEX_TABLE_ENTRIES;
+
+/** German primary language not defined, LANGUAGE_GERMAN belongs to Germany. */
+const LanguageType PRV_LANGUAGE_GERMAN_PRIM = LANGUAGE_GERMAN & LANGUAGE_MASK_PRIMARY;
+/** French primary language not defined, LANGUAGE_FRENCH belongs to France. */
+const LanguageType PRV_LANGUAGE_FRENCH_PRIM = LANGUAGE_FRENCH & LANGUAGE_MASK_PRIMARY;
+/** Parent language identifier for Asian languages (LANGUAGE_CHINESE is a primary only ID). */
+const LanguageType PRV_LANGUAGE_ASIAN_PRIM = LANGUAGE_CHINESE;
+
+// ----------------------------------------------------------------------------
+
+/** Stores the number format used in Calc for an Excel built-in number format. */
+struct XclBuiltInFormat
+{
+ sal_uInt16 mnXclNumFmt; /// Excel built-in index.
+ const sal_Char* mpFormat; /// Format string, may be 0 (meOffset used then).
+ NfIndexTableOffset meOffset; /// SvNumberFormatter format index, if mpFormat==0.
+ sal_uInt16 mnXclReuseFmt; /// Use this Excel format, if meOffset==PRV_NF_INDEX_REUSE.
+};
+
+// ----------------------------------------------------------------------------
+
+/** Defines a literal Excel built-in number format. */
+#define EXC_NUMFMT_STRING( nXclNumFmt, pcUtf8 ) \
+ { nXclNumFmt, pcUtf8, NF_NUMBER_STANDARD, 0 }
+
+/** Defines an Excel built-in number format that maps to an own built-in format. */
+#define EXC_NUMFMT_OFFSET( nXclNumFmt, eOffset ) \
+ { nXclNumFmt, 0, eOffset, 0 }
+
+/** Defines an Excel built-in number format that is the same as the specified. */
+#define EXC_NUMFMT_REUSE( nXclNumFmt, nXclReuse ) \
+ { nXclNumFmt, 0, PRV_NF_INDEX_REUSE, nXclReuse }
+
+/** Terminates an Excel built-in number format table. */
+#define EXC_NUMFMT_ENDTABLE() \
+ { EXC_FORMAT_NOTFOUND, 0, NF_NUMBER_STANDARD, 0 }
+
+// ----------------------------------------------------------------------------
+
+// Currency unit characters
+#define UTF8_BAHT "\340\270\277"
+#define UTF8_EURO "\342\202\254"
+#define UTF8_POUND_UK "\302\243"
+#define UTF8_SHEQEL "\342\202\252"
+#define UTF8_WON "\357\277\246"
+#define UTF8_YEN_CS "\357\277\245"
+#define UTF8_YEN_JP "\302\245"
+
+// Japanese/Chinese date/time characters
+#define UTF8_CJ_YEAR "\345\271\264"
+#define UTF8_CJ_MON "\346\234\210"
+#define UTF8_CJ_DAY "\346\227\245"
+#define UTF8_CJ_HOUR "\346\231\202"
+#define UTF8_CJ_MIN "\345\210\206"
+#define UTF8_CJ_SEC "\347\247\222"
+
+// Chinese Simplified date/time characters
+#define UTF8_CS_HOUR "\346\227\266"
+
+// Korean date/time characters
+#define UTF8_KO_YEAR "\353\205\204"
+#define UTF8_KO_MON "\354\233\224"
+#define UTF8_KO_DAY "\354\235\274"
+#define UTF8_KO_HOUR "\354\213\234"
+#define UTF8_KO_MIN "\353\266\204"
+#define UTF8_KO_SEC "\354\264\210"
+
+// ----------------------------------------------------------------------------
+
+/** Default number format table. Last parent of all other tables, used for unknown languages. */
+static const XclBuiltInFormat spBuiltInFormats_DONTKNOW[] =
+{
+ EXC_NUMFMT_OFFSET( 0, NF_NUMBER_STANDARD ), // General
+ EXC_NUMFMT_OFFSET( 1, NF_NUMBER_INT ), // 0
+ EXC_NUMFMT_OFFSET( 2, NF_NUMBER_DEC2 ), // 0.00
+ EXC_NUMFMT_OFFSET( 3, NF_NUMBER_1000INT ), // #,##0
+ EXC_NUMFMT_OFFSET( 4, NF_NUMBER_1000DEC2 ), // #,##0.00
+ // 5...8 contained in file
+ EXC_NUMFMT_OFFSET( 9, NF_PERCENT_INT ), // 0%
+ EXC_NUMFMT_OFFSET( 10, NF_PERCENT_DEC2 ), // 0.00%
+ EXC_NUMFMT_OFFSET( 11, NF_SCIENTIFIC_000E00 ), // 0.00E+00
+ EXC_NUMFMT_OFFSET( 12, NF_FRACTION_1 ), // # ?/?
+ EXC_NUMFMT_OFFSET( 13, NF_FRACTION_2 ), // # ??/??
+
+ // 14...22 date and time formats
+ EXC_NUMFMT_OFFSET( 14, NF_DATE_SYS_DDMMYYYY ),
+ EXC_NUMFMT_OFFSET( 15, NF_DATE_SYS_DMMMYY ),
+ EXC_NUMFMT_OFFSET( 16, NF_DATE_SYS_DDMMM ),
+ EXC_NUMFMT_OFFSET( 17, NF_DATE_SYS_MMYY ),
+ EXC_NUMFMT_OFFSET( 18, NF_TIME_HHMMAMPM ),
+ EXC_NUMFMT_OFFSET( 19, NF_TIME_HHMMSSAMPM ),
+ EXC_NUMFMT_OFFSET( 20, NF_TIME_HHMM ),
+ EXC_NUMFMT_OFFSET( 21, NF_TIME_HHMMSS ),
+ EXC_NUMFMT_OFFSET( 22, NF_DATETIME_SYSTEM_SHORT_HHMM ),
+
+ // 23...36 international formats
+ EXC_NUMFMT_REUSE( 23, 0 ),
+ EXC_NUMFMT_REUSE( 24, 0 ),
+ EXC_NUMFMT_REUSE( 25, 0 ),
+ EXC_NUMFMT_REUSE( 26, 0 ),
+ EXC_NUMFMT_REUSE( 27, 14 ),
+ EXC_NUMFMT_REUSE( 28, 14 ),
+ EXC_NUMFMT_REUSE( 29, 14 ),
+ EXC_NUMFMT_REUSE( 30, 14 ),
+ EXC_NUMFMT_REUSE( 31, 14 ),
+ EXC_NUMFMT_REUSE( 32, 21 ),
+ EXC_NUMFMT_REUSE( 33, 21 ),
+ EXC_NUMFMT_REUSE( 34, 21 ),
+ EXC_NUMFMT_REUSE( 35, 21 ),
+ EXC_NUMFMT_REUSE( 36, 14 ),
+
+ // 37...44 accounting formats
+ // 41...44 contained in file
+ EXC_NUMFMT_STRING( 37, "#,##0;-#,##0" ),
+ EXC_NUMFMT_STRING( 38, "#,##0;[RED]-#,##0" ),
+ EXC_NUMFMT_STRING( 39, "#,##0.00;-#,##0.00" ),
+ EXC_NUMFMT_STRING( 40, "#,##0.00;[RED]-#,##0.00" ),
+
+ // 45...49 more special formats
+ EXC_NUMFMT_STRING( 45, "mm:ss" ),
+ EXC_NUMFMT_STRING( 46, "[h]:mm:ss" ),
+ EXC_NUMFMT_STRING( 47, "mm:ss.0" ),
+ EXC_NUMFMT_STRING( 48, "##0.0E+0" ),
+ EXC_NUMFMT_OFFSET( 49, NF_TEXT ),
+
+ // 50...81 international formats
+ EXC_NUMFMT_REUSE( 50, 14 ),
+ EXC_NUMFMT_REUSE( 51, 14 ),
+ EXC_NUMFMT_REUSE( 52, 14 ),
+ EXC_NUMFMT_REUSE( 53, 14 ),
+ EXC_NUMFMT_REUSE( 54, 14 ),
+ EXC_NUMFMT_REUSE( 55, 14 ),
+ EXC_NUMFMT_REUSE( 56, 14 ),
+ EXC_NUMFMT_REUSE( 57, 14 ),
+ EXC_NUMFMT_REUSE( 58, 14 ),
+ EXC_NUMFMT_REUSE( 59, 1 ),
+ EXC_NUMFMT_REUSE( 60, 2 ),
+ EXC_NUMFMT_REUSE( 61, 3 ),
+ EXC_NUMFMT_REUSE( 62, 4 ),
+ EXC_NUMFMT_REUSE( 67, 9 ),
+ EXC_NUMFMT_REUSE( 68, 10 ),
+ EXC_NUMFMT_REUSE( 69, 12 ),
+ EXC_NUMFMT_REUSE( 70, 13 ),
+ EXC_NUMFMT_REUSE( 71, 14 ),
+ EXC_NUMFMT_REUSE( 72, 14 ),
+ EXC_NUMFMT_REUSE( 73, 15 ),
+ EXC_NUMFMT_REUSE( 74, 16 ),
+ EXC_NUMFMT_REUSE( 75, 17 ),
+ EXC_NUMFMT_REUSE( 76, 20 ),
+ EXC_NUMFMT_REUSE( 77, 21 ),
+ EXC_NUMFMT_REUSE( 78, 22 ),
+ EXC_NUMFMT_REUSE( 79, 45 ),
+ EXC_NUMFMT_REUSE( 80, 46 ),
+ EXC_NUMFMT_REUSE( 81, 47 ),
+
+ // 82...163 not used, must not occur in a file (Excel may crash)
+
+ EXC_NUMFMT_ENDTABLE()
+};
+
+// ENGLISH --------------------------------------------------------------------
+
+/** Base table for English locales. */
+static const XclBuiltInFormat spBuiltInFormats_ENGLISH[] =
+{
+ EXC_NUMFMT_STRING( 15, "DD-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "DD-MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM-YY" ),
+ EXC_NUMFMT_STRING( 18, "h:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "h:mm:ss AM/PM" ),
+ EXC_NUMFMT_STRING( 22, "DD/MM/YYYY hh:mm" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_ENGLISH_UK[] =
+{
+ EXC_NUMFMT_STRING( 63, UTF8_POUND_UK "#,##0;-" UTF8_POUND_UK "#,##0" ),
+ EXC_NUMFMT_STRING( 64, UTF8_POUND_UK "#,##0;[RED]-" UTF8_POUND_UK "#,##0" ),
+ EXC_NUMFMT_STRING( 65, UTF8_POUND_UK "#,##0.00;-" UTF8_POUND_UK "#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, UTF8_POUND_UK "#,##0.00;[RED]-" UTF8_POUND_UK "#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_ENGLISH_EIRE[] =
+{
+ EXC_NUMFMT_STRING( 63, UTF8_EURO "#,##0;-" UTF8_EURO "#,##0" ),
+ EXC_NUMFMT_STRING( 64, UTF8_EURO "#,##0;[RED]-" UTF8_EURO "#,##0" ),
+ EXC_NUMFMT_STRING( 65, UTF8_EURO "#,##0.00;-" UTF8_EURO "#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, UTF8_EURO "#,##0.00;[RED]-" UTF8_EURO "#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_ENGLISH_US[] =
+{
+ EXC_NUMFMT_STRING( 14, "M/D/YYYY" ),
+ EXC_NUMFMT_STRING( 15, "D-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "D-MMM" ),
+ EXC_NUMFMT_STRING( 20, "h:mm" ),
+ EXC_NUMFMT_STRING( 21, "h:mm:ss" ),
+ EXC_NUMFMT_STRING( 22, "M/D/YYYY h:mm" ),
+ EXC_NUMFMT_STRING( 37, "#,##0_);(#,##0)" ),
+ EXC_NUMFMT_STRING( 38, "#,##0_);[RED](#,##0)" ),
+ EXC_NUMFMT_STRING( 39, "#,##0.00_);(#,##0.00)" ),
+ EXC_NUMFMT_STRING( 40, "#,##0.00_);[RED](#,##0.00)" ),
+ EXC_NUMFMT_STRING( 63, "$#,##0_);($#,##0)" ),
+ EXC_NUMFMT_STRING( 64, "$#,##0_);[RED]($#,##0)" ),
+ EXC_NUMFMT_STRING( 65, "$#,##0.00_);($#,##0.00)" ),
+ EXC_NUMFMT_STRING( 66, "$#,##0.00_);[RED]($#,##0.00)" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_ENGLISH_CAN[] =
+{
+ EXC_NUMFMT_STRING( 20, "h:mm" ),
+ EXC_NUMFMT_STRING( 21, "h:mm:ss" ),
+ EXC_NUMFMT_STRING( 22, "DD/MM/YYYY h:mm" ),
+ EXC_NUMFMT_STRING( 63, "$#,##0;-$#,##0" ),
+ EXC_NUMFMT_STRING( 64, "$#,##0;[RED]-$#,##0" ),
+ EXC_NUMFMT_STRING( 65, "$#,##0.00;-$#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, "$#,##0.00;[RED]-$#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_ENGLISH_AUS[] =
+{
+ EXC_NUMFMT_STRING( 14, "D/MM/YYYY" ),
+ EXC_NUMFMT_STRING( 15, "D-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "D-MMM" ),
+ EXC_NUMFMT_STRING( 20, "h:mm" ),
+ EXC_NUMFMT_STRING( 21, "h:mm:ss" ),
+ EXC_NUMFMT_STRING( 22, "D/MM/YYYY h:mm" ),
+ EXC_NUMFMT_STRING( 63, "$#,##0;-$#,##0" ),
+ EXC_NUMFMT_STRING( 64, "$#,##0;[RED]-$#,##0" ),
+ EXC_NUMFMT_STRING( 65, "$#,##0.00;-$#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, "$#,##0.00;[RED]-$#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_ENGLISH_SAFRICA[] =
+{
+ EXC_NUMFMT_STRING( 14, "YYYY/MM/DD" ),
+ EXC_NUMFMT_OFFSET( 18, NF_TIME_HHMMAMPM ),
+ EXC_NUMFMT_OFFSET( 19, NF_TIME_HHMMSSAMPM ),
+ EXC_NUMFMT_STRING( 22, "YYYY/MM/DD hh:mm" ),
+ EXC_NUMFMT_STRING( 63, "\\R #,##0;\\R -#,##0" ),
+ EXC_NUMFMT_STRING( 64, "\\R #,##0;[RED]\\R -#,##0" ),
+ EXC_NUMFMT_STRING( 65, "\\R #,##0.00;\\R -#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, "\\R #,##0.00;[RED]\\R -#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+// FRENCH ---------------------------------------------------------------------
+
+/** Base table for French locales. */
+static const XclBuiltInFormat spBuiltInFormats_FRENCH[] =
+{
+ EXC_NUMFMT_STRING( 15, "DD-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "DD-MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM-YY" ),
+ EXC_NUMFMT_STRING( 18, "h:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "h:mm:ss AM/PM" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_FRENCH_FRANCE[] =
+{
+ EXC_NUMFMT_STRING( 22, "DD/MM/YYYY hh:mm" ),
+ EXC_NUMFMT_STRING( 37, "#,##0\\ _" UTF8_EURO ";-#,##0\\ _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 38, "#,##0\\ _" UTF8_EURO ";[RED]-#,##0\\ _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 39, "#,##0.00\\ _" UTF8_EURO ";-#,##0.00\\ _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 40, "#,##0.00\\ _" UTF8_EURO ";[RED]-#,##0.00\\ _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 63, "#,##0\\ " UTF8_EURO ";-#,##0\\ " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 64, "#,##0\\ " UTF8_EURO ";[RED]-#,##0\\ " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 65, "#,##0.00\\ " UTF8_EURO ";-#,##0.00\\ " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 66, "#,##0.00\\ " UTF8_EURO ";[RED]-#,##0.00\\ " UTF8_EURO ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_FRENCH_CANADIAN[] =
+{
+ EXC_NUMFMT_STRING( 22, "YYYY-MM-DD hh:mm" ),
+ EXC_NUMFMT_STRING( 37, "#,##0\\ _$_-;#,##0\\ _$-" ),
+ EXC_NUMFMT_STRING( 38, "#,##0\\ _$_-;[RED]#,##0\\ _$-" ),
+ EXC_NUMFMT_STRING( 39, "#,##0.00\\ _$_-;#,##0.00\\ _$-" ),
+ EXC_NUMFMT_STRING( 40, "#,##0.00\\ _$_-;[RED]#,##0.00\\ _$-" ),
+ EXC_NUMFMT_STRING( 63, "#,##0\\ $_-;#,##0\\ $-" ),
+ EXC_NUMFMT_STRING( 64, "#,##0\\ $_-;[RED]#,##0\\ $-" ),
+ EXC_NUMFMT_STRING( 65, "#,##0.00\\ $_-;#,##0.00\\ $-" ),
+ EXC_NUMFMT_STRING( 66, "#,##0.00\\ $_-;[RED]#,##0.00\\ $-" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_FRENCH_SWISS[] =
+{
+ EXC_NUMFMT_STRING( 15, "DD.MMM.YY" ),
+ EXC_NUMFMT_STRING( 16, "DD.MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM.YY" ),
+ EXC_NUMFMT_STRING( 22, "DD.MM.YYYY hh:mm" ),
+ EXC_NUMFMT_STRING( 63, "\"SFr. \"#,##0;\"SFr. \"-#,##0" ),
+ EXC_NUMFMT_STRING( 64, "\"SFr. \"#,##0;[RED]\"SFr. \"-#,##0" ),
+ EXC_NUMFMT_STRING( 65, "\"SFr. \"#,##0.00;\"SFr. \"-#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, "\"SFr. \"#,##0.00;[RED]\"SFr. \"-#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_FRENCH_BELGIAN[] =
+{
+ EXC_NUMFMT_STRING( 14, "D/MM/YYYY" ),
+ EXC_NUMFMT_STRING( 15, "D-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "D-MMM" ),
+ EXC_NUMFMT_STRING( 20, "h:mm" ),
+ EXC_NUMFMT_STRING( 21, "h:mm:ss" ),
+ EXC_NUMFMT_STRING( 22, "D/MM/YYYY h:mm" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+// GERMAN ---------------------------------------------------------------------
+
+/** Base table for German locales. */
+static const XclBuiltInFormat spBuiltInFormats_GERMAN[] =
+{
+ EXC_NUMFMT_STRING( 15, "DD. MMM YY" ),
+ EXC_NUMFMT_STRING( 16, "DD. MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM YY" ),
+ EXC_NUMFMT_STRING( 18, "h:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "h:mm:ss AM/PM" ),
+ EXC_NUMFMT_STRING( 22, "DD.MM.YYYY hh:mm" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_GERMAN_GERMANY[] =
+{
+ EXC_NUMFMT_STRING( 37, "#,##0 _" UTF8_EURO ";-#,##0 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 38, "#,##0 _" UTF8_EURO ";[RED]-#,##0 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 39, "#,##0.00 _" UTF8_EURO ";-#,##0.00 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 40, "#,##0.00 _" UTF8_EURO ";[RED]-#,##0.00 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 63, "#,##0 " UTF8_EURO ";-#,##0 " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 64, "#,##0 " UTF8_EURO ";[RED]-#,##0 " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 65, "#,##0.00 " UTF8_EURO ";-#,##0.00 " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 66, "#,##0.00 " UTF8_EURO ";[RED]-#,##0.00 " UTF8_EURO ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_GERMAN_AUSTRIAN[] =
+{
+ EXC_NUMFMT_STRING( 15, "DD.MMM.YY" ),
+ EXC_NUMFMT_STRING( 16, "DD.MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM.YY" ),
+ EXC_NUMFMT_STRING( 63, UTF8_EURO " #,##0;-" UTF8_EURO " #,##0" ),
+ EXC_NUMFMT_STRING( 64, UTF8_EURO " #,##0;[RED]-" UTF8_EURO " #,##0" ),
+ EXC_NUMFMT_STRING( 65, UTF8_EURO " #,##0.00;-" UTF8_EURO " #,##0.00" ),
+ EXC_NUMFMT_STRING( 66, UTF8_EURO " #,##0.00;[RED]-" UTF8_EURO " #,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_GERMAN_SWISS[] =
+{
+ EXC_NUMFMT_STRING( 63, "\"SFr. \"#,##0;\"SFr. \"-#,##0" ),
+ EXC_NUMFMT_STRING( 64, "\"SFr. \"#,##0;[RED]\"SFr. \"-#,##0" ),
+ EXC_NUMFMT_STRING( 65, "\"SFr. \"#,##0.00;\"SFr. \"-#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, "\"SFr. \"#,##0.00;[RED]\"SFr. \"-#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_GERMAN_LUXEMBOURG[] =
+{
+ EXC_NUMFMT_STRING( 15, "DD.MMM.YY" ),
+ EXC_NUMFMT_STRING( 16, "DD.MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM.YY" ),
+ EXC_NUMFMT_STRING( 37, "#,##0 _" UTF8_EURO ";-#,##0 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 38, "#,##0 _" UTF8_EURO ";[RED]-#,##0 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 39, "#,##0.00 _" UTF8_EURO ";-#,##0.00 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 40, "#,##0.00 _" UTF8_EURO ";[RED]-#,##0.00 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 63, "#,##0 " UTF8_EURO ";-#,##0 " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 64, "#,##0 " UTF8_EURO ";[RED]-#,##0 " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 65, "#,##0.00 " UTF8_EURO ";-#,##0.00 " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 66, "#,##0.00 " UTF8_EURO ";[RED]-#,##0.00 " UTF8_EURO ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_GERMAN_LIECHTENSTEIN[] =
+{
+ EXC_NUMFMT_STRING( 63, "\"CHF \"#,##0;\"CHF \"-#,##0" ),
+ EXC_NUMFMT_STRING( 64, "\"CHF \"#,##0;[RED]\"CHF \"-#,##0" ),
+ EXC_NUMFMT_STRING( 65, "\"CHF \"#,##0.00;\"CHF \"-#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, "\"CHF \"#,##0.00;[RED]\"CHF \"-#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+// ITALIAN --------------------------------------------------------------------
+
+static const XclBuiltInFormat spBuiltInFormats_ITALIAN_ITALY[] =
+{
+ EXC_NUMFMT_STRING( 15, "DD-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "DD-MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM-YY" ),
+ EXC_NUMFMT_STRING( 18, "h:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "h:mm:ss AM/PM" ),
+ EXC_NUMFMT_STRING( 20, "h:mm" ),
+ EXC_NUMFMT_STRING( 21, "h:mm:ss" ),
+ EXC_NUMFMT_STRING( 22, "DD/MM/YYYY h:mm" ),
+ EXC_NUMFMT_STRING( 63, UTF8_EURO " #,##0;-" UTF8_EURO " #,##0" ),
+ EXC_NUMFMT_STRING( 64, UTF8_EURO " #,##0;[RED]-" UTF8_EURO " #,##0" ),
+ EXC_NUMFMT_STRING( 65, UTF8_EURO " #,##0.00;-" UTF8_EURO " #,##0.00" ),
+ EXC_NUMFMT_STRING( 66, UTF8_EURO " #,##0.00;[RED]-" UTF8_EURO " #,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_ITALIAN_SWISS[] =
+{
+ EXC_NUMFMT_STRING( 15, "DD.MMM.YY" ),
+ EXC_NUMFMT_STRING( 16, "DD.MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM.YY" ),
+ EXC_NUMFMT_STRING( 18, "h:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "h:mm:ss AM/PM" ),
+ EXC_NUMFMT_STRING( 22, "DD.MM.YYYY hh:mm" ),
+ EXC_NUMFMT_STRING( 63, "\"SFr. \"#,##0;\"SFr. \"-#,##0" ),
+ EXC_NUMFMT_STRING( 64, "\"SFr. \"#,##0;[RED]\"SFr. \"-#,##0" ),
+ EXC_NUMFMT_STRING( 65, "\"SFr. \"#,##0.00;\"SFr. \"-#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, "\"SFr. \"#,##0.00;[RED]\"SFr. \"-#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+// SWEDISH --------------------------------------------------------------------
+
+static const XclBuiltInFormat spBuiltInFormats_SWEDISH_SWEDEN[] =
+{
+ EXC_NUMFMT_STRING( 15, "DD-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "DD-MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM-YY" ),
+ EXC_NUMFMT_STRING( 18, "h:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "h:mm:ss AM/PM" ),
+ EXC_NUMFMT_STRING( 22, "YYYY-MM-DD hh:mm" ),
+ EXC_NUMFMT_STRING( 37, "#,##0 _k_r;-#,##0 _k_r" ),
+ EXC_NUMFMT_STRING( 38, "#,##0 _k_r;[RED]-#,##0 _k_r" ),
+ EXC_NUMFMT_STRING( 39, "#,##0.00 _k_r;-#,##0.00 _k_r" ),
+ EXC_NUMFMT_STRING( 40, "#,##0.00 _k_r;[RED]-#,##0.00 _k_r" ),
+ EXC_NUMFMT_STRING( 63, "#,##0 \"kr\";-#,##0 \"kr\"" ),
+ EXC_NUMFMT_STRING( 64, "#,##0 \"kr\";[RED]-#,##0 \"kr\"" ),
+ EXC_NUMFMT_STRING( 65, "#,##0.00 \"kr\";-#,##0.00 \"kr\"" ),
+ EXC_NUMFMT_STRING( 66, "#,##0.00 \"kr\";[RED]-#,##0.00 \"kr\"" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_SWEDISH_FINLAND[] =
+{
+ EXC_NUMFMT_STRING( 9, "0 %" ),
+ EXC_NUMFMT_STRING( 10, "0.00 %" ),
+ EXC_NUMFMT_STRING( 15, "DD.MMM.YY" ),
+ EXC_NUMFMT_STRING( 16, "DD.MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM.YY" ),
+ EXC_NUMFMT_STRING( 18, "h:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "h:mm:ss AM/PM" ),
+ EXC_NUMFMT_STRING( 22, "D.M.YYYY hh:mm" ),
+ EXC_NUMFMT_STRING( 37, "#,##0 _" UTF8_EURO ";-#,##0 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 38, "#,##0 _" UTF8_EURO ";[RED]-#,##0 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 39, "#,##0.00 _" UTF8_EURO ";-#,##0.00 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 40, "#,##0.00 _" UTF8_EURO ";[RED]-#,##0.00 _" UTF8_EURO ),
+ EXC_NUMFMT_STRING( 63, "#,##0 " UTF8_EURO ";-#,##0 " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 64, "#,##0 " UTF8_EURO ";[RED]-#,##0 " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 65, "#,##0.00 " UTF8_EURO ";-#,##0.00 " UTF8_EURO ),
+ EXC_NUMFMT_STRING( 66, "#,##0.00 " UTF8_EURO ";[RED]-#,##0.00 " UTF8_EURO ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+// ASIAN ----------------------------------------------------------------------
+
+/** Base table for Asian locales. */
+static const XclBuiltInFormat spBuiltInFormats_ASIAN[] =
+{
+ EXC_NUMFMT_STRING( 18, "h:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "h:mm:ss AM/PM" ),
+ EXC_NUMFMT_STRING( 20, "h:mm" ),
+ EXC_NUMFMT_STRING( 21, "h:mm:ss" ),
+ EXC_NUMFMT_STRING( 23, "$#,##0_);($#,##0)" ),
+ EXC_NUMFMT_STRING( 24, "$#,##0_);[RED]($#,##0)" ),
+ EXC_NUMFMT_STRING( 25, "$#,##0.00_);($#,##0.00)" ),
+ EXC_NUMFMT_STRING( 26, "$#,##0.00_);[RED]($#,##0.00)" ),
+ EXC_NUMFMT_REUSE( 29, 28 ),
+ EXC_NUMFMT_REUSE( 36, 27 ),
+ EXC_NUMFMT_REUSE( 50, 27 ),
+ EXC_NUMFMT_REUSE( 51, 28 ),
+ EXC_NUMFMT_REUSE( 52, 34 ),
+ EXC_NUMFMT_REUSE( 53, 35 ),
+ EXC_NUMFMT_REUSE( 54, 28 ),
+ EXC_NUMFMT_REUSE( 55, 34 ),
+ EXC_NUMFMT_REUSE( 56, 35 ),
+ EXC_NUMFMT_REUSE( 57, 27 ),
+ EXC_NUMFMT_REUSE( 58, 28 ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_JAPANESE[] =
+{
+ EXC_NUMFMT_STRING( 14, "YYYY/M/D" ),
+ EXC_NUMFMT_STRING( 15, "D-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "D-MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM-YY" ),
+ EXC_NUMFMT_STRING( 22, "YYYY/M/D h:mm" ),
+ EXC_NUMFMT_STRING( 27, "[$-0411]GE.M.D" ),
+ EXC_NUMFMT_STRING( 28, "[$-0411]GGGE" UTF8_CJ_YEAR "M" UTF8_CJ_MON "D" UTF8_CJ_DAY ),
+ EXC_NUMFMT_STRING( 30, "[$-0411]M/D/YY" ),
+ EXC_NUMFMT_STRING( 31, "[$-0411]YYYY" UTF8_CJ_YEAR "M" UTF8_CJ_MON "D" UTF8_CJ_DAY ),
+ EXC_NUMFMT_STRING( 32, "[$-0411]h" UTF8_CJ_HOUR "mm" UTF8_CJ_MIN ),
+ EXC_NUMFMT_STRING( 33, "[$-0411]h" UTF8_CJ_HOUR "mm" UTF8_CJ_MIN "ss" UTF8_CJ_SEC ),
+ EXC_NUMFMT_STRING( 34, "[$-0411]YYYY" UTF8_CJ_YEAR "M" UTF8_CJ_MON ),
+ EXC_NUMFMT_STRING( 35, "[$-0411]M" UTF8_CJ_MON "D" UTF8_CJ_DAY ),
+ EXC_NUMFMT_STRING( 63, UTF8_YEN_JP "#,##0;-" UTF8_YEN_JP "#,##0" ),
+ EXC_NUMFMT_STRING( 64, UTF8_YEN_JP "#,##0;[RED]-" UTF8_YEN_JP "#,##0" ),
+ EXC_NUMFMT_STRING( 65, UTF8_YEN_JP "#,##0.00;-" UTF8_YEN_JP "#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, UTF8_YEN_JP "#,##0.00;[RED]-" UTF8_YEN_JP "#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_KOREAN[] =
+{
+ EXC_NUMFMT_STRING( 14, "YYYY-MM-DD" ),
+ EXC_NUMFMT_STRING( 15, "DD-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "DD-MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM-YY" ),
+ EXC_NUMFMT_STRING( 22, "YYYY-MM-DD h:mm" ),
+ EXC_NUMFMT_STRING( 27, "[$-0412]YYYY" UTF8_CJ_YEAR " MM" UTF8_CJ_MON " DD" UTF8_CJ_DAY ),
+ EXC_NUMFMT_STRING( 28, "[$-0412]MM-DD" ),
+ EXC_NUMFMT_STRING( 30, "[$-0412]MM-DD-YY" ),
+ EXC_NUMFMT_STRING( 31, "[$-0412]YYYY" UTF8_KO_YEAR " MM" UTF8_KO_MON " DD" UTF8_KO_DAY ),
+ EXC_NUMFMT_STRING( 32, "[$-0412]h" UTF8_KO_HOUR " mm" UTF8_KO_MIN ),
+ EXC_NUMFMT_STRING( 33, "[$-0412]h" UTF8_KO_HOUR " mm" UTF8_KO_MIN " ss" UTF8_KO_SEC ),
+ EXC_NUMFMT_STRING( 34, "[$-0412]YYYY\"/\"MM\"/\"DD" ),
+ EXC_NUMFMT_STRING( 35, "[$-0412]YYYY-MM-DD" ),
+ EXC_NUMFMT_STRING( 63, UTF8_WON "#,##0;-" UTF8_WON "#,##0" ),
+ EXC_NUMFMT_STRING( 64, UTF8_WON "#,##0;[RED]-" UTF8_WON "#,##0" ),
+ EXC_NUMFMT_STRING( 65, UTF8_WON "#,##0.00;-" UTF8_WON "#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, UTF8_WON "#,##0.00;[RED]-" UTF8_WON "#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_CHINESE_SIMPLIFIED[] =
+{
+ EXC_NUMFMT_STRING( 14, "YYYY-M-D" ),
+ EXC_NUMFMT_STRING( 15, "D-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "D-MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM-YY" ),
+ EXC_NUMFMT_STRING( 22, "YYYY-M-D h:mm" ),
+ EXC_NUMFMT_STRING( 27, "[$-0804]YYYY" UTF8_CJ_YEAR "M" UTF8_CJ_MON ),
+ EXC_NUMFMT_STRING( 28, "[$-0804]M" UTF8_CJ_MON "D" UTF8_CJ_DAY ),
+ EXC_NUMFMT_STRING( 30, "[$-0804]M-D-YY" ),
+ EXC_NUMFMT_STRING( 31, "[$-0804]YYYY" UTF8_CJ_YEAR "M" UTF8_CJ_MON "D" UTF8_CJ_DAY ),
+ EXC_NUMFMT_STRING( 32, "[$-0804]h" UTF8_CS_HOUR "mm" UTF8_CJ_MIN ),
+ EXC_NUMFMT_STRING( 33, "[$-0804]h" UTF8_CS_HOUR "mm" UTF8_CJ_MIN "ss" UTF8_CJ_SEC ),
+ EXC_NUMFMT_STRING( 34, "[$-0804]AM/PMh" UTF8_CS_HOUR "mm" UTF8_CJ_MIN ),
+ EXC_NUMFMT_STRING( 35, "[$-0804]AM/PMh" UTF8_CS_HOUR "mm" UTF8_CJ_MIN "ss" UTF8_CJ_SEC ),
+ EXC_NUMFMT_REUSE( 52, 27 ),
+ EXC_NUMFMT_REUSE( 53, 28 ),
+ EXC_NUMFMT_STRING( 63, UTF8_YEN_CS "#,##0;-" UTF8_YEN_CS "#,##0" ),
+ EXC_NUMFMT_STRING( 64, UTF8_YEN_CS "#,##0;[RED]-" UTF8_YEN_CS "#,##0" ),
+ EXC_NUMFMT_STRING( 65, UTF8_YEN_CS "#,##0.00;-" UTF8_YEN_CS "#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, UTF8_YEN_CS "#,##0.00;[RED]-" UTF8_YEN_CS "#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_CHINESE_TRADITIONAL[] =
+{
+ EXC_NUMFMT_STRING( 15, "D-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "D-MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM-YY" ),
+ EXC_NUMFMT_STRING( 18, "hh:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "hh:mm:ss AM/PM" ),
+ EXC_NUMFMT_OFFSET( 20, NF_TIME_HHMM ),
+ EXC_NUMFMT_OFFSET( 21, NF_TIME_HHMMSS ),
+ EXC_NUMFMT_STRING( 22, "YYYY/M/D hh:mm" ),
+ EXC_NUMFMT_STRING( 23, "US$#,##0_);(US$#,##0)" ),
+ EXC_NUMFMT_STRING( 24, "US$#,##0_);[RED](US$#,##0)" ),
+ EXC_NUMFMT_STRING( 25, "US$#,##0.00_);(US$#,##0.00)" ),
+ EXC_NUMFMT_STRING( 26, "US$#,##0.00_);[RED](US$#,##0.00)" ),
+ EXC_NUMFMT_STRING( 27, "[$-0404]E/M/D" ),
+ EXC_NUMFMT_STRING( 28, "[$-0404]E" UTF8_CJ_YEAR "M" UTF8_CJ_MON "D" UTF8_CJ_DAY ),
+ EXC_NUMFMT_STRING( 30, "[$-0404]M/D/YY" ),
+ EXC_NUMFMT_STRING( 31, "[$-0404]YYYY" UTF8_CJ_YEAR "M" UTF8_CJ_MON "D" UTF8_CJ_DAY ),
+ EXC_NUMFMT_STRING( 32, "[$-0404]hh" UTF8_CJ_HOUR "mm" UTF8_CJ_MIN ),
+ EXC_NUMFMT_STRING( 33, "[$-0404]hh" UTF8_CJ_HOUR "mm" UTF8_CJ_MIN "ss" UTF8_CJ_SEC ),
+ EXC_NUMFMT_STRING( 34, "[$-0404]AM/PMhh" UTF8_CJ_HOUR "mm" UTF8_CJ_MIN ),
+ EXC_NUMFMT_STRING( 35, "[$-0404]AM/PMhh" UTF8_CJ_HOUR "mm" UTF8_CJ_MIN "ss" UTF8_CJ_SEC ),
+ EXC_NUMFMT_STRING( 63, "$#,##0;-$#,##0" ),
+ EXC_NUMFMT_STRING( 64, "$#,##0;[RED]-$#,##0" ),
+ EXC_NUMFMT_STRING( 65, "$#,##0.00;-$#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, "$#,##0.00;[RED]-$#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+// OTHER ----------------------------------------------------------------------
+
+static const XclBuiltInFormat spBuiltInFormats_HEBREW[] =
+{
+ EXC_NUMFMT_STRING( 15, "DD-MMMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "DD-MMMM" ),
+ EXC_NUMFMT_STRING( 17, "MMMM-YY" ),
+ EXC_NUMFMT_STRING( 18, "h:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "h:mm:ss AM/PM" ),
+ EXC_NUMFMT_STRING( 63, UTF8_SHEQEL " #,##0;" UTF8_SHEQEL " -#,##0" ),
+ EXC_NUMFMT_STRING( 64, UTF8_SHEQEL " #,##0;[RED]" UTF8_SHEQEL " -#,##0" ),
+ EXC_NUMFMT_STRING( 65, UTF8_SHEQEL " #,##0.00;" UTF8_SHEQEL " -#,##0.00" ),
+ EXC_NUMFMT_STRING( 66, UTF8_SHEQEL " #,##0.00;[RED]" UTF8_SHEQEL " -#,##0.00" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+static const XclBuiltInFormat spBuiltInFormats_THAI[] =
+{
+ EXC_NUMFMT_STRING( 14, "D/M/YYYY" ),
+ EXC_NUMFMT_STRING( 15, "D-MMM-YY" ),
+ EXC_NUMFMT_STRING( 16, "D-MMM" ),
+ EXC_NUMFMT_STRING( 17, "MMM-YY" ),
+ EXC_NUMFMT_STRING( 18, "h:mm AM/PM" ),
+ EXC_NUMFMT_STRING( 19, "h:mm:ss AM/PM" ),
+ EXC_NUMFMT_STRING( 22, "D/M/YYYY h:mm" ),
+ EXC_NUMFMT_STRING( 59, "t0" ),
+ EXC_NUMFMT_STRING( 60, "t0.00" ),
+ EXC_NUMFMT_STRING( 61, "t#,##0" ),
+ EXC_NUMFMT_STRING( 62, "t#,##0.00" ),
+ EXC_NUMFMT_STRING( 63, "t" UTF8_BAHT "#,##0_);t(" UTF8_BAHT "#,##0)" ),
+ EXC_NUMFMT_STRING( 64, "t" UTF8_BAHT "#,##0_);[RED]t(" UTF8_BAHT "#,##0)" ),
+ EXC_NUMFMT_STRING( 65, "t" UTF8_BAHT "#,##0.00_);t(" UTF8_BAHT "#,##0.00)" ),
+ EXC_NUMFMT_STRING( 66, "t" UTF8_BAHT "#,##0.00_);[RED]t(" UTF8_BAHT "#,##0.00)" ),
+ EXC_NUMFMT_STRING( 67, "t0%" ),
+ EXC_NUMFMT_STRING( 68, "t0.00%" ),
+ EXC_NUMFMT_STRING( 69, "t# ?/?" ),
+ EXC_NUMFMT_STRING( 70, "t# ?\?/?\?" ),
+ EXC_NUMFMT_STRING( 71, "tD/M/EE" ),
+ EXC_NUMFMT_STRING( 72, "tD-MMM-E" ),
+ EXC_NUMFMT_STRING( 73, "tD-MMM" ),
+ EXC_NUMFMT_STRING( 74, "tMMM-E" ),
+ EXC_NUMFMT_STRING( 75, "th:mm" ),
+ EXC_NUMFMT_STRING( 76, "th:mm:ss" ),
+ EXC_NUMFMT_STRING( 77, "tD/M/EE h:mm" ),
+ EXC_NUMFMT_STRING( 78, "tmm:ss" ),
+ EXC_NUMFMT_STRING( 79, "t[h]:mm:ss" ),
+ EXC_NUMFMT_STRING( 80, "tmm:ss.0" ),
+ EXC_NUMFMT_STRING( 81, "D/M/E" ),
+ EXC_NUMFMT_ENDTABLE()
+};
+
+// ----------------------------------------------------------------------------
+
+#undef EXC_NUMFMT_ENDTABLE
+#undef EXC_NUMFMT_REUSE
+#undef EXC_NUMFMT_OFFSET
+#undef EXC_NUMFMT_STRING
+
+// ----------------------------------------------------------------------------
+
+/** Specifies a number format table for a specific langauge. */
+struct XclBuiltInFormatTable
+{
+ LanguageType meLanguage; /// The language of this table.
+ LanguageType meParentLang; /// The language of the parent table.
+ const XclBuiltInFormat* mpFormats; /// The number format table.
+};
+
+static const XclBuiltInFormatTable spBuiltInFormatTables[] =
+{ // language parent language format table
+ { LANGUAGE_DONTKNOW, LANGUAGE_NONE, spBuiltInFormats_DONTKNOW },
+
+ { LANGUAGE_ENGLISH, LANGUAGE_DONTKNOW, spBuiltInFormats_ENGLISH },
+ { LANGUAGE_ENGLISH_UK, LANGUAGE_ENGLISH, spBuiltInFormats_ENGLISH_UK },
+ { LANGUAGE_ENGLISH_EIRE, LANGUAGE_ENGLISH, spBuiltInFormats_ENGLISH_EIRE },
+ { LANGUAGE_ENGLISH_US, LANGUAGE_ENGLISH, spBuiltInFormats_ENGLISH_US },
+ { LANGUAGE_ENGLISH_CAN, LANGUAGE_ENGLISH, spBuiltInFormats_ENGLISH_CAN },
+ { LANGUAGE_ENGLISH_AUS, LANGUAGE_ENGLISH, spBuiltInFormats_ENGLISH_AUS },
+ { LANGUAGE_ENGLISH_SAFRICA, LANGUAGE_ENGLISH, spBuiltInFormats_ENGLISH_SAFRICA },
+ { LANGUAGE_ENGLISH_NZ, LANGUAGE_ENGLISH_AUS, 0 },
+
+ { PRV_LANGUAGE_FRENCH_PRIM, LANGUAGE_DONTKNOW, spBuiltInFormats_FRENCH },
+ { LANGUAGE_FRENCH, PRV_LANGUAGE_FRENCH_PRIM, spBuiltInFormats_FRENCH_FRANCE },
+ { LANGUAGE_FRENCH_CANADIAN, PRV_LANGUAGE_FRENCH_PRIM, spBuiltInFormats_FRENCH_CANADIAN },
+ { LANGUAGE_FRENCH_SWISS, PRV_LANGUAGE_FRENCH_PRIM, spBuiltInFormats_FRENCH_SWISS },
+ { LANGUAGE_FRENCH_BELGIAN, LANGUAGE_FRENCH, spBuiltInFormats_FRENCH_BELGIAN },
+ { LANGUAGE_FRENCH_LUXEMBOURG, LANGUAGE_FRENCH, 0 },
+ { LANGUAGE_FRENCH_MONACO, LANGUAGE_FRENCH, 0 },
+
+ { PRV_LANGUAGE_GERMAN_PRIM, LANGUAGE_DONTKNOW, spBuiltInFormats_GERMAN },
+ { LANGUAGE_GERMAN, PRV_LANGUAGE_GERMAN_PRIM, spBuiltInFormats_GERMAN_GERMANY },
+ { LANGUAGE_GERMAN_AUSTRIAN, PRV_LANGUAGE_GERMAN_PRIM, spBuiltInFormats_GERMAN_AUSTRIAN },
+ { LANGUAGE_GERMAN_SWISS, PRV_LANGUAGE_GERMAN_PRIM, spBuiltInFormats_GERMAN_SWISS },
+ { LANGUAGE_GERMAN_LUXEMBOURG, PRV_LANGUAGE_GERMAN_PRIM, spBuiltInFormats_GERMAN_LUXEMBOURG },
+ { LANGUAGE_GERMAN_LIECHTENSTEIN, PRV_LANGUAGE_GERMAN_PRIM, spBuiltInFormats_GERMAN_LIECHTENSTEIN },
+
+ { LANGUAGE_ITALIAN, LANGUAGE_DONTKNOW, spBuiltInFormats_ITALIAN_ITALY },
+ { LANGUAGE_ITALIAN_SWISS, LANGUAGE_DONTKNOW, spBuiltInFormats_ITALIAN_SWISS },
+
+ { LANGUAGE_SWEDISH, LANGUAGE_DONTKNOW, spBuiltInFormats_SWEDISH_SWEDEN },
+ { LANGUAGE_SWEDISH_FINLAND, LANGUAGE_DONTKNOW, spBuiltInFormats_SWEDISH_FINLAND },
+
+ { PRV_LANGUAGE_ASIAN_PRIM, LANGUAGE_DONTKNOW, spBuiltInFormats_ASIAN },
+ { LANGUAGE_JAPANESE, PRV_LANGUAGE_ASIAN_PRIM, spBuiltInFormats_JAPANESE },
+ { LANGUAGE_KOREAN, PRV_LANGUAGE_ASIAN_PRIM, spBuiltInFormats_KOREAN },
+ { LANGUAGE_CHINESE_SIMPLIFIED, PRV_LANGUAGE_ASIAN_PRIM, spBuiltInFormats_CHINESE_SIMPLIFIED },
+ { LANGUAGE_CHINESE_TRADITIONAL, PRV_LANGUAGE_ASIAN_PRIM, spBuiltInFormats_CHINESE_TRADITIONAL },
+
+ { LANGUAGE_HEBREW, LANGUAGE_DONTKNOW, spBuiltInFormats_HEBREW },
+ { LANGUAGE_THAI, LANGUAGE_DONTKNOW, spBuiltInFormats_THAI }
+};
+
+// ----------------------------------------------------------------------------
+
+} // namespace
+
+// ============================================================================
+
+XclNumFmtBuffer::XclNumFmtBuffer( const XclRoot& rRoot ) :
+ meSysLang( rRoot.GetSysLanguage() ),
+ mnStdScNumFmt( rRoot.GetFormatter().GetStandardFormat( ScGlobal::eLnge ) )
+{
+ // *** insert default formats (BIFF5+ only)***
+
+ if( rRoot.GetBiff() >= EXC_BIFF5 )
+ InsertBuiltinFormats();
+}
+
+void XclNumFmtBuffer::InitializeImport()
+{
+ maFmtMap.clear();
+}
+
+void XclNumFmtBuffer::InsertFormat( sal_uInt16 nXclNumFmt, const String& rFormat )
+{
+ XclNumFmt& rNumFmt = maFmtMap[ nXclNumFmt ];
+ rNumFmt.maFormat = rFormat;
+ // #i62053# rFormat may be an empty string, meOffset must be initialized
+ rNumFmt.meOffset = NF_NUMBER_STANDARD;
+ rNumFmt.meLanguage = LANGUAGE_SYSTEM;
+}
+
+void XclNumFmtBuffer::InsertBuiltinFormats()
+{
+ // build a map containing tables for all languages
+ typedef ::std::map< LanguageType, const XclBuiltInFormatTable* > XclBuiltInMap;
+ XclBuiltInMap aBuiltInMap;
+ for( const XclBuiltInFormatTable* pTable = spBuiltInFormatTables;
+ pTable != STATIC_TABLE_END( spBuiltInFormatTables ); ++pTable )
+ aBuiltInMap[ pTable->meLanguage ] = pTable;
+
+ // build a list of table pointers for the current language, with all parent tables
+ typedef ::std::vector< const XclBuiltInFormatTable* > XclBuiltInVec;
+ XclBuiltInVec aBuiltInVec;
+ for( XclBuiltInMap::const_iterator aMIt = aBuiltInMap.find( meSysLang ), aMEnd = aBuiltInMap.end();
+ aMIt != aMEnd; aMIt = aBuiltInMap.find( aMIt->second->meParentLang ) )
+ aBuiltInVec.push_back( aMIt->second );
+ // language not supported
+ if( aBuiltInVec.empty() )
+ {
+ OSL_TRACE( "XclNumFmtBuffer::InsertBuiltinFormats - language 0x%04hX not supported (#i29949#)", meSysLang );
+ XclBuiltInMap::const_iterator aMIt = aBuiltInMap.find( LANGUAGE_DONTKNOW );
+ DBG_ASSERT( aMIt != aBuiltInMap.end(), "XclNumFmtBuffer::InsertBuiltinFormats - default map not found" );
+ if( aMIt != aBuiltInMap.end() )
+ aBuiltInVec.push_back( aMIt->second );
+ }
+
+ // insert the default formats in the format map, from root parent to system language
+ typedef ::std::map< sal_uInt16, sal_uInt16 > XclReuseMap;
+ XclReuseMap aReuseMap;
+ for( XclBuiltInVec::reverse_iterator aVIt = aBuiltInVec.rbegin(), aVEnd = aBuiltInVec.rend(); aVIt != aVEnd; ++aVIt )
+ {
+ // put LANGUAGE_SYSTEM for all entries in default table
+ LanguageType eLang = ((*aVIt)->meLanguage == LANGUAGE_DONTKNOW) ? LANGUAGE_SYSTEM : meSysLang;
+ for( const XclBuiltInFormat* pBuiltIn = (*aVIt)->mpFormats; pBuiltIn && (pBuiltIn->mnXclNumFmt != EXC_FORMAT_NOTFOUND); ++pBuiltIn )
+ {
+ XclNumFmt& rNumFmt = maFmtMap[ pBuiltIn->mnXclNumFmt ];
+
+ rNumFmt.meOffset = pBuiltIn->meOffset;
+ rNumFmt.meLanguage = eLang;
+
+ if( pBuiltIn->mpFormat )
+ rNumFmt.maFormat = String( pBuiltIn->mpFormat, RTL_TEXTENCODING_UTF8 );
+ else
+ rNumFmt.maFormat = EMPTY_STRING;
+
+ if( pBuiltIn->meOffset == PRV_NF_INDEX_REUSE )
+ aReuseMap[ pBuiltIn->mnXclNumFmt ] = pBuiltIn->mnXclReuseFmt;
+ else
+ aReuseMap.erase( pBuiltIn->mnXclNumFmt );
+ }
+ }
+
+ // copy reused number formats
+ for( XclReuseMap::const_iterator aRIt = aReuseMap.begin(), aREnd = aReuseMap.end(); aRIt != aREnd; ++aRIt )
+ maFmtMap[ aRIt->first ] = maFmtMap[ aRIt->second ];
+}
+
+// Cell formatting data (XF) ==================================================
+
+XclCellProt::XclCellProt() :
+ mbLocked( true ), // default in Excel and Calc
+ mbHidden( false )
+{
+}
+
+bool operator==( const XclCellProt& rLeft, const XclCellProt& rRight )
+{
+ return (rLeft.mbLocked == rRight.mbLocked) && (rLeft.mbHidden == rRight.mbHidden);
+}
+
+// ----------------------------------------------------------------------------
+
+XclCellAlign::XclCellAlign() :
+ mnHorAlign( EXC_XF_HOR_GENERAL ),
+ mnVerAlign( EXC_XF_VER_BOTTOM ),
+ mnOrient( EXC_ORIENT_NONE ),
+ mnTextDir( EXC_XF_TEXTDIR_CONTEXT ),
+ mnRotation( EXC_ROT_NONE ),
+ mnIndent( 0 ),
+ mbLineBreak( false ),
+ mbShrink( false )
+{
+}
+
+SvxCellHorJustify XclCellAlign::GetScHorAlign() const
+{
+ SvxCellHorJustify eHorJust = SVX_HOR_JUSTIFY_STANDARD;
+ switch( mnHorAlign )
+ {
+ case EXC_XF_HOR_GENERAL: eHorJust = SVX_HOR_JUSTIFY_STANDARD; break;
+ case EXC_XF_HOR_LEFT: eHorJust = SVX_HOR_JUSTIFY_LEFT; break;
+ case EXC_XF_HOR_CENTER_AS:
+ case EXC_XF_HOR_CENTER: eHorJust = SVX_HOR_JUSTIFY_CENTER; break;
+ case EXC_XF_HOR_RIGHT: eHorJust = SVX_HOR_JUSTIFY_RIGHT; break;
+ case EXC_XF_HOR_FILL: eHorJust = SVX_HOR_JUSTIFY_REPEAT; break;
+ case EXC_XF_HOR_JUSTIFY:
+ case EXC_XF_HOR_DISTRIB: eHorJust = SVX_HOR_JUSTIFY_BLOCK; break;
+ default: DBG_ERRORFILE( "XclCellAlign::GetScHorAlign - unknown horizontal alignment" );
+ }
+ return eHorJust;
+}
+
+SvxCellJustifyMethod XclCellAlign::GetScHorJustifyMethod() const
+{
+ return (mnHorAlign == EXC_XF_HOR_DISTRIB) ? SVX_JUSTIFY_METHOD_DISTRIBUTE : SVX_JUSTIFY_METHOD_AUTO;
+}
+
+SvxCellVerJustify XclCellAlign::GetScVerAlign() const
+{
+ SvxCellVerJustify eVerJust = SVX_VER_JUSTIFY_STANDARD;
+ switch( mnVerAlign )
+ {
+ case EXC_XF_VER_TOP: eVerJust = SVX_VER_JUSTIFY_TOP; break;
+ case EXC_XF_VER_CENTER: eVerJust = SVX_VER_JUSTIFY_CENTER; break;
+ case EXC_XF_VER_BOTTOM: eVerJust = SVX_VER_JUSTIFY_STANDARD; break;
+ case EXC_XF_VER_JUSTIFY:
+ case EXC_XF_VER_DISTRIB: eVerJust = SVX_VER_JUSTIFY_BLOCK; break;
+ default: DBG_ERRORFILE( "XclCellAlign::GetScVerAlign - unknown vertical alignment" );
+ }
+ return eVerJust;
+}
+
+SvxCellJustifyMethod XclCellAlign::GetScVerJustifyMethod() const
+{
+ return (mnVerAlign == EXC_XF_VER_DISTRIB) ? SVX_JUSTIFY_METHOD_DISTRIBUTE : SVX_JUSTIFY_METHOD_AUTO;
+}
+
+SvxFrameDirection XclCellAlign::GetScFrameDir() const
+{
+ SvxFrameDirection eFrameDir = FRMDIR_ENVIRONMENT;
+ switch( mnTextDir )
+ {
+ case EXC_XF_TEXTDIR_CONTEXT: eFrameDir = FRMDIR_ENVIRONMENT; break;
+ case EXC_XF_TEXTDIR_LTR: eFrameDir = FRMDIR_HORI_LEFT_TOP; break;
+ case EXC_XF_TEXTDIR_RTL: eFrameDir = FRMDIR_HORI_RIGHT_TOP; break;
+ default: DBG_ERRORFILE( "XclCellAlign::GetScFrameDir - unknown CTL text direction" );
+ }
+ return eFrameDir;
+}
+
+void XclCellAlign::SetScHorAlign( SvxCellHorJustify eHorJust )
+{
+ switch( eHorJust )
+ {
+ case SVX_HOR_JUSTIFY_STANDARD: mnHorAlign = EXC_XF_HOR_GENERAL; break;
+ case SVX_HOR_JUSTIFY_LEFT: mnHorAlign = EXC_XF_HOR_LEFT; break;
+ case SVX_HOR_JUSTIFY_CENTER: mnHorAlign = EXC_XF_HOR_CENTER; break;
+ case SVX_HOR_JUSTIFY_RIGHT: mnHorAlign = EXC_XF_HOR_RIGHT; break;
+ case SVX_HOR_JUSTIFY_BLOCK: mnHorAlign = EXC_XF_HOR_JUSTIFY; break;
+ case SVX_HOR_JUSTIFY_REPEAT: mnHorAlign = EXC_XF_HOR_FILL; break;
+ default: mnHorAlign = EXC_XF_HOR_GENERAL;
+ OSL_FAIL( "XclCellAlign::SetScHorAlign - unknown horizontal alignment" );
+ }
+}
+
+void XclCellAlign::SetScVerAlign( SvxCellVerJustify eVerJust )
+{
+ switch( eVerJust )
+ {
+ case SVX_VER_JUSTIFY_STANDARD: mnVerAlign = EXC_XF_VER_BOTTOM; break;
+ case SVX_VER_JUSTIFY_TOP: mnVerAlign = EXC_XF_VER_TOP; break;
+ case SVX_VER_JUSTIFY_CENTER: mnVerAlign = EXC_XF_VER_CENTER; break;
+ case SVX_VER_JUSTIFY_BOTTOM: mnVerAlign = EXC_XF_VER_BOTTOM; break;
+ default: mnVerAlign = EXC_XF_VER_BOTTOM;
+ OSL_FAIL( "XclCellAlign::SetScVerAlign - unknown vertical alignment" );
+ }
+}
+
+void XclCellAlign::SetScFrameDir( SvxFrameDirection eFrameDir )
+{
+ switch( eFrameDir )
+ {
+ case FRMDIR_ENVIRONMENT: mnTextDir = EXC_XF_TEXTDIR_CONTEXT; break;
+ case FRMDIR_HORI_LEFT_TOP: mnTextDir = EXC_XF_TEXTDIR_LTR; break;
+ case FRMDIR_HORI_RIGHT_TOP: mnTextDir = EXC_XF_TEXTDIR_RTL; break;
+ default: mnTextDir = EXC_XF_TEXTDIR_CONTEXT;
+ DBG_ERRORFILE( "XclCellAlign::SetScFrameDir - unknown CTL text direction" );
+ }
+}
+
+bool operator==( const XclCellAlign& rLeft, const XclCellAlign& rRight )
+{
+ return
+ (rLeft.mnHorAlign == rRight.mnHorAlign) && (rLeft.mnVerAlign == rRight.mnVerAlign) &&
+ (rLeft.mnTextDir == rRight.mnTextDir) && (rLeft.mnOrient == rRight.mnOrient) &&
+ (rLeft.mnRotation == rRight.mnRotation) && (rLeft.mnIndent == rRight.mnIndent) &&
+ (rLeft.mbLineBreak == rRight.mbLineBreak) && (rLeft.mbShrink == rRight.mbShrink);
+}
+
+// ----------------------------------------------------------------------------
+
+XclCellBorder::XclCellBorder() :
+ mnLeftColor( 0 ),
+ mnRightColor( 0 ),
+ mnTopColor( 0 ),
+ mnBottomColor( 0 ),
+ mnDiagColor( 0 ),
+ mnLeftLine( EXC_LINE_NONE ),
+ mnRightLine( EXC_LINE_NONE ),
+ mnTopLine( EXC_LINE_NONE ),
+ mnBottomLine( EXC_LINE_NONE ),
+ mnDiagLine( EXC_LINE_NONE ),
+ mbDiagTLtoBR( false ),
+ mbDiagBLtoTR( false )
+{
+}
+
+bool operator==( const XclCellBorder& rLeft, const XclCellBorder& rRight )
+{
+ return
+ (rLeft.mnLeftColor == rRight.mnLeftColor) && (rLeft.mnRightColor == rRight.mnRightColor) &&
+ (rLeft.mnTopColor == rRight.mnTopColor) && (rLeft.mnBottomColor == rRight.mnBottomColor) &&
+ (rLeft.mnLeftLine == rRight.mnLeftLine) && (rLeft.mnRightLine == rRight.mnRightLine) &&
+ (rLeft.mnTopLine == rRight.mnTopLine) && (rLeft.mnBottomLine == rRight.mnBottomLine) &&
+ (rLeft.mnDiagColor == rRight.mnDiagColor) && (rLeft.mnDiagLine == rRight.mnDiagLine) &&
+ (rLeft.mbDiagTLtoBR == rRight.mbDiagTLtoBR) && (rLeft.mbDiagBLtoTR == rRight.mbDiagBLtoTR);
+}
+
+// ----------------------------------------------------------------------------
+
+XclCellArea::XclCellArea() :
+ mnForeColor( EXC_COLOR_WINDOWTEXT ),
+ mnBackColor( EXC_COLOR_WINDOWBACK ),
+ mnPattern( EXC_PATT_NONE )
+{
+}
+
+bool XclCellArea::IsTransparent() const
+{
+ return (mnPattern == EXC_PATT_NONE) && (mnBackColor == EXC_COLOR_WINDOWBACK);
+}
+
+bool operator==( const XclCellArea& rLeft, const XclCellArea& rRight )
+{
+ return
+ (rLeft.mnForeColor == rRight.mnForeColor) && (rLeft.mnBackColor == rRight.mnBackColor) &&
+ (rLeft.mnPattern == rRight.mnPattern);
+}
+
+// ----------------------------------------------------------------------------
+
+XclXFBase::XclXFBase( bool bCellXF ) :
+ mnParent( bCellXF ? EXC_XF_DEFAULTSTYLE : EXC_XF_STYLEPARENT ),
+ mbCellXF( bCellXF )
+{
+ SetAllUsedFlags( false );
+}
+
+XclXFBase::~XclXFBase()
+{
+}
+
+void XclXFBase::SetAllUsedFlags( bool bUsed )
+{
+ mbProtUsed = mbFontUsed = mbFmtUsed = mbAlignUsed = mbBorderUsed = mbAreaUsed = bUsed;
+}
+
+bool XclXFBase::HasUsedFlags() const
+{
+ return mbProtUsed || mbFontUsed || mbFmtUsed || mbAlignUsed || mbBorderUsed || mbAreaUsed;
+}
+
+bool XclXFBase::Equals( const XclXFBase& rCmp ) const
+{
+ return
+ (mbCellXF == rCmp.mbCellXF) && (mnParent == rCmp.mnParent) &&
+ (mbProtUsed == rCmp.mbProtUsed) && (mbFontUsed == rCmp.mbFontUsed) &&
+ (mbFmtUsed == rCmp.mbFmtUsed) && (mbAlignUsed == rCmp.mbAlignUsed) &&
+ (mbBorderUsed == rCmp.mbBorderUsed) && (mbAreaUsed == rCmp.mbAreaUsed);
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xltoolbar.cxx b/sc/source/filter/excel/xltoolbar.cxx
new file mode 100644
index 000000000000..749cb4808fb1
--- /dev/null
+++ b/sc/source/filter/excel/xltoolbar.cxx
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is
+ * Noel Power <noel.power@novell.com>
+ * Portions created by the Initial Developer are Copyright (C) 2010 the
+ * Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Noel Power <noel.power@novell.com>
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+#include "xltoolbar.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <stdarg.h>
+#include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
+#include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
+#include <com/sun/star/ui/XModuleUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/ui/XImageManager.hpp>
+#include <com/sun/star/ui/ItemType.hpp>
+#include <fstream>
+#include <comphelper/processfactory.hxx>
+#include <vcl/graph.hxx>
+#include <map>
+using namespace com::sun::star;
+
+typedef std::map< sal_Int16, rtl::OUString > IdToString;
+
+class MSOExcelCommandConvertor : public MSOCommandConvertor
+{
+ IdToString msoToOOcmd;
+ IdToString tcidToOOcmd;
+public:
+ MSOExcelCommandConvertor();
+ virtual rtl::OUString MSOCommandToOOCommand( sal_Int16 msoCmd );
+ virtual rtl::OUString MSOTCIDToOOCommand( sal_Int16 key );
+};
+
+MSOExcelCommandConvertor::MSOExcelCommandConvertor()
+{
+/*
+ // mso command id to ooo command string
+ // #FIXME and *HUNDREDS* of id's to added here
+ msoToOOcmd[ 0x20b ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".uno:CloseDoc") );
+ msoToOOcmd[ 0x50 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".uno:Open") );
+
+ // mso tcid to ooo command string
+ // #FIXME and *HUNDREDS* of id's to added here
+ tcidToOOcmd[ 0x9d9 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".uno:Print") );
+*/
+}
+
+rtl::OUString MSOExcelCommandConvertor::MSOCommandToOOCommand( sal_Int16 key )
+{
+ rtl::OUString sResult;
+ IdToString::iterator it = msoToOOcmd.find( key );
+ if ( it != msoToOOcmd.end() )
+ sResult = it->second;
+ return sResult;
+}
+
+rtl::OUString MSOExcelCommandConvertor::MSOTCIDToOOCommand( sal_Int16 key )
+{
+ rtl::OUString sResult;
+ IdToString::iterator it = tcidToOOcmd.find( key );
+ if ( it != tcidToOOcmd.end() )
+ sResult = it->second;
+ return sResult;
+}
+
+
+
+CTBS::CTBS() : bSignature(0), bVersion(0), reserved1(0), reserved2(0), reserved3(0), ctb(0), ctbViews(0), ictbView(0)
+{
+}
+
+CTB::CTB() : nViews( 0 ), ectbid(0)
+{
+}
+
+CTB::CTB(sal_uInt16 nNum ) : nViews( nNum ), ectbid(0)
+{
+}
+
+bool CTB::Read( SvStream *pS )
+{
+ OSL_TRACE("CTB::Read() stream pos 0x%x", pS->Tell() );
+ nOffSet = pS->Tell();
+ tb.Read( pS );
+ for ( sal_uInt16 index = 0; index < nViews; ++index )
+ {
+ TBVisualData aVisData;
+ aVisData.Read( pS );
+ rVisualData.push_back( aVisData );
+ }
+ *pS >> ectbid;
+
+ for ( sal_Int16 index = 0; index < tb.getcCL(); ++index )
+ {
+ TBC aTBC;
+ aTBC.Read( pS );
+ rTBC.push_back( aTBC );
+ }
+ return true;
+}
+
+void CTB::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf( fp, "[ 0x%x ] CTB -- dump\n", nOffSet );
+ indent_printf( fp, " nViews 0x%x\n", nViews);
+ tb.Print( fp );
+
+ std::vector<TBVisualData>::iterator visData_end = rVisualData.end();
+ sal_Int32 counter = 0;
+ for ( std::vector<TBVisualData>::iterator it = rVisualData.begin(); it != visData_end; ++it )
+ {
+
+ indent_printf( fp, " TBVisualData [%d]\n", counter++ );
+ Indent b;
+ it->Print( fp );
+ }
+ indent_printf( fp, " ectbid 0x%x\n", ectbid);
+ std::vector<TBC>::iterator it_end = rTBC.end();
+ counter = 0;
+ for ( std::vector<TBC>::iterator it = rTBC.begin(); it != it_end; ++it )
+ {
+ indent_printf( fp, " TBC [%d]\n", counter++);
+ Indent c;
+ it->Print( fp );
+ }
+}
+
+bool CTB::IsMenuToolbar()
+{
+ return tb.IsMenuToolbar();
+}
+
+bool CTB::ImportMenuTB( CTBWrapper& rWrapper, const css::uno::Reference< css::container::XIndexContainer >& xMenuDesc, CustomToolBarImportHelper& helper )
+{
+ sal_Int32 index = 0;
+ for ( std::vector< TBC >::iterator it = rTBC.begin(); it != rTBC.end(); ++it, ++index )
+ {
+ if ( !it->ImportToolBarControl( rWrapper, xMenuDesc, helper, IsMenuToolbar() ) )
+ return false;
+ }
+ return true;
+}
+
+bool CTB::ImportCustomToolBar( CTBWrapper& rWrapper, CustomToolBarImportHelper& helper )
+{
+
+ static rtl::OUString sToolbarPrefix( RTL_CONSTASCII_USTRINGPARAM( "private:resource/toolbar/custom_" ) );
+ bool bRes = false;
+ try
+ {
+ if ( !tb.IsEnabled() )
+ return true; // didn't fail, just ignoring
+
+ // Create default setting
+ uno::Reference< container::XIndexContainer > xIndexContainer( helper.getCfgManager()->createSettings(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xIndexContainer, uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xProps( xIndexContainer, uno::UNO_QUERY_THROW );
+ WString& name = tb.getName();
+ // set UI name for toolbar
+ xProps->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("UIName") ), uno::makeAny( name.getString() ) );
+
+ rtl::OUString sToolBarName = sToolbarPrefix.concat( name.getString() );
+ for ( std::vector< TBC >::iterator it = rTBC.begin(); it != rTBC.end(); ++it )
+ {
+ if ( !it->ImportToolBarControl( rWrapper, xIndexContainer, helper, IsMenuToolbar() ) )
+ return false;
+ }
+
+ OSL_TRACE("Name of toolbar :-/ %s", rtl::OUStringToOString( sToolBarName, RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ helper.getCfgManager()->insertSettings( sToolBarName, xIndexAccess );
+ helper.applyIcons();
+
+ uno::Reference< ui::XUIConfigurationPersistence > xPersistence( helper.getCfgManager()->getImageManager(), uno::UNO_QUERY_THROW );
+ xPersistence->store();
+
+ xPersistence.set( helper.getCfgManager(), uno::UNO_QUERY_THROW );
+ xPersistence->store();
+
+ bRes = true;
+ }
+ catch( uno::Exception& )
+ {
+ bRes = false;
+ }
+ return bRes;
+}
+bool CTBS::Read( SvStream *pS )
+{
+ OSL_TRACE("CTBS::Read() stream pos 0x%x", pS->Tell() );
+ nOffSet = pS->Tell();
+ *pS >> bSignature >> bVersion >> reserved1 >> reserved2 >> reserved3 >> ctb >> ctbViews >> ictbView;
+ return true;
+}
+
+void CTBS::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf( fp, "[ 0x%x ] CTBS -- dump\n", nOffSet );
+
+ indent_printf( fp, " bSignature 0x%x\n", bSignature);
+ indent_printf( fp, " bVersion 0x%x\n", bVersion);
+
+ indent_printf( fp, " reserved1 0x%x\n", reserved1 );
+ indent_printf( fp, " reserved2 0x%x\n", reserved2 );
+ indent_printf( fp, " reserved3 0x%x\n", reserved3 );
+
+ indent_printf( fp, " ctb 0x%x\n", ctb );
+ indent_printf( fp, " ctbViews 0x%x\n", ctbViews );
+ indent_printf( fp, " ictbView 0x%x\n", ictbView );
+}
+
+TBC::TBC()
+{
+}
+
+bool
+TBC::Read(SvStream *pS)
+{
+ OSL_TRACE("TBC::Read() stream pos 0x%x", pS->Tell() );
+ nOffSet = pS->Tell();
+ if ( !tbch.Read( pS ) )
+ return false;
+ sal_uInt16 tcid = tbch.getTcID();
+ sal_uInt8 tct = tbch.getTct();
+ if ( ( tcid != 0x0001 && tcid != 0x06CC && tcid != 0x03D8 && tcid != 0x03EC && tcid != 0x1051 ) && ( ( tct > 0 && tct < 0x0B ) || ( ( tct > 0x0B && tct < 0x10 ) || tct == 0x15 ) ) )
+ {
+ tbcCmd.reset( new TBCCmd );
+ if ( ! tbcCmd->Read( pS ) )
+ return false;
+ }
+ if ( tct != 0x16 )
+ {
+ tbcd.reset( new TBCData( tbch ) );
+ if ( !tbcd->Read( pS ) )
+ return false;
+ }
+ return true;
+}
+
+
+void
+TBC::Print(FILE* fp)
+{
+ Indent a;
+ indent_printf( fp, "[ 0x%x ] TBC -- dump\n", nOffSet );
+ tbch.Print( fp );
+ if ( tbcCmd.get() )
+ tbcCmd->Print( fp );
+ if ( tbcd.get() )
+ tbcd->Print( fp );
+}
+
+bool TBC::ImportToolBarControl( CTBWrapper& rWrapper, const css::uno::Reference< css::container::XIndexContainer >& toolbarcontainer, CustomToolBarImportHelper& helper, bool bIsMenuToolbar )
+{
+ // how to identify built-in-command ?
+// bool bBuiltin = false;
+ if ( tbcd.get() )
+ {
+ std::vector< css::beans::PropertyValue > props;
+ bool bBeginGroup = false;
+ if ( ! tbcd->ImportToolBarControl( helper, props, bBeginGroup, bIsMenuToolbar ) )
+ return false;
+ TBCMenuSpecific* pMenu = tbcd->getMenuSpecific();
+ if ( pMenu )
+ {
+ // search for CTB with the appropriate name ( it contains the
+ // menu items, although we cannot import ( or create ) a menu on
+ // a custom toolbar we can import the menu items in a separate
+ // toolbar ( better than nothing )
+ CTB* pCustTB = rWrapper.GetCustomizationData( pMenu->Name() );
+ if ( pCustTB )
+ {
+ uno::Reference< container::XIndexContainer > xMenuDesc;
+ uno::Reference< lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
+ xMenuDesc.set( xMSF->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.IndexedPropertyValues" ) ) ), uno::UNO_QUERY_THROW );
+ if ( !pCustTB->ImportMenuTB( rWrapper, xMenuDesc, helper ) )
+ return false;
+ if ( !bIsMenuToolbar )
+ {
+ if ( !helper.createMenu( pMenu->Name(), uno::Reference< container::XIndexAccess >( xMenuDesc, uno::UNO_QUERY ), true ) )
+ return false;
+ }
+ else
+ {
+ beans::PropertyValue aProp;
+ aProp.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ItemDescriptorContainer") );
+ aProp.Value <<= xMenuDesc;
+ props.push_back( aProp );
+ }
+ }
+ }
+
+ if ( bBeginGroup )
+ {
+ // insert spacer
+ uno::Sequence< beans::PropertyValue > sProps( 1 );
+ sProps[ 0 ].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Type") );
+ sProps[ 0 ].Value = uno::makeAny( ui::ItemType::SEPARATOR_LINE );
+ toolbarcontainer->insertByIndex( toolbarcontainer->getCount(), uno::makeAny( sProps ) );
+ }
+ uno::Sequence< beans::PropertyValue > sProps( props.size() );
+ beans::PropertyValue* pProp = sProps.getArray();
+
+ for ( std::vector< css::beans::PropertyValue >::iterator it = props.begin(); it != props.end(); ++it, ++pProp )
+ *pProp = *it;
+
+ toolbarcontainer->insertByIndex( toolbarcontainer->getCount(), uno::makeAny( sProps ) );
+ }
+ return true;
+}
+
+void
+TBCCmd::Print(FILE* fp)
+{
+ Indent a;
+ indent_printf( fp, " TBCCmd -- dump\n" );
+ indent_printf( fp, " cmdID 0x%x\n", cmdID );
+ indent_printf( fp, " A ( fHideDrawing ) %s\n", A ? "true" : "false" );
+ indent_printf( fp, " B ( reserved - ignored ) %s\n", A ? "true" : "false" );
+ indent_printf( fp, " cmdType 0x%x\n", cmdType );
+ indent_printf( fp, " C ( reserved - ignored ) %s\n", A ? "true" : "false" );
+ indent_printf( fp, " reserved3 0x%x\n", reserved3 );
+}
+
+bool TBCCmd::Read( SvStream *pS )
+{
+ OSL_TRACE("TBCCmd::Read() stream pos 0x%x", pS->Tell() );
+ nOffSet = pS->Tell();
+ *pS >> cmdID;
+ sal_uInt16 temp;
+ *pS >> temp;
+ OSL_TRACE("TBCmd temp = 0x%x", temp );
+ A = (temp & 0x8000 ) == 0x8000;
+ B = (temp & 0x4000) == 0x4000;
+ cmdType = ( temp & 0x3E00 ) >> 9;
+ C = ( temp & 0x100 ) == 0x100;
+ reserved3 = ( temp & 0xFF );
+ return true;
+}
+
+CTBWrapper::CTBWrapper()
+{
+}
+
+CTBWrapper::~CTBWrapper()
+{
+}
+
+bool
+CTBWrapper::Read( SvStream *pS)
+{
+ OSL_TRACE("CTBWrapper::Read() stream pos 0x%x", pS->Tell() );
+ nOffSet = pS->Tell();
+ if ( !ctbSet.Read( pS ) )
+ return false;
+ for ( sal_uInt16 index = 0; index < ctbSet.ctb; ++index )
+ {
+ CTB aCTB( ctbSet.ctbViews );
+ if ( !aCTB.Read( pS ) )
+ return false;
+ rCTB.push_back( aCTB );
+ }
+ return true;
+}
+
+void
+CTBWrapper::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf( fp, "[ 0x%x ] CTBWrapper -- dump\n", nOffSet );
+ ctbSet.Print( fp );
+ std::vector<CTB>::iterator it_end = rCTB.end();
+ for ( std::vector<CTB>::iterator it = rCTB.begin(); it != it_end; ++it )
+ {
+ Indent b;
+ it->Print( fp );
+ }
+}
+
+CTB* CTBWrapper::GetCustomizationData( const rtl::OUString& sTBName )
+{
+ CTB* pCTB = NULL;
+ for ( std::vector< CTB >::iterator it = rCTB.begin(); it != rCTB.end(); ++it )
+ {
+ if ( it->GetName().equals( sTBName ) )
+ {
+ pCTB = &(*it);
+ break;
+ }
+ }
+ return pCTB;
+}
+
+bool CTBWrapper::ImportCustomToolBar( SfxObjectShell& rDocSh )
+{
+ std::vector<CTB>::iterator it_end = rCTB.end();
+ for ( std::vector<CTB>::iterator it = rCTB.begin(); it != it_end; ++it )
+ {
+ // for each customtoolbar
+ uno::Reference< lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
+ uno::Reference< ui::XModuleUIConfigurationManagerSupplier > xAppCfgSupp( xMSF->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.ModuleUIConfigurationManagerSupplier" ) ) ), uno::UNO_QUERY_THROW );
+ CustomToolBarImportHelper helper( rDocSh, xAppCfgSupp->getUIConfigurationManager( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sheet.SpreadsheetDocument" ) ) ) );
+ helper.setMSOCommandMap( new MSOExcelCommandConvertor() );
+ // Ignore menu toolbars, excel doesn't ( afaics ) store
+ // menu customizations ( but you can have menus in a customtoolbar
+ // such menus will be dealt with when they are encountered
+ // as part of importing the appropriate MenuSpecific toolbar control )
+
+
+ if ( !(*it).IsMenuToolbar() )
+ {
+ if ( !(*it).ImportCustomToolBar( *this, helper ) )
+ return false;
+ }
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xltoolbar.hxx b/sc/source/filter/excel/xltoolbar.hxx
new file mode 100644
index 000000000000..22e2bcd71f41
--- /dev/null
+++ b/sc/source/filter/excel/xltoolbar.hxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is
+ * Noel Power <noel.power@novell.com>
+ * Portions created by the Initial Developer are Copyright (C) 2010 the
+ * Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Noel Power <noel.power@novell.com>
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+#ifndef _XLTOOLBAR_HXX
+#define _XLTOOLBAR_HXX
+
+#include <filter/msfilter/mstoolbar.hxx>
+
+namespace css = ::com::sun::star;
+
+class CTBWrapper;
+// hmm I don't normally use these packed structures
+// but.. hey always good to do something different
+class TBCCmd : public TBBase
+{
+public:
+ TBCCmd() : cmdID(0), A(0), B(0), cmdType(0), C(0), reserved3(0) {}
+ sal_uInt16 cmdID;
+ sal_uInt16 A:1;
+ sal_uInt16 B:1;
+ sal_uInt16 cmdType:5;
+ sal_uInt16 C:1;
+ sal_uInt16 reserved3:8;
+ bool Read( SvStream* pS );
+ void Print(FILE* fp);
+};
+
+class TBC : public TBBase
+{
+ TBCHeader tbch;
+ boost::shared_ptr<TBCCmd> tbcCmd; // optional
+ boost::shared_ptr<TBCData> tbcd;
+public:
+ TBC();
+ ~TBC(){}
+ void Print( FILE* );
+ bool Read(SvStream *pS);
+ bool ImportToolBarControl( CTBWrapper&, const com::sun::star::uno::Reference< com::sun::star::container::XIndexContainer >& toolbarcontainer, CustomToolBarImportHelper& helper, bool bIsMenuBar );
+};
+
+class CTB : public TBBase
+{
+ sal_uInt16 nViews;
+ TB tb;
+ std::vector<TBVisualData> rVisualData;
+ sal_uInt32 ectbid;
+ std::vector< TBC > rTBC;
+ bool ImportCustomToolBar_Impl( CTBWrapper&, CustomToolBarImportHelper& );
+public:
+ CTB();
+ CTB(sal_uInt16);
+ ~CTB(){}
+ void Print( FILE* );
+ bool Read(SvStream *pS);
+ bool IsMenuToolbar();
+ bool ImportCustomToolBar( CTBWrapper&, CustomToolBarImportHelper& );
+ bool ImportMenuTB( CTBWrapper&, const css::uno::Reference< css::container::XIndexContainer >&, CustomToolBarImportHelper& );
+ rtl::OUString GetName() { return tb.getName().getString(); }
+
+
+};
+
+class CTBS : public TBBase
+{
+public:
+ sal_uInt8 bSignature;
+ sal_uInt8 bVersion;
+ sal_uInt16 reserved1;
+ sal_uInt16 reserved2;
+ sal_uInt16 reserved3;
+ sal_uInt16 ctb;
+ sal_uInt16 ctbViews;
+ sal_uInt16 ictbView;
+ CTBS(const CTBS&);
+ CTBS& operator = ( const CTBS&);
+ CTBS();
+ ~CTBS(){}
+ void Print( FILE* );
+ bool Read(SvStream *pS);
+};
+
+class CTBWrapper : public TBBase
+{
+ CTBS ctbSet;
+
+ std::vector< CTB > rCTB;
+
+public:
+ CTBWrapper();
+ ~CTBWrapper();
+ bool Read(SvStream *pS);
+ void Print( FILE* );
+ bool ImportCustomToolBar( SfxObjectShell& rDocSh );
+ CTB* GetCustomizationData( const rtl::OUString& name );
+};
+
+
+#endif //_XLTOOLBAR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xltools.cxx b/sc/source/filter/excel/xltools.cxx
new file mode 100644
index 000000000000..aba8b38fc340
--- /dev/null
+++ b/sc/source/filter/excel/xltools.cxx
@@ -0,0 +1,750 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <algorithm>
+#include <math.h>
+#include <sal/mathconf.h>
+#include <unotools/fontcvt.hxx>
+#include <sfx2/objsh.hxx>
+#include <sal/macros.h>
+#include <editeng/editstat.hxx>
+#include <filter/msfilter/msvbahelper.hxx>
+#include "xestream.hxx"
+#include "document.hxx"
+#include "docuno.hxx"
+#include "editutil.hxx"
+#include "formula/errorcodes.hxx"
+#include "globstr.hrc"
+#include "xlstyle.hxx"
+#include "xlname.hxx"
+#include "xistream.hxx"
+#include "xiroot.hxx"
+#include "xltools.hxx"
+
+using ::rtl::OUString;
+
+// GUID import/export =========================================================
+
+XclGuid::XclGuid()
+{
+ ::std::fill( mpnData, STATIC_TABLE_END( mpnData ), 0 );
+}
+
+XclGuid::XclGuid(
+ sal_uInt32 nData1, sal_uInt16 nData2, sal_uInt16 nData3,
+ sal_uInt8 nData41, sal_uInt8 nData42, sal_uInt8 nData43, sal_uInt8 nData44,
+ sal_uInt8 nData45, sal_uInt8 nData46, sal_uInt8 nData47, sal_uInt8 nData48 )
+{
+ // convert to little endian -> makes streaming easy
+ UInt32ToSVBT32( nData1, mpnData );
+ ShortToSVBT16( nData2, mpnData + 4 );
+ ShortToSVBT16( nData3, mpnData + 6 );
+ mpnData[ 8 ] = nData41;
+ mpnData[ 9 ] = nData42;
+ mpnData[ 10 ] = nData43;
+ mpnData[ 11 ] = nData44;
+ mpnData[ 12 ] = nData45;
+ mpnData[ 13 ] = nData46;
+ mpnData[ 14 ] = nData47;
+ mpnData[ 15 ] = nData48;
+}
+
+bool operator==( const XclGuid& rCmp1, const XclGuid& rCmp2 )
+{
+ return ::std::equal( rCmp1.mpnData, STATIC_TABLE_END( rCmp1.mpnData ), rCmp2.mpnData );
+}
+
+bool operator<( const XclGuid& rCmp1, const XclGuid& rCmp2 )
+{
+ return ::std::lexicographical_compare(
+ rCmp1.mpnData, STATIC_TABLE_END( rCmp1.mpnData ),
+ rCmp2.mpnData, STATIC_TABLE_END( rCmp2.mpnData ) );
+}
+
+XclImpStream& operator>>( XclImpStream& rStrm, XclGuid& rGuid )
+{
+ rStrm.Read( rGuid.mpnData, 16 ); // mpnData always in little endian
+ return rStrm;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const XclGuid& rGuid )
+{
+ rStrm.Write( rGuid.mpnData, 16 ); // mpnData already in little endian
+ return rStrm;
+}
+
+// Excel Tools ================================================================
+
+// GUID's ---------------------------------------------------------------------
+
+const XclGuid XclTools::maGuidStdLink(
+ 0x79EAC9D0, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B );
+
+const XclGuid XclTools::maGuidUrlMoniker(
+ 0x79EAC9E0, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B );
+
+const XclGuid XclTools::maGuidFileMoniker(
+ 0x00000303, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 );
+
+// numeric conversion ---------------------------------------------------------
+
+double XclTools::GetDoubleFromRK( sal_Int32 nRKValue )
+{
+ union
+ {
+ double fVal;
+ sal_math_Double smD;
+ };
+ fVal = 0.0;
+
+ if( ::get_flag( nRKValue, EXC_RK_INTFLAG ) )
+ {
+ sal_Int32 nTemp = nRKValue >> 2;
+ ::set_flag< sal_Int32 >( nTemp, 0xE0000000, nRKValue < 0 );
+ fVal = nTemp;
+ }
+ else
+ {
+ smD.w32_parts.msw = nRKValue & EXC_RK_VALUEMASK;
+ }
+
+ if( ::get_flag( nRKValue, EXC_RK_100FLAG ) )
+ fVal /= 100.0;
+
+ return fVal;
+}
+
+bool XclTools::GetRKFromDouble( sal_Int32& rnRKValue, double fValue )
+{
+ double fFrac, fInt;
+
+ // integer
+ fFrac = modf( fValue, &fInt );
+ if( (fFrac == 0.0) && (fInt >= -536870912.0) && (fInt <= 536870911.0) ) // 2^29
+ {
+ rnRKValue = static_cast< sal_Int32 >( fInt );
+ rnRKValue <<= 2;
+ rnRKValue |= EXC_RK_INT;
+ return true;
+ }
+
+ // integer/100
+ fFrac = modf( fValue * 100.0, &fInt );
+ if( (fFrac == 0.0) && (fInt >= -536870912.0) && (fInt <= 536870911.0) )
+ {
+ rnRKValue = static_cast< sal_Int32 >( fInt );
+ rnRKValue <<= 2;
+ rnRKValue |= EXC_RK_INT100;
+ return true;
+ }
+
+ // double
+ return false;
+}
+
+sal_Int32 XclTools::GetScRotation( sal_uInt16 nXclRot, sal_Int32 nRotForStacked )
+{
+ if( nXclRot == EXC_ROT_STACKED )
+ return nRotForStacked;
+ DBG_ASSERT( nXclRot <= 180, "XclTools::GetScRotation - illegal rotation angle" );
+ return static_cast< sal_Int32 >( (nXclRot <= 180) ? (100 * ((nXclRot > 90) ? (450 - nXclRot) : nXclRot)) : 0 );
+}
+
+sal_uInt8 XclTools::GetXclRotation( sal_Int32 nScRot )
+{
+ sal_Int32 nXclRot = nScRot / 100;
+ if( (0 <= nXclRot) && (nXclRot <= 90) )
+ return static_cast< sal_uInt8 >( nXclRot );
+ if( nXclRot < 180 )
+ return static_cast< sal_uInt8 >( 270 - nXclRot );
+ if( nXclRot < 270 )
+ return static_cast< sal_uInt8 >( nXclRot - 180 );
+ if( nXclRot < 360 )
+ return static_cast< sal_uInt8 >( 450 - nXclRot );
+ return 0;
+}
+
+sal_uInt8 XclTools::GetXclRotFromOrient( sal_uInt8 nXclOrient )
+{
+ switch( nXclOrient )
+ {
+ case EXC_ORIENT_NONE: return EXC_ROT_NONE;
+ case EXC_ORIENT_STACKED: return EXC_ROT_STACKED;
+ case EXC_ORIENT_90CCW: return EXC_ROT_90CCW;
+ case EXC_ORIENT_90CW: return EXC_ROT_90CW;
+ default: DBG_ERRORFILE( "XclTools::GetXclRotFromOrient - unknown text orientation" );
+ }
+ return EXC_ROT_NONE;
+}
+
+sal_uInt8 XclTools::GetXclOrientFromRot( sal_uInt16 nXclRot )
+{
+ if( nXclRot == EXC_ROT_STACKED )
+ return EXC_ORIENT_STACKED;
+ DBG_ASSERT( nXclRot <= 180, "XclTools::GetXclOrientFromRot - unknown text rotation" );
+ if( (45 < nXclRot) && (nXclRot <= 90) )
+ return EXC_ORIENT_90CCW;
+ if( (135 < nXclRot) && (nXclRot <= 180) )
+ return EXC_ORIENT_90CW;
+ return EXC_ORIENT_NONE;
+}
+
+sal_uInt8 XclTools::GetXclErrorCode( sal_uInt16 nScError )
+{
+ using namespace ScErrorCodes;
+ switch( nScError )
+ {
+ case errIllegalArgument: return EXC_ERR_VALUE;
+ case errIllegalFPOperation: return EXC_ERR_NUM; // maybe DIV/0 or NUM...
+ case errDivisionByZero: return EXC_ERR_DIV0;
+ case errIllegalParameter: return EXC_ERR_VALUE;
+ case errPairExpected: return EXC_ERR_VALUE;
+ case errOperatorExpected: return EXC_ERR_VALUE;
+ case errVariableExpected: return EXC_ERR_VALUE;
+ case errParameterExpected: return EXC_ERR_VALUE;
+ case errNoValue: return EXC_ERR_VALUE;
+ case errCircularReference: return EXC_ERR_VALUE;
+ case errNoCode: return EXC_ERR_NULL;
+ case errNoRef: return EXC_ERR_REF;
+ case errNoName: return EXC_ERR_NAME;
+ case errNoAddin: return EXC_ERR_NAME;
+ case errNoMacro: return EXC_ERR_NAME;
+ case NOTAVAILABLE: return EXC_ERR_NA;
+ }
+ return EXC_ERR_NA;
+}
+
+sal_uInt16 XclTools::GetScErrorCode( sal_uInt8 nXclError )
+{
+ using namespace ScErrorCodes;
+ switch( nXclError )
+ {
+ case EXC_ERR_NULL: return errNoCode;
+ case EXC_ERR_DIV0: return errDivisionByZero;
+ case EXC_ERR_VALUE: return errNoValue;
+ case EXC_ERR_REF: return errNoRef;
+ case EXC_ERR_NAME: return errNoName;
+ case EXC_ERR_NUM: return errIllegalFPOperation;
+ case EXC_ERR_NA: return NOTAVAILABLE;
+ default: DBG_ERRORFILE( "XclTools::GetScErrorCode - unknown error code" );
+ }
+ return NOTAVAILABLE;
+}
+
+double XclTools::ErrorToDouble( sal_uInt8 nXclError )
+{
+ union
+ {
+ double fVal;
+ sal_math_Double smD;
+ };
+ ::rtl::math::setNan( &fVal );
+ smD.nan_parts.fraction_lo = GetScErrorCode( nXclError );
+ return fVal;
+}
+
+XclBoolError XclTools::ErrorToEnum( double& rfDblValue, sal_uInt8 bErrOrBool, sal_uInt8 nValue )
+{
+ XclBoolError eType;
+ if( bErrOrBool )
+ {
+ // error value
+ switch( nValue )
+ {
+ case EXC_ERR_NULL: eType = xlErrNull; break;
+ case EXC_ERR_DIV0: eType = xlErrDiv0; break;
+ case EXC_ERR_VALUE: eType = xlErrValue; break;
+ case EXC_ERR_REF: eType = xlErrRef; break;
+ case EXC_ERR_NAME: eType = xlErrName; break;
+ case EXC_ERR_NUM: eType = xlErrNum; break;
+ case EXC_ERR_NA: eType = xlErrNA; break;
+ default: eType = xlErrUnknown;
+ }
+ rfDblValue = 0.0;
+ }
+ else
+ {
+ // Boolean value
+ eType = nValue ? xlErrTrue : xlErrFalse;
+ rfDblValue = nValue ? 1.0 : 0.0;
+ }
+ return eType;
+}
+
+sal_uInt16 XclTools::GetTwipsFromInch( double fInches )
+{
+ return static_cast< sal_uInt16 >(
+ ::std::min( ::std::max( (fInches * EXC_TWIPS_PER_INCH + 0.5), 0.0 ), 65535.0 ) );
+}
+
+sal_uInt16 XclTools::GetTwipsFromHmm( sal_Int32 nHmm )
+{
+ return GetTwipsFromInch( static_cast< double >( nHmm ) / 1000.0 / CM_PER_INCH );
+}
+
+double XclTools::GetInchFromTwips( sal_Int32 nTwips )
+{
+ return static_cast< double >( nTwips ) / EXC_TWIPS_PER_INCH;
+}
+
+double XclTools::GetInchFromHmm( sal_Int32 nHmm )
+{
+ return GetInchFromTwips( GetTwipsFromHmm( nHmm ) );
+}
+
+sal_Int32 XclTools::GetHmmFromInch( double fInches )
+{
+ return static_cast< sal_Int32 >( fInches * CM_PER_INCH * 1000 );
+}
+
+sal_Int32 XclTools::GetHmmFromTwips( sal_Int32 nTwips )
+{
+ return GetHmmFromInch( GetInchFromTwips( nTwips ) );
+}
+
+sal_uInt16 XclTools::GetScColumnWidth( sal_uInt16 nXclWidth, long nScCharWidth )
+{
+ double fScWidth = static_cast< double >( nXclWidth ) / 256.0 * nScCharWidth + 0.5;
+ return limit_cast< sal_uInt16 >( fScWidth );
+}
+
+sal_uInt16 XclTools::GetXclColumnWidth( sal_uInt16 nScWidth, long nScCharWidth )
+{
+ double fXclWidth = static_cast< double >( nScWidth ) * 256.0 / nScCharWidth + 0.5;
+ return limit_cast< sal_uInt16 >( fXclWidth );
+}
+
+double XclTools::GetXclDefColWidthCorrection( long nXclDefFontHeight )
+{
+ return 40960.0 / ::std::max( nXclDefFontHeight - 15L, 60L ) + 50.0;
+}
+
+// formatting -----------------------------------------------------------------
+
+Color XclTools::GetPatternColor( const Color& rPattColor, const Color& rBackColor, sal_uInt16 nXclPattern )
+{
+ // 0x00 == 0% transparence (full rPattColor)
+ // 0x80 == 100% transparence (full rBackColor)
+ static const sal_uInt8 pnRatioTable[] =
+ {
+ 0x80, 0x00, 0x40, 0x20, 0x60, 0x40, 0x40, 0x40, // 00 - 07
+ 0x40, 0x40, 0x20, 0x60, 0x60, 0x60, 0x60, 0x48, // 08 - 15
+ 0x50, 0x70, 0x78 // 16 - 18
+ };
+ return (nXclPattern < SAL_N_ELEMENTS( pnRatioTable )) ?
+ ScfTools::GetMixedColor( rPattColor, rBackColor, pnRatioTable[ nXclPattern ] ) : rPattColor;
+}
+
+// text encoding --------------------------------------------------------------
+
+namespace {
+
+const struct XclCodePageEntry
+{
+ sal_uInt16 mnCodePage;
+ rtl_TextEncoding meTextEnc;
+}
+pCodePageTable[] =
+{
+ { 437, RTL_TEXTENCODING_IBM_437 }, // OEM US
+// { 720, RTL_TEXTENCODING_IBM_720 }, // OEM Arabic
+ { 737, RTL_TEXTENCODING_IBM_737 }, // OEM Greek
+ { 775, RTL_TEXTENCODING_IBM_775 }, // OEM Baltic
+ { 850, RTL_TEXTENCODING_IBM_850 }, // OEM Latin I
+ { 852, RTL_TEXTENCODING_IBM_852 }, // OEM Latin II (Central European)
+ { 855, RTL_TEXTENCODING_IBM_855 }, // OEM Cyrillic
+ { 857, RTL_TEXTENCODING_IBM_857 }, // OEM Turkish
+// { 858, RTL_TEXTENCODING_IBM_858 }, // OEM Multilingual Latin I with Euro
+ { 860, RTL_TEXTENCODING_IBM_860 }, // OEM Portugese
+ { 861, RTL_TEXTENCODING_IBM_861 }, // OEM Icelandic
+ { 862, RTL_TEXTENCODING_IBM_862 }, // OEM Hebrew
+ { 863, RTL_TEXTENCODING_IBM_863 }, // OEM Canadian (French)
+ { 864, RTL_TEXTENCODING_IBM_864 }, // OEM Arabic
+ { 865, RTL_TEXTENCODING_IBM_865 }, // OEM Nordic
+ { 866, RTL_TEXTENCODING_IBM_866 }, // OEM Cyrillic (Russian)
+ { 869, RTL_TEXTENCODING_IBM_869 }, // OEM Greek (Modern)
+ { 874, RTL_TEXTENCODING_MS_874 }, // MS Windows Thai
+ { 932, RTL_TEXTENCODING_MS_932 }, // MS Windows Japanese Shift-JIS
+ { 936, RTL_TEXTENCODING_MS_936 }, // MS Windows Chinese Simplified GBK
+ { 949, RTL_TEXTENCODING_MS_949 }, // MS Windows Korean (Wansung)
+ { 950, RTL_TEXTENCODING_MS_950 }, // MS Windows Chinese Traditional BIG5
+ { 1200, RTL_TEXTENCODING_DONTKNOW }, // Unicode (BIFF8) - return *_DONTKNOW to preserve old code page
+ { 1250, RTL_TEXTENCODING_MS_1250 }, // MS Windows Latin II (Central European)
+ { 1251, RTL_TEXTENCODING_MS_1251 }, // MS Windows Cyrillic
+ { 1252, RTL_TEXTENCODING_MS_1252 }, // MS Windows Latin I (BIFF4-BIFF8)
+ { 1253, RTL_TEXTENCODING_MS_1253 }, // MS Windows Greek
+ { 1254, RTL_TEXTENCODING_MS_1254 }, // MS Windows Turkish
+ { 1255, RTL_TEXTENCODING_MS_1255 }, // MS Windows Hebrew
+ { 1256, RTL_TEXTENCODING_MS_1256 }, // MS Windows Arabic
+ { 1257, RTL_TEXTENCODING_MS_1257 }, // MS Windows Baltic
+ { 1258, RTL_TEXTENCODING_MS_1258 }, // MS Windows Vietnamese
+ { 1361, RTL_TEXTENCODING_MS_1361 }, // MS Windows Korean (Johab)
+ { 10000, RTL_TEXTENCODING_APPLE_ROMAN }, // Apple Roman
+ { 32768, RTL_TEXTENCODING_APPLE_ROMAN }, // Apple Roman
+ { 32769, RTL_TEXTENCODING_MS_1252 } // MS Windows Latin I (BIFF2-BIFF3)
+};
+const XclCodePageEntry* const pCodePageTableEnd = STATIC_TABLE_END( pCodePageTable );
+
+struct XclCodePageEntry_CPPred
+{
+ inline explicit XclCodePageEntry_CPPred( sal_uInt16 nCodePage ) : mnCodePage( nCodePage ) {}
+ inline bool operator()( const XclCodePageEntry& rEntry ) const { return rEntry.mnCodePage == mnCodePage; }
+ sal_uInt16 mnCodePage;
+};
+
+struct XclCodePageEntry_TEPred
+{
+ inline explicit XclCodePageEntry_TEPred( rtl_TextEncoding eTextEnc ) : meTextEnc( eTextEnc ) {}
+ inline bool operator()( const XclCodePageEntry& rEntry ) const { return rEntry.meTextEnc == meTextEnc; }
+ rtl_TextEncoding meTextEnc;
+};
+
+} // namespace
+
+rtl_TextEncoding XclTools::GetTextEncoding( sal_uInt16 nCodePage )
+{
+ const XclCodePageEntry* pEntry = ::std::find_if( pCodePageTable, pCodePageTableEnd, XclCodePageEntry_CPPred( nCodePage ) );
+ if( pEntry == pCodePageTableEnd )
+ {
+ OSL_TRACE( "XclTools::GetTextEncoding - unknown code page: 0x%04hX (%d)", nCodePage, nCodePage );
+ return RTL_TEXTENCODING_DONTKNOW;
+ }
+ return pEntry->meTextEnc;
+}
+
+sal_uInt16 XclTools::GetXclCodePage( rtl_TextEncoding eTextEnc )
+{
+ if( eTextEnc == RTL_TEXTENCODING_UNICODE )
+ return 1200; // for BIFF8
+
+ const XclCodePageEntry* pEntry = ::std::find_if( pCodePageTable, pCodePageTableEnd, XclCodePageEntry_TEPred( eTextEnc ) );
+ if( pEntry == pCodePageTableEnd )
+ {
+ OSL_TRACE( "XclTools::GetXclCodePage - unsupported text encoding: %d", eTextEnc );
+ return 1252;
+ }
+ return pEntry->mnCodePage;
+}
+
+// font names -----------------------------------------------------------------
+
+String XclTools::GetXclFontName( const String& rFontName )
+{
+ // substitute with MS fonts
+ String aNewName( GetSubsFontName( rFontName, SUBSFONT_ONLYONE | SUBSFONT_MS ) );
+ if( aNewName.Len() )
+ return aNewName;
+ return rFontName;
+}
+
+// built-in defined names -----------------------------------------------------
+
+const String XclTools::maDefNamePrefix( RTL_CONSTASCII_USTRINGPARAM( "Excel_BuiltIn_" ) );
+
+const String XclTools::maDefNamePrefixXml ( RTL_CONSTASCII_USTRINGPARAM( "_xlnm." ) );
+
+static const sal_Char* const ppcDefNames[] =
+{
+ "Consolidate_Area",
+ "Auto_Open",
+ "Auto_Close",
+ "Extract",
+ "Database",
+ "Criteria",
+ "Print_Area",
+ "Print_Titles",
+ "Recorder",
+ "Data_Form",
+ "Auto_Activate",
+ "Auto_Deactivate",
+ "Sheet_Title",
+ "_FilterDatabase"
+};
+
+String XclTools::GetXclBuiltInDefName( sal_Unicode cBuiltIn )
+{
+ DBG_ASSERT( SAL_N_ELEMENTS( ppcDefNames ) == EXC_BUILTIN_UNKNOWN,
+ "XclTools::GetXclBuiltInDefName - built-in defined name list modified" );
+ String aDefName;
+ if( cBuiltIn < SAL_N_ELEMENTS( ppcDefNames ) )
+ aDefName.AssignAscii( ppcDefNames[ cBuiltIn ] );
+ else
+ aDefName = String::CreateFromInt32( cBuiltIn );
+ return aDefName;
+}
+
+String XclTools::GetBuiltInDefName( sal_Unicode cBuiltIn )
+{
+ return String( maDefNamePrefix ).Append( GetXclBuiltInDefName( cBuiltIn ) );
+}
+
+String XclTools::GetBuiltInDefNameXml( sal_Unicode cBuiltIn )
+{
+ return String( maDefNamePrefixXml ).Append( GetXclBuiltInDefName( cBuiltIn ) );
+}
+
+sal_Unicode XclTools::GetBuiltInDefNameIndex( const String& rDefName )
+{
+ xub_StrLen nPrefixLen = maDefNamePrefix.Len();
+ if( rDefName.EqualsIgnoreCaseAscii( maDefNamePrefix, 0, nPrefixLen ) )
+ {
+ for( sal_Unicode cBuiltIn = 0; cBuiltIn < EXC_BUILTIN_UNKNOWN; ++cBuiltIn )
+ {
+ String aBuiltInName( GetXclBuiltInDefName( cBuiltIn ) );
+ xub_StrLen nBuiltInLen = aBuiltInName.Len();
+ if( rDefName.EqualsIgnoreCaseAscii( aBuiltInName, nPrefixLen, nBuiltInLen ) )
+ {
+ // name can be followed by underline or space character
+ xub_StrLen nNextCharPos = nPrefixLen + nBuiltInLen;
+ sal_Unicode cNextChar = (rDefName.Len() > nNextCharPos) ? rDefName.GetChar( nNextCharPos ) : '\0';
+ if( (cNextChar == '\0') || (cNextChar == ' ') || (cNextChar == '_') )
+ return cBuiltIn;
+ }
+ }
+ }
+ return EXC_BUILTIN_UNKNOWN;
+}
+
+// built-in style names -------------------------------------------------------
+
+const String XclTools::maStyleNamePrefix1( RTL_CONSTASCII_USTRINGPARAM( "Excel_BuiltIn_" ) );
+const String XclTools::maStyleNamePrefix2( RTL_CONSTASCII_USTRINGPARAM( "Excel Built-in " ) );
+
+static const sal_Char* const ppcStyleNames[] =
+{
+ "", // "Normal" not used directly, but localized "Default"
+ "RowLevel_", // outline level will be appended
+ "ColumnLevel_", // outline level will be appended
+ "Comma",
+ "Currency",
+ "Percent",
+ "Comma_0",
+ "Currency_0",
+ "Hyperlink",
+ "Followed_Hyperlink"
+};
+
+String XclTools::GetBuiltInStyleName( sal_uInt8 nStyleId, const String& rName, sal_uInt8 nLevel )
+{
+ String aStyleName;
+
+ if( nStyleId == EXC_STYLE_NORMAL ) // "Normal" becomes "Default" style
+ {
+ aStyleName = ScGlobal::GetRscString( STR_STYLENAME_STANDARD );
+ }
+ else
+ {
+ aStyleName = maStyleNamePrefix1;
+ if( nStyleId < SAL_N_ELEMENTS( ppcStyleNames ) )
+ aStyleName.AppendAscii( ppcStyleNames[ nStyleId ] );
+ else if( rName.Len() > 0 )
+ aStyleName.Append( rName );
+ else
+ aStyleName.Append( String::CreateFromInt32( nStyleId ) );
+ if( (nStyleId == EXC_STYLE_ROWLEVEL) || (nStyleId == EXC_STYLE_COLLEVEL) )
+ aStyleName.Append( String::CreateFromInt32( nLevel + 1 ) );
+ }
+
+ return aStyleName;
+}
+
+String XclTools::GetBuiltInStyleName( const String& rStyleName )
+{
+ return String( maStyleNamePrefix1 ).Append( rStyleName );
+}
+
+bool XclTools::IsBuiltInStyleName( const String& rStyleName, sal_uInt8* pnStyleId, xub_StrLen* pnNextChar )
+{
+ // "Default" becomes "Normal"
+ if( rStyleName == ScGlobal::GetRscString( STR_STYLENAME_STANDARD ) )
+ {
+ if( pnStyleId ) *pnStyleId = EXC_STYLE_NORMAL;
+ if( pnNextChar ) *pnNextChar = rStyleName.Len();
+ return true;
+ }
+
+ // try the other built-in styles
+ sal_uInt8 nFoundId = 0;
+ xub_StrLen nNextChar = 0;
+
+ xub_StrLen nPrefixLen = 0;
+ if( rStyleName.EqualsIgnoreCaseAscii( maStyleNamePrefix1, 0, maStyleNamePrefix1.Len() ) )
+ nPrefixLen = maStyleNamePrefix1.Len();
+ else if( rStyleName.EqualsIgnoreCaseAscii( maStyleNamePrefix2, 0, maStyleNamePrefix2.Len() ) )
+ nPrefixLen = maStyleNamePrefix2.Len();
+ if( nPrefixLen > 0 )
+ {
+ String aShortName;
+ for( sal_uInt8 nId = 0; nId < SAL_N_ELEMENTS( ppcStyleNames ); ++nId )
+ {
+ if( nId != EXC_STYLE_NORMAL )
+ {
+ aShortName.AssignAscii( ppcStyleNames[ nId ] );
+ if( rStyleName.EqualsIgnoreCaseAscii( aShortName, nPrefixLen, aShortName.Len() ) &&
+ (nNextChar < nPrefixLen + aShortName.Len()) )
+ {
+ nFoundId = nId;
+ nNextChar = nPrefixLen + aShortName.Len();
+ }
+ }
+ }
+ }
+
+ if( nNextChar > 0 )
+ {
+ if( pnStyleId ) *pnStyleId = nFoundId;
+ if( pnNextChar ) *pnNextChar = nNextChar;
+ return true;
+ }
+
+ if( pnStyleId ) *pnStyleId = EXC_STYLE_USERDEF;
+ if( pnNextChar ) *pnNextChar = 0;
+ return nPrefixLen > 0; // also return true for unknown built-in styles
+}
+
+bool XclTools::GetBuiltInStyleId( sal_uInt8& rnStyleId, sal_uInt8& rnLevel, const String& rStyleName )
+{
+ sal_uInt8 nStyleId;
+ xub_StrLen nNextChar;
+ if( IsBuiltInStyleName( rStyleName, &nStyleId, &nNextChar ) && (nStyleId != EXC_STYLE_USERDEF) )
+ {
+ if( (nStyleId == EXC_STYLE_ROWLEVEL) || (nStyleId == EXC_STYLE_COLLEVEL) )
+ {
+ String aLevel( rStyleName, nNextChar, STRING_LEN );
+ sal_Int32 nLevel = aLevel.ToInt32();
+ if( (String::CreateFromInt32( nLevel ) == aLevel) && (nLevel > 0) && (nLevel <= EXC_STYLE_LEVELCOUNT) )
+ {
+ rnStyleId = nStyleId;
+ rnLevel = static_cast< sal_uInt8 >( nLevel - 1 );
+ return true;
+ }
+ }
+ else if( rStyleName.Len() == nNextChar )
+ {
+ rnStyleId = nStyleId;
+ rnLevel = EXC_STYLE_NOLEVEL;
+ return true;
+ }
+ }
+ rnStyleId = EXC_STYLE_USERDEF;
+ rnLevel = EXC_STYLE_NOLEVEL;
+ return false;
+}
+
+// conditional formatting style names -----------------------------------------
+
+const String XclTools::maCFStyleNamePrefix1( RTL_CONSTASCII_USTRINGPARAM( "Excel_CondFormat_" ) );
+const String XclTools::maCFStyleNamePrefix2( RTL_CONSTASCII_USTRINGPARAM( "ConditionalStyle_" ) );
+
+String XclTools::GetCondFormatStyleName( SCTAB nScTab, sal_Int32 nFormat, sal_uInt16 nCondition )
+{
+ return String( maCFStyleNamePrefix1 ).Append( String::CreateFromInt32( nScTab + 1 ) ).
+ Append( '_' ).Append( String::CreateFromInt32( nFormat + 1 ) ).
+ Append( '_' ).Append( String::CreateFromInt32( nCondition + 1 ) );
+}
+
+bool XclTools::IsCondFormatStyleName( const String& rStyleName, xub_StrLen* pnNextChar )
+{
+ xub_StrLen nPrefixLen = 0;
+ if( rStyleName.EqualsIgnoreCaseAscii( maCFStyleNamePrefix1, 0, maCFStyleNamePrefix1.Len() ) )
+ nPrefixLen = maCFStyleNamePrefix1.Len();
+ else if( rStyleName.EqualsIgnoreCaseAscii( maCFStyleNamePrefix2, 0, maCFStyleNamePrefix2.Len() ) )
+ nPrefixLen = maCFStyleNamePrefix2.Len();
+ if( pnNextChar ) *pnNextChar = nPrefixLen;
+ return nPrefixLen > 0;
+}
+
+// stream handling ------------------------------------------------------------
+
+void XclTools::SkipSubStream( XclImpStream& rStrm )
+{
+ bool bLoop = true;
+ while( bLoop && rStrm.StartNextRecord() )
+ {
+ sal_uInt16 nRecId = rStrm.GetRecId();
+ bLoop = nRecId != EXC_ID_EOF;
+ if( (nRecId == EXC_ID2_BOF) || (nRecId == EXC_ID3_BOF) || (nRecId == EXC_ID4_BOF) || (nRecId == EXC_ID5_BOF) )
+ SkipSubStream( rStrm );
+ }
+}
+
+// Basic macro names ----------------------------------------------------------
+
+const OUString XclTools::maSbMacroPrefix( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.script:" ) );
+const OUString XclTools::maSbMacroSuffix( RTL_CONSTASCII_USTRINGPARAM( "?language=Basic&location=document" ) );
+
+OUString XclTools::GetSbMacroUrl( const String& rMacroName, SfxObjectShell* pDocShell )
+{
+ OSL_ENSURE( rMacroName.Len() > 0, "XclTools::GetSbMacroUrl - macro name is empty" );
+ ::ooo::vba::MacroResolvedInfo aMacroInfo = ::ooo::vba::resolveVBAMacro( pDocShell, rMacroName, false );
+ if( aMacroInfo.mbFound )
+ return ::ooo::vba::makeMacroURL( aMacroInfo.msResolvedMacro );
+ return OUString();
+}
+
+OUString XclTools::GetSbMacroUrl( const String& rModuleName, const String& rMacroName, SfxObjectShell* pDocShell )
+{
+ OSL_ENSURE( rModuleName.Len() > 0, "XclTools::GetSbMacroUrl - module name is empty" );
+ OSL_ENSURE( rMacroName.Len() > 0, "XclTools::GetSbMacroUrl - macro name is empty" );
+ return GetSbMacroUrl( rModuleName + OUString( sal_Unicode( '.' ) ) + rMacroName, pDocShell );
+}
+
+String XclTools::GetXclMacroName( const OUString& rSbMacroUrl )
+{
+ sal_Int32 nSbMacroUrlLen = rSbMacroUrl.getLength();
+ sal_Int32 nMacroNameLen = nSbMacroUrlLen - maSbMacroPrefix.getLength() - maSbMacroSuffix.getLength();
+ if( (nMacroNameLen > 0) && rSbMacroUrl.matchIgnoreAsciiCase( maSbMacroPrefix, 0 ) &&
+ rSbMacroUrl.matchIgnoreAsciiCase( maSbMacroSuffix, nSbMacroUrlLen - maSbMacroSuffix.getLength() ) )
+ {
+ sal_Int32 nPrjDot = rSbMacroUrl.indexOf( '.', maSbMacroPrefix.getLength() ) + 1;
+ return rSbMacroUrl.copy( nPrjDot, nSbMacroUrlLen - nPrjDot - maSbMacroSuffix.getLength() );
+ }
+ return String::EmptyString();
+}
+
+// read/write colors ----------------------------------------------------------
+
+XclImpStream& operator>>( XclImpStream& rStrm, Color& rColor )
+{
+ sal_uInt8 nR, nG, nB, nD;
+ rStrm >> nR >> nG >> nB >> nD;
+ rColor.SetColor( RGB_COLORDATA( nR, nG, nB ) );
+ return rStrm;
+}
+
+XclExpStream& operator<<( XclExpStream& rStrm, const Color& rColor )
+{
+ return rStrm << rColor.GetRed() << rColor.GetGreen() << rColor.GetBlue() << sal_uInt8( 0 );
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xltracer.cxx b/sc/source/filter/excel/xltracer.cxx
new file mode 100644
index 000000000000..a5351a1da9bf
--- /dev/null
+++ b/sc/source/filter/excel/xltracer.cxx
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// ============================================================================
+#include "xltracer.hxx"
+#include <filter/msfilter/msfiltertracer.hxx>
+#include "address.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::beans::PropertyValue;
+
+// ============================================================================
+
+// Trace Table details are grouped by functionality using the context entry.
+// Each separate context starts at the next 1000 interval. New entries should
+// be added to their appropriate context. New contexts should be added onto
+// the end. Any gaps in the 1000 sequence or within the 1000 are the result
+// of trace events no longer present.
+static const XclTracerDetails pTracerDetails[] =
+{
+ { eUnKnown, 0, "UNKNOWN", "UNKNOWN", "Unknown trace property." },
+ { eRowLimitExceeded, 1000, "Limits", "Sheet", "Row limit exceeded." },
+ { eTabLimitExceeded, 1001, "Limits", "Sheet", "Sheet limit exceeded." },
+ { ePassword, 2000, "Protection", "Password", "Document is password protected." },
+ { ePrintRange, 3000, "Print", "Print Range", "Print Range present." },
+ { eShortDate, 4000, "CellFormatting", "Short Dates", "Possible Date format issue." },
+ { eBorderLineStyle, 4004, "CellFormatting", "Border", "Line style not supported.", },
+ { eFillPattern, 4005, "CellFormatting", "Pattern", "Fill Pattern not supported.", },
+ { eInvisibleGrid, 5000, "Properties", "Grid Invisible", "Grid invisible on first sheet." },
+ { eFormattedNote, 6000, "Notes", "Formatting", "Text may be formatted." },
+ { eFormulaExtName, 7000, "Formula", "External Name", "External names not supported." },
+ { eFormulaMissingArg, 7001, "Formula", "Missing Argument","Parameter missing." },
+ { ePivotDataSource, 8000, "Chart", "Pivot", "External data source not supported."},
+ { ePivotChartExists, 8001, "Chart", "Pivot", "Pivot Chart not supported."},
+ { eChartUnKnownType, 8002, "Chart", "Type", "Chart Type not supported."},
+ { eChartTrendLines, 8003, "Chart", "Type", "Chart trendlines not supported."},
+ { eChartOnlySheet, 8004, "Chart", "Type", "Chart only sheet not supported."},
+ { eChartRange, 8005, "Chart", "Source Data", "Chart source ranges too complex."},
+ { eChartDSName, 8006, "Chart", "Source Data", "Series titles not linked to cells."},
+ { eChartDataTable, 8007, "Chart", "Legend", "Data table not supported."},
+ { eChartLegendPosition, 8008, "Chart", "Legend", "Position not guaranteed."},
+ { eChartTextFormatting, 8009, "Chart", "Formatting", "Text formatting present."},
+ { eChartEmbeddedObj, 8010, "Chart", "Area", "Object inside chart."},
+ { eChartAxisAuto, 8012, "Chart", "Axis", "Axis interval is automatic."},
+ { eChartInvalidXY, 8013, "Chart", "Scatter", "Unsupported or invalid data range for XY chart."},
+ { eChartErrorBars, 8014, "Chart", "Type", "Chart error bars not supported."},
+ { eChartAxisManual, 8015, "Chart", "Axis", "Manual axis crossing point adjusted."},
+ { eUnsupportedObject, 9000, "Object", "Type", "Limited Object support."},
+ { eObjectNotPrintable, 9001, "Object", "Print", "Object not printable."},
+ { eDVType, 10000, "DataValidation", "Type", "Custom type present."}
+};
+
+XclTracer::XclTracer( const String& rDocUrl, const OUString& rConfigPath ) :
+ maFirstTimes(eTraceLength,true)
+{
+ Sequence< PropertyValue > aConfigData( 1 );
+ aConfigData[ 0 ].Name = CREATE_OUSTRING( "DocumentURL" );
+ aConfigData[ 0 ].Value <<= OUString( rDocUrl );
+ mpTracer.reset( new MSFilterTracer( rConfigPath, &aConfigData ) );
+ mpTracer->StartTracing();
+ mbEnabled = mpTracer->IsEnabled();
+}
+
+XclTracer::~XclTracer()
+{
+ mpTracer->EndTracing();
+}
+
+void XclTracer::AddAttribute( const OUString& rName, const OUString& rValue )
+{
+ if( mbEnabled )
+ mpTracer->AddAttribute( rName, rValue );
+}
+
+void XclTracer::Trace( const OUString& rElementID, const OUString& rMessage )
+{
+ if( mbEnabled )
+ {
+ mpTracer->Trace( rElementID, rMessage );
+ mpTracer->ClearAttributes();
+ }
+}
+
+void XclTracer::TraceLog( XclTracerId eProblem, sal_Int32 nValue )
+{
+ if( mbEnabled )
+ {
+ OUString sID( CREATE_STRING( "SC" ) );
+ sID += OUString::valueOf( static_cast< sal_Int32 >( pTracerDetails[ eProblem ].mnID ) );
+ OUString sProblem = OUString::createFromAscii( pTracerDetails[ eProblem ].mpProblem );
+
+ switch (eProblem)
+ {
+ case eRowLimitExceeded:
+ Context(eProblem,static_cast<SCTAB>(nValue));
+ break;
+ case eTabLimitExceeded:
+ Context(eProblem,static_cast<SCTAB>(nValue));
+ break;
+ default:
+ Context(eProblem);
+ break;
+ }
+ Trace(sID, sProblem);
+ }
+}
+
+void XclTracer::Context( XclTracerId eProblem, SCTAB nTab )
+{
+ OUString sContext = OUString::createFromAscii( pTracerDetails[ eProblem ].mpContext );
+ OUString sDetail = OUString::createFromAscii( pTracerDetails[ eProblem ].mpDetail );
+
+ switch (eProblem)
+ {
+ case eRowLimitExceeded:
+ case eTabLimitExceeded:
+ sDetail += OUString::valueOf( static_cast< sal_Int32 >( nTab + 1 ) );
+ break;
+ default:
+ break;
+ }
+ AddAttribute(sContext, sDetail);
+}
+
+void XclTracer::ProcessTraceOnce(XclTracerId eProblem, SCTAB nTab)
+{
+ if( mbEnabled && maFirstTimes[eProblem])
+ {
+ TraceLog(pTracerDetails[eProblem].meProblemId, nTab);
+ maFirstTimes[eProblem] = false;
+ }
+}
+
+void XclTracer::TraceInvalidAddress( const ScAddress& rPos, const ScAddress& rMaxPos )
+{
+ TraceInvalidRow(rPos.Tab(), rPos.Row(), rMaxPos.Row());
+ TraceInvalidTab(rPos.Tab(), rMaxPos.Tab());
+}
+
+void XclTracer::TraceInvalidRow( SCTAB nTab, sal_uInt32 nRow, sal_uInt32 nMaxRow )
+{
+ if(nRow > nMaxRow)
+ ProcessTraceOnce(eRowLimitExceeded, nTab);
+}
+
+void XclTracer::TraceInvalidTab( SCTAB nTab, SCTAB nMaxTab )
+{
+ if(nTab > nMaxTab)
+ ProcessTraceOnce(eTabLimitExceeded, nTab);
+}
+
+void XclTracer::TracePrintRange()
+{
+ ProcessTraceOnce( ePrintRange);
+}
+
+void XclTracer::TraceDates( sal_uInt16 nNumFmt)
+{
+ // Short Date = 14 and Short Date+Time = 22
+ if(nNumFmt == 14 || nNumFmt == 22)
+ ProcessTraceOnce(eShortDate);
+}
+
+void XclTracer::TraceBorderLineStyle( bool bBorderLineStyle)
+{
+ if(bBorderLineStyle)
+ ProcessTraceOnce(eBorderLineStyle);
+}
+
+void XclTracer::TraceFillPattern( bool bFillPattern)
+{
+ if(bFillPattern)
+ ProcessTraceOnce(eFillPattern);
+}
+
+void XclTracer::TraceFormulaMissingArg()
+{
+ // missing parameter in Formula record
+ ProcessTraceOnce(eFormulaMissingArg);
+}
+
+void XclTracer::TracePivotDataSource( bool bExternal)
+{
+ if(bExternal)
+ ProcessTraceOnce(ePivotDataSource);
+}
+
+void XclTracer::TracePivotChartExists()
+{
+ // Pivot Charts not currently displayed.
+ ProcessTraceOnce(ePivotChartExists);
+}
+
+void XclTracer::TraceChartUnKnownType()
+{
+ ProcessTraceOnce(eChartUnKnownType);
+}
+
+void XclTracer::TraceChartOnlySheet()
+{
+ ProcessTraceOnce(eChartOnlySheet);
+}
+
+void XclTracer::TraceChartDataTable()
+{
+ // Data table is not supported.
+ ProcessTraceOnce(eChartDataTable);
+}
+
+void XclTracer::TraceChartLegendPosition()
+{
+ // If position is set to "not docked or inside the plot area" then
+ // we cannot guarantee the legend position.
+ ProcessTraceOnce(eChartLegendPosition);
+}
+
+void XclTracer::TraceUnsupportedObjects()
+{
+ // Called from Excel 5.0 - limited Graphical object support.
+ ProcessTraceOnce(eUnsupportedObject);
+}
+
+void XclTracer::TraceObjectNotPrintable()
+{
+ ProcessTraceOnce(eObjectNotPrintable);
+}
+
+void XclTracer::TraceDVType( bool bType)
+{
+ // Custom types work if 'Data->validity dialog' is not OKed.
+ if(bType)
+ ProcessTraceOnce(eDVType);
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xlview.cxx b/sc/source/filter/excel/xlview.cxx
new file mode 100644
index 000000000000..63512e4ec2d5
--- /dev/null
+++ b/sc/source/filter/excel/xlview.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xlview.hxx"
+#include "ftools.hxx"
+
+// Structs ====================================================================
+
+XclDocViewData::XclDocViewData() :
+ mnWinX( 0 ),
+ mnWinY( 0 ),
+ mnWinWidth( 0 ),
+ mnWinHeight( 0 ),
+ mnFlags( EXC_WIN1_HOR_SCROLLBAR | EXC_WIN1_VER_SCROLLBAR | EXC_WIN1_TABBAR ),
+ mnDisplXclTab( 0 ),
+ mnFirstVisXclTab( 0 ),
+ mnXclSelectCnt( 1 ),
+ mnTabBarWidth( 600 )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclTabViewData::XclTabViewData() :
+ maFirstXclPos( ScAddress::UNINITIALIZED ),
+ maSecondXclPos( ScAddress::UNINITIALIZED )
+{
+ SetDefaults();
+}
+
+XclTabViewData::~XclTabViewData()
+{
+}
+
+void XclTabViewData::SetDefaults()
+{
+ maSelMap.clear();
+ maGridColor.SetColor( COL_AUTO );
+ maFirstXclPos.Set( 0, 0 );
+ maSecondXclPos.Set( 0, 0 );
+ mnSplitX = mnSplitY = 0;
+ mnNormalZoom = EXC_WIN2_NORMALZOOM_DEF;
+ mnPageZoom = EXC_WIN2_PAGEZOOM_DEF;
+ mnCurrentZoom = 0; // default to mnNormalZoom or mnPageZoom
+ mnActivePane = EXC_PANE_TOPLEFT;
+ mbSelected = mbDisplayed = false;
+ mbMirrored = false;
+ mbFrozenPanes = false;
+ mbPageMode = false;
+ mbDefGridColor = true;
+ mbShowFormulas = false;
+ mbShowGrid = mbShowHeadings = mbShowZeros = mbShowOutline = true;
+ maTabBgColor.SetColor( COL_AUTO );
+}
+
+bool XclTabViewData::IsSplit() const
+{
+ return (mnSplitX > 0) || (mnSplitY > 0);
+}
+
+bool XclTabViewData::HasPane( sal_uInt8 nPaneId ) const
+{
+ switch( nPaneId )
+ {
+ case EXC_PANE_BOTTOMRIGHT: return (mnSplitX > 0) && (mnSplitY > 0);
+ case EXC_PANE_TOPRIGHT: return mnSplitX > 0;
+ case EXC_PANE_BOTTOMLEFT: return mnSplitY > 0;
+ case EXC_PANE_TOPLEFT: return true;
+ }
+ DBG_ERRORFILE( "XclExpPane::HasPane - wrong pane ID" );
+ return false;
+}
+
+const XclSelectionData* XclTabViewData::GetSelectionData( sal_uInt8 nPane ) const
+{
+ XclSelectionMap::const_iterator aIt = maSelMap.find( nPane );
+ return (aIt == maSelMap.end()) ? 0 : aIt->second.get();
+}
+
+XclSelectionData& XclTabViewData::CreateSelectionData( sal_uInt8 nPane )
+{
+ XclSelectionDataRef& rxSelData = maSelMap[ nPane ];
+ if( !rxSelData )
+ rxSelData.reset( new XclSelectionData );
+ return *rxSelData;
+}
+
+// ============================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */