summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu8
-rw-r--r--sc/Library_sc.mk1
-rw-r--r--sc/inc/cellvalues.hxx60
-rw-r--r--sc/inc/column.hxx7
-rw-r--r--sc/inc/document.hxx5
-rw-r--r--sc/inc/formulacell.hxx1
-rw-r--r--sc/inc/globstr.hrc3
-rw-r--r--sc/inc/sc.hrc5
-rw-r--r--sc/inc/table.hxx8
-rw-r--r--sc/sdi/cellsh.sdi2
-rw-r--r--sc/sdi/scalc.sdi27
-rw-r--r--sc/source/core/data/cellvalues.cxx202
-rw-r--r--sc/source/core/data/column4.cxx149
-rw-r--r--sc/source/core/data/document10.cxx41
-rw-r--r--sc/source/core/data/formulacell.cxx9
-rw-r--r--sc/source/core/data/table7.cxx21
-rw-r--r--sc/source/ui/docshell/docfunc.cxx34
-rw-r--r--sc/source/ui/inc/docfunc.hxx2
-rw-r--r--sc/source/ui/inc/undoconvert.hxx37
-rw-r--r--sc/source/ui/inc/viewfunc.hxx1
-rw-r--r--sc/source/ui/src/globstr.src5
-rw-r--r--sc/source/ui/undo/undoconvert.cxx51
-rw-r--r--sc/source/ui/view/cellsh1.cxx5
-rw-r--r--sc/source/ui/view/viewfun2.cxx11
24 files changed, 692 insertions, 3 deletions
diff --git a/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu
index a0f7e86bb6d9..d81f35b32901 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu
@@ -1709,6 +1709,14 @@
<value>1</value>
</prop>
</node>
+ <node oor:name=".uno:ConvertFormulaToValue" oor:op="replace">
+ <prop oor:name="Label" oor:type="xs:string">
+ <value xml:lang="en-US">Convert Formula to Value</value>
+ </prop>
+ <prop oor:name="Properties" oor:type="xs:int">
+ <value>1</value>
+ </prop>
+ </node>
</node>
<node oor:name="Popups">
<node oor:name=".uno:AuditMenu" oor:op="replace">
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 639946a9b786..55988a153df5 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -514,6 +514,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
sc/source/ui/undo/undoblk3 \
sc/source/ui/undo/undocell \
sc/source/ui/undo/undocell2 \
+ sc/source/ui/undo/undoconvert \
sc/source/ui/undo/undodat \
sc/source/ui/undo/undodraw \
sc/source/ui/undo/undoolk \
diff --git a/sc/inc/cellvalues.hxx b/sc/inc/cellvalues.hxx
index 4f4c50fab4fd..b545fcdd9115 100644
--- a/sc/inc/cellvalues.hxx
+++ b/sc/inc/cellvalues.hxx
@@ -11,13 +11,29 @@
#define INCLUDED_SC_INC_CELLVALUES_HXX
#include "address.hxx"
+#include <global.hxx>
class ScColumn;
+namespace svl {
+
+class SharedString;
+
+}
+
namespace sc {
struct CellValuesImpl;
+struct CellValueSpan
+{
+ SCROW mnRow1;
+ SCROW mnRow2;
+ CellType meType;
+
+ CellValueSpan( SCROW nRow1, SCROW nRow2, CellType eType );
+};
+
/**
* Think of this as a mini-ScColumn like storage that only stores cell
* values in a column.
@@ -45,16 +61,60 @@ public:
void transferTo( ScColumn& rCol, SCROW nRow );
void copyTo( ScColumn& rCol, SCROW nRow ) const;
+ void swapNonEmpty( ScColumn& rCol );
void assign( const std::vector<double>& rVals );
size_t size() const;
+ void reset( size_t nSize );
+ void setValue( size_t nRow, double fVal );
+ void setValue( size_t nRow, const svl::SharedString& rStr );
+
+ void swap( CellValues& r );
+
+ std::vector<CellValueSpan> getNonEmptySpans() const;
+
private:
void copyCellsTo( ScColumn& rCol, SCROW nRow ) const;
void copyCellTextAttrsTo( ScColumn& rCol, SCROW nRow ) const;
};
+/**
+ * Stores cell values for multiple tables.
+ */
+class TableValues
+{
+ struct Impl;
+
+ Impl* mpImpl;
+
+ TableValues( const TableValues& ); // disabled
+ TableValues& operator= ( const TableValues& ); // disabled
+
+public:
+
+ TableValues();
+ TableValues( const ScRange& rRange );
+ ~TableValues();
+
+ const ScRange& getRange() const;
+
+ /**
+ * Swap the entire column.
+ */
+ void swap( SCTAB nTab, SCCOL nCol, CellValues& rColValue );
+
+ /**
+ * Swap non-empty blocks with the column storage.
+ */
+ void swapNonEmpty( SCTAB nTab, SCCOL nCol, ScColumn& rCol );
+
+ std::vector<CellValueSpan> getNonEmptySpans( SCTAB nTab, SCCOL nCol ) const;
+
+ void swap( TableValues& rOther );
+};
+
}
#endif
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 893ef1391e68..c694513ad491 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -60,6 +60,7 @@ class EditTextIterator;
struct NoteEntry;
class DocumentStreamAccess;
class CellValues;
+class TableValues;
struct RowSpan;
class RowHeightContext;
class CompileFormulaContext;
@@ -153,6 +154,7 @@ friend class sc::SingleColumnSpanSet;
friend class sc::ColumnSpanSet;
friend class sc::EditTextIterator;
friend class sc::CellValues;
+friend class sc::TableValues;
ScColumn(const ScColumn&); // disabled
ScColumn& operator= (const ScColumn&); // disabled
@@ -601,6 +603,11 @@ public:
void TransferCellValuesTo( SCROW nRow, size_t nLen, sc::CellValues& rDest );
void CopyCellValuesFrom( SCROW nRow, const sc::CellValues& rSrc );
+ void ConvertFormulaToValue(
+ sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2, sc::TableValues* pUndo );
+
+ void SwapNonEmpty(
+ sc::TableValues& rValues, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt );
#if DEBUG_COLUMN_STORAGE
void DumpFormulaGroups() const;
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 1d14b9f0382b..41fcffbd5f27 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -75,6 +75,7 @@ struct FormulaGroupContext;
class DocumentStreamAccess;
class DocumentLinkManager;
class CellValues;
+class TableValues;
class RowHeightContext;
struct SetFormulaDirtyContext;
class RefMovedHint;
@@ -2110,6 +2111,10 @@ public:
void SetCalcConfig( const ScCalcConfig& rConfig );
const ScCalcConfig& GetCalcConfig() const { return maCalcConfig; }
+ void ConvertFormulaToValue( const ScRange& rRange, sc::TableValues* pUndo );
+
+ void SwapNonEmpty( sc::TableValues& rValues );
+
private:
/**
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index b765ff07b63f..475bea34c9a2 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -300,6 +300,7 @@ public:
sal_uInt16 GetRawError(); // don't interpret, just return code or result error
bool GetErrorOrValue( sal_uInt16& rErr, double& rVal );
sc::FormulaResultValue GetResult();
+ sc::FormulaResultValue GetResult() const;
sal_uInt8 GetMatrixFlag() const { return cMatrixFlag;}
ScTokenArray* GetCode() { return pCode;}
const ScTokenArray* GetCode() const { return pCode;}
diff --git a/sc/inc/globstr.hrc b/sc/inc/globstr.hrc
index 0b2a6606b2d7..eab98cc892bc 100644
--- a/sc/inc/globstr.hrc
+++ b/sc/inc/globstr.hrc
@@ -693,8 +693,9 @@
#define STR_PRINT_PREVIEW_EMPTY_RANGE 530
#define STR_UNDO_CONDFORMAT 531
+#define STR_UNDO_FORMULA_TO_VALUE 532
-#define SC_GLOBSTR_STR_COUNT 532 /**< the count of permanently resident strings */
+#define SC_GLOBSTR_STR_COUNT 533 /**< the count of permanently resident strings */
#endif
diff --git a/sc/inc/sc.hrc b/sc/inc/sc.hrc
index 420d1492497a..2d7d228762e9 100644
--- a/sc/inc/sc.hrc
+++ b/sc/inc/sc.hrc
@@ -275,8 +275,9 @@
// functions
-#define SID_OPEN_CALC (SC_FUNCTION_START + 4)
-#define FILE_MENU_END (SC_FUNCTION_START + 20)
+#define SID_OPEN_CALC (SC_FUNCTION_START + 4)
+#define SID_CONVERT_FORMULA_TO_VALUE (SC_FUNCTION_START + 5)
+#define FILE_MENU_END (SC_FUNCTION_START + 20)
#define EDIT_MENU_START (FILE_MENU_END)
#define FID_DELETE_CELL (EDIT_MENU_START + 2)
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index fb5d6f9dcada..e0c6e2170b52 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -69,6 +69,7 @@ struct RefUpdateMoveTabContext;
struct NoteEntry;
class DocumentStreamAccess;
class CellValues;
+class TableValues;
class RowHeightContext;
class CompileFormulaContext;
struct SetFormulaDirtyContext;
@@ -934,6 +935,13 @@ public:
void TransferCellValuesTo( SCCOL nCol, SCROW nRow, size_t nLen, sc::CellValues& rDest );
void CopyCellValuesFrom( SCCOL nCol, SCROW nRow, const sc::CellValues& rSrc );
+ void ConvertFormulaToValue(
+ sc::EndListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ sc::TableValues* pUndo );
+
+ void SwapNonEmpty(
+ sc::TableValues& rValues, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt );
+
#if DEBUG_COLUMN_STORAGE
void DumpFormulaGroups( SCCOL nCol ) const;
#endif
diff --git a/sc/sdi/cellsh.sdi b/sc/sdi/cellsh.sdi
index 8447768121b2..9bc9444df90f 100644
--- a/sc/sdi/cellsh.sdi
+++ b/sc/sdi/cellsh.sdi
@@ -218,6 +218,8 @@ interface CellSelection
SID_HANGUL_HANJA_CONVERSION [ ExecMethod = ExecuteEdit; StateMethod = GetState; ]
SID_CHINESE_CONVERSION [ ExecMethod = ExecuteEdit; StateMethod = GetState; ]
+ SID_CONVERT_FORMULA_TO_VALUE [ ExecMethod = ExecuteEdit; StateMethod = GetBlockState; ]
+
SID_TRANSLITERATE_SENTENCE_CASE [ ExecMethod = ExecuteTrans; StateMethod = GetBlockState; ]
SID_TRANSLITERATE_TITLE_CASE [ ExecMethod = ExecuteTrans; StateMethod = GetBlockState; ]
SID_TRANSLITERATE_TOGGLE_CASE [ ExecMethod = ExecuteTrans; StateMethod = GetBlockState; ]
diff --git a/sc/sdi/scalc.sdi b/sc/sdi/scalc.sdi
index 1835459e540a..f9c6cc770d04 100644
--- a/sc/sdi/scalc.sdi
+++ b/sc/sdi/scalc.sdi
@@ -8753,6 +8753,33 @@ SfxVoidItem OpenFromCalc SID_OPEN_CALC
GroupId = GID_OPTIONS;
]
+SfxVoidItem ConvertFormulaToValue SID_CONVERT_FORMULA_TO_VALUE
+()
+[
+ /* flags: */
+ AutoUpdate = FALSE,
+ Cachable = Cachable,
+ FastCall = FALSE,
+ HasCoreId = FALSE,
+ HasDialog = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Synchron;
+
+ /* status: */
+ SlotType = SfxStringItem
+
+ /* config: */
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ StatusBarConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = GID_OPTIONS;
+]
+
SfxVoidItem ShowDetail SID_OUTLINE_SHOW
()
[
diff --git a/sc/source/core/data/cellvalues.cxx b/sc/source/core/data/cellvalues.cxx
index 083b4d1ac7a8..fb38ed52cae8 100644
--- a/sc/source/core/data/cellvalues.cxx
+++ b/sc/source/core/data/cellvalues.cxx
@@ -16,10 +16,44 @@
namespace sc {
+namespace {
+
+struct BlockPos
+{
+ size_t mnStart;
+ size_t mnEnd;
+};
+
+CellType toCellType( mdds::mtv::element_t eType )
+{
+ switch (eType)
+ {
+ case element_type_numeric:
+ return CELLTYPE_VALUE;
+ case element_type_string:
+ return CELLTYPE_STRING;
+ case element_type_edittext:
+ return CELLTYPE_EDIT;
+ case element_type_formula:
+ return CELLTYPE_FORMULA;
+ default:
+ ;
+ }
+
+ return CELLTYPE_NONE;
+}
+
+}
+
+CellValueSpan::CellValueSpan( SCROW nRow1, SCROW nRow2, CellType eType ) :
+ mnRow1(nRow1), mnRow2(nRow2), meType(eType) {}
+
struct CellValuesImpl : boost::noncopyable
{
CellStoreType maCells;
CellTextAttrStoreType maCellTextAttrs;
+ CellStoreType::iterator miCellPos;
+ CellTextAttrStoreType::iterator miAttrPos;
};
CellValues::CellValues() :
@@ -53,6 +87,34 @@ void CellValues::copyTo( ScColumn& rCol, SCROW nRow ) const
copyCellTextAttrsTo(rCol, nRow);
}
+void CellValues::swapNonEmpty( ScColumn& rCol )
+{
+ std::vector<BlockPos> aBlocksToSwap;
+
+ {
+ // Go through static value blocks and record their positions and sizes.
+ sc::CellStoreType::const_iterator it = mpImpl->maCells.begin(), itEnd = mpImpl->maCells.end();
+ for (; it != itEnd; ++it)
+ {
+ if (it->type == sc::element_type_empty)
+ continue;
+
+ BlockPos aPos;
+ aPos.mnStart = it->position;
+ aPos.mnEnd = aPos.mnStart + it->size - 1;
+ aBlocksToSwap.push_back(aPos);
+ }
+ }
+
+ // Do the swapping. The undo storage will store the replaced formula cells after this.
+ std::vector<BlockPos>::const_iterator it = aBlocksToSwap.begin(), itEnd = aBlocksToSwap.end();
+ for (; it != itEnd; ++it)
+ {
+ rCol.maCells.swap(it->mnStart, it->mnEnd, mpImpl->maCells, it->mnStart);
+ rCol.maCellTextAttrs.swap(it->mnStart, it->mnEnd, mpImpl->maCellTextAttrs, it->mnStart);
+ }
+}
+
void CellValues::assign( const std::vector<double>& rVals )
{
mpImpl->maCells.resize(rVals.size());
@@ -70,6 +132,51 @@ size_t CellValues::size() const
return mpImpl->maCells.size();
}
+void CellValues::reset( size_t nSize )
+{
+ mpImpl->maCells.clear();
+ mpImpl->maCells.resize(nSize);
+ mpImpl->maCellTextAttrs.clear();
+ mpImpl->maCellTextAttrs.resize(nSize);
+
+ mpImpl->miCellPos = mpImpl->maCells.begin();
+ mpImpl->miAttrPos = mpImpl->maCellTextAttrs.begin();
+}
+
+void CellValues::setValue( size_t nRow, double fVal )
+{
+ mpImpl->miCellPos = mpImpl->maCells.set(mpImpl->miCellPos, nRow, fVal);
+ mpImpl->miAttrPos = mpImpl->maCellTextAttrs.set(mpImpl->miAttrPos, nRow, sc::CellTextAttr());
+}
+
+void CellValues::setValue( size_t nRow, const svl::SharedString& rStr )
+{
+ mpImpl->miCellPos = mpImpl->maCells.set(mpImpl->miCellPos, nRow, rStr);
+ mpImpl->miAttrPos = mpImpl->maCellTextAttrs.set(mpImpl->miAttrPos, nRow, sc::CellTextAttr());
+}
+
+void CellValues::swap( CellValues& r )
+{
+ std::swap(mpImpl, r.mpImpl);
+}
+
+std::vector<CellValueSpan> CellValues::getNonEmptySpans() const
+{
+ std::vector<CellValueSpan> aRet;
+ CellStoreType::const_iterator it = mpImpl->maCells.begin(), itEnd = mpImpl->maCells.end();
+ for (; it != itEnd; ++it)
+ {
+ if (it->type != element_type_empty)
+ {
+ // Record this span.
+ size_t nRow1 = it->position;
+ size_t nRow2 = nRow1 + it->size - 1;
+ aRet.push_back(CellValueSpan(nRow1, nRow2, toCellType(it->type)));
+ }
+ }
+ return aRet;
+}
+
void CellValues::copyCellsTo( ScColumn& rCol, SCROW nRow ) const
{
CellStoreType& rDest = rCol.maCells;
@@ -167,6 +274,101 @@ void CellValues::copyCellTextAttrsTo( ScColumn& rCol, SCROW nRow ) const
}
}
+typedef boost::ptr_vector<CellValues> TableType;
+typedef boost::ptr_vector<TableType> TablesType;
+
+struct TableValues::Impl
+{
+ ScRange maRange;
+ TablesType maTables;
+
+ Impl( const ScRange& rRange ) : maRange(rRange)
+ {
+ size_t nTabs = rRange.aEnd.Tab() - rRange.aStart.Tab() + 1;
+ size_t nCols = rRange.aEnd.Col() - rRange.aStart.Col() + 1;
+
+ for (size_t nTab = 0; nTab < nTabs; ++nTab)
+ {
+ maTables.push_back(new TableType);
+ TableType& rTab = maTables.back();
+ for (size_t nCol = 0; nCol < nCols; ++nCol)
+ rTab.push_back(new CellValues);
+ }
+ }
+
+ CellValues* getCellValues( SCTAB nTab, SCCOL nCol )
+ {
+ if (nTab < maRange.aStart.Tab() || maRange.aEnd.Tab() < nTab)
+ // sheet index out of bound.
+ return NULL;
+
+ if (nCol < maRange.aStart.Col() || maRange.aEnd.Col() < nCol)
+ // column index out of bound.
+ return NULL;
+
+ size_t nTabOffset = nTab - maRange.aStart.Tab();
+ if (nTabOffset >= maTables.size())
+ return NULL;
+
+ TableType& rTab = maTables[nTab-maRange.aStart.Tab()];
+
+ size_t nColOffset = nCol - maRange.aStart.Col();
+ if (nColOffset >= rTab.size())
+ return NULL;
+
+ return &rTab[nColOffset];
+ }
+};
+
+TableValues::TableValues() :
+ mpImpl(new Impl(ScRange(ScAddress::INITIALIZE_INVALID))) {}
+
+TableValues::TableValues( const ScRange& rRange ) :
+ mpImpl(new Impl(rRange)) {}
+
+TableValues::~TableValues()
+{
+ delete mpImpl;
+}
+
+const ScRange& TableValues::getRange() const
+{
+ return mpImpl->maRange;
+}
+
+void TableValues::swap( SCTAB nTab, SCCOL nCol, CellValues& rColValue )
+{
+ CellValues* pCol = mpImpl->getCellValues(nTab, nCol);
+ if (!pCol)
+ return;
+
+ pCol->swap(rColValue);
+}
+
+void TableValues::swapNonEmpty( SCTAB nTab, SCCOL nCol, ScColumn& rCol )
+{
+ CellValues* pCol = mpImpl->getCellValues(nTab, nCol);
+ if (!pCol)
+ return;
+
+ pCol->swapNonEmpty(rCol);
+}
+
+std::vector<CellValueSpan> TableValues::getNonEmptySpans( SCTAB nTab, SCCOL nCol ) const
+{
+ std::vector<CellValueSpan> aRet;
+ CellValues* pCol = mpImpl->getCellValues(nTab, nCol);
+ if (pCol)
+ aRet = pCol->getNonEmptySpans();
+
+ return aRet;
+}
+
+void TableValues::swap( TableValues& rOther )
+{
+ std::swap(mpImpl, rOther.mpImpl);
+}
+
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 3be685704057..c0c1fde3cb3f 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -322,6 +322,155 @@ void ScColumn::CopyCellValuesFrom( SCROW nRow, const sc::CellValues& rSrc )
BroadcastCells(aRows, SC_HINT_DATACHANGED);
}
+namespace {
+
+class ConvertFormulaToValueHandler
+{
+ SCTAB mnTab;
+ SCCOL mnCol;
+ sc::CellValues maResValues;
+ bool mbModified;
+
+public:
+ ConvertFormulaToValueHandler( SCTAB nTab, SCCOL nCol ) :
+ mnTab(nTab),
+ mnCol(nCol),
+ mbModified(false)
+ {
+ maResValues.reset(MAXROWCOUNT);
+ }
+
+ void operator() ( size_t nRow, const ScFormulaCell* pCell )
+ {
+ sc::FormulaResultValue aRes = pCell->GetResult();
+ switch (aRes.meType)
+ {
+ case sc::FormulaResultValue::Value:
+ maResValues.setValue(nRow, aRes.mfValue);
+ break;
+ case sc::FormulaResultValue::String:
+ maResValues.setValue(nRow, aRes.maString);
+ break;
+ case sc::FormulaResultValue::Error:
+ case sc::FormulaResultValue::Invalid:
+ default:
+ maResValues.setValue(nRow, svl::SharedString::getEmptyString());
+ }
+
+ mbModified = true;
+ }
+
+ bool isModified() const { return mbModified; }
+
+ sc::CellValues& getResValues() { return maResValues; }
+};
+
+}
+
+void ScColumn::ConvertFormulaToValue(
+ sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2, sc::TableValues* pUndo )
+{
+ if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
+ return;
+
+ std::vector<SCROW> aBounds;
+ aBounds.push_back(nRow1);
+ if (nRow2 < MAXROW-1)
+ aBounds.push_back(nRow2+1);
+
+ // Split formula cell groups at top and bottom boundaries (if applicable).
+ sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
+
+ // Parse all formulas within the range and store their results into temporary storage.
+ ConvertFormulaToValueHandler aFunc(nTab, nCol);
+ sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
+ if (!aFunc.isModified())
+ // No formula cells encountered.
+ return;
+
+ DetachFormulaCells(rCxt, nRow1, nRow2);
+
+ // Undo storage to hold static values which will get swapped to the cell storage later.
+ sc::CellValues aUndoCells;
+ aFunc.getResValues().swap(aUndoCells);
+ aUndoCells.swapNonEmpty(*this);
+ if (pUndo)
+ pUndo->swap(nTab, nCol, aUndoCells);
+}
+
+namespace {
+
+class StartListeningHandler
+{
+ sc::StartListeningContext& mrCxt;
+
+public:
+ StartListeningHandler( sc::StartListeningContext& rCxt ) :
+ mrCxt(rCxt) {}
+
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
+ {
+ pCell->StartListeningTo(mrCxt);
+ }
+};
+
+class EndListeningHandler
+{
+ sc::EndListeningContext& mrCxt;
+
+public:
+ EndListeningHandler( sc::EndListeningContext& rCxt ) :
+ mrCxt(rCxt) {}
+
+ void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
+ {
+ pCell->EndListeningTo(mrCxt);
+ }
+};
+
+}
+
+void ScColumn::SwapNonEmpty(
+ sc::TableValues& rValues, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt )
+{
+ const ScRange& rRange = rValues.getRange();
+ std::vector<SCROW> aBounds;
+ aBounds.push_back(rRange.aStart.Row());
+ if (rRange.aEnd.Row() < MAXROW-1)
+ aBounds.push_back(rRange.aEnd.Row()+1);
+
+ // Split formula cell groups at top and bottom boundaries (if applicable).
+ sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
+ std::vector<sc::CellValueSpan> aSpans = rValues.getNonEmptySpans(nTab, nCol);
+
+ // Detach formula cells within the spans (if any).
+ EndListeningHandler aEndLisFunc(rEndCxt);
+ std::vector<sc::CellValueSpan>::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
+ sc::CellStoreType::iterator itPos = maCells.begin();
+ for (; it != itEnd; ++it)
+ {
+ SCROW nRow1 = it->mnRow1;
+ SCROW nRow2 = it->mnRow2;
+ itPos = sc::ProcessFormula(itPos, maCells, nRow1, nRow2, aEndLisFunc);
+ }
+
+ rValues.swapNonEmpty(nTab, nCol, *this);
+ RegroupFormulaCells();
+
+ // Attach formula cells within the spans (if any).
+ StartListeningHandler aStartLisFunc(rStartCxt);
+ it = aSpans.begin();
+ itPos = maCells.begin();
+ for (; it != itEnd; ++it)
+ {
+ SCROW nRow1 = it->mnRow1;
+ SCROW nRow2 = it->mnRow2;
+ itPos = sc::ProcessFormula(itPos, maCells, nRow1, nRow2, aStartLisFunc);
+ }
+
+ CellStorageModified();
+}
+
void ScColumn::DeleteRanges( const std::vector<sc::RowSpan>& rRanges, InsertDeleteFlags nDelFlag, bool bBroadcast )
{
std::vector<sc::RowSpan>::const_iterator itSpan = rRanges.begin(), itSpanEnd = rRanges.end();
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index 51b85ec0cfc4..183e8e5d02e8 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -18,6 +18,7 @@
#include <tokenstringcontext.hxx>
#include <poolhelp.hxx>
#include <bcaslot.hxx>
+#include <cellvalues.hxx>
#include "dociter.hxx"
#include "patattr.hxx"
@@ -302,6 +303,46 @@ void ScDocument::SetCalcConfig( const ScCalcConfig& rConfig )
maCalcConfig = rConfig;
}
+void ScDocument::ConvertFormulaToValue( const ScRange& rRange, sc::TableValues* pUndo )
+{
+ sc::EndListeningContext aCxt(*this);
+
+ for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
+ {
+ ScTable* pTab = FetchTable(nTab);
+ if (!pTab)
+ continue;
+
+ pTab->ConvertFormulaToValue(
+ aCxt, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(),
+ pUndo);
+ }
+
+ aCxt.purgeEmptyBroadcasters();
+}
+
+void ScDocument::SwapNonEmpty( sc::TableValues& rValues )
+{
+ const ScRange& rRange = rValues.getRange();
+ if (!rRange.IsValid())
+ return;
+
+ boost::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(new sc::ColumnBlockPositionSet(*this));
+ sc::StartListeningContext aStartCxt(*this, pPosSet);
+ sc::EndListeningContext aEndCxt(*this, pPosSet);
+
+ for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
+ {
+ ScTable* pTab = FetchTable(nTab);
+ if (!pTab)
+ continue;
+
+ pTab->SwapNonEmpty(rValues, aStartCxt, aEndCxt);
+ }
+
+ aEndCxt.purgeEmptyBroadcasters();
+}
+
void ScDocument::PreprocessRangeNameUpdate()
{
sc::EndListeningContext aEndListenCxt(*this);
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index d10b9d4ff763..8cd95986c73c 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2513,6 +2513,15 @@ sc::FormulaResultValue ScFormulaCell::GetResult()
return aResult.GetResult();
}
+sc::FormulaResultValue ScFormulaCell::GetResult() const
+{
+ sal_uInt16 nErr = pCode->GetCodeError();
+ if (nErr)
+ return sc::FormulaResultValue(nErr);
+
+ return aResult.GetResult();
+}
+
bool ScFormulaCell::HasOneReference( ScRange& r ) const
{
pCode->Reset();
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index 407a8ba0d155..2104b6f983bc 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -14,6 +14,7 @@
#include <bcaslot.hxx>
#include <segmenttree.hxx>
#include <sharedformula.hxx>
+#include <cellvalues.hxx>
bool ScTable::IsMerged( SCCOL nCol, SCROW nRow ) const
{
@@ -82,6 +83,26 @@ void ScTable::CopyCellValuesFrom( SCCOL nCol, SCROW nRow, const sc::CellValues&
aCol[nCol].CopyCellValuesFrom(nRow, rSrc);
}
+void ScTable::ConvertFormulaToValue(
+ sc::EndListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ sc::TableValues* pUndo )
+{
+ if (!ValidCol(nCol1) || !ValidCol(nCol2) || nCol1 > nCol2)
+ return;
+
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ aCol[nCol].ConvertFormulaToValue(rCxt, nRow1, nRow2, pUndo);
+}
+
+void ScTable::SwapNonEmpty(
+ sc::TableValues& rValues, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt )
+{
+ const ScRange& rRange = rValues.getRange();
+ assert(rRange.IsValid());
+ for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
+ aCol[nCol].SwapNonEmpty(rValues, rStartCxt, rEndCxt);
+}
+
void ScTable::PreprocessRangeNameUpdate(
sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt )
{
diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx
index c20992abf876..f3a6245ca7d4 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -84,6 +84,8 @@
#include "cellvalue.hxx"
#include "tokenarray.hxx"
#include <rowheightcontext.hxx>
+#include <cellvalues.hxx>
+#include <undoconvert.hxx>
#include <memory>
#include <utility>
@@ -5384,6 +5386,38 @@ void ScDocFunc::SetConditionalFormatList( ScConditionalFormatList* pList, SCTAB
SfxGetpApp()->Broadcast(SfxSimpleHint(SC_HINT_AREAS_CHANGED));
}
+void ScDocFunc::ConvertFormulaToValue( const ScRange& rRange, bool bRecord, bool bInteraction )
+{
+ ScDocShellModificator aModificator(rDocShell);
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScEditableTester aTester(&rDoc, rRange);
+ if (!aTester.IsEditable())
+ {
+ if (bInteraction)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ sc::TableValues aUndoVals(rRange);
+ sc::TableValues* pUndoVals = bRecord ? &aUndoVals : NULL;
+
+ rDoc.ConvertFormulaToValue(rRange, pUndoVals);
+
+ if (bRecord && pUndoVals)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ new sc::UndoFormulaToValue(&rDocShell, *pUndoVals));
+ }
+
+ rDocShell.PostPaint(rRange, PAINT_GRID);
+ rDocShell.PostDataChanged();
+ rDoc.BroadcastCells(rRange, SC_HINT_DATACHANGED);
+ aModificator.SetDocumentModified();
+}
+
void ScDocFunc::EnterListAction( sal_uInt16 nNameResId )
{
OUString aUndo( ScGlobal::GetRscString( nNameResId ) );
diff --git a/sc/source/ui/inc/docfunc.hxx b/sc/source/ui/inc/docfunc.hxx
index 37bf4aac12b7..ebd7ac371aeb 100644
--- a/sc/source/ui/inc/docfunc.hxx
+++ b/sc/source/ui/inc/docfunc.hxx
@@ -222,6 +222,8 @@ public:
* @param nTab the tab to which the conditional format list belongs
*/
void SetConditionalFormatList( ScConditionalFormatList* pList, SCTAB nTab );
+
+ void ConvertFormulaToValue( const ScRange& rRange, bool bRecord, bool bInteraction );
};
class ScDocFuncDirect : public ScDocFunc
diff --git a/sc/source/ui/inc/undoconvert.hxx b/sc/source/ui/inc/undoconvert.hxx
new file mode 100644
index 000000000000..99ce97f51e7c
--- /dev/null
+++ b/sc/source/ui/inc/undoconvert.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SC_UNDOCONVERT_HXX
+#define INCLUDED_SC_UNDOCONVERT_HXX
+
+#include <undobase.hxx>
+#include <cellvalues.hxx>
+
+namespace sc {
+
+class UndoFormulaToValue : public ScSimpleUndo
+{
+ TableValues maUndoValues;
+
+public:
+ UndoFormulaToValue( ScDocShell* pDocSh, TableValues& rUndoValues );
+
+ virtual OUString GetComment() const SAL_OVERRIDE;
+ virtual void Undo() SAL_OVERRIDE;
+ virtual void Redo() SAL_OVERRIDE;
+
+private:
+ void Execute();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/viewfunc.hxx b/sc/source/ui/inc/viewfunc.hxx
index cd664cd5b45d..70c7e0f8df4b 100644
--- a/sc/source/ui/inc/viewfunc.hxx
+++ b/sc/source/ui/inc/viewfunc.hxx
@@ -240,6 +240,7 @@ public:
void FillAuto( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount, bool bRecord = true );
void FillCrossDblClick();
+ void ConvertFormulaToValue();
void TransliterateText( sal_Int32 nType );
diff --git a/sc/source/ui/src/globstr.src b/sc/source/ui/src/globstr.src
index 3d167fdef221..985644afec1f 100644
--- a/sc/source/ui/src/globstr.src
+++ b/sc/source/ui/src/globstr.src
@@ -2076,6 +2076,11 @@ Resource RID_GLOBSTR
{
Text [ en-US ] = "Conditional Format";
};
+
+ String STR_UNDO_FORMULA_TO_VALUE
+ {
+ Text [ en-US ] = "Convert Formula To Value";
+ };
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoconvert.cxx b/sc/source/ui/undo/undoconvert.cxx
new file mode 100644
index 000000000000..995ab8f3e2fd
--- /dev/null
+++ b/sc/source/ui/undo/undoconvert.cxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <undoconvert.hxx>
+#include <globstr.hrc>
+#include <undoutil.hxx>
+
+namespace sc {
+
+UndoFormulaToValue::UndoFormulaToValue( ScDocShell* pDocSh, TableValues& rUndoValues ) :
+ ScSimpleUndo(pDocSh)
+{
+ maUndoValues.swap(rUndoValues);
+}
+
+OUString UndoFormulaToValue::GetComment() const
+{
+ return ScGlobal::GetRscString(STR_UNDO_FORMULA_TO_VALUE);
+}
+
+void UndoFormulaToValue::Undo()
+{
+ Execute();
+}
+
+void UndoFormulaToValue::Redo()
+{
+ Execute();
+}
+
+void UndoFormulaToValue::Execute()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.SwapNonEmpty(maUndoValues);
+
+ ScUndoUtil::MarkSimpleBlock(pDocShell, maUndoValues.getRange());
+
+ pDocShell->PostPaint(maUndoValues.getRange(), PAINT_GRID);
+ pDocShell->PostDataChanged();
+ rDoc.BroadcastCells(maUndoValues.getRange(), SC_HINT_DATACHANGED);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/cellsh1.cxx b/sc/source/ui/view/cellsh1.cxx
index bb9ce1ad1cae..511d4b7e2e9d 100644
--- a/sc/source/ui/view/cellsh1.cxx
+++ b/sc/source/ui/view/cellsh1.cxx
@@ -1754,6 +1754,11 @@ void ScCellShell::ExecuteEdit( SfxRequest& rReq )
}
break;
+ case SID_CONVERT_FORMULA_TO_VALUE:
+ {
+ pTabViewShell->ConvertFormulaToValue();
+ }
+ break;
case SID_THESAURUS:
pTabViewShell->DoThesaurus();
break;
diff --git a/sc/source/ui/view/viewfun2.cxx b/sc/source/ui/view/viewfun2.cxx
index df5fb973cb6e..1f395fc4aad6 100644
--- a/sc/source/ui/view/viewfun2.cxx
+++ b/sc/source/ui/view/viewfun2.cxx
@@ -1414,6 +1414,17 @@ void ScViewFunc::FillCrossDblClick()
}
}
+void ScViewFunc::ConvertFormulaToValue()
+{
+ ScRange aRange;
+ GetViewData().GetSimpleArea(aRange);
+ aRange.Justify();
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ pDocSh->GetDocFunc().ConvertFormulaToValue(aRange, true, true);
+ pDocSh->PostPaint(aRange, PAINT_GRID);
+}
+
void ScViewFunc::TransliterateText( sal_Int32 nType )
{
ScMarkData aFuncMark = GetViewData().GetMarkData();