Hey,
I propose this patch as a late feature. It improves our handling of
references when we copy between different documents. Our old behavior
was wrong as it did rely on the sheet index and did not update the
references correctly. We now copied Excel's behavior and transform
absolute sheet references to external references if they do not point
to a copied cell. This behavior respects that marking a reference as
abolute should always point to the same cells.
The patch includes a small new feature, external references to unsaved
files. This is necessary because we can not gurantee that the source
document is already saved. The reference to the unsaved document is
transformed to a normal external reference as soon as the original
document is saved. If you save a document with references to an
unsaved document you get a warning message that you loose data and if
you confirm the document is saved.
The patch should mainly affect copying between different documents and
add the support for external references to unsaved files and should
not affect other areas. You can test this feature already in master
where this feature has been added some time ago.
Regards,
Markus
From f6fe694a2c9fde8ef8b84b652225bca584bb40b4 Mon Sep 17 00:00:00 2001
From: Markus Mohrhard <markus.mohrhard@googlemail.com>
Date: Wed, 4 Jan 2012 15:31:18 +0100
Subject: [PATCH] improve copy/paste between different documents
Absolute sheet refs are transformed to external references pointing to
the old document
---
sc/inc/document.hxx | 12 +-
sc/inc/externalrefmgr.hxx | 30 +++++-
sc/inc/globstr.hrc | 3 +-
sc/inc/reftokenhelper.hxx | 1 +
sc/inc/tokenarray.hxx | 15 +++
sc/qa/unit/ucalc.cxx | 2 +-
sc/source/core/data/cell.cxx | 13 ++
sc/source/core/data/documen2.cxx | 24 +++--
sc/source/core/data/document.cxx | 195 +++++++++++-------------------
sc/source/core/tool/reftokenhelper.cxx | 59 +++++++++
sc/source/core/tool/token.cxx | 173 ++++++++++++++++++++++++++
sc/source/ui/docshell/docsh.cxx | 31 +++--
sc/source/ui/docshell/externalrefmgr.cxx | 75 +++++++++++-
sc/source/ui/src/globstr.src | 4 +
sc/source/ui/view/viewfun2.cxx | 5 +
15 files changed, 488 insertions(+), 154 deletions(-)
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index d39940f..83ad4a1 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -242,6 +242,7 @@ private:
ScValidationDataList* pValidationList; // validity
SvNumberFormatterIndexTable* pFormatExchangeList; // for application of number formats
TableContainer maTabs;
+ std::vector<rtl::OUString> maTabNames; // for undo document, we need the
information tab name <-> index
mutable ScRangeName* pRangeName;
ScDBCollection* pDBCollection;
ScDPCollection* pDPCollection;
@@ -280,8 +281,9 @@ private:
mutable ::std::auto_ptr< ScFormulaParserPool >
mxFormulaParserPool; /// Pool for all external formula parsers
used by this document.
- rtl::OUString aDocName; // optional: name of document
- rtl::OUString aDocCodeName; // optional: name of document
(twice?)
+ rtl::OUString aDocName; // optional: name of document
+ rtl::OUString aDocCodeName; // optional: name of document (twice?)
+ rtl::OUString maFileURL; // file URL for copy & paste
ScRangePairListRef xColNameRanges;
ScRangePairListRef xRowNameRanges;
@@ -432,6 +434,7 @@ public:
void SetName( const rtl::OUString& r ) { aDocName = r; }
const rtl::OUString& GetCodeName() const { return aDocCodeName; }
void SetCodeName( const rtl::OUString& r ) { aDocCodeName = r; }
+ const rtl::OUString& GetFileURL() const { return maFileURL; }
void GetDocStat( ScDocStat& rDocStat );
@@ -533,6 +536,7 @@ public:
SC_DLLPUBLIC bool GetCodeName( SCTAB nTab, rtl::OUString& rName ) const;
SC_DLLPUBLIC bool SetCodeName( SCTAB nTab, const rtl::OUString& rName );
SC_DLLPUBLIC bool GetTable( const rtl::OUString& rName, SCTAB& rTab ) const;
+ rtl::OUString GetCopyTabName(SCTAB nTab) const;
SC_DLLPUBLIC void SetAnonymousDBData(SCTAB nTab, ScDBData* pDBData);
SC_DLLPUBLIC ScDBData* GetAnonymousDBData(SCTAB nTab);
@@ -1860,10 +1864,6 @@ private: // CLOOK-Impl-methods
void CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const
ScMarkData* pMarks, bool bAllTabs);
void CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, SCTAB nTab);
- void CopyRangeNamesFromClip(ScDocument* pClipDoc, ScClipRangeNameData& rRangeNames);
- void UpdateRangeNamesInFormulas(
- ScClipRangeNameData& rRangeNames, const ScRangeList& rDestRanges, const ScMarkData& rMark,
- SCCOL nXw, SCROW nYw);
bool HasPartOfMerged( const ScRange& rRange );
diff --git a/sc/inc/externalrefmgr.hxx b/sc/inc/externalrefmgr.hxx
index e39ac2e..c44c8f1 100644
--- a/sc/inc/externalrefmgr.hxx
+++ b/sc/inc/externalrefmgr.hxx
@@ -33,9 +33,11 @@
#include "address.hxx"
#include "sfx2/objsh.hxx"
#include "sfx2/lnkbase.hxx"
+#include "sfx2/event.hxx"
#include "tools/time.hxx"
#include "vcl/timer.hxx"
#include "svl/zforlist.hxx"
+#include "svl/lstner.hxx"
#include "scmatrix.hxx"
#include "rangelst.hxx"
#include "formula/token.hxx"
@@ -46,6 +48,7 @@
#include <vector>
#include <list>
#include <set>
+#include <iostream>
#include <formula/ExternalReferenceHelper.hxx>
class ScDocument;
@@ -353,7 +356,7 @@ private:
mutable DocDataType maDocs;
};
-class SC_DLLPUBLIC ScExternalRefManager : public formula::ExternalReferenceHelper
+class SC_DLLPUBLIC ScExternalRefManager : public formula::ExternalReferenceHelper, SfxListener
{
public:
@@ -426,6 +429,7 @@ public:
::rtl::OUString maRelativeName;
::rtl::OUString maFilterName;
::rtl::OUString maFilterOptions;
+ bool bUnsaved;
void maybeCreateRealFileName(const String& rOwnDocName);
};
@@ -673,6 +677,23 @@ public:
*/
bool isFileLoadable(const ::rtl::OUString& rFile) const;
+ /**
+ * If in maUnsavedDocShells move it to maDocShells and create a correct
+ * external reference entry
+ *
+ * @param Pointer to the newly saved DocumentShell
+ */
+ void transformUnsavedRefToSavedRef( SfxObjectShell* pShell );
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
+
+ /**
+ * If we still contain unsaved files we should warn the user before saving
+ *
+ * @return true if the document still contains references to an unsaved file
+ */
+ bool containsUnsavedReferences() { return !maUnsavedDocShells.empty(); }
+
private:
ScExternalRefManager();
ScExternalRefManager(const ScExternalRefManager&);
@@ -749,6 +770,7 @@ private:
sal_uInt32 getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, const ScDocument*
pSrcDoc);
+
private:
/** cache of referenced ranges and names from source documents. */
ScExternalRefCache maRefCache;
@@ -761,6 +783,12 @@ private:
*/
DocShellMap maDocShells;
+ /**
+ * DocShells to unsaved but referenced documents. If not empty ask before saving!
+ * Move to maDocShells if document referenced here is saved
+ */
+ DocShellMap maUnsavedDocShells;
+
/** list of source documents that are managed by the link manager. */
LinkedDocMap maLinkedDocs;
diff --git a/sc/inc/globstr.hrc b/sc/inc/globstr.hrc
index 2363aaf..a545a0e 100644
--- a/sc/inc/globstr.hrc
+++ b/sc/inc/globstr.hrc
@@ -599,8 +599,9 @@
#define STR_ERR_NAME_EXISTS 463
#define STR_ERR_NAME_INVALID 464
+#define STR_UNSAVED_EXT_REF 465
-#define STR_COUNT 465
+#define STR_COUNT 466
#endif
diff --git a/sc/inc/reftokenhelper.hxx b/sc/inc/reftokenhelper.hxx
index 9119e3e..c076f34 100644
--- a/sc/inc/reftokenhelper.hxx
+++ b/sc/inc/reftokenhelper.hxx
@@ -58,6 +58,7 @@ public:
const sal_Unicode cSep, ::formula::FormulaGrammar::Grammar eGrammar);
static bool getRangeFromToken(ScRange& rRange, const ScTokenRef& pToken, bool bExternal =
false);
+ static bool getAbsRangeFromToken(ScRange& rRange, const ScTokenRef& pToken, const ScAddress&
rPos, bool bExternal = false);
static void getRangeListFromTokens(ScRangeList& rRangeList, const ::std::vector<ScTokenRef>&
pTokens);
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index b2f4565..df214b0 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -95,6 +95,21 @@ public:
void ReadjustRelative3DReferences(
const ScAddress& rOldPos,
const ScAddress& rNewPos );
+
+ /**
+ * Make all absolute references external references pointing to the old document
+ *
+ * @param pOldDoc old document
+ * @param pNewDoc new document
+ * @param rPos position of the cell to determine if the reference is in the copied area
+ * @param bRangeName set for range names, range names have special handling for absolute sheet
ref + relative col/row ref
+ */
+ void ReadjustAbsolute3DReferences( const ScDocument* pOldDoc, const ScDocument* pNewDoc, const
ScAddress& rPos, bool bRangeName = false );
+
+ /**
+ * Make all absolute references pointing to the copied range if the range is copied too
+ */
+ void AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddress& rOldPos, const ScAddress&
rNewPos );
};
#endif // SC_TOKENARRAY_HXX
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index a4158c3..f98195d 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -2738,8 +2738,8 @@ void Test::testCopyPaste()
//check values after copying
rtl::OUString aString;
m_pDoc->GetValue(1,1,1, aValue);
- CPPUNIT_ASSERT_MESSAGE("copied formula should return 2", aValue == 2);
m_pDoc->GetFormula(1,1,1, aString);
+ CPPUNIT_ASSERT_MESSAGE("copied formula should return 2", aValue == 2);
CPPUNIT_ASSERT_MESSAGE("formula string was not copied correctly", aString == aFormulaString);
m_pDoc->GetValue(0,1,1, aValue);
CPPUNIT_ASSERT_MESSAGE("copied value should be 1", aValue == 1);
diff --git a/sc/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx
index 6cc8209..cf5f70f 100644
--- a/sc/source/core/data/cell.cxx
+++ b/sc/source/core/data/cell.cxx
@@ -179,6 +179,12 @@ void adjustRangeName(ScToken* pToken, ScDocument& rNewDoc, const ScDocument*
pOl
{
bNewGlobal = bOldGlobal;
pRangeData = new ScRangeData(*pOldRangeData, &rNewDoc);
+ ScTokenArray* pRangeNameToken = pRangeData->GetCode();
+ if (rNewDoc.GetPool() != const_cast<ScDocument*>(pOldDoc)->GetPool())
+ {
+ pRangeNameToken->ReadjustAbsolute3DReferences(pOldDoc, &rNewDoc, pRangeData->GetPos(),
true);
+ }
+
bool bInserted;
if (bNewGlobal)
bInserted = rNewDoc.GetRangeName()->insert(pRangeData);
@@ -881,6 +887,13 @@ ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc,
cons
adjustDBRange(pToken, rDoc, rCell.pDocument);
}
}
+
+ if (pDocument->GetPool() != rCell.pDocument->GetPool())
+ {
+ pCode->ReadjustAbsolute3DReferences( rCell.pDocument, &rDoc, rCell.aPos);
+ }
+
+ pCode->AdjustAbsoluteRefs( rCell.pDocument, rCell.aPos, aPos );
}
if( !bCompile )
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 37005ee..aa99070 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -41,6 +41,7 @@
#include <svx/svdobj.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
#include <sfx2/printer.hxx>
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
@@ -48,6 +49,7 @@
#include <comphelper/processfactory.hxx>
#include <svl/PasswordHelper.hxx>
#include <tools/tenccvt.hxx>
+#include <tools/urlobj.hxx>
#include <rtl/crc.h>
#include <basic/basmgr.hxx>
@@ -920,8 +922,21 @@ sal_uLong ScDocument::TransferTab( ScDocument* pSrcDoc, SCTAB nSrcPos,
bool bResultsOnly )
{
sal_uLong nRetVal = 1; // 0 => Fehler 1 = ok
- // 2 => RefBox, 3 => NameBox
+ // 3 => NameBox
// 4 => beides
+
+ if (pSrcDoc->pShell->GetMedium())
+ {
+ pSrcDoc->maFileURL =
pSrcDoc->pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
+ // for unsaved files use the title name and adjust during save of file
+ if (pSrcDoc->maFileURL.isEmpty())
+ pSrcDoc->maFileURL = pSrcDoc->pShell->GetName();
+ }
+ else
+ {
+ pSrcDoc->maFileURL = pSrcDoc->pShell->GetName();
+ }
+
bool bValid = true;
if (bInsertNew) // neu einfuegen
{
@@ -1046,15 +1061,8 @@ sal_uLong ScDocument::TransferTab( ScDocument* pSrcDoc, SCTAB nSrcPos,
maTabs[nDestPos]->UpdateReference(URM_COPY, 0, 0, nDestPos,
MAXCOL, MAXROW, nDestPos,
0, 0, nDz, NULL);
- // Test for outside absolute references for info box
- bool bIsAbsRef = pSrcDoc->maTabs[nSrcPos]->TestTabRefAbs(nSrcPos);
// Readjust self-contained absolute references to this sheet
maTabs[nDestPos]->TestTabRefAbs(nSrcPos);
- if (bIsAbsRef)
- {
- nRetVal += 1;
- // InfoBox AbsoluteRefs sind moeglicherweise nicht mehr korrekt!!
- }
if (bNamesLost)
{
nRetVal += 2;
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index efb003b..eb03a74 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -42,12 +42,14 @@
#include <svx/svdocapt.hxx>
#include <sfx2/app.hxx>
#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
#include <svl/poolcach.hxx>
#include <unotools/saveopt.hxx>
#include <svl/zforlist.hxx>
#include <unotools/charclass.hxx>
#include <unotools/transliterationwrapper.hxx>
#include <tools/tenccvt.hxx>
+#include <tools/urlobj.hxx>
#include <com/sun/star/text/WritingMode2.hpp>
#include <com/sun/star/script/vba/XVBACompatibility.hpp>
@@ -97,6 +99,9 @@
#include <map>
#include <limits>
+#include <rtl/oustringostreaminserter.hxx>
+#include <iostream>
+
using ::editeng::SvxBorderLine;
using namespace ::com::sun::star;
@@ -180,6 +185,14 @@ bool ScDocument::GetName( SCTAB nTab, rtl::OUString& rName ) const
return false;
}
+rtl::OUString ScDocument::GetCopyTabName( SCTAB nTab ) const
+{
+ if (nTab < static_cast<SCTAB>(maTabNames.size()))
+ return maTabNames[nTab];
+ else
+ return rtl::OUString();
+}
+
bool ScDocument::SetCodeName( SCTAB nTab, const rtl::OUString& rName )
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
@@ -1675,6 +1688,7 @@ void ScDocument::InitUndoSelected( ScDocument* pSrcDoc, const ScMarkData&
rTabSe
xPoolHelper = pSrcDoc->xPoolHelper;
+
rtl::OUString aString;
for (SCTAB nTab = 0; nTab <= rTabSelection.GetLastSelected(); nTab++)
if ( rTabSelection.GetTableSelect( nTab ) )
@@ -1694,9 +1708,9 @@ void ScDocument::InitUndoSelected( ScDocument* pSrcDoc, const ScMarkData&
rTabSe
}
}
else
- {
+ {
OSL_FAIL("InitUndo");
- }
+ }
}
@@ -1708,6 +1722,12 @@ void ScDocument::InitUndo( ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
Clear();
xPoolHelper = pSrcDoc->xPoolHelper;
+ if (pSrcDoc->pShell->GetMedium())
+ {
+ maFileURL =
pSrcDoc->pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
+ std::cout << "SfxMedium: " << maFileURL << std::endl;
+ std::cout << "GetName: " << rtl::OUString(pSrcDoc->pShell->GetName()) << std::endl;
+ }
rtl::OUString aString;
if ( nTab2 >= static_cast<SCTAB>(maTabs.size()))
@@ -1893,6 +1913,31 @@ void ScDocument::CopyToClip(const ScClipParam& rClipParam,
pClipDoc = SC_MOD()->GetClipDoc();
}
+ if (pShell->GetMedium())
+ {
+ pClipDoc->maFileURL =
pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
+ // for unsaved files use the title name and adjust during save of file
+ if (pClipDoc->maFileURL.isEmpty())
+ pClipDoc->maFileURL = pShell->GetName();
+ }
+ else
+ {
+ pClipDoc->maFileURL = pShell->GetName();
+ }
+
+ //init maTabNames
+ for (TableContainer::iterator itr = maTabs.begin(); itr != maTabs.end(); ++itr)
+ {
+ if( *itr )
+ {
+ rtl::OUString aTabName;
+ (*itr)->GetName(aTabName);
+ pClipDoc->maTabNames.push_back(aTabName);
+ }
+ else
+ pClipDoc->maTabNames.push_back(rtl::OUString());
+ }
+
pClipDoc->aDocName = aDocName;
pClipDoc->SetClipParam(rClipParam);
ScRange aClipRange = rClipParam.getWholeRange();
@@ -1943,6 +1988,31 @@ void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
{
if (!bIsClip)
{
+ if (pShell->GetMedium())
+ {
+ pClipDoc->maFileURL =
pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
+ // for unsaved files use the title name and adjust during save of file
+ if (pClipDoc->maFileURL.isEmpty())
+ pClipDoc->maFileURL = pShell->GetName();
+ }
+ else
+ {
+ pClipDoc->maFileURL = pShell->GetName();
+ }
+
+ //init maTabNames
+ for (TableContainer::iterator itr = maTabs.begin(); itr != maTabs.end(); ++itr)
+ {
+ if( *itr )
+ {
+ rtl::OUString aTabName;
+ (*itr)->GetName(aTabName);
+ pClipDoc->maTabNames.push_back(aTabName);
+ }
+ else
+ pClipDoc->maTabNames.push_back(rtl::OUString());
+ }
+
PutInOrder( nCol1, nCol2 );
PutInOrder( nRow1, nRow2 );
if (!pClipDoc)
@@ -2114,116 +2184,6 @@ void ScDocument::MergeNumberFormatter(ScDocument* pSrcDoc)
}
}
-void ScDocument::CopyRangeNamesFromClip(ScDocument* pClipDoc, ScClipRangeNameData& rRangeNames)
-{
- if (!pClipDoc->pRangeName)
- return;
-
- ScClipRangeNameData aClipRangeNames;
-
- ScRangeName::const_iterator itr = pClipDoc->pRangeName->begin();
- ScRangeName::const_iterator itrEnd = pClipDoc->pRangeName->end();
- for (; itr != itrEnd; ++itr) //! DB-Bereiche Pivot-Bereiche auch
- {
- /* Copy only if the name doesn't exist in this document.
- If it exists we use the already existing name instead,
- another possibility could be to create new names if
- documents differ.
- A proper solution would ask the user how to proceed.
- The adjustment of the indices in the formulas is done later.
- */
- const ScRangeData* pExistingData = GetRangeName()->findByUpperName(itr->first);
- if (pExistingData)
- {
- sal_uInt16 nOldIndex = itr->second->GetIndex();
- sal_uInt16 nNewIndex = pExistingData->GetIndex();
- aClipRangeNames.insert(nOldIndex, nNewIndex);
- if ( !aClipRangeNames.mbReplace )
- aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
- }
- else
- {
- ScRangeData* pData = new ScRangeData( *itr->second );
- pData->SetDocument(this);
- if ( pRangeName->findByIndex( pData->GetIndex() ) )
- pData->SetIndex(0); // need new index, done in Insert
- if ( pRangeName->insert(pData) )
- {
- aClipRangeNames.mpRangeNames.push_back(pData);
- sal_uInt16 nOldIndex = itr->second->GetIndex();
- sal_uInt16 nNewIndex = pData->GetIndex();
- aClipRangeNames.insert(nOldIndex, nNewIndex);
- if ( !aClipRangeNames.mbReplace )
- aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
- }
- else
- { // must be an overflow
- pData = NULL;
- aClipRangeNames.insert(itr->second->GetIndex(), 0);
- aClipRangeNames.mbReplace = true;
- }
- }
- }
- rRangeNames = aClipRangeNames;
-}
-
-void ScDocument::UpdateRangeNamesInFormulas(
- ScClipRangeNameData& rRangeNames, const ScRangeList& rDestRanges, const ScMarkData& rMark,
- SCCOL nXw, SCROW nYw)
-{
- // nXw and nYw are the extra width and height of the destination range
- // extended due to presence of merged cell(s).
-
- if (!rRangeNames.mbReplace)
- return;
-
- // first update all inserted named formulas if they contain other
- // range names and used indices changed
- for (size_t i = 0, n = rRangeNames.mpRangeNames.size(); i < n; ++i) //! DB-Bereiche
Pivot-Bereiche auch
- {
- rRangeNames.mpRangeNames[i]->ReplaceRangeNamesInUse(rRangeNames.maRangeMap);
- }
- // then update the formulas, they might need just the updated range names
- for ( size_t nRange = 0, n = rDestRanges.size(); nRange < n; ++nRange )
- {
- const ScRange* pRange = rDestRanges[nRange];
- SCCOL nCol1 = pRange->aStart.Col();
- SCROW nRow1 = pRange->aStart.Row();
- SCCOL nCol2 = pRange->aEnd.Col();
- SCROW nRow2 = pRange->aEnd.Row();
-
- SCCOL nC1 = nCol1;
- SCROW nR1 = nRow1;
- SCCOL nC2 = nC1 + nXw;
- if (nC2 > nCol2)
- nC2 = nCol2;
- SCROW nR2 = nR1 + nYw;
- if (nR2 > nRow2)
- nR2 = nRow2;
- do
- {
- do
- {
- ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
- for (; itr != itrEnd; ++itr)
- {
- if ( maTabs[*itr] )
- maTabs[*itr]->ReplaceRangeNamesInUse(nC1, nR1,
- nC2, nR2, rRangeNames.maRangeMap);
- }
- nC1 = nC2 + 1;
- nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
- } while (nC1 <= nCol2);
- nC1 = nCol1;
- nC2 = nC1 + nXw;
- if (nC2 > nCol2)
- nC2 = nCol2;
- nR1 = nR2 + 1;
- nR2 = Min((SCROW)(nR1 + nYw), nRow2);
- } while (nR1 <= nRow2);
- }
-}
-
ScClipParam& ScDocument::GetClipParam()
{
if (!mpClipParam.get())
@@ -2428,9 +2388,6 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData&
rMar
NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
- ScClipRangeNameData aClipRangeNames;
- CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
-
SCCOL nAllCol1 = rDestRange.aStart.Col();
SCROW nAllRow1 = rDestRange.aStart.Row();
SCCOL nAllCol2 = rDestRange.aEnd.Col();
@@ -2587,8 +2544,6 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData&
rMar
bInsertingFromOtherDoc = false;
- UpdateRangeNamesInFormulas(aClipRangeNames, *pDestRanges, rMark, nXw, nYw);
-
// Listener aufbauen nachdem alles inserted wurde
StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
// nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
@@ -2631,9 +2586,6 @@ void ScDocument::CopyMultiRangeFromClip(
NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
- ScClipRangeNameData aClipRangeNames;
- CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
-
SCCOL nCol1 = rDestPos.Col();
SCROW nRow1 = rDestPos.Row();
ScClipParam& rClipParam = pClipDoc->GetClipParam();
@@ -2728,9 +2680,6 @@ void ScDocument::CopyMultiRangeFromClip(
ScRangeList aRanges;
aRanges.Append(aDestRange);
- SCCOL nCols = aDestRange.aEnd.Col() - aDestRange.aStart.Col() + 1;
- SCROW nRows = aDestRange.aEnd.Row() - aDestRange.aStart.Row() + 1;
- UpdateRangeNamesInFormulas(aClipRangeNames, aRanges, rMark, nCols-1, nRows-1);
// Listener aufbauen nachdem alles inserted wurde
StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
diff --git a/sc/source/core/tool/reftokenhelper.cxx b/sc/source/core/tool/reftokenhelper.cxx
index 0a7ed4e..1d966f1 100644
--- a/sc/source/core/tool/reftokenhelper.cxx
+++ b/sc/source/core/tool/reftokenhelper.cxx
@@ -136,6 +136,9 @@ void ScRefTokenHelper::compileRangeRepresentation(
rRefTokens.clear();
}
+namespace {
+
+//may return a relative address
void singleRefToAddr(const ScSingleRefData& rRef, ScAddress& rAddr)
{
if (rRef.IsColRel())
@@ -154,6 +157,27 @@ void singleRefToAddr(const ScSingleRefData& rRef, ScAddress& rAddr)
rAddr.SetTab(rRef.nTab);
}
+//returns an absolute address in reference to rPos
+void singleRefToAbsAddr(const ScSingleRefData& rRef, ScAddress& rAddr, const ScAddress& rPos)
+{
+ if (rRef.IsColRel())
+ rAddr.SetCol(rRef.nRelCol + rPos.Col());
+ else
+ rAddr.SetCol(rRef.nCol);
+
+ if (rRef.IsRowRel())
+ rAddr.SetRow(rRef.nRelRow + rPos.Row());
+ else
+ rAddr.SetRow(rRef.nRow);
+
+ if (rRef.IsTabRel())
+ rAddr.SetTab(rRef.nRelTab + rPos.Tab());
+ else
+ rAddr.SetTab(rRef.nTab);
+}
+
+}
+
bool ScRefTokenHelper::getRangeFromToken(ScRange& rRange, const ScTokenRef& pToken, bool bExternal)
{
StackVar eType = pToken->GetType();
@@ -189,6 +213,41 @@ bool ScRefTokenHelper::getRangeFromToken(ScRange& rRange, const ScTokenRef&
pTok
return false;
}
+bool ScRefTokenHelper::getAbsRangeFromToken(ScRange& rRange, const ScTokenRef& pToken, const
ScAddress& rPos, bool bExternal)
+{
+ StackVar eType = pToken->GetType();
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ case svExternalSingleRef:
+ {
+ if ((eType == svExternalSingleRef && !bExternal) ||
+ (eType == svSingleRef && bExternal))
+ return false;
+
+ const ScSingleRefData& rRefData = pToken->GetSingleRef();
+ singleRefToAbsAddr(rRefData, rRange.aStart, rPos);
+ rRange.aEnd = rRange.aStart;
+ return true;
+ }
+ case svDoubleRef:
+ case svExternalDoubleRef:
+ {
+ if ((eType == svExternalDoubleRef && !bExternal) ||
+ (eType == svDoubleRef && bExternal))
+ return false;
+
+ const ScComplexRefData& rRefData = pToken->GetDoubleRef();
+ singleRefToAbsAddr(rRefData.Ref1, rRange.aStart, rPos);
+ singleRefToAbsAddr(rRefData.Ref2, rRange.aEnd, rPos);
+ return true;
+ }
+ default:
+ ; // do nothing
+ }
+ return false;
+}
+
void ScRefTokenHelper::getRangeListFromTokens(ScRangeList& rRangeList, const vector<ScTokenRef>&
rTokens)
{
vector<ScTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 1178022..6ef4346 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -37,9 +37,12 @@
#include <string.h>
#include <tools/mempool.hxx>
#include <osl/diagnose.h>
+#include <sfx2/docfile.hxx>
#include "token.hxx"
#include "tokenarray.hxx"
+#include "reftokenhelper.hxx"
+#include "clipparam.hxx"
#include "compiler.hxx"
#include <formula/compiler.hrc>
#include "rechead.hxx"
@@ -49,6 +52,9 @@
#include "externalrefmgr.hxx"
#include "document.hxx"
+#include <iostream>
+#include <rtl/oustringostreaminserter.hxx>
+
using ::std::vector;
#include <com/sun/star/sheet/ComplexReference.hpp>
@@ -1815,5 +1821,172 @@ void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos,
}
}
+namespace {
+
+void GetExternalTableData(const ScDocument* pOldDoc, const ScDocument* pNewDoc, const SCTAB nTab,
rtl::OUString& rTabName, sal_uInt16& rFileId)
+{
+ rtl::OUString aFileName = pOldDoc->GetFileURL();;
+ std::cout << aFileName << std::endl;
+ rFileId = pNewDoc->GetExternalRefManager()->getExternalFileId(aFileName);
+ rTabName = pOldDoc->GetCopyTabName(nTab);
+ if (rTabName.isEmpty())
+ pOldDoc->GetName(nTab, rTabName);
+ std::cout << "TabName: " << rTabName << std::endl;
+}
+
+bool IsInCopyRange( const ScRange& rRange, const ScDocument* pClipDoc )
+{
+ ScClipParam& rClipParam = const_cast<ScDocument*>(pClipDoc)->GetClipParam();
+ std::cout << "Col: " << rRange.aStart.Col() << "Row: " << rRange.aStart.Row() << "Tab: " <<
rRange.aStart.Tab() << std::endl;
+ return rClipParam.maRanges.In(rRange);
+}
+
+bool SkipReference(ScToken* pToken, const ScAddress& rPos, const ScDocument* pOldDoc, bool
bRangeName)
+{
+ ScRange aRange;
+ if (!ScRefTokenHelper::getAbsRangeFromToken(aRange, pToken, rPos))
+ return true;
+
+ if (bRangeName && aRange.aStart.Tab() == rPos.Tab())
+ {
+ switch (pToken->GetType())
+ {
+ case svDoubleRef:
+ {
+ ScSingleRefData& rRef = pToken->GetSingleRef2();
+ if (rRef.IsColRel() || rRef.IsRowRel())
+ return true;
+ } // fall through
+ case svSingleRef:
+ {
+ ScSingleRefData& rRef = pToken->GetSingleRef();
+ if (rRef.IsColRel() || rRef.IsRowRel())
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (IsInCopyRange(aRange, pOldDoc))
+ return true;
+
+ return false;
+}
+
+void AdjustSingleRefData( ScSingleRefData& rRef, const ScAddress& rOldPos, const ScAddress&
rNewPos)
+{
+ SCsCOL nCols = rNewPos.Col() - rOldPos.Col();
+ SCsROW nRows = rNewPos.Row() - rOldPos.Row();
+ SCsTAB nTabs = rNewPos.Tab() - rOldPos.Tab();
+
+ if (!rRef.IsColRel())
+ rRef.nCol += nCols;
+
+ if (!rRef.IsRowRel())
+ rRef.nRow += nRows;
+
+ if (!rRef.IsTabRel())
+ rRef.nTab += nTabs;
+}
+
+}
+
+void ScTokenArray::ReadjustAbsolute3DReferences( const ScDocument* pOldDoc, const ScDocument*
pNewDoc, const ScAddress& rPos, bool bRangeName )
+{
+ for ( sal_uInt16 j=0; j<nLen; ++j )
+ {
+ switch ( pCode[j]->GetType() )
+ {
+ case svDoubleRef :
+ {
+ if (SkipReference(static_cast<ScToken*>(pCode[j]), rPos, pOldDoc, bRangeName))
+ continue;
+
+ ScComplexRefData& rRef = static_cast<ScToken*>(pCode[j])->GetDoubleRef();
+ ScSingleRefData& rRef2 = rRef.Ref2;
+ ScSingleRefData& rRef1 = rRef.Ref1;
+
+ if ( (rRef2.IsFlag3D() && !rRef2.IsTabRel()) || (rRef1.IsFlag3D() &&
!rRef1.IsTabRel()) )
+ {
+ rtl::OUString aTabName;
+ sal_uInt16 nFileId;
+ GetExternalTableData(pOldDoc, pNewDoc, rRef1.nTab, aTabName, nFileId);
+ pCode[j]->DecRef();
+ ScExternalDoubleRefToken* pToken = new ScExternalDoubleRefToken(nFileId,
aTabName, rRef);
+ pToken->IncRef();
+ pCode[j] = pToken;
+ }
+ }
+ break;
+ case svSingleRef :
+ {
+ if (SkipReference(static_cast<ScToken*>(pCode[j]), rPos, pOldDoc, bRangeName))
+ continue;
+
+ ScSingleRefData& rRef = static_cast<ScToken*>(pCode[j])->GetSingleRef();
+
+ if ( rRef.IsFlag3D() && !rRef.IsTabRel() )
+ {
+ rtl::OUString aTabName;
+ sal_uInt16 nFileId;
+ GetExternalTableData(pOldDoc, pNewDoc, rRef.nTab, aTabName, nFileId);
+ //replace with ScExternalSingleRefToken and adjust references
+ pCode[j]->DecRef();
+ ScExternalSingleRefToken* pToken = new ScExternalSingleRefToken(nFileId,
aTabName, rRef);
+ pToken->IncRef();
+ pCode[j] = pToken;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+}
+
+void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddress& rOldPos, const
ScAddress& rNewPos)
+{
+ for ( sal_uInt16 j=0; j<nLen; ++j )
+ {
+ switch ( pCode[j]->GetType() )
+ {
+ case svDoubleRef :
+ {
+ if (!SkipReference(static_cast<ScToken*>(pCode[j]), rOldPos, pOldDoc, false))
+ continue;
+
+ ScComplexRefData& rRef = static_cast<ScToken*>(pCode[j])->GetDoubleRef();
+ ScSingleRefData& rRef2 = rRef.Ref2;
+ ScSingleRefData& rRef1 = rRef.Ref1;
+
+ AdjustSingleRefData( rRef1, rOldPos, rNewPos );
+ AdjustSingleRefData( rRef2, rOldPos, rNewPos );
+
+ }
+ break;
+ case svSingleRef :
+ {
+ if (!SkipReference(static_cast<ScToken*>(pCode[j]), rOldPos, pOldDoc, false))
+ continue;
+
+ ScSingleRefData& rRef = static_cast<ScToken*>(pCode[j])->GetSingleRef();
+
+ AdjustSingleRefData( rRef, rOldPos, rNewPos );
+
+
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx
index 9fa5769..8f4f3fc 100644
--- a/sc/source/ui/docshell/docsh.cxx
+++ b/sc/source/ui/docshell/docsh.cxx
@@ -913,11 +913,25 @@ void ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint )
if ( !bSuccess )
SetError( ERRCODE_IO_ABORT, ::rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); // this error code will produce no error
message, but will break the further saving process
}
+
+
if (pSheetSaveData)
pSheetSaveData->SetInSupportedSave(true);
}
break;
case SFX_EVENT_SAVEASDOC:
+ {
+ if ( GetDocument()->GetExternalRefManager()->containsUnsavedReferences() )
+ {
+ WarningBox aBox( GetActiveDialogParent(), WinBits( WB_YES_NO ),
+ ScGlobal::GetRscString( STR_UNSAVED_EXT_REF ) );
+
+ if( RET_NO == aBox.Execute())
+ {
+ SetError( ERRCODE_IO_ABORT, ::rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); // this error code will produce no error
message, but will break the further saving process
+ }
+ }
+ } // fall through
case SFX_EVENT_SAVETODOC:
// #i108978# If no event is sent before saving, there will also be no "...DONE"
event,
// and SAVE/SAVEAS can't be distinguished from SAVETO. So stream copying is only
enabled
@@ -926,21 +940,11 @@ void ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint )
pSheetSaveData->SetInSupportedSave(true);
break;
case SFX_EVENT_SAVEDOCDONE:
+ case SFX_EVENT_SAVEASDOCDONE:
{
- if ( IsDocShared() && !SC_MOD()->IsInSharedDocSaving() )
- {
- }
+ // new positions are used after "save" and "save as", but not "save to"
UseSheetSaveEntries(); // use positions from saved file for next saving
- if (pSheetSaveData)
- pSheetSaveData->SetInSupportedSave(false);
- }
- break;
- case SFX_EVENT_SAVEASDOCDONE:
- // new positions are used after "save" and "save as", but not "save to"
- UseSheetSaveEntries(); // use positions from saved file for next saving
- if (pSheetSaveData)
- pSheetSaveData->SetInSupportedSave(false);
- break;
+ } // fall through
case SFX_EVENT_SAVETODOCDONE:
// only reset the flag, don't use the new positions
if (pSheetSaveData)
@@ -1567,6 +1571,7 @@ sal_Bool ScDocShell::SaveAs( SfxMedium& rMedium )
return false;
}
+
ScRefreshTimerProtector( aDocument.GetRefreshTimerControlAddress() );
PrepareSaveGuard aPrepareGuard( *this);
diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx
index 6d23ab9..4ad9a91 100644
--- a/sc/source/ui/docshell/externalrefmgr.cxx
+++ b/sc/source/ui/docshell/externalrefmgr.cxx
@@ -2092,7 +2092,7 @@ const ScDocument* ScExternalRefManager::getInMemorySrcDocument(sal_uInt16
nFileI
while (pShell)
{
SfxMedium* pMedium = pShell->GetMedium();
- if (pMedium)
+ if (pMedium && pMedium->GetName().Len())
{
OUString aName = pMedium->GetName();
// TODO: We should make the case sensitivity platform dependent.
@@ -2103,6 +2103,21 @@ const ScDocument* ScExternalRefManager::getInMemorySrcDocument(sal_uInt16
nFileI
break;
}
}
+ else
+ {
+ // handle unsaved documents here
+ OUString aName = pShell->GetName();
+ if (pFileName->equalsIgnoreAsciiCase(aName))
+ {
+ // Found !
+ SrcShell aSrcDoc;
+ aSrcDoc.maShell = pShell;
+ maUnsavedDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc));
+ StartListening(*pShell);
+ pSrcDoc = pShell->GetDocument();
+ break;
+ }
+ }
pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, &aType, false));
}
@@ -2127,6 +2142,17 @@ const ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
return static_cast<ScDocShell*>(p)->GetDocument();
}
+ itrEnd = maUnsavedDocShells.end();
+ itr = maUnsavedDocShells.find(nFileId);
+ if (itr != itrEnd)
+ {
+ //document is unsaved document
+
+ SfxObjectShell* p = itr->second.maShell;
+ itr->second.maLastAccess = Time( Time::SYSTEM );
+ return static_cast<ScDocShell*>(p)->GetDocument();
+ }
+
const OUString* pFile = getExternalFileName(nFileId);
if (!pFile)
// no file name associated with this ID.
@@ -2341,6 +2367,17 @@ bool ScExternalRefManager::isOwnDocument(const OUString& rFile) const
void ScExternalRefManager::convertToAbsName(OUString& rFile) const
{
+ // unsaved documents have no AbsName
+ TypeId aType(TYPE(ScDocShell));
+ ScDocShell* pShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(&aType, false));
+ while (pShell)
+ {
+ if (rFile == rtl::OUString(pShell->GetName()))
+ return;
+
+ pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, &aType, false));
+ }
+
SfxObjectShell* pDocShell = mpDoc->GetDocumentShell();
rFile = ScGlobal::GetAbsDocName(rFile, pDocShell);
}
@@ -2644,6 +2681,42 @@ sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId,
sal_u
return nNumFmt;
}
+void ScExternalRefManager::transformUnsavedRefToSavedRef( SfxObjectShell* pShell )
+{
+ DocShellMap::iterator itr = maUnsavedDocShells.begin();
+ while( itr != maUnsavedDocShells.end() )
+ {
+ if (&(itr->second.maShell) == pShell)
+ {
+ // found that the shell is marked as unsaved
+ rtl::OUString aFileURL =
pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
+ switchSrcFile(itr->first, aFileURL, rtl::OUString());
+ EndListening(*pShell);
+ maUnsavedDocShells.erase(itr++);
+ }
+ }
+}
+
+void ScExternalRefManager::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.ISA( SfxEventHint ) )
+ {
+ sal_uLong nEventId = ((SfxEventHint&)rHint).GetEventId();
+ switch ( nEventId )
+ {
+ case SFX_EVENT_SAVEDOCDONE:
+ case SFX_EVENT_SAVEASDOCDONE:
+ {
+ SfxObjectShell* pObjShell = static_cast<const SfxEventHint&>( rHint
).GetObjShell();
+ transformUnsavedRefToSavedRef(pObjShell);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
IMPL_LINK(ScExternalRefManager, TimeOutHdl, AutoTimer*, pTimer)
{
if (pTimer == &maSrcDocTimer)
diff --git a/sc/source/ui/src/globstr.src b/sc/source/ui/src/globstr.src
index 464f141..8d6425d 100644
--- a/sc/source/ui/src/globstr.src
+++ b/sc/source/ui/src/globstr.src
@@ -1851,5 +1851,9 @@ Resource RID_GLOBSTR
{
Text [ en-US ] = "Invalid name. Only use letters, numbers and underscore.";
};
+ String STR_UNSAVED_EXT_REF
+ {
+ Text [ en-US ] = "This Document contains external references to unsaved documents.\n\nDo
you want to continue?";
+ };
};
diff --git a/sc/source/ui/view/viewfun2.cxx b/sc/source/ui/view/viewfun2.cxx
index cfa027e..e2c950c 100644
--- a/sc/source/ui/view/viewfun2.cxx
+++ b/sc/source/ui/view/viewfun2.cxx
@@ -89,6 +89,7 @@
#include "docuno.hxx"
#include "charthelper.hxx"
#include "tabbgcolor.hxx"
+#include "clipparam.hxx"
#include <basic/sbstar.hxx>
#include <com/sun/star/container/XNameContainer.hpp>
@@ -2562,6 +2563,7 @@ void ScViewFunc::MoveTable(
if(nDestTab==SC_TAB_APPEND)
nDestTab=pDestDoc->GetTableCount();
SCTAB nDestTab1=nDestTab;
+ ScClipParam aParam;
for( sal_uInt16 j=0; j<TheTabs.size(); ++j, ++nDestTab1 )
{ // insert sheets first and update all references
rtl::OUString aName;
@@ -2576,7 +2578,10 @@ void ScViewFunc::MoveTable(
nErrVal = 0; // total error
break; // for
}
+ ScRange aRange( 0, 0, TheTabs[j], MAXCOL, MAXROW, TheTabs[j] );
+ aParam.maRanges.Append(aRange);
}
+ pDoc->SetClipParam(aParam);
if ( nErrVal > 0 )
{
nDestTab1 = nDestTab;
--
1.7.3.4
Context
- [Libreoffice] [Patch] [Review 3.5 - Late Feature] Improved copying between different calc documents · Markus Mohrhard
Privacy Policy |
Impressum (Legal Info) |
Copyright information: Unless otherwise specified, all text and images
on this website are licensed under the
Creative Commons Attribution-Share Alike 3.0 License.
This does not include the source code of LibreOffice, which is
licensed under the Mozilla Public License (
MPLv2).
"LibreOffice" and "The Document Foundation" are
registered trademarks of their corresponding registered owners or are
in actual use as trademarks in one or more countries. Their respective
logos and icons are also subject to international copyright laws. Use
thereof is explained in our
trademark policy.