/* -*- 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ #include "xmltabi.hxx" #include "xmlimprt.hxx" #include "xmlrowi.hxx" #include "xmlcoli.hxx" #include "xmlsceni.hxx" #include "xmlexternaltabi.hxx" #include "xmlnexpi.hxx" #include "document.hxx" #include "docuno.hxx" #include "olinetab.hxx" #include "XMLConverter.hxx" #include "XMLTableShapesContext.hxx" #include "XMLTableSourceContext.hxx" #include "XMLStylesImportHelper.hxx" #include "rangeutl.hxx" #include "externalrefmgr.hxx" #include "sheetdata.hxx" #include "xmlcondformat.hxx" #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; using namespace xmloff::token; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::xml::sax::XAttributeList; using ::rtl::OUString; /** * Determine whether this table is an external reference cache from its * name. There is currently no way of determining whether a table is a * regular table or an external reference cache other than examining the * name itself. We should probably introduce a new boolean value for * table:table element and use it instead of doing this, to make it more * reliable and future-proof. * * @param rName * * @return */ static bool lcl_isExternalRefCache(const rtl::OUString& rName, rtl::OUString& rUrl, rtl::OUString& rExtTabName) { // 'file:///path/to/file.ods'#MySheet // 'file:///path/to/file.ods'#MySheet with space // 'file:///path/to/file's.ods'#Sheet (Notice the quote in the file name. // That's allowed.) if ( rName.toChar() != '\'' ) // initial quote return false; // #i114504# Other schemes besides "file:" are also allowed. // CompareProtocolScheme is quick, only looks at the start of the string. INetProtocol eProt = INetURLObject::CompareProtocolScheme( rName.copy(1) ); if ( eProt == INET_PROT_NOT_VALID ) return false; rtl::OUString aPrefix = INetURLObject::GetScheme( eProt ); sal_Int32 nPrefLen = aPrefix.getLength(); rtl::OUStringBuffer aUrlBuf, aTabNameBuf; aUrlBuf.append( aPrefix ); sal_Int32 n = rName.getLength(); const sal_Unicode* p = rName.getStr(); bool bInUrl = true; sal_Unicode cPrev = 0; for (sal_Int32 i = nPrefLen+1; i < n; ++i) // start the loop after quote and prefix { const sal_Unicode c = p[i]; if (bInUrl) { // parsing file URL if (c == '#') { if (cPrev != '\'') return false; rUrl = aUrlBuf.makeStringAndClear(); rUrl = rUrl.copy(0, rUrl.getLength()-1); // remove the trailing single-quote. bInUrl = false; } else aUrlBuf.append(c); } else // parsing sheet name. aTabNameBuf.append(c); cPrev = c; } if (bInUrl) return false; if (aTabNameBuf.getLength() == 0) return false; rExtTabName = aTabNameBuf.makeStringAndClear(); return true; } ScXMLExternalTabData::ScXMLExternalTabData() : mpCacheTable(), mnRow(0), mnCol(0), mnFileId(0) { } //------------------------------------------------------------------ ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport, sal_uInt16 nPrfx, const ::rtl::OUString& rLName, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ) : SvXMLImportContext( rImport, nPrfx, rLName ), pExternalRefInfo(NULL), nStartOffset(-1), bStartFormPage(false), bPrintEntireSheet(true) { // get start offset in file (if available) nStartOffset = GetScImport().GetByteOffset(); ScXMLTabProtectionData aProtectData; rtl::OUString sName; rtl::OUString sStyleName; sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0); const SvXMLTokenMap& rAttrTokenMap = GetScImport().GetTableAttrTokenMap(); for( sal_Int16 i=0; i < nAttrCount; ++i ) { const rtl::OUString& sAttrName(xAttrList->getNameByIndex( i )); rtl::OUString aLocalName; sal_uInt16 nPrefix(GetScImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName )); const rtl::OUString& sValue(xAttrList->getValueByIndex( i )); switch( rAttrTokenMap.Get( nPrefix, aLocalName ) ) { case XML_TOK_TABLE_NAME: sName = sValue; break; case XML_TOK_TABLE_STYLE_NAME: sStyleName = sValue; break; case XML_TOK_TABLE_PROTECTED: aProtectData.mbProtected = IsXMLToken(sValue, XML_TRUE); break; case XML_TOK_TABLE_PRINT_RANGES: sPrintRanges = sValue; break; case XML_TOK_TABLE_PASSWORD: aProtectData.maPassword = sValue; break; case XML_TOK_TABLE_PASSHASH: aProtectData.meHash1 = ScPassHashHelper::getHashTypeFromURI(sValue); break; case XML_TOK_TABLE_PASSHASH_2: aProtectData.meHash2 = ScPassHashHelper::getHashTypeFromURI(sValue); break; case XML_TOK_TABLE_PRINT: { if (IsXMLToken(sValue, XML_FALSE)) bPrintEntireSheet = false; } break; } } rtl::OUString aExtUrl, aExtTabName; if (lcl_isExternalRefCache(sName, aExtUrl, aExtTabName)) { // This is an external ref cache table. pExternalRefInfo.reset(new ScXMLExternalTabData); pExternalRefInfo->maFileUrl = aExtUrl; ScDocument* pDoc = GetScImport().GetDocument(); if (pDoc) { ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); pExternalRefInfo->mnFileId = pRefMgr->getExternalFileId(aExtUrl); pExternalRefInfo->mpCacheTable = pRefMgr->getCacheTable(pExternalRefInfo->mnFileId, aExtTabName, true); pExternalRefInfo->mpCacheTable->setWholeTableCached(); } } else { // This is a regular table. GetScImport().GetTables().NewSheet(sName, sStyleName, aProtectData); } } ScXMLTableContext::~ScXMLTableContext() { } SvXMLImportContext *ScXMLTableContext::CreateChildContext( sal_uInt16 nPrefix, const ::rtl::OUString& rLName, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ) { const SvXMLTokenMap& rTokenMap(GetScImport().GetTableElemTokenMap()); sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLName); if (pExternalRefInfo.get()) { // We only care about the table-row and table-source elements for // external cache data. switch (nToken) { case XML_TOK_TABLE_ROW_GROUP: case XML_TOK_TABLE_HEADER_ROWS: case XML_TOK_TABLE_ROWS: // #i101319# don't discard rows in groups or header (repeat range) return new ScXMLExternalRefRowsContext( GetScImport(), nPrefix, rLName, xAttrList, *pExternalRefInfo); case XML_TOK_TABLE_ROW: return new ScXMLExternalRefRowContext( GetScImport(), nPrefix, rLName, xAttrList, *pExternalRefInfo); case XML_TOK_TABLE_SOURCE: return new ScXMLExternalRefTabSourceContext( GetScImport(), nPrefix, rLName, xAttrList, *pExternalRefInfo); default: ; } return new SvXMLImportContext(GetImport(), nPrefix, rLName); } SvXMLImportContext *pContext(0); switch (nToken) { case XML_TOK_TABLE_NAMED_EXPRESSIONS: { SCTAB nTab = GetScImport().GetTables().GetCurrentSheet(); pContext = new ScXMLNamedExpressionsContext( GetScImport(), nPrefix, rLName, xAttrList, new ScXMLNamedExpressionsContext::SheetLocalInserter(GetScImport(), nTab)); } break; case XML_TOK_TABLE_COL_GROUP: pContext = new ScXMLTableColsContext( GetScImport(), nPrefix, rLName, xAttrList, false, true ); break; case XML_TOK_TABLE_HEADER_COLS: pContext = new ScXMLTableColsContext( GetScImport(), nPrefix, rLName, xAttrList, true, false ); break; case XML_TOK_TABLE_COLS: pContext = new ScXMLTableColsContext( GetScImport(), nPrefix, rLName, xAttrList, false, false ); break; case XML_TOK_TABLE_COL: pContext = new ScXMLTableColContext( GetScImport(), nPrefix, rLName, xAttrList ); break; case XML_TOK_TABLE_PROTECTION: pContext = new ScXMLTableProtectionContext( GetScImport(), nPrefix, rLName, xAttrList ); break; case XML_TOK_TABLE_ROW_GROUP: pContext = new ScXMLTableRowsContext( GetScImport(), nPrefix, rLName, xAttrList, false, true ); break; case XML_TOK_TABLE_HEADER_ROWS: pContext = new ScXMLTableRowsContext( GetScImport(), nPrefix, rLName, xAttrList, true, false ); break; case XML_TOK_TABLE_ROWS: pContext = new ScXMLTableRowsContext( GetScImport(), nPrefix, rLName, xAttrList, false, false ); break; case XML_TOK_TABLE_ROW: pContext = new ScXMLTableRowContext( GetScImport(), nPrefix, rLName, xAttrList//, //this ); break; case XML_TOK_TABLE_SOURCE: pContext = new ScXMLTableSourceContext( GetScImport(), nPrefix, rLName, xAttrList); break; case XML_TOK_TABLE_SCENARIO: pContext = new ScXMLTableScenarioContext( GetScImport(), nPrefix, rLName, xAttrList); break; case XML_TOK_TABLE_SHAPES: pContext = new ScXMLTableShapesContext( GetScImport(), nPrefix, rLName, xAttrList); break; case XML_TOK_TABLE_FORMS: { GetScImport().GetFormImport()->startPage(GetScImport().GetTables().GetCurrentXDrawPage()); bStartFormPage = true; pContext = GetScImport().GetFormImport()->createOfficeFormsContext( GetScImport(), nPrefix, rLName ); } break; case XML_TOK_TABLE_EVENT_LISTENERS: case XML_TOK_TABLE_EVENT_LISTENERS_EXT: { // use XEventsSupplier interface of the sheet uno::Reference xSupplier( GetScImport().GetTables().GetCurrentXSheet(), uno::UNO_QUERY ); pContext = new XMLEventsImportContext( GetImport(), nPrefix, rLName, xSupplier ); } break; case XML_TOK_TABLE_CONDFORMATS: pContext = new ScXMLConditionalFormatsContext( GetScImport(), nPrefix, rLName ); break; default: ; } if( !pContext ) pContext = new SvXMLImportContext( GetImport(), nPrefix, rLName ); return pContext; } void ScXMLTableContext::EndElement() { ScXMLImport::MutexGuard aMutexGuard(GetScImport()); ScXMLImport& rImport = GetScImport(); rImport.GetStylesImportHelper()->EndTable(); ScDocument* pDoc(rImport.GetDocument()); if (!pDoc) return; ScMyTables& rTables = rImport.GetTables(); SCTAB nCurTab = rTables.GetCurrentSheet(); if (!sPrintRanges.isEmpty()) { Reference< sheet::XPrintAreas > xPrintAreas( rTables.GetCurrentXSheet(), UNO_QUERY); if( xPrintAreas.is() ) { Sequence< table::CellRangeAddress > aRangeList; ScRangeStringConverter::GetRangeListFromString( aRangeList, sPrintRanges, pDoc, ::formula::FormulaGrammar::CONV_OOO ); xPrintAreas->setPrintAreas( aRangeList ); } } else if (!bPrintEntireSheet) // Sheet has "print entire sheet" option by default. Remove it. pDoc->ClearPrintRanges(nCurTab); ScOutlineTable* pOutlineTable(pDoc->GetOutlineTable(nCurTab, false)); if (pOutlineTable) { ScOutlineArray* pColArray(pOutlineTable->GetColArray()); size_t nDepth = pColArray->GetDepth(); for (size_t i = 0; i < nDepth; ++i) { size_t nCount = pColArray->GetCount(i); for (size_t j = 0; j < nCount; ++j) { const ScOutlineEntry* pEntry = pColArray->GetEntry(i, j); if (pEntry->IsHidden()) pColArray->SetVisibleBelow(i, j, false); } } ScOutlineArray* pRowArray(pOutlineTable->GetRowArray()); nDepth = pRowArray->GetDepth(); for (size_t i = 0; i < nDepth; ++i) { size_t nCount = pRowArray->GetCount(i); for (size_t j = 0; j < nCount; ++j) { const ScOutlineEntry* pEntry = pRowArray->GetEntry(i, j); if (pEntry->IsHidden()) pRowArray->SetVisibleBelow(i, j, false); } } } if (rTables.HasDrawPage()) { if (rTables.HasXShapes()) { rImport.GetShapeImport()->popGroupAndSort(); uno::Reference < drawing::XShapes > xTempShapes(rTables.GetCurrentXShapes()); rImport.GetShapeImport()->endPage(xTempShapes); } if (bStartFormPage) rImport.GetFormImport()->endPage(); } rTables.DeleteTable(); rImport.ProgressBarIncrement(false); // store stream positions if (!pExternalRefInfo.get() && nStartOffset >= 0 /* && nEndOffset >= 0 */) { ScSheetSaveData* pSheetData = ScModelObj::getImplementation(rImport.GetModel())->GetSheetSaveData(); SCTAB nTab = rTables.GetCurrentSheet(); // pSheetData->AddStreamPos( nTab, nStartOffset, nEndOffset ); pSheetData->StartStreamPos( nTab, nStartOffset ); } } // ============================================================================ ScXMLImport& ScXMLTableProtectionContext::GetScImport() { return static_cast(GetImport()); } ScXMLTableProtectionContext::ScXMLTableProtectionContext( ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName, const Reference& xAttrList ) : SvXMLImportContext( rImport, nPrefix, rLName ) { const SvXMLTokenMap& rAttrTokenMap = GetScImport().GetTableProtectionAttrTokenMap(); bool bSelectProtectedCells = false; bool bSelectUnprotectedCells = false; sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; for (sal_Int16 i = 0; i < nAttrCount; ++i) { const OUString& aAttrName = xAttrList->getNameByIndex(i); const OUString aValue = xAttrList->getValueByIndex(i); OUString aLocalName; sal_uInt16 nLocalPrefix = GetScImport().GetNamespaceMap().GetKeyByAttrName( aAttrName, &aLocalName); switch (rAttrTokenMap.Get(nLocalPrefix, aLocalName)) { case XML_TOK_TABLE_SELECT_PROTECTED_CELLS: bSelectProtectedCells = IsXMLToken(aValue, XML_TRUE); break; case XML_TOK_TABLE_SELECT_UNPROTECTED_CELLS: bSelectUnprotectedCells = IsXMLToken(aValue, XML_TRUE); break; default: ; } } ScXMLTabProtectionData& rProtectData = GetScImport().GetTables().GetCurrentProtectionData(); rProtectData.mbSelectProtectedCells = bSelectProtectedCells; rProtectData.mbSelectUnprotectedCells = bSelectUnprotectedCells; } ScXMLTableProtectionContext::~ScXMLTableProtectionContext() { } SvXMLImportContext* ScXMLTableProtectionContext::CreateChildContext( sal_uInt16 /*nPrefix*/, const OUString& /*rLocalName*/, const Reference& /*xAttrList*/ ) { return NULL; } void ScXMLTableProtectionContext::EndElement() { } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */