2008-12-12 09:38:47 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
*
|
|
|
|
* Copyright 2008 by Sun Microsystems, Inc.
|
|
|
|
*
|
|
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
|
|
*
|
|
|
|
* $RCSfile: externalrefmgr.cxx,v $
|
|
|
|
* $Revision: 1.1.2.33 $
|
|
|
|
*
|
|
|
|
* 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 ---------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "externalrefmgr.hxx"
|
|
|
|
#include "document.hxx"
|
|
|
|
#include "token.hxx"
|
|
|
|
#include "tokenarray.hxx"
|
|
|
|
#include "address.hxx"
|
|
|
|
#include "tablink.hxx"
|
|
|
|
#include "docsh.hxx"
|
|
|
|
#include "scextopt.hxx"
|
|
|
|
#include "rangenam.hxx"
|
|
|
|
#include "cell.hxx"
|
|
|
|
#include "viewdata.hxx"
|
|
|
|
#include "tabvwsh.hxx"
|
|
|
|
#include "sc.hrc"
|
|
|
|
|
|
|
|
#include "sfx2/app.hxx"
|
|
|
|
#include "sfx2/docfilt.hxx"
|
|
|
|
#include "sfx2/docfile.hxx"
|
|
|
|
#include "sfx2/fcontnr.hxx"
|
|
|
|
#include "sfx2/sfxsids.hrc"
|
|
|
|
#include "sfx2/objsh.hxx"
|
|
|
|
#include "svtools/broadcast.hxx"
|
|
|
|
#include "svtools/smplhint.hxx"
|
|
|
|
#include "svtools/itemset.hxx"
|
|
|
|
#include "svtools/stritem.hxx"
|
|
|
|
#include "svtools/urihelper.hxx"
|
|
|
|
#include "svtools/zformat.hxx"
|
|
|
|
#include "svx/linkmgr.hxx"
|
|
|
|
#include "tools/urlobj.hxx"
|
|
|
|
#include "unotools/ucbhelper.hxx"
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
using ::std::auto_ptr;
|
|
|
|
using ::com::sun::star::uno::Any;
|
|
|
|
using ::rtl::OUString;
|
|
|
|
using ::std::vector;
|
|
|
|
using ::std::find;
|
|
|
|
using ::std::find_if;
|
|
|
|
using ::std::distance;
|
|
|
|
using ::std::pair;
|
|
|
|
using ::std::list;
|
|
|
|
|
|
|
|
#define SRCDOC_LIFE_SPAN 6000 // 1 minute (in 100th of a sec)
|
|
|
|
#define SRCDOC_SCAN_INTERVAL 1000*5 // every 5 seconds (in msec)
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class TabNameSearchPredicate : ::std::unary_function<bool, ScExternalRefCache::TableName>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit TabNameSearchPredicate(const String& rSearchName) :
|
|
|
|
maSearchName(ScGlobal::pCharClass->upper(rSearchName))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(const ScExternalRefCache::TableName& rTabNameSet) const
|
|
|
|
{
|
|
|
|
// Ok, I'm doing case insensitive search here.
|
|
|
|
return rTabNameSet.maUpperName.Equals(maSearchName);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
String maSearchName;
|
|
|
|
};
|
|
|
|
|
|
|
|
class FindSrcFileByName : public ::std::unary_function<ScExternalRefManager::SrcFileData, bool>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FindSrcFileByName(const String& rMatchName) :
|
|
|
|
mrMatchName(rMatchName)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(const ScExternalRefManager::SrcFileData& rSrcData) const
|
|
|
|
{
|
|
|
|
return rSrcData.maFileName.Equals(mrMatchName);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const String& mrMatchName;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
ScExternalRefCache::Table::Table()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::Table::~Table()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::Table::setCell(SCCOL nCol, SCROW nRow, TokenRef pToken, sal_uInt32 nFmtIndex)
|
|
|
|
{
|
|
|
|
using ::std::pair;
|
|
|
|
RowsDataType::iterator itrRow = maRows.find(nRow);
|
|
|
|
if (itrRow == maRows.end())
|
|
|
|
{
|
|
|
|
// This row does not exist yet.
|
|
|
|
pair<RowsDataType::iterator, bool> res = maRows.insert(
|
|
|
|
RowsDataType::value_type(nRow, RowDataType()));
|
|
|
|
|
|
|
|
if (!res.second)
|
|
|
|
return;
|
|
|
|
|
|
|
|
itrRow = res.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert this token into the specified column location. I don't need to
|
|
|
|
// check for existing data. Just overwrite it.
|
|
|
|
RowDataType& rRow = itrRow->second;
|
|
|
|
ScExternalRefCache::Cell aCell;
|
|
|
|
aCell.mxToken = pToken;
|
|
|
|
aCell.mnFmtIndex = nFmtIndex;
|
|
|
|
rRow.insert(RowDataType::value_type(nCol, aCell));
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TokenRef ScExternalRefCache::Table::getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex) const
|
|
|
|
{
|
|
|
|
RowsDataType::const_iterator itrTable = maRows.find(nRow);
|
|
|
|
if (itrTable == maRows.end())
|
|
|
|
{
|
|
|
|
// this table doesn't have the specified row.
|
|
|
|
return TokenRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
const RowDataType& rRowData = itrTable->second;
|
|
|
|
RowDataType::const_iterator itrRow = rRowData.find(nCol);
|
|
|
|
if (itrRow == rRowData.end())
|
|
|
|
{
|
|
|
|
// this row doesn't have the specified column.
|
|
|
|
return TokenRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
const Cell& rCell = itrRow->second;
|
|
|
|
if (pnFmtIndex)
|
|
|
|
*pnFmtIndex = rCell.mnFmtIndex;
|
|
|
|
|
|
|
|
return rCell.mxToken;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScExternalRefCache::Table::hasRow( SCROW nRow ) const
|
|
|
|
{
|
|
|
|
RowsDataType::const_iterator itrRow = maRows.find(nRow);
|
|
|
|
return itrRow != maRows.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows) const
|
|
|
|
{
|
|
|
|
vector<SCROW> aRows;
|
|
|
|
aRows.reserve(maRows.size());
|
|
|
|
RowsDataType::const_iterator itr = maRows.begin(), itrEnd = maRows.end();
|
|
|
|
for (; itr != itrEnd; ++itr)
|
|
|
|
aRows.push_back(itr->first);
|
|
|
|
|
|
|
|
// hash map is not ordered, so we need to explicitly sort it.
|
|
|
|
::std::sort(aRows.begin(), aRows.end());
|
|
|
|
rRows.swap(aRows);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols) const
|
|
|
|
{
|
|
|
|
RowsDataType::const_iterator itrRow = maRows.find(nRow);
|
|
|
|
if (itrRow == maRows.end())
|
|
|
|
// this table doesn't have the specified row.
|
|
|
|
return;
|
|
|
|
|
|
|
|
const RowDataType& rRowData = itrRow->second;
|
|
|
|
vector<SCCOL> aCols;
|
|
|
|
aCols.reserve(rRowData.size());
|
|
|
|
RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
|
|
|
|
for (; itrCol != itrColEnd; ++itrCol)
|
|
|
|
aCols.push_back(itrCol->first);
|
|
|
|
|
|
|
|
// hash map is not ordered, so we need to explicitly sort it.
|
|
|
|
::std::sort(aCols.begin(), aCols.end());
|
|
|
|
rCols.swap(aCols);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::Table::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
|
|
|
|
{
|
|
|
|
RowsDataType::const_iterator itrRow = maRows.begin(), itrRowEnd = maRows.end();
|
|
|
|
for (; itrRow != itrRowEnd; ++itrRow)
|
|
|
|
{
|
|
|
|
const RowDataType& rRowData = itrRow->second;
|
|
|
|
RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
|
|
|
|
for (; itrCol != itrColEnd; ++itrCol)
|
|
|
|
{
|
|
|
|
const Cell& rCell = itrCol->second;
|
|
|
|
rNumFmts.push_back(rCell.mnFmtIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
ScExternalRefCache::TableName::TableName(const String& rUpper, const String& rReal) :
|
|
|
|
maUpperName(rUpper), maRealName(rReal)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
ScExternalRefCache::CellFormat::CellFormat() :
|
|
|
|
mbIsSet(false), mnType(NUMBERFORMAT_ALL), mnIndex(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
ScExternalRefCache::ScExternalRefCache()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
ScExternalRefCache::~ScExternalRefCache()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
const String* ScExternalRefCache::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const
|
|
|
|
{
|
|
|
|
DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
|
|
|
|
if (itrDoc == maDocs.end())
|
|
|
|
{
|
|
|
|
// specified document is not cached.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const DocItem& rDoc = itrDoc->second;
|
|
|
|
TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(
|
|
|
|
ScGlobal::pCharClass->upper(rTabName));
|
|
|
|
if (itrTabId == rDoc.maTableNameIndex.end())
|
|
|
|
{
|
|
|
|
// the specified table is not in cache.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &rDoc.maTableNames[itrTabId->second].maRealName;
|
|
|
|
}
|
|
|
|
|
|
|
|
const String* ScExternalRefCache::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const
|
|
|
|
{
|
|
|
|
DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
|
|
|
|
if (itrDoc == maDocs.end())
|
|
|
|
{
|
|
|
|
// specified document is not cached.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const DocItem& rDoc = itrDoc->second;
|
|
|
|
NamePairMap::const_iterator itr = rDoc.maRealRangeNameMap.find(
|
|
|
|
ScGlobal::pCharClass->upper(rRangeName));
|
|
|
|
if (itr == rDoc.maRealRangeNameMap.end())
|
|
|
|
// range name not found.
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return &itr->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TokenRef ScExternalRefCache::getCellData(
|
|
|
|
sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, sal_uInt32* pnFmtIndex)
|
|
|
|
{
|
|
|
|
DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
|
|
|
|
if (itrDoc == maDocs.end())
|
|
|
|
{
|
|
|
|
// specified document is not cached.
|
|
|
|
return TokenRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
const DocItem& rDoc = itrDoc->second;
|
|
|
|
TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(
|
|
|
|
ScGlobal::pCharClass->upper(rTabName));
|
|
|
|
if (itrTabId == rDoc.maTableNameIndex.end())
|
|
|
|
{
|
|
|
|
// the specified table is not in cache.
|
|
|
|
return TokenRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
const TableTypeRef& pTableData = rDoc.maTables[itrTabId->second];
|
|
|
|
if (!pTableData.get())
|
|
|
|
{
|
|
|
|
// the table data is not instantiated yet.
|
|
|
|
return TokenRef();
|
|
|
|
}
|
|
|
|
return pTableData->getCell(nCol, nRow, pnFmtIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange)
|
|
|
|
{
|
|
|
|
DocDataType::iterator itrDoc = maDocs.find(nFileId);
|
|
|
|
if (itrDoc == maDocs.end())
|
|
|
|
// specified document is not cached.
|
|
|
|
return TokenArrayRef();
|
|
|
|
|
|
|
|
DocItem& rDoc = itrDoc->second;
|
|
|
|
RangeArrayMap::const_iterator itrRange = rDoc.maRangeArrays.find(rRange);
|
|
|
|
if (itrRange != rDoc.maRangeArrays.end())
|
|
|
|
{
|
|
|
|
return itrRange->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find(
|
|
|
|
ScGlobal::pCharClass->upper(rTabName));
|
|
|
|
if (itrTabId == rDoc.maTableNameIndex.end())
|
|
|
|
// the specified table is not in cache.
|
|
|
|
return TokenArrayRef();
|
|
|
|
|
|
|
|
const ScAddress& s = rRange.aStart;
|
|
|
|
const ScAddress& e = rRange.aEnd;
|
|
|
|
|
|
|
|
SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
|
|
|
|
SCCOL nCol1 = s.Col(), nCol2 = e.Col();
|
|
|
|
SCROW nRow1 = s.Row(), nRow2 = e.Row();
|
|
|
|
|
|
|
|
// Make sure I have all the tables cached.
|
|
|
|
size_t nTabFirstId = itrTabId->second;
|
|
|
|
size_t nTabLastId = nTabFirstId + nTab2 - nTab1;
|
|
|
|
if (nTabLastId >= rDoc.maTables.size())
|
|
|
|
// not all tables are cached.
|
|
|
|
return TokenArrayRef();
|
|
|
|
|
|
|
|
TokenArrayRef pArray(new ScTokenArray);
|
|
|
|
bool bFirstTab = true;
|
|
|
|
for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab)
|
|
|
|
{
|
|
|
|
TableTypeRef pTab = rDoc.maTables[nTab];
|
|
|
|
if (!pTab.get())
|
|
|
|
return TokenArrayRef();
|
|
|
|
|
|
|
|
ScMatrixRef xMat = new ScMatrix(
|
|
|
|
static_cast<SCSIZE>(nCol2-nCol1+1), static_cast<SCSIZE>(nRow2-nRow1+1));
|
|
|
|
|
|
|
|
for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
|
|
|
|
{
|
|
|
|
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
|
|
|
|
{
|
|
|
|
ScToken* pToken = pTab->getCell(nCol, nRow).get();
|
|
|
|
if (!pToken)
|
|
|
|
return TokenArrayRef();
|
|
|
|
|
|
|
|
SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
|
|
|
|
switch (pToken->GetType())
|
|
|
|
{
|
|
|
|
case svDouble:
|
|
|
|
xMat->PutDouble(pToken->GetDouble(), nC, nR);
|
|
|
|
break;
|
|
|
|
case svString:
|
|
|
|
xMat->PutString(pToken->GetString(), nC, nR);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
xMat->PutEmpty(nC, nR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bFirstTab)
|
|
|
|
pArray->AddOpCode(ocSep);
|
|
|
|
|
|
|
|
ScMatrix* pMat2 = xMat;
|
|
|
|
ScMatrixToken aToken(pMat2);
|
|
|
|
pArray->AddToken(aToken);
|
|
|
|
|
|
|
|
bFirstTab = false;
|
|
|
|
}
|
|
|
|
rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray));
|
|
|
|
return pArray;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TokenArrayRef ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId, const String& rName)
|
|
|
|
{
|
|
|
|
DocItem* pDoc = getDocItem(nFileId);
|
|
|
|
if (!pDoc)
|
|
|
|
return TokenArrayRef();
|
|
|
|
|
|
|
|
RangeNameMap& rMap = pDoc->maRangeNames;
|
|
|
|
RangeNameMap::const_iterator itr = rMap.find(
|
|
|
|
ScGlobal::pCharClass->upper(rName));
|
|
|
|
if (itr == rMap.end())
|
|
|
|
return TokenArrayRef();
|
|
|
|
|
|
|
|
return itr->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray)
|
|
|
|
{
|
|
|
|
DocItem* pDoc = getDocItem(nFileId);
|
|
|
|
if (!pDoc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
String aUpperName = ScGlobal::pCharClass->upper(rName);
|
|
|
|
RangeNameMap& rMap = pDoc->maRangeNames;
|
|
|
|
rMap.insert(RangeNameMap::value_type(aUpperName, pArray));
|
|
|
|
pDoc->maRealRangeNameMap.insert(NamePairMap::value_type(aUpperName, rName));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol,
|
|
|
|
TokenRef pToken, sal_uInt32 nFmtIndex)
|
|
|
|
{
|
|
|
|
if (!isDocInitialized(nFileId))
|
|
|
|
return;
|
|
|
|
|
|
|
|
using ::std::pair;
|
|
|
|
DocItem* pDocItem = getDocItem(nFileId);
|
|
|
|
if (!pDocItem)
|
|
|
|
return;
|
|
|
|
|
|
|
|
DocItem& rDoc = *pDocItem;
|
|
|
|
|
|
|
|
// See if the table by this name already exists.
|
|
|
|
TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(
|
|
|
|
ScGlobal::pCharClass->upper(rTabName));
|
|
|
|
if (itrTabName == rDoc.maTableNameIndex.end())
|
|
|
|
// Table not found. Maybe the table name or the file id is wrong ???
|
|
|
|
return;
|
|
|
|
|
|
|
|
TableTypeRef& pTableData = rDoc.maTables[itrTabName->second];
|
|
|
|
if (!pTableData.get())
|
|
|
|
pTableData.reset(new Table);
|
|
|
|
|
|
|
|
pTableData->setCell(nCol, nRow, pToken, nFmtIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const vector<SingleRangeData>& rData,
|
|
|
|
TokenArrayRef pArray)
|
|
|
|
{
|
|
|
|
using ::std::pair;
|
|
|
|
if (rData.empty() || !isDocInitialized(nFileId))
|
|
|
|
// nothing to cache
|
|
|
|
return;
|
|
|
|
|
|
|
|
// First, get the document item for the given file ID.
|
|
|
|
DocItem* pDocItem = getDocItem(nFileId);
|
|
|
|
if (!pDocItem)
|
|
|
|
return;
|
|
|
|
|
|
|
|
DocItem& rDoc = *pDocItem;
|
|
|
|
|
|
|
|
// Now, find the table position of the first table to cache.
|
|
|
|
const String& rFirstTabName = rData.front().maTableName;
|
|
|
|
TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(
|
|
|
|
ScGlobal::pCharClass->upper(rFirstTabName));
|
|
|
|
if (itrTabName == rDoc.maTableNameIndex.end())
|
|
|
|
{
|
|
|
|
// table index not found.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t nTab1 = itrTabName->second;
|
|
|
|
SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
|
|
|
|
SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
|
|
|
|
vector<SingleRangeData>::const_iterator itrDataBeg = rData.begin(), itrDataEnd = rData.end();
|
|
|
|
for (vector<SingleRangeData>::const_iterator itrData = itrDataBeg; itrData != itrDataEnd; ++itrData)
|
|
|
|
{
|
|
|
|
size_t i = nTab1 + ::std::distance(itrDataBeg, itrData);
|
|
|
|
TableTypeRef& pTabData = rDoc.maTables[i];
|
|
|
|
if (!pTabData.get())
|
|
|
|
pTabData.reset(new Table);
|
|
|
|
|
|
|
|
for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
|
|
|
|
{
|
|
|
|
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
|
|
|
|
{
|
|
|
|
SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
|
|
|
|
TokenRef pToken;
|
|
|
|
const ScMatrixRef& pMat = itrData->mpRangeData;
|
|
|
|
if (pMat->IsValue(nC, nR))
|
|
|
|
pToken.reset(new ScDoubleToken(pMat->GetDouble(nC, nR)));
|
|
|
|
else if (pMat->IsString(nC, nR))
|
|
|
|
pToken.reset(new ScStringToken(pMat->GetString(nC, nR)));
|
|
|
|
else
|
|
|
|
pToken.reset(new ScEmptyCellToken(false, false));
|
|
|
|
|
|
|
|
pTabData->setCell(nCol, nRow, pToken);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScExternalRefCache::isDocInitialized(sal_uInt16 nFileId)
|
|
|
|
{
|
|
|
|
DocItem* pDoc = getDocItem(nFileId);
|
|
|
|
if (!pDoc)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return pDoc->mbInitFromSource;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lcl_getTableDataIndex(const ScExternalRefCache::TableNameIndexMap& rMap, const String& rName, size_t& rIndex)
|
|
|
|
{
|
|
|
|
ScExternalRefCache::TableNameIndexMap::const_iterator itr = rMap.find(rName);
|
|
|
|
if (itr == rMap.end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
rIndex = itr->second;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId, const vector<String>& rTabNames)
|
|
|
|
{
|
|
|
|
DocItem* pDoc = getDocItem(nFileId);
|
|
|
|
if (!pDoc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
size_t n = rTabNames.size();
|
|
|
|
|
|
|
|
// table name list - the list must include all table names in the source
|
|
|
|
// document and only to be populated when loading the source document, not
|
|
|
|
// when loading cached data from, say, Excel XCT/CRN records.
|
|
|
|
vector<TableName> aNewTabNames;
|
|
|
|
aNewTabNames.reserve(n);
|
|
|
|
for (vector<String>::const_iterator itr = rTabNames.begin(), itrEnd = rTabNames.end();
|
|
|
|
itr != itrEnd; ++itr)
|
|
|
|
{
|
|
|
|
TableName aNameItem(ScGlobal::pCharClass->upper(*itr), *itr);
|
|
|
|
aNewTabNames.push_back(aNameItem);
|
|
|
|
}
|
|
|
|
pDoc->maTableNames.swap(aNewTabNames);
|
|
|
|
|
|
|
|
// data tables - preserve any existing data that may have been set during
|
|
|
|
// file import.
|
|
|
|
vector<TableTypeRef> aNewTables(n);
|
|
|
|
for (size_t i = 0; i < n; ++i)
|
|
|
|
{
|
|
|
|
size_t nIndex;
|
|
|
|
if (lcl_getTableDataIndex(pDoc->maTableNameIndex, pDoc->maTableNames[i].maUpperName, nIndex))
|
|
|
|
{
|
|
|
|
aNewTables[i] = pDoc->maTables[nIndex];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pDoc->maTables.swap(aNewTables);
|
|
|
|
|
|
|
|
// name index map
|
|
|
|
TableNameIndexMap aNewNameIndex;
|
|
|
|
for (size_t i = 0; i < n; ++i)
|
|
|
|
aNewNameIndex.insert(TableNameIndexMap::value_type(pDoc->maTableNames[i].maUpperName, i));
|
|
|
|
pDoc->maTableNameIndex.swap(aNewNameIndex);
|
|
|
|
|
|
|
|
pDoc->mbInitFromSource = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
String ScExternalRefCache::getTableName(sal_uInt16 nFileId, size_t nCacheId) const
|
|
|
|
{
|
|
|
|
if( DocItem* pDoc = getDocItem( nFileId ) )
|
|
|
|
if( nCacheId < pDoc->maTableNames.size() )
|
|
|
|
return pDoc->maTableNames[ nCacheId ].maRealName;
|
|
|
|
return EMPTY_STRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const
|
|
|
|
{
|
|
|
|
rTabNames.clear();
|
|
|
|
DocItem* pDoc = getDocItem(nFileId);
|
|
|
|
if (!pDoc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
size_t n = pDoc->maTableNames.size();
|
|
|
|
rTabNames.reserve(n);
|
|
|
|
for (vector<TableName>::const_iterator itr = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end();
|
|
|
|
itr != itrEnd; ++itr)
|
|
|
|
rTabNames.push_back(itr->maRealName);
|
|
|
|
}
|
|
|
|
|
|
|
|
SCsTAB ScExternalRefCache::getTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const
|
|
|
|
{
|
|
|
|
DocItem* pDoc = getDocItem(nFileId);
|
|
|
|
if (!pDoc)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin();
|
|
|
|
vector<TableName>::const_iterator itrEnd = pDoc->maTableNames.end();
|
|
|
|
|
|
|
|
vector<TableName>::const_iterator itrStartTab = ::std::find_if( itrBeg, itrEnd,
|
|
|
|
TabNameSearchPredicate( rStartTabName));
|
|
|
|
if (itrStartTab == itrEnd)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
vector<TableName>::const_iterator itrEndTab = ::std::find_if( itrBeg, itrEnd,
|
|
|
|
TabNameSearchPredicate( rEndTabName));
|
|
|
|
if (itrEndTab == itrEnd)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
size_t nStartDist = ::std::distance( itrBeg, itrStartTab);
|
|
|
|
size_t nEndDist = ::std::distance( itrBeg, itrEndTab);
|
|
|
|
return nStartDist <= nEndDist ? nEndDist - nStartDist + 1 : -(nStartDist - nEndDist + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
|
|
|
|
{
|
|
|
|
using ::std::sort;
|
|
|
|
using ::std::unique;
|
|
|
|
|
|
|
|
vector<sal_uInt32> aNumFmts;
|
|
|
|
for (DocDataType::const_iterator itrDoc = maDocs.begin(), itrDocEnd = maDocs.end();
|
|
|
|
itrDoc != itrDocEnd; ++itrDoc)
|
|
|
|
{
|
|
|
|
const vector<TableTypeRef>& rTables = itrDoc->second.maTables;
|
|
|
|
for (vector<TableTypeRef>::const_iterator itrTab = rTables.begin(), itrTabEnd = rTables.end();
|
|
|
|
itrTab != itrTabEnd; ++itrTab)
|
|
|
|
{
|
|
|
|
TableTypeRef pTab = *itrTab;
|
|
|
|
if (!pTab)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pTab->getAllNumberFormats(aNumFmts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove duplicates.
|
|
|
|
sort(aNumFmts.begin(), aNumFmts.end());
|
|
|
|
aNumFmts.erase(unique(aNumFmts.begin(), aNumFmts.end()), aNumFmts.end());
|
|
|
|
rNumFmts.swap(aNumFmts);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScExternalRefCache::hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const
|
|
|
|
{
|
|
|
|
DocItem* pDoc = getDocItem(nFileId);
|
|
|
|
if (!pDoc)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
String aUpperName = ScGlobal::pCharClass->upper(rTabName);
|
|
|
|
vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end();
|
|
|
|
vector<TableName>::const_iterator itr = ::std::find_if(
|
|
|
|
itrBeg, itrEnd, TabNameSearchPredicate(aUpperName));
|
|
|
|
|
|
|
|
return itr != itrEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t ScExternalRefCache::getCacheTableCount(sal_uInt16 nFileId) const
|
|
|
|
{
|
|
|
|
DocItem* pDoc = getDocItem(nFileId);
|
|
|
|
return pDoc ? pDoc->maTables.size() : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
|
|
|
|
{
|
|
|
|
DocItem* pDoc = getDocItem(nFileId);
|
|
|
|
if (!pDoc || nTabIndex >= pDoc->maTables.size())
|
|
|
|
return TableTypeRef();
|
|
|
|
|
|
|
|
return pDoc->maTables[nTabIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex)
|
|
|
|
{
|
|
|
|
DocItem* pDoc = getDocItem(nFileId);
|
|
|
|
if (!pDoc)
|
|
|
|
return TableTypeRef();
|
|
|
|
|
|
|
|
DocItem& rDoc = *pDoc;
|
|
|
|
|
|
|
|
size_t nIndex;
|
|
|
|
String aTabNameUpper = ScGlobal::pCharClass->upper(rTabName);
|
|
|
|
if (lcl_getTableDataIndex(rDoc.maTableNameIndex, aTabNameUpper, nIndex))
|
|
|
|
{
|
|
|
|
// specified table found.
|
|
|
|
if( pnIndex ) *pnIndex = nIndex;
|
|
|
|
return rDoc.maTables[nIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bCreateNew)
|
|
|
|
return TableTypeRef();
|
|
|
|
|
|
|
|
// Specified table doesn't exist yet. Create one.
|
|
|
|
nIndex = rDoc.maTables.size();
|
|
|
|
if( pnIndex ) *pnIndex = nIndex;
|
|
|
|
TableTypeRef pTab(new Table);
|
|
|
|
rDoc.maTables.push_back(pTab);
|
|
|
|
rDoc.maTableNames.push_back(TableName(aTabNameUpper, rTabName));
|
|
|
|
rDoc.maTableNameIndex.insert(
|
|
|
|
TableNameIndexMap::value_type(aTabNameUpper, nIndex));
|
|
|
|
return pTab;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefCache::clearCache(sal_uInt16 nFileId)
|
|
|
|
{
|
|
|
|
maDocs.erase(nFileId);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::DocItem* ScExternalRefCache::getDocItem(sal_uInt16 nFileId) const
|
|
|
|
{
|
|
|
|
using ::std::pair;
|
|
|
|
DocDataType::iterator itrDoc = maDocs.find(nFileId);
|
|
|
|
if (itrDoc == maDocs.end())
|
|
|
|
{
|
|
|
|
// specified document is not cached.
|
|
|
|
pair<DocDataType::iterator, bool> res = maDocs.insert(
|
|
|
|
DocDataType::value_type(nFileId, DocItem()));
|
|
|
|
|
|
|
|
if (!res.second)
|
|
|
|
// insertion failed.
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
itrDoc = res.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &itrDoc->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
ScExternalRefLink::ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter) :
|
|
|
|
::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL, FORMAT_FILE),
|
|
|
|
mnFileId(nFileId),
|
|
|
|
maFilterName(rFilter),
|
|
|
|
mpDoc(pDoc),
|
|
|
|
mbDoRefresh(true)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefLink::~ScExternalRefLink()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefLink::Closed()
|
|
|
|
{
|
|
|
|
ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
|
|
|
|
pMgr->removeSrcDocument(mnFileId, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rValue*/)
|
|
|
|
{
|
|
|
|
if (!mbDoRefresh)
|
|
|
|
return;
|
|
|
|
|
|
|
|
String aFile, aFilter;
|
|
|
|
mpDoc->GetLinkManager()->GetDisplayNames(this, NULL, &aFile, NULL, &aFilter);
|
|
|
|
ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
|
|
|
|
const String* pCurFile = pMgr->getExternalFileName(mnFileId);
|
|
|
|
if (!pCurFile)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (pCurFile->Equals(aFile))
|
|
|
|
{
|
|
|
|
// Refresh the current source document.
|
|
|
|
pMgr->refreshNames(mnFileId);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// The source document has changed.
|
|
|
|
pMgr->switchSrcFile(mnFileId, aFile);
|
|
|
|
maFilterName = aFilter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefLink::Edit(Window* pParent, const Link& /*rEndEditHdl*/)
|
|
|
|
{
|
|
|
|
SvBaseLink::Edit(pParent, LINK(this, ScExternalRefLink, ExternalRefEndEditHdl));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefLink::SetDoReferesh(bool b)
|
|
|
|
{
|
|
|
|
mbDoRefresh = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPL_LINK( ScExternalRefLink, ExternalRefEndEditHdl, ::sfx2::SvBaseLink*, EMPTYARG )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
static ScToken* lcl_convertToToken(ScBaseCell* pCell)
|
|
|
|
{
|
|
|
|
if (!pCell || pCell->HasEmptyData())
|
|
|
|
{
|
|
|
|
bool bInherited = (pCell && pCell->GetCellType() == CELLTYPE_FORMULA);
|
|
|
|
return new ScEmptyCellToken( bInherited, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (pCell->GetCellType())
|
|
|
|
{
|
|
|
|
case CELLTYPE_EDIT:
|
|
|
|
{
|
|
|
|
String aStr;
|
|
|
|
static_cast<ScEditCell*>(pCell)->GetString(aStr);
|
|
|
|
return new ScStringToken(aStr);
|
|
|
|
}
|
|
|
|
//break;
|
|
|
|
case CELLTYPE_STRING:
|
|
|
|
{
|
|
|
|
String aStr;
|
|
|
|
static_cast<ScStringCell*>(pCell)->GetString(aStr);
|
|
|
|
return new ScStringToken(aStr);
|
|
|
|
}
|
|
|
|
//break;
|
|
|
|
case CELLTYPE_VALUE:
|
|
|
|
{
|
|
|
|
double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
|
|
|
|
return new ScDoubleToken(fVal);
|
|
|
|
}
|
|
|
|
//break;
|
|
|
|
case CELLTYPE_FORMULA:
|
|
|
|
{
|
|
|
|
ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
|
|
|
|
USHORT nError = pFCell->GetErrCode();
|
|
|
|
if (nError)
|
|
|
|
return new ScErrorToken( nError);
|
|
|
|
else if (pFCell->IsValue())
|
|
|
|
{
|
|
|
|
double fVal = pFCell->GetValue();
|
|
|
|
return new ScDoubleToken(fVal);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
String aStr;
|
|
|
|
pFCell->GetString(aStr);
|
|
|
|
return new ScStringToken(aStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//break;
|
|
|
|
default:
|
|
|
|
DBG_ERROR("attempted to convert an unknown cell type.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, const ScRange& rRange,
|
|
|
|
vector<ScExternalRefCache::SingleRangeData>& rCacheData)
|
|
|
|
{
|
|
|
|
const ScAddress& s = rRange.aStart;
|
|
|
|
const ScAddress& e = rRange.aEnd;
|
|
|
|
|
|
|
|
SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
|
|
|
|
SCCOL nCol1 = s.Col(), nCol2 = e.Col();
|
|
|
|
SCROW nRow1 = s.Row(), nRow2 = e.Row();
|
|
|
|
|
|
|
|
if (nTab2 != nTab1)
|
|
|
|
// For now, we don't support multi-sheet ranges intentionally because
|
|
|
|
// we don't have a way to express them in a single token. In the
|
|
|
|
// future we can introduce a new stack variable type svMatrixList with
|
|
|
|
// a new token type that can store a 3D matrix value and convert a 3D
|
|
|
|
// range to it.
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
auto_ptr<ScTokenArray> pArray(new ScTokenArray);
|
|
|
|
bool bFirstTab = true;
|
|
|
|
vector<ScExternalRefCache::SingleRangeData>::iterator
|
|
|
|
itrCache = rCacheData.begin(), itrCacheEnd = rCacheData.end();
|
|
|
|
for (SCTAB nTab = nTab1; nTab <= nTab2 && itrCache != itrCacheEnd; ++nTab, ++itrCache)
|
|
|
|
{
|
|
|
|
ScMatrixRef xMat = new ScMatrix(
|
|
|
|
static_cast<SCSIZE>(nCol2-nCol1+1),
|
|
|
|
static_cast<SCSIZE>(nRow2-nRow1+1));
|
|
|
|
|
|
|
|
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
|
|
|
|
{
|
|
|
|
for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
|
|
|
|
{
|
|
|
|
SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
|
|
|
|
ScBaseCell* pCell;
|
|
|
|
pSrcDoc->GetCell(nCol, nRow, nTab, pCell);
|
|
|
|
if (!pCell || pCell->HasEmptyData())
|
|
|
|
xMat->PutEmpty(nC, nR);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (pCell->GetCellType())
|
|
|
|
{
|
|
|
|
case CELLTYPE_EDIT:
|
|
|
|
{
|
|
|
|
String aStr;
|
|
|
|
static_cast<ScEditCell*>(pCell)->GetString(aStr);
|
|
|
|
xMat->PutString(aStr, nC, nR);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CELLTYPE_STRING:
|
|
|
|
{
|
|
|
|
String aStr;
|
|
|
|
static_cast<ScStringCell*>(pCell)->GetString(aStr);
|
|
|
|
xMat->PutString(aStr, nC, nR);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CELLTYPE_VALUE:
|
|
|
|
{
|
|
|
|
double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
|
|
|
|
xMat->PutDouble(fVal, nC, nR);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CELLTYPE_FORMULA:
|
|
|
|
{
|
|
|
|
ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
|
|
|
|
USHORT nError = pFCell->GetErrCode();
|
|
|
|
if (nError)
|
|
|
|
xMat->PutDouble( CreateDoubleError( nError), nC, nR);
|
|
|
|
else if (pFCell->IsValue())
|
|
|
|
{
|
|
|
|
double fVal = pFCell->GetValue();
|
|
|
|
xMat->PutDouble(fVal, nC, nR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
String aStr;
|
|
|
|
pFCell->GetString(aStr);
|
|
|
|
xMat->PutString(aStr, nC, nR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBG_ERROR("attempted to convert an unknown cell type.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!bFirstTab)
|
|
|
|
pArray->AddOpCode(ocSep);
|
|
|
|
|
|
|
|
ScMatrix* pMat2 = xMat;
|
|
|
|
ScMatrixToken aToken(pMat2);
|
|
|
|
pArray->AddToken(aToken);
|
|
|
|
|
|
|
|
itrCache->mpRangeData = xMat;
|
|
|
|
|
|
|
|
bFirstTab = false;
|
|
|
|
}
|
|
|
|
return pArray.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefManager::ScExternalRefManager(ScDocument* pDoc) :
|
|
|
|
mpDoc(pDoc)
|
|
|
|
{
|
|
|
|
maSrcDocTimer.SetTimeoutHdl( LINK(this, ScExternalRefManager, TimeOutHdl) );
|
|
|
|
maSrcDocTimer.SetTimeout(SRCDOC_SCAN_INTERVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefManager::~ScExternalRefManager()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
String ScExternalRefManager::getCacheTableName(sal_uInt16 nFileId, size_t nTabIndex) const
|
|
|
|
{
|
|
|
|
return maRefCache.getTableName(nFileId, nTabIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
|
|
|
|
{
|
|
|
|
return maRefCache.getCacheTable(nFileId, nTabIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex)
|
|
|
|
{
|
|
|
|
return maRefCache.getCacheTable(nFileId, rTabName, bCreateNew, pnIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
ScExternalRefManager::RefCells::TabItem::TabItem(SCTAB nIndex) :
|
|
|
|
mnIndex(nIndex)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefManager::RefCells::TabItem::TabItem(const TabItem& r) :
|
|
|
|
mnIndex(r.mnIndex),
|
|
|
|
maCols(r.maCols)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefManager::RefCells::RefCells()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefManager::RefCells::~RefCells()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
list<ScExternalRefManager::RefCells::TabItemRef>::iterator ScExternalRefManager::RefCells::getTabPos(SCTAB nTab)
|
|
|
|
{
|
|
|
|
list<TabItemRef>::iterator itr = maTables.begin(), itrEnd = maTables.end();
|
|
|
|
for (; itr != itrEnd; ++itr)
|
|
|
|
if ((*itr)->mnIndex >= nTab)
|
|
|
|
return itr;
|
|
|
|
// Not found. return the end position.
|
|
|
|
return itrEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::RefCells::insertCell(const ScAddress& rAddr)
|
|
|
|
{
|
|
|
|
SCTAB nTab = rAddr.Tab();
|
|
|
|
SCCOL nCol = rAddr.Col();
|
|
|
|
SCROW nRow = rAddr.Row();
|
|
|
|
|
|
|
|
// Search by table index.
|
|
|
|
list<TabItemRef>::iterator itrTab = getTabPos(nTab);
|
|
|
|
TabItemRef xTabRef;
|
|
|
|
if (itrTab == maTables.end())
|
|
|
|
{
|
|
|
|
// All previous tables come before the specificed table.
|
|
|
|
xTabRef.reset(new TabItem(nTab));
|
|
|
|
maTables.push_back(xTabRef);
|
|
|
|
}
|
|
|
|
else if ((*itrTab)->mnIndex > nTab)
|
|
|
|
{
|
|
|
|
// Insert at the current iterator position.
|
|
|
|
xTabRef.reset(new TabItem(nTab));
|
|
|
|
maTables.insert(itrTab, xTabRef);
|
|
|
|
}
|
|
|
|
else if ((*itrTab)->mnIndex == nTab)
|
|
|
|
{
|
|
|
|
// The table found.
|
|
|
|
xTabRef = *itrTab;
|
|
|
|
}
|
|
|
|
ColSet& rCols = xTabRef->maCols;
|
|
|
|
|
|
|
|
// Then by column index.
|
|
|
|
ColSet::iterator itrCol = rCols.find(nCol);
|
|
|
|
if (itrCol == rCols.end())
|
|
|
|
{
|
|
|
|
RowSet aRows;
|
|
|
|
pair<ColSet::iterator, bool> r = rCols.insert(ColSet::value_type(nCol, aRows));
|
|
|
|
if (!r.second)
|
|
|
|
// column insertion failed.
|
|
|
|
return;
|
|
|
|
itrCol = r.first;
|
|
|
|
}
|
|
|
|
RowSet& rRows = itrCol->second;
|
|
|
|
|
|
|
|
// Finally, insert the row index.
|
|
|
|
rRows.insert(nRow);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::RefCells::removeCell(const ScAddress& rAddr)
|
|
|
|
{
|
|
|
|
SCTAB nTab = rAddr.Tab();
|
|
|
|
SCCOL nCol = rAddr.Col();
|
|
|
|
SCROW nRow = rAddr.Row();
|
|
|
|
|
|
|
|
// Search by table index.
|
|
|
|
list<TabItemRef>::iterator itrTab = getTabPos(nTab);
|
|
|
|
if (itrTab == maTables.end() || (*itrTab)->mnIndex != nTab)
|
|
|
|
// No such table.
|
|
|
|
return;
|
|
|
|
|
|
|
|
ColSet& rCols = (*itrTab)->maCols;
|
|
|
|
|
|
|
|
// Then by column index.
|
|
|
|
ColSet::iterator itrCol = rCols.find(nCol);
|
|
|
|
if (itrCol == rCols.end())
|
|
|
|
// No such column
|
|
|
|
return;
|
|
|
|
|
|
|
|
RowSet& rRows = itrCol->second;
|
|
|
|
rRows.erase(nRow);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::RefCells::moveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy)
|
|
|
|
{
|
|
|
|
if (nOldTab == nNewTab)
|
|
|
|
// Nothing to do here.
|
|
|
|
return;
|
|
|
|
|
|
|
|
list<TabItemRef>::iterator itrOld = getTabPos(nOldTab);
|
|
|
|
if (itrOld == maTables.end() || (*itrOld)->mnIndex != nOldTab)
|
|
|
|
// No table to move or copy.
|
|
|
|
return;
|
|
|
|
|
|
|
|
list<TabItemRef>::iterator itrNew = getTabPos(nNewTab);
|
|
|
|
if (bCopy)
|
|
|
|
{
|
|
|
|
// Simply make a duplicate of the original table, insert it at the
|
|
|
|
// new tab position, and increment the table index for all tables
|
|
|
|
// that come after that inserted table.
|
|
|
|
|
|
|
|
TabItemRef xNewTab(new TabItem(*(*itrOld)));
|
|
|
|
xNewTab->mnIndex = nNewTab;
|
|
|
|
maTables.insert(itrNew, xNewTab);
|
|
|
|
list<TabItemRef>::iterator itr = itrNew, itrEnd = maTables.end();
|
|
|
|
for (++itr; itr != itrEnd; ++itr)
|
|
|
|
(*itr)->mnIndex += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (itrOld == itrNew)
|
|
|
|
{
|
|
|
|
// No need to move the table. Just update the table index.
|
|
|
|
(*itrOld)->mnIndex = nNewTab;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nOldTab < nNewTab)
|
|
|
|
{
|
|
|
|
// Iterate from the old tab position to the new tab position (not
|
|
|
|
// inclusive of the old tab itself), and decrement their tab
|
|
|
|
// index by one.
|
|
|
|
list<TabItemRef>::iterator itr = itrOld;
|
|
|
|
for (++itr; itr != itrNew; ++itr)
|
|
|
|
(*itr)->mnIndex -= 1;
|
|
|
|
|
|
|
|
// Insert a duplicate of the original table. This does not
|
|
|
|
// invalidate the iterators.
|
|
|
|
(*itrOld)->mnIndex = nNewTab - 1;
|
|
|
|
if (itrNew == maTables.end())
|
|
|
|
maTables.push_back(*itrOld);
|
|
|
|
else
|
|
|
|
maTables.insert(itrNew, *itrOld);
|
|
|
|
|
|
|
|
// Remove the original table.
|
|
|
|
maTables.erase(itrOld);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// nNewTab < nOldTab
|
|
|
|
|
|
|
|
// Iterate from the new tab position to the one before the old tab
|
|
|
|
// position, and increment their tab index by one.
|
|
|
|
list<TabItemRef>::iterator itr = itrNew;
|
|
|
|
for (++itr; itr != itrOld; ++itr)
|
|
|
|
(*itr)->mnIndex += 1;
|
|
|
|
|
|
|
|
(*itrOld)->mnIndex = nNewTab;
|
|
|
|
maTables.insert(itrNew, *itrOld);
|
|
|
|
|
|
|
|
// Remove the original table.
|
|
|
|
maTables.erase(itrOld);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::RefCells::insertTable(SCTAB nPos)
|
|
|
|
{
|
|
|
|
TabItemRef xNewTab(new TabItem(nPos));
|
|
|
|
list<TabItemRef>::iterator itr = getTabPos(nPos);
|
|
|
|
if (itr == maTables.end())
|
|
|
|
maTables.push_back(xNewTab);
|
|
|
|
else
|
|
|
|
maTables.insert(itr, xNewTab);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::RefCells::removeTable(SCTAB nPos)
|
|
|
|
{
|
|
|
|
list<TabItemRef>::iterator itr = getTabPos(nPos);
|
|
|
|
if (itr == maTables.end())
|
|
|
|
// nothing to remove.
|
|
|
|
return;
|
|
|
|
|
|
|
|
maTables.erase(itr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::RefCells::refreshAllCells(ScExternalRefManager& rRefMgr)
|
|
|
|
{
|
|
|
|
// Get ALL the cell positions for re-compilation.
|
|
|
|
for (list<TabItemRef>::iterator itrTab = maTables.begin(), itrTabEnd = maTables.end();
|
|
|
|
itrTab != itrTabEnd; ++itrTab)
|
|
|
|
{
|
|
|
|
SCTAB nTab = (*itrTab)->mnIndex;
|
|
|
|
ColSet& rCols = (*itrTab)->maCols;
|
|
|
|
for (ColSet::iterator itrCol = rCols.begin(), itrColEnd = rCols.end();
|
|
|
|
itrCol != itrColEnd; ++itrCol)
|
|
|
|
{
|
|
|
|
SCCOL nCol = itrCol->first;
|
|
|
|
RowSet& rRows = itrCol->second;
|
|
|
|
RowSet aNewRows;
|
|
|
|
for (RowSet::iterator itrRow = rRows.begin(), itrRowEnd = rRows.end();
|
|
|
|
itrRow != itrRowEnd; ++itrRow)
|
|
|
|
{
|
|
|
|
SCROW nRow = *itrRow;
|
|
|
|
ScAddress aCell(nCol, nRow, nTab);
|
|
|
|
if (rRefMgr.compileTokensByCell(aCell))
|
|
|
|
// This cell still contains an external refernce.
|
|
|
|
aNewRows.insert(nRow);
|
|
|
|
}
|
|
|
|
// Update the rows so that cells with no external references are
|
|
|
|
// no longer tracked.
|
|
|
|
rRows.swap(aNewRows);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const
|
|
|
|
{
|
|
|
|
maRefCache.getAllTableNames(nFileId, rTabNames);
|
|
|
|
}
|
|
|
|
|
|
|
|
SCsTAB ScExternalRefManager::getCachedTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const
|
|
|
|
{
|
|
|
|
return maRefCache.getTabSpan( nFileId, rStartTabName, rEndTabName);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::getAllCachedNumberFormats(vector<sal_uInt32>& rNumFmts) const
|
|
|
|
{
|
|
|
|
maRefCache.getAllNumberFormats(rNumFmts);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScExternalRefManager::hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const
|
|
|
|
{
|
|
|
|
return maRefCache.hasCacheTable(nFileId, rTabName);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t ScExternalRefManager::getCacheTableCount(sal_uInt16 nFileId) const
|
|
|
|
{
|
|
|
|
return maRefCache.getCacheTableCount(nFileId);
|
|
|
|
}
|
|
|
|
|
|
|
|
sal_uInt16 ScExternalRefManager::getExternalFileCount() const
|
|
|
|
{
|
|
|
|
return static_cast< sal_uInt16 >( maSrcFiles.size() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray)
|
|
|
|
{
|
|
|
|
ScExternalRefCache::TokenArrayRef pArray(rArray.Clone());
|
|
|
|
maRefCache.setRangeNameTokens(nFileId, rName, pArray);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
|
|
|
|
sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell,
|
|
|
|
const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt)
|
|
|
|
{
|
|
|
|
if (pCurPos)
|
|
|
|
insertRefCell(nFileId, *pCurPos);
|
|
|
|
|
|
|
|
maybeLinkExternalFile(nFileId);
|
|
|
|
|
|
|
|
if (pTab)
|
|
|
|
*pTab = -1;
|
|
|
|
|
|
|
|
if (pFmt)
|
|
|
|
pFmt->mbIsSet = false;
|
|
|
|
|
|
|
|
// Check if the given table name and the cell position is cached.
|
|
|
|
sal_uInt32 nFmtIndex = 0;
|
|
|
|
ScExternalRefCache::TokenRef pToken = maRefCache.getCellData(
|
|
|
|
nFileId, rTabName, rCell.Row(), rCell.Col(), &nFmtIndex);
|
|
|
|
if (pToken)
|
|
|
|
{
|
|
|
|
if (pFmt)
|
|
|
|
{
|
|
|
|
short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
|
|
|
|
if (nFmtType != NUMBERFORMAT_UNDEFINED)
|
|
|
|
{
|
|
|
|
pFmt->mbIsSet = true;
|
|
|
|
pFmt->mnIndex = nFmtIndex;
|
|
|
|
pFmt->mnType = nFmtType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pToken;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reference not cached. read from the source document.
|
|
|
|
ScDocument* pSrcDoc = getSrcDocument(nFileId);
|
|
|
|
if (!pSrcDoc)
|
|
|
|
{
|
|
|
|
return ScExternalRefCache::TokenRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
ScBaseCell* pCell = NULL;
|
|
|
|
SCTAB nTab;
|
|
|
|
if (!pSrcDoc->GetTable(rTabName, nTab))
|
|
|
|
{
|
|
|
|
// specified table name doesn't exist in the source document.
|
|
|
|
return ScExternalRefCache::TokenRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pTab)
|
|
|
|
*pTab = nTab;
|
|
|
|
|
|
|
|
pSrcDoc->GetCell(rCell.Col(), rCell.Row(), nTab, pCell);
|
|
|
|
ScExternalRefCache::TokenRef pTok(lcl_convertToToken(pCell));
|
|
|
|
|
|
|
|
pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), nTab, nFmtIndex);
|
|
|
|
nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc);
|
|
|
|
if (pFmt)
|
|
|
|
{
|
|
|
|
short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
|
|
|
|
if (nFmtType != NUMBERFORMAT_UNDEFINED)
|
|
|
|
{
|
|
|
|
pFmt->mbIsSet = true;
|
|
|
|
pFmt->mnIndex = nFmtIndex;
|
|
|
|
pFmt->mnType = nFmtType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pTok.get())
|
|
|
|
{
|
|
|
|
// Generate an error for unresolvable cells.
|
|
|
|
pTok.reset( new ScErrorToken( errNoValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now, insert the token into cache table.
|
|
|
|
maRefCache.setCellData(nFileId, rTabName, rCell.Row(), rCell.Col(), pTok, nFmtIndex);
|
|
|
|
return pTok;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
|
|
|
|
{
|
|
|
|
if (pCurPos)
|
|
|
|
insertRefCell(nFileId, *pCurPos);
|
|
|
|
|
|
|
|
maybeLinkExternalFile(nFileId);
|
|
|
|
|
|
|
|
// Check if the given table name and the cell position is cached.
|
|
|
|
ScExternalRefCache::TokenArrayRef p = maRefCache.getCellRangeData(nFileId, rTabName, rRange);
|
|
|
|
if (p.get())
|
|
|
|
return p;
|
|
|
|
|
|
|
|
ScDocument* pSrcDoc = getSrcDocument(nFileId);
|
|
|
|
if (!pSrcDoc)
|
|
|
|
return ScExternalRefCache::TokenArrayRef();
|
|
|
|
|
|
|
|
SCTAB nTab1;
|
|
|
|
if (!pSrcDoc->GetTable(rTabName, nTab1))
|
|
|
|
// specified table name doesn't exist in the source document.
|
|
|
|
return ScExternalRefCache::TokenArrayRef();
|
|
|
|
|
|
|
|
ScRange aRange(rRange);
|
|
|
|
SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
|
|
|
|
|
|
|
|
vector<ScExternalRefCache::SingleRangeData> aCacheData;
|
|
|
|
aCacheData.reserve(nTabSpan+1);
|
|
|
|
aCacheData.push_back(ScExternalRefCache::SingleRangeData());
|
|
|
|
aCacheData.back().maTableName = ScGlobal::pCharClass->upper(rTabName);
|
|
|
|
|
|
|
|
for (SCTAB i = 1; i < nTabSpan + 1; ++i)
|
|
|
|
{
|
|
|
|
String aTabName;
|
|
|
|
if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
|
|
|
|
// source document doesn't have any table by the specified name.
|
|
|
|
break;
|
|
|
|
|
|
|
|
aCacheData.push_back(ScExternalRefCache::SingleRangeData());
|
|
|
|
aCacheData.back().maTableName = ScGlobal::pCharClass->upper(aTabName);
|
|
|
|
}
|
|
|
|
|
|
|
|
aRange.aStart.SetTab(nTab1);
|
|
|
|
aRange.aEnd.SetTab(nTab1 + nTabSpan);
|
|
|
|
|
|
|
|
ScExternalRefCache::TokenArrayRef pArray;
|
|
|
|
pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
|
|
|
|
|
|
|
|
if (pArray)
|
|
|
|
// Cache these values.
|
|
|
|
maRefCache.setCellRangeData(nFileId, rRange, aCacheData, pArray);
|
|
|
|
|
|
|
|
return pArray;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
|
|
|
|
{
|
|
|
|
if (pCurPos)
|
|
|
|
insertRefCell(nFileId, *pCurPos);
|
|
|
|
|
|
|
|
maybeLinkExternalFile(nFileId);
|
|
|
|
|
|
|
|
ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName);
|
|
|
|
if (pArray.get())
|
|
|
|
return pArray;
|
|
|
|
|
|
|
|
ScDocument* pSrcDoc = getSrcDocument(nFileId);
|
|
|
|
if (!pSrcDoc)
|
|
|
|
return ScExternalRefCache::TokenArrayRef();
|
|
|
|
|
|
|
|
ScRangeName* pExtNames = pSrcDoc->GetRangeName();
|
|
|
|
String aUpperName = ScGlobal::pCharClass->upper(rName);
|
|
|
|
USHORT n;
|
|
|
|
bool bRes = pExtNames->SearchNameUpper(aUpperName, n);
|
|
|
|
if (!bRes)
|
|
|
|
return ScExternalRefCache::TokenArrayRef();
|
|
|
|
|
|
|
|
ScRangeData* pRangeData = (*pExtNames)[n];
|
|
|
|
if (!pRangeData)
|
|
|
|
return ScExternalRefCache::TokenArrayRef();
|
|
|
|
|
|
|
|
// Parse all tokens in this external range data, and replace each absolute
|
|
|
|
// reference token with an external reference token, and cache them. Also
|
|
|
|
// register the source document with the link manager if it's a new
|
|
|
|
// source.
|
|
|
|
|
|
|
|
ScExternalRefCache::TokenArrayRef pNew(new ScTokenArray);
|
|
|
|
|
|
|
|
ScTokenArray* pCode = pRangeData->GetCode();
|
|
|
|
for (ScToken* pToken = pCode->First(); pToken; pToken = pCode->Next())
|
|
|
|
{
|
|
|
|
bool bTokenAdded = false;
|
|
|
|
switch (pToken->GetType())
|
|
|
|
{
|
|
|
|
case svSingleRef:
|
|
|
|
{
|
CWS-TOOLING: integrate CWS frmdlg
2008-12-18 09:13:09 +0100 oj r265667 : merge from odff05
2008-12-18 07:58:16 +0100 oj r265658 : #i94555# patch from <regina>, ODFF:
Add GAMMA, CHISQDIST, CHISQINV.
Make the 'cumulative' parameter of GAMMADIST optional.
Adapt the domain of CHIDIST to allow negative x.
Remove the constraint "degrees of freedom < 1.0E5" from CHIDIST and CHIINV.
Plus a mechanism to write the now optional parameter of GAMMADIST to PODF and
ODFF if omitted, for backwards compatibility.
2008-12-15 14:06:11 +0100 oj r265490 : CWS-TOOLING: rebase CWS frmdlg to trunk@264807 (milestone: DEV300:m37)
2008-12-15 13:55:28 +0100 oj r265488 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:55:07 +0100 oj r265487 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:54:48 +0100 oj r265486 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:54:36 +0100 oj r265485 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:54:24 +0100 oj r265484 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:48:11 +0100 oj r265483 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:31:12 +0100 oj r265479 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:13:58 +0100 oj r265477 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:10:09 +0100 oj r265476 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:05:11 +0100 oj r265475 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 10:47:17 +0100 oj r265467 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 10:46:19 +0100 oj r265466 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 10:45:47 +0100 oj r265465 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 07:35:07 +0100 oj r265458 : add dependency to formula
2008-12-15 07:34:24 +0100 oj r265457 : add dependency to formula
2008-12-12 13:22:00 +0100 msc r265413 : #i97089#
2008-12-12 13:20:25 +0100 msc r265412 : #i97089#
2008-12-12 12:35:12 +0100 msc r265406 : #i97089#
2008-12-12 12:34:16 +0100 msc r265405 : #i97089#
2008-12-12 12:33:05 +0100 msc r265404 : #i97089#
2008-12-12 12:31:11 +0100 msc r265403 : #i97089#
2008-12-08 11:59:10 +0100 oj r264981 : insert RTL_LOG
2008-12-08 11:50:17 +0100 oj r264980 : some small changes
2008-12-05 12:57:57 +0100 oj r264902 : eof changed
2008-12-05 12:56:46 +0100 oj r264901 : eof changed
2008-12-05 12:28:47 +0100 oj r264899 : wrong var used
2008-12-05 10:08:57 +0100 oj r264890 : token order reversed
2008-12-04 13:49:22 +0100 oc r264843 : #i96688: Adapt autotests because of outsourced functionwizard
2008-12-04 13:45:27 +0100 oc r264842 : #i96688: Adapt autotests because of outsourced functionwizard
2008-12-04 13:42:54 +0100 oc r264841 : #i96688: Adapt autotests because of outsourced functionwizard
2008-12-04 13:37:41 +0100 oc r264840 : #i96688: Adapt autotests because of outsourced functionwizard
2008-12-04 13:34:11 +0100 oc r264839 : #i96688: Adapt autotests because of outsourced functionwizard
2008-12-04 12:35:31 +0100 oj r264835 : new help ids for struct and function tabpage
2008-12-04 12:00:35 +0100 oj r264828 : set explicit help id
2008-12-03 14:53:27 +0100 oj r264786 : #i96845# change ref button
2008-12-03 14:51:49 +0100 oj r264785 : #i96845# change ref button
2008-12-03 08:51:57 +0100 oj r264746 : convert dos to unix lineends
2008-12-03 08:50:45 +0100 oj r264745 : convert dos to unix lineends
2008-12-03 08:50:05 +0100 oj r264744 : convert dos to unix lineends
2008-12-02 12:28:33 +0100 oj r264686 : clear help text when new helpid is set
2008-12-02 12:28:02 +0100 oj r264685 : set help id for listbox category
2008-12-02 07:15:56 +0100 oj r264655 : remove define to auto generate help ids
2008-12-01 14:36:43 +0100 oj r264604 : use temp var
2008-12-01 14:18:31 +0100 oj r264601 : moved ScJumpToken to formula
2008-12-01 14:18:11 +0100 oj r264600 : moved ScJumpToken to formula
2008-12-01 14:14:35 +0100 oj r264599 : moved ScJumpToken from sc
2008-12-01 10:48:51 +0100 oj r264589 : change quickhelptext from Shrink to Select
2008-12-01 10:28:41 +0100 oj r264588 : fix opcode data, has to be Any.Void
2008-11-28 11:16:48 +0100 oj r264532 : add help ids
2008-11-28 10:16:56 +0100 oj r264529 : set help id
2008-11-28 10:16:43 +0100 oj r264528 : set help id
2008-11-26 13:55:04 +0100 oj r264381 : #94535# use of optional instead of deleting a string myself and some small changes
2008-11-26 09:53:20 +0100 oj r264346 : compile error with debug/without debug
2008-11-25 07:41:28 +0100 oj r264271 : put static into the method which make use of them
2008-11-24 08:16:07 +0100 oj r264196 : removed not needed classes for op code
2008-11-24 08:13:44 +0100 oj r264195 : removed not needed classes for op code
2008-11-21 14:05:53 +0100 oj r264135 : make GetOpCode inline
2008-11-21 12:35:27 +0100 oj r264124 : hold symbols
2008-11-20 09:27:27 +0100 oj r264028 : merged code from DEV300_m35 which got lost
2008-11-19 20:42:12 +0100 oj r264022 : more changes for formula dialog remove
2008-11-19 20:37:41 +0100 oj r264021 : removed unused var
2008-11-19 20:35:35 +0100 oj r264020 : some more changes at token
2008-11-19 10:59:47 +0100 oj r263967 : deleted
2008-11-19 10:58:24 +0100 oj r263966 : add forui and for res files
2008-11-18 15:27:36 +0100 oj r263777 : unused para removed
2008-11-18 15:23:23 +0100 oj r263775 : add insert button to add field dlg
2008-11-18 13:39:53 +0100 oj r263764 : enable the formula dialog as well for conditional print as for conditional formatting
2008-11-18 12:03:25 +0100 oj r263760 : rename isRef in IsRef
2008-11-17 11:46:16 +0100 oj r263711 : patches for function handling
2008-11-17 11:36:22 +0100 oj r263710 : add new for forui and res file
2008-11-17 09:21:12 +0100 oj r263704 : patches for some resource for libformula
2008-11-15 12:45:30 +0100 oj r263701 : changes for formula editor extraction
2008-11-07 08:23:27 +0100 oj r263416 : merge from DEV300:m35
2008-11-07 08:22:35 +0100 oj r263415 : merge from DEV300:m35
2008-11-07 08:22:16 +0100 oj r263414 : merge from DEV300:m35
2008-11-07 08:21:41 +0100 oj r263413 : merge from DEV300:m35
2008-11-07 08:21:31 +0100 oj r263412 : merge from DEV300:m35
2008-11-07 08:20:38 +0100 oj r263411 : merge from DEV300:m35
2008-11-07 08:20:00 +0100 oj r263410 : merge from DEV300:m35
2008-11-07 08:18:50 +0100 oj r263409 : merge from DEV300:m35
2008-11-07 08:18:19 +0100 oj r263408 : merge from DEV300:m35
2008-11-07 08:10:27 +0100 oj r263407 : merge from DEV300:m35
2008-10-21 07:43:46 +0200 oj r262560 : some compile errors resolved
2008-10-17 16:40:01 +0200 oj r262291 : dep for 1st target
2008-10-07 10:08:39 +0200 oj r262077 : copy
2008-10-07 09:45:31 +0200 oj r262076 : #i94535#
2008-10-07 09:44:26 +0200 oj r262075 : #i94535# new base class
2008-10-07 09:43:21 +0200 oj r262074 : moved to formula
2008-10-07 09:41:51 +0200 oj r262073 : new images
2008-10-07 09:03:01 +0200 oj r262072 : new ids for formula
2008-10-02 08:46:27 +0200 oj r262024 : #i94535# move the formula compiler to formula
2008-10-02 08:08:54 +0200 oj r262023 : #i94535#
2008-10-02 08:06:28 +0200 oj r262022 : #i94535#
2008-10-02 08:05:52 +0200 oj r262021 : #i94535#
2008-10-01 17:15:29 +0200 oj r262014 : #i94535#
2008-10-01 17:12:40 +0200 oj r262013 : new module formula
2008-10-01 17:04:55 +0200 oj r262012 : #i94535#
2008-10-01 16:49:03 +0200 oj r262010 : #i94535#
2008-10-01 16:46:59 +0200 oj r262009 : #i94535#
2009-01-08 10:47:13 +00:00
|
|
|
const ScSingleRefData& rRef = pToken->GetSingleRef();
|
2008-12-12 09:38:47 +00:00
|
|
|
String aTabName;
|
|
|
|
pSrcDoc->GetName(rRef.nTab, aTabName);
|
|
|
|
ScExternalSingleRefToken aNewToken(nFileId, aTabName, pToken->GetSingleRef());
|
|
|
|
pNew->AddToken(aNewToken);
|
|
|
|
bTokenAdded = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case svDoubleRef:
|
|
|
|
{
|
CWS-TOOLING: integrate CWS frmdlg
2008-12-18 09:13:09 +0100 oj r265667 : merge from odff05
2008-12-18 07:58:16 +0100 oj r265658 : #i94555# patch from <regina>, ODFF:
Add GAMMA, CHISQDIST, CHISQINV.
Make the 'cumulative' parameter of GAMMADIST optional.
Adapt the domain of CHIDIST to allow negative x.
Remove the constraint "degrees of freedom < 1.0E5" from CHIDIST and CHIINV.
Plus a mechanism to write the now optional parameter of GAMMADIST to PODF and
ODFF if omitted, for backwards compatibility.
2008-12-15 14:06:11 +0100 oj r265490 : CWS-TOOLING: rebase CWS frmdlg to trunk@264807 (milestone: DEV300:m37)
2008-12-15 13:55:28 +0100 oj r265488 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:55:07 +0100 oj r265487 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:54:48 +0100 oj r265486 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:54:36 +0100 oj r265485 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:54:24 +0100 oj r265484 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:48:11 +0100 oj r265483 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:31:12 +0100 oj r265479 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:13:58 +0100 oj r265477 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:10:09 +0100 oj r265476 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 13:05:11 +0100 oj r265475 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 10:47:17 +0100 oj r265467 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 10:46:19 +0100 oj r265466 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 10:45:47 +0100 oj r265465 : CWS-TOOLING: do not delete this file, it's needed for 'cws rebase -C'
CWS: frmdlg
New MWS: DEV300
New milestone: m37
2008-12-15 07:35:07 +0100 oj r265458 : add dependency to formula
2008-12-15 07:34:24 +0100 oj r265457 : add dependency to formula
2008-12-12 13:22:00 +0100 msc r265413 : #i97089#
2008-12-12 13:20:25 +0100 msc r265412 : #i97089#
2008-12-12 12:35:12 +0100 msc r265406 : #i97089#
2008-12-12 12:34:16 +0100 msc r265405 : #i97089#
2008-12-12 12:33:05 +0100 msc r265404 : #i97089#
2008-12-12 12:31:11 +0100 msc r265403 : #i97089#
2008-12-08 11:59:10 +0100 oj r264981 : insert RTL_LOG
2008-12-08 11:50:17 +0100 oj r264980 : some small changes
2008-12-05 12:57:57 +0100 oj r264902 : eof changed
2008-12-05 12:56:46 +0100 oj r264901 : eof changed
2008-12-05 12:28:47 +0100 oj r264899 : wrong var used
2008-12-05 10:08:57 +0100 oj r264890 : token order reversed
2008-12-04 13:49:22 +0100 oc r264843 : #i96688: Adapt autotests because of outsourced functionwizard
2008-12-04 13:45:27 +0100 oc r264842 : #i96688: Adapt autotests because of outsourced functionwizard
2008-12-04 13:42:54 +0100 oc r264841 : #i96688: Adapt autotests because of outsourced functionwizard
2008-12-04 13:37:41 +0100 oc r264840 : #i96688: Adapt autotests because of outsourced functionwizard
2008-12-04 13:34:11 +0100 oc r264839 : #i96688: Adapt autotests because of outsourced functionwizard
2008-12-04 12:35:31 +0100 oj r264835 : new help ids for struct and function tabpage
2008-12-04 12:00:35 +0100 oj r264828 : set explicit help id
2008-12-03 14:53:27 +0100 oj r264786 : #i96845# change ref button
2008-12-03 14:51:49 +0100 oj r264785 : #i96845# change ref button
2008-12-03 08:51:57 +0100 oj r264746 : convert dos to unix lineends
2008-12-03 08:50:45 +0100 oj r264745 : convert dos to unix lineends
2008-12-03 08:50:05 +0100 oj r264744 : convert dos to unix lineends
2008-12-02 12:28:33 +0100 oj r264686 : clear help text when new helpid is set
2008-12-02 12:28:02 +0100 oj r264685 : set help id for listbox category
2008-12-02 07:15:56 +0100 oj r264655 : remove define to auto generate help ids
2008-12-01 14:36:43 +0100 oj r264604 : use temp var
2008-12-01 14:18:31 +0100 oj r264601 : moved ScJumpToken to formula
2008-12-01 14:18:11 +0100 oj r264600 : moved ScJumpToken to formula
2008-12-01 14:14:35 +0100 oj r264599 : moved ScJumpToken from sc
2008-12-01 10:48:51 +0100 oj r264589 : change quickhelptext from Shrink to Select
2008-12-01 10:28:41 +0100 oj r264588 : fix opcode data, has to be Any.Void
2008-11-28 11:16:48 +0100 oj r264532 : add help ids
2008-11-28 10:16:56 +0100 oj r264529 : set help id
2008-11-28 10:16:43 +0100 oj r264528 : set help id
2008-11-26 13:55:04 +0100 oj r264381 : #94535# use of optional instead of deleting a string myself and some small changes
2008-11-26 09:53:20 +0100 oj r264346 : compile error with debug/without debug
2008-11-25 07:41:28 +0100 oj r264271 : put static into the method which make use of them
2008-11-24 08:16:07 +0100 oj r264196 : removed not needed classes for op code
2008-11-24 08:13:44 +0100 oj r264195 : removed not needed classes for op code
2008-11-21 14:05:53 +0100 oj r264135 : make GetOpCode inline
2008-11-21 12:35:27 +0100 oj r264124 : hold symbols
2008-11-20 09:27:27 +0100 oj r264028 : merged code from DEV300_m35 which got lost
2008-11-19 20:42:12 +0100 oj r264022 : more changes for formula dialog remove
2008-11-19 20:37:41 +0100 oj r264021 : removed unused var
2008-11-19 20:35:35 +0100 oj r264020 : some more changes at token
2008-11-19 10:59:47 +0100 oj r263967 : deleted
2008-11-19 10:58:24 +0100 oj r263966 : add forui and for res files
2008-11-18 15:27:36 +0100 oj r263777 : unused para removed
2008-11-18 15:23:23 +0100 oj r263775 : add insert button to add field dlg
2008-11-18 13:39:53 +0100 oj r263764 : enable the formula dialog as well for conditional print as for conditional formatting
2008-11-18 12:03:25 +0100 oj r263760 : rename isRef in IsRef
2008-11-17 11:46:16 +0100 oj r263711 : patches for function handling
2008-11-17 11:36:22 +0100 oj r263710 : add new for forui and res file
2008-11-17 09:21:12 +0100 oj r263704 : patches for some resource for libformula
2008-11-15 12:45:30 +0100 oj r263701 : changes for formula editor extraction
2008-11-07 08:23:27 +0100 oj r263416 : merge from DEV300:m35
2008-11-07 08:22:35 +0100 oj r263415 : merge from DEV300:m35
2008-11-07 08:22:16 +0100 oj r263414 : merge from DEV300:m35
2008-11-07 08:21:41 +0100 oj r263413 : merge from DEV300:m35
2008-11-07 08:21:31 +0100 oj r263412 : merge from DEV300:m35
2008-11-07 08:20:38 +0100 oj r263411 : merge from DEV300:m35
2008-11-07 08:20:00 +0100 oj r263410 : merge from DEV300:m35
2008-11-07 08:18:50 +0100 oj r263409 : merge from DEV300:m35
2008-11-07 08:18:19 +0100 oj r263408 : merge from DEV300:m35
2008-11-07 08:10:27 +0100 oj r263407 : merge from DEV300:m35
2008-10-21 07:43:46 +0200 oj r262560 : some compile errors resolved
2008-10-17 16:40:01 +0200 oj r262291 : dep for 1st target
2008-10-07 10:08:39 +0200 oj r262077 : copy
2008-10-07 09:45:31 +0200 oj r262076 : #i94535#
2008-10-07 09:44:26 +0200 oj r262075 : #i94535# new base class
2008-10-07 09:43:21 +0200 oj r262074 : moved to formula
2008-10-07 09:41:51 +0200 oj r262073 : new images
2008-10-07 09:03:01 +0200 oj r262072 : new ids for formula
2008-10-02 08:46:27 +0200 oj r262024 : #i94535# move the formula compiler to formula
2008-10-02 08:08:54 +0200 oj r262023 : #i94535#
2008-10-02 08:06:28 +0200 oj r262022 : #i94535#
2008-10-02 08:05:52 +0200 oj r262021 : #i94535#
2008-10-01 17:15:29 +0200 oj r262014 : #i94535#
2008-10-01 17:12:40 +0200 oj r262013 : new module formula
2008-10-01 17:04:55 +0200 oj r262012 : #i94535#
2008-10-01 16:49:03 +0200 oj r262010 : #i94535#
2008-10-01 16:46:59 +0200 oj r262009 : #i94535#
2009-01-08 10:47:13 +00:00
|
|
|
const ScSingleRefData& rRef = pToken->GetSingleRef();
|
2008-12-12 09:38:47 +00:00
|
|
|
String aTabName;
|
|
|
|
pSrcDoc->GetName(rRef.nTab, aTabName);
|
|
|
|
ScExternalDoubleRefToken aNewToken(nFileId, aTabName, pToken->GetDoubleRef());
|
|
|
|
pNew->AddToken(aNewToken);
|
|
|
|
bTokenAdded = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
; // nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bTokenAdded)
|
|
|
|
pNew->AddToken(*pToken);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure to pass the correctly-cased range name here.
|
|
|
|
maRefCache.setRangeNameTokens(nFileId, pRangeData->GetName(), pNew);
|
|
|
|
return pNew;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId)
|
|
|
|
{
|
|
|
|
RefCellMap::iterator itrFile = maRefCells.find(nFileId);
|
|
|
|
if (itrFile == maRefCells.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
RefCells& rRefCells = itrFile->second;
|
|
|
|
rRefCells.refreshAllCells(*this);
|
|
|
|
|
|
|
|
ScViewData* pViewData = ScDocShell::GetViewData();
|
|
|
|
if (!pViewData)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ScTabViewShell* pVShell = pViewData->GetViewShell();
|
|
|
|
if (!pVShell)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Repainting the grid also repaints the texts, but is there a better way
|
|
|
|
// to refresh texts?
|
|
|
|
pVShell->Invalidate(FID_REPAINT);
|
|
|
|
pVShell->PaintGrid();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell)
|
|
|
|
{
|
|
|
|
RefCellMap::iterator itr = maRefCells.find(nFileId);
|
|
|
|
if (itr == maRefCells.end())
|
|
|
|
{
|
|
|
|
RefCells aRefCells;
|
|
|
|
pair<RefCellMap::iterator, bool> r = maRefCells.insert(
|
|
|
|
RefCellMap::value_type(nFileId, aRefCells));
|
|
|
|
if (!r.second)
|
|
|
|
// insertion failed.
|
|
|
|
return;
|
|
|
|
|
|
|
|
itr = r.first;
|
|
|
|
}
|
|
|
|
itr->second.insertCell(rCell);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
|
|
|
|
{
|
|
|
|
if (!mpDoc->IsExecuteLinkEnabled())
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
DocShellMap::iterator itrEnd = maDocShells.end();
|
|
|
|
DocShellMap::iterator itr = maDocShells.find(nFileId);
|
|
|
|
|
|
|
|
if (itr != itrEnd)
|
|
|
|
{
|
|
|
|
SfxObjectShell* p = itr->second.maShell;
|
|
|
|
itr->second.maLastAccess = Time();
|
|
|
|
return static_cast<ScDocShell*>(p)->GetDocument();
|
|
|
|
}
|
|
|
|
|
|
|
|
const String* pFile = getExternalFileName(nFileId);
|
|
|
|
if (!pFile)
|
|
|
|
// no file name associated with this ID.
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
String aFilter;
|
|
|
|
SrcShell aSrcDoc;
|
|
|
|
aSrcDoc.maShell = loadSrcDocument(nFileId, aFilter);
|
|
|
|
if (!aSrcDoc.maShell.Is())
|
|
|
|
{
|
|
|
|
// source document could not be loaded.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maDocShells.empty())
|
|
|
|
{
|
|
|
|
// If this is the first source document insertion, start up the timer.
|
|
|
|
maSrcDocTimer.Start();
|
|
|
|
}
|
|
|
|
|
|
|
|
maDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc));
|
|
|
|
SfxObjectShell* p = aSrcDoc.maShell;
|
|
|
|
ScDocument* pSrcDoc = static_cast<ScDocShell*>(p)->GetDocument();
|
|
|
|
|
|
|
|
SCTAB nTabCount = pSrcDoc->GetTableCount();
|
|
|
|
if (!maRefCache.isDocInitialized(nFileId) && nTabCount)
|
|
|
|
{
|
|
|
|
// Populate the cache with all table names in the source document.
|
|
|
|
vector<String> aTabNames;
|
|
|
|
aTabNames.reserve(nTabCount);
|
|
|
|
for (SCTAB i = 0; i < nTabCount; ++i)
|
|
|
|
{
|
|
|
|
String aName;
|
|
|
|
pSrcDoc->GetName(i, aName);
|
|
|
|
aTabNames.push_back(aName);
|
|
|
|
}
|
|
|
|
maRefCache.initializeDoc(nFileId, aTabNames);
|
|
|
|
}
|
|
|
|
return pSrcDoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, String& rFilter)
|
|
|
|
{
|
|
|
|
const SrcFileData* pFileData = getExternalFileData(nFileId);
|
|
|
|
if (!pFileData)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
String aFile = pFileData->maFileName;
|
|
|
|
if (!isFileLoadable(aFile))
|
|
|
|
{
|
|
|
|
// The original file path is not loadable. Try the relative path.
|
|
|
|
// Note that the path is relative to the content.xml substream which
|
|
|
|
// is one-level higher than the file itself.
|
|
|
|
|
|
|
|
if (!pFileData->maRelativeName.Len())
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
INetURLObject aBaseURL(getOwnDocumentName());
|
|
|
|
aBaseURL.insertName(OUString::createFromAscii("content.xml"));
|
|
|
|
bool bWasAbs = false;
|
|
|
|
aFile = aBaseURL.smartRel2Abs(pFileData->maRelativeName, bWasAbs).GetMainURL(INetURLObject::NO_DECODE);
|
|
|
|
if (!isFileLoadable(aFile))
|
|
|
|
// Ok, I've tried both paths but no success. Bail out.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
String aOptions;
|
|
|
|
ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false);
|
|
|
|
const SfxFilter* pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter);
|
|
|
|
|
|
|
|
if (!pFileData->maRelativeName.Len())
|
|
|
|
{
|
|
|
|
// Generate a relative file path.
|
|
|
|
INetURLObject aBaseURL(getOwnDocumentName());
|
|
|
|
aBaseURL.insertName(OUString::createFromAscii("content.xml"));
|
|
|
|
|
|
|
|
String aStr = URIHelper::simpleNormalizedMakeRelative(
|
|
|
|
aBaseURL.GetMainURL(INetURLObject::NO_DECODE), aFile);
|
|
|
|
|
|
|
|
setRelativeFileName(nFileId, aStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the filter data now that we are loading it again.
|
|
|
|
setFilterData(nFileId, rFilter, aOptions);
|
|
|
|
|
|
|
|
SfxItemSet* pSet = new SfxAllItemSet(SFX_APP()->GetPool());
|
|
|
|
if (aOptions.Len())
|
|
|
|
pSet->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
|
|
|
|
|
|
|
|
auto_ptr<SfxMedium> pMedium(new SfxMedium(aFile, STREAM_STD_READ, false, pFilter, pSet));
|
|
|
|
if (pMedium->GetError() != ERRCODE_NONE)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
pMedium->UseInteractionHandler(false);
|
|
|
|
|
|
|
|
ScDocShell* pNewShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL);
|
|
|
|
SfxObjectShellRef aRef = pNewShell;
|
|
|
|
|
|
|
|
// increment the recursive link count of the source document.
|
|
|
|
ScExtDocOptions* pExtOpt = mpDoc->GetExtDocOptions();
|
|
|
|
sal_uInt32 nLinkCount = pExtOpt ? pExtOpt->GetDocSettings().mnLinkCnt : 0;
|
|
|
|
ScDocument* pSrcDoc = pNewShell->GetDocument();
|
|
|
|
ScExtDocOptions* pExtOptNew = pSrcDoc->GetExtDocOptions();
|
|
|
|
if (!pExtOptNew)
|
|
|
|
{
|
|
|
|
pExtOptNew = new ScExtDocOptions;
|
|
|
|
pSrcDoc->SetExtDocOptions(pExtOptNew);
|
|
|
|
}
|
|
|
|
pExtOptNew->GetDocSettings().mnLinkCnt = nLinkCount + 1;
|
|
|
|
|
|
|
|
pNewShell->DoLoad(pMedium.release());
|
|
|
|
return aRef;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScExternalRefManager::isFileLoadable(const String& rFile) const
|
|
|
|
{
|
|
|
|
if (isOwnDocument(rFile))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (utl::UCBContentHelper::IsFolder(rFile))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return utl::UCBContentHelper::Exists(rFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId)
|
|
|
|
{
|
|
|
|
if (maLinkedDocs.count(nFileId))
|
|
|
|
// file alerady linked.
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Source document not linked yet. Link it now.
|
|
|
|
const String* pFileName = getExternalFileName(nFileId);
|
|
|
|
if (!pFileName)
|
|
|
|
return;
|
|
|
|
|
|
|
|
String aFilter, aOptions;
|
|
|
|
ScDocumentLoader::GetFilterName(*pFileName, aFilter, aOptions, true, false);
|
|
|
|
SvxLinkManager* pLinkMgr = mpDoc->GetLinkManager();
|
|
|
|
ScExternalRefLink* pLink = new ScExternalRefLink(mpDoc, nFileId, aFilter);
|
|
|
|
DBG_ASSERT(pFileName, "ScExternalRefManager::insertExternalFileLink: file name pointer is NULL");
|
|
|
|
pLinkMgr->InsertFileLink(*pLink, OBJECT_CLIENT_FILE, *pFileName, &aFilter);
|
|
|
|
|
|
|
|
pLink->SetDoReferesh(false);
|
|
|
|
pLink->Update();
|
|
|
|
pLink->SetDoReferesh(true);
|
|
|
|
|
|
|
|
maLinkedDocs.insert(nFileId);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScExternalRefManager::compileTokensByCell(const ScAddress& rCell)
|
|
|
|
{
|
|
|
|
ScBaseCell* pCell;
|
|
|
|
mpDoc->GetCell(rCell.Col(), rCell.Row(), rCell.Tab(), pCell);
|
|
|
|
|
|
|
|
if (!pCell || pCell->GetCellType() != CELLTYPE_FORMULA)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
|
|
|
|
|
|
|
|
// Check to make sure the cell really contains ocExternalRef.
|
|
|
|
// External names, external cell and range references all have a
|
|
|
|
// ocExternalRef token.
|
|
|
|
const ScTokenArray* pCode = pFC->GetCode();
|
|
|
|
if (!pCode->HasOpCode( ocExternalRef))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ScTokenArray* pArray = pFC->GetCode();
|
|
|
|
if (pArray)
|
|
|
|
// Clear the error code, or a cell with error won't get re-compiled.
|
|
|
|
pArray->SetCodeError(0);
|
|
|
|
|
|
|
|
pFC->SetCompile(true);
|
|
|
|
pFC->CompileTokenArray();
|
|
|
|
pFC->SetDirty();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const String& ScExternalRefManager::getOwnDocumentName() const
|
|
|
|
{
|
|
|
|
SfxObjectShell* pShell = mpDoc->GetDocumentShell();
|
|
|
|
if (!pShell)
|
|
|
|
// This should not happen!
|
|
|
|
return EMPTY_STRING;
|
|
|
|
|
|
|
|
SfxMedium* pMed = pShell->GetMedium();
|
|
|
|
if (!pMed)
|
|
|
|
return EMPTY_STRING;
|
|
|
|
|
|
|
|
return pMed->GetName();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScExternalRefManager::isOwnDocument(const String& rFile) const
|
|
|
|
{
|
|
|
|
return getOwnDocumentName().Equals(rFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::convertToAbsName(String& rFile) const
|
|
|
|
{
|
|
|
|
SfxObjectShell* pDocShell = mpDoc->GetDocumentShell();
|
|
|
|
rFile = ScGlobal::GetAbsDocName(rFile, pDocShell);
|
|
|
|
}
|
|
|
|
|
|
|
|
sal_uInt16 ScExternalRefManager::getExternalFileId(const String& rFile)
|
|
|
|
{
|
|
|
|
vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
|
|
|
|
vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
|
|
|
|
if (itr != itrEnd)
|
|
|
|
{
|
|
|
|
size_t nId = distance(itrBeg, itr);
|
|
|
|
return static_cast<sal_uInt16>(nId);
|
|
|
|
}
|
|
|
|
|
|
|
|
SrcFileData aData;
|
|
|
|
aData.maFileName = rFile;
|
|
|
|
maSrcFiles.push_back(aData);
|
|
|
|
return static_cast<sal_uInt16>(maSrcFiles.size() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId) const
|
|
|
|
{
|
|
|
|
if (nFileId >= maSrcFiles.size())
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return &maSrcFiles[nFileId].maFileName;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId) const
|
|
|
|
{
|
|
|
|
return nFileId < maSrcFiles.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScExternalRefManager::hasExternalFile(const String& rFile) const
|
|
|
|
{
|
|
|
|
vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
|
|
|
|
vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
|
|
|
|
return itr != itrEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ScExternalRefManager::SrcFileData* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId) const
|
|
|
|
{
|
|
|
|
if (nFileId >= maSrcFiles.size())
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return &maSrcFiles[nFileId];
|
|
|
|
}
|
|
|
|
|
|
|
|
const String* ScExternalRefManager::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const
|
|
|
|
{
|
|
|
|
return maRefCache.getRealTableName(nFileId, rTabName);
|
|
|
|
}
|
|
|
|
|
|
|
|
const String* ScExternalRefManager::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const
|
|
|
|
{
|
|
|
|
return maRefCache.getRealRangeName(nFileId, rRangeName);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename MapContainer>
|
|
|
|
void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap)
|
|
|
|
{
|
|
|
|
typename MapContainer::iterator itr = rMap.find(nFileId);
|
|
|
|
if (itr != rMap.end())
|
|
|
|
rMap.erase(itr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::refreshNames(sal_uInt16 nFileId)
|
|
|
|
{
|
|
|
|
removeSrcDocument(nFileId, false);
|
|
|
|
|
|
|
|
// Update all cells containing names from this source document.
|
|
|
|
refreshAllRefCells(nFileId);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const String& rNewFile)
|
|
|
|
{
|
|
|
|
maSrcFiles[nFileId].maFileName = rNewFile;
|
|
|
|
maSrcFiles[nFileId].maRelativeName.Erase();
|
|
|
|
refreshNames(nFileId);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl)
|
|
|
|
{
|
|
|
|
if (nFileId >= maSrcFiles.size())
|
|
|
|
return;
|
|
|
|
maSrcFiles[nFileId].maRelativeName = rRelUrl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const String& rFilterName, const String& rOptions)
|
|
|
|
{
|
|
|
|
if (nFileId >= maSrcFiles.size())
|
|
|
|
return;
|
|
|
|
maSrcFiles[nFileId].maFilterName = rFilterName;
|
|
|
|
maSrcFiles[nFileId].maFilterOptions = rOptions;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::removeSrcDocument(sal_uInt16 nFileId, bool bBreakLink)
|
|
|
|
{
|
|
|
|
maRefCache.clearCache(nFileId);
|
|
|
|
lcl_removeByFileId(nFileId, maDocShells);
|
|
|
|
|
|
|
|
if (bBreakLink)
|
|
|
|
maLinkedDocs.erase(nFileId);
|
|
|
|
|
|
|
|
if (maDocShells.empty())
|
|
|
|
maSrcDocTimer.Stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::clear()
|
|
|
|
{
|
|
|
|
DocShellMap::iterator itrEnd = maDocShells.end();
|
|
|
|
for (DocShellMap::iterator itr = maDocShells.begin(); itr != itrEnd; ++itr)
|
|
|
|
itr->second.maShell->DoClose();
|
|
|
|
|
|
|
|
maDocShells.clear();
|
|
|
|
maSrcDocTimer.Stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScExternalRefManager::hasExternalData() const
|
|
|
|
{
|
|
|
|
return !maSrcFiles.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::resetSrcFileData()
|
|
|
|
{
|
|
|
|
INetURLObject aBaseURL(getOwnDocumentName());
|
|
|
|
aBaseURL.insertName(OUString::createFromAscii("content.xml"));
|
|
|
|
String aBaseUrlStr = aBaseURL.GetMainURL(INetURLObject::NO_DECODE);
|
|
|
|
for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
|
|
|
|
itr != itrEnd; ++itr)
|
|
|
|
{
|
|
|
|
if (!itr->maRelativeName.Len())
|
|
|
|
{
|
|
|
|
itr->maRelativeName = URIHelper::simpleNormalizedMakeRelative(
|
|
|
|
aBaseUrlStr, itr->maFileName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::updateRefCell(const ScAddress& rOldPos, const ScAddress& rNewPos, bool bCopy)
|
|
|
|
{
|
|
|
|
for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
|
|
|
|
{
|
|
|
|
if (!bCopy)
|
|
|
|
itr->second.removeCell(rOldPos);
|
|
|
|
itr->second.insertCell(rNewPos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::updateRefMoveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy)
|
|
|
|
{
|
|
|
|
for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
|
|
|
|
itr->second.moveTable(nOldTab, nNewTab, bCopy);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::updateRefInsertTable(SCTAB nPos)
|
|
|
|
{
|
|
|
|
for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
|
|
|
|
itr->second.insertTable(nPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::updateRefDeleteTable(SCTAB nPos)
|
|
|
|
{
|
|
|
|
for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
|
|
|
|
itr->second.removeTable(nPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut)
|
|
|
|
{
|
|
|
|
DocShellMap aNewDocShells;
|
|
|
|
DocShellMap::iterator itr = maDocShells.begin(), itrEnd = maDocShells.end();
|
|
|
|
for (; itr != itrEnd; ++itr)
|
|
|
|
{
|
|
|
|
// in 100th of a second.
|
|
|
|
sal_Int32 nSinceLastAccess = (Time() - itr->second.maLastAccess).GetTime();
|
|
|
|
if (nSinceLastAccess < nTimeOut)
|
|
|
|
aNewDocShells.insert(*itr);
|
|
|
|
}
|
|
|
|
maDocShells.swap(aNewDocShells);
|
|
|
|
|
|
|
|
if (maDocShells.empty())
|
|
|
|
maSrcDocTimer.Stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc)
|
|
|
|
{
|
|
|
|
NumFmtMap::iterator itr = maNumFormatMap.find(nFileId);
|
|
|
|
if (itr == maNumFormatMap.end())
|
|
|
|
{
|
|
|
|
// Number formatter map is not initialized for this external document.
|
|
|
|
pair<NumFmtMap::iterator, bool> r = maNumFormatMap.insert(
|
|
|
|
NumFmtMap::value_type(nFileId, SvNumberFormatterMergeMap()));
|
|
|
|
|
|
|
|
if (!r.second)
|
|
|
|
// insertion failed.
|
|
|
|
return nNumFmt;
|
|
|
|
|
|
|
|
itr = r.first;
|
|
|
|
mpDoc->GetFormatTable()->MergeFormatter( *pSrcDoc->GetFormatTable());
|
|
|
|
SvNumberFormatterMergeMap aMap = mpDoc->GetFormatTable()->ConvertMergeTableToMap();
|
|
|
|
itr->second.swap(aMap);
|
|
|
|
}
|
|
|
|
const SvNumberFormatterMergeMap& rMap = itr->second;
|
|
|
|
SvNumberFormatterMergeMap::const_iterator itrNumFmt = rMap.find(nNumFmt);
|
|
|
|
if (itrNumFmt != rMap.end())
|
|
|
|
// mapped value found.
|
|
|
|
return itrNumFmt->second;
|
|
|
|
|
|
|
|
return nNumFmt;
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPL_LINK(ScExternalRefManager, TimeOutHdl, AutoTimer*, pTimer)
|
|
|
|
{
|
|
|
|
if (pTimer == &maSrcDocTimer)
|
|
|
|
purgeStaleSrcDocument(SRCDOC_LIFE_SPAN);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|