sc: Add sheet view sync for CreatePivotTableOperation

For pivot tables we operate with ScDPObject as input, which has
the input and output ranges. We	need to	convert	the ranges to the
default	view tab, so the pivot table is	created	on the default view.
Sync will take pivot tables into account when copying the content
to sheet views,	so we don't need to do anything	special	here.

Change-Id: Ie28fda2d04576fd689d11010401709c6c02431c8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201695
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/202115
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
(cherry picked from commit a36ac18990c89f740b8329b8325e4abe3d3e2087)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205551
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Tomaž Vajngerl
2026-05-24 16:38:47 +02:00
committed by Xisco Fauli
parent 86c3b212a8
commit 7f2a75d8d7
6 changed files with 142 additions and 28 deletions
+1
View File
@@ -44,6 +44,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sc_sheetview_test, \
$(eval $(call gb_CppunitTest_use_externals,sc_sheetview_test,\
boost_headers \
libxml2 \
mdds_headers \
))
$(eval $(call gb_CppunitTest_set_include,sc_sheetview_test,\
+1 -1
View File
@@ -437,7 +437,7 @@ public:
SC_DLLPUBLIC ScDPObject& operator[](size_t nIndex);
SC_DLLPUBLIC const ScDPObject& operator[](size_t nIndex) const;
ScDPObject* GetByName(std::u16string_view rName) const;
SC_DLLPUBLIC ScDPObject* GetByName(std::u16string_view rName) const;
void DeleteOnTab( SCTAB nTab );
void UpdateReference( UpdateRefMode eUpdateRefMode,
+100
View File
@@ -37,9 +37,15 @@
#include <Sparkline.hxx>
#include <SparklineAttributes.hxx>
#include <SparklineGroup.hxx>
#include <dpobject.hxx>
#include <dpshttab.hxx>
#include <dpsave.hxx>
#include <generalfunction.hxx>
#include <svx/svdorect.hxx>
#include <svx/svdpage.hxx>
#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
using namespace css;
class SheetViewTest : public ScTiledRenderingTest
@@ -3724,6 +3730,100 @@ CPPUNIT_TEST_FIXTURE(SyncTest, testSync_DeleteSparklineGroup_DefaultAndSheetView
}
}
CPPUNIT_TEST_FIXTURE(SyncTest, testSync_CreatePivotTable_DefaultAndSheetView)
{
// test sync to sheet view when creating a new pivot table
ScModelObj* pModelObj = createDoc("empty.ods");
pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
ScDocShell* pDocShell = dynamic_cast<ScDocShell*>(pModelObj->GetEmbeddedObject());
ScDocument& rDocument = pDocShell->GetDocument();
// Set up source data: A1:B4 with headers and values
rDocument.SetString(ScAddress(0, 0, 0), u"Category"_ustr);
rDocument.SetString(ScAddress(1, 0, 0), u"Value"_ustr);
rDocument.SetString(ScAddress(0, 1, 0), u"A"_ustr);
rDocument.SetString(ScAddress(0, 2, 0), u"A"_ustr);
rDocument.SetString(ScAddress(0, 3, 0), u"B"_ustr);
rDocument.SetValue(ScAddress(1, 1, 0), 10.0);
rDocument.SetValue(ScAddress(1, 2, 0), 20.0);
rDocument.SetValue(ScAddress(1, 3, 0), 30.0);
setupViews();
// Create sheet view
{
switchToSheetView();
createNewSheetViewInCurrentView();
}
SCTAB nSheetViewTab = mpTabViewSheetView->GetViewData().GetTabNumber();
SCTAB nDefaultViewTab = mpTabViewDefaultView->GetViewData().GetTabNumber();
// Create pivot table from default view
{
switchToDefaultView();
ScDPObject aDPObject(&rDocument);
ScSheetSourceDesc aSheetDesc(&rDocument);
aSheetDesc.SetSourceRange(ScRange(0, 0, nDefaultViewTab, 1, 3, nDefaultViewTab));
aDPObject.SetSheetDesc(aSheetDesc);
aDPObject.SetOutRange(ScRange(ScAddress(4, 0, nDefaultViewTab)));
ScDPSaveData aSaveData;
ScDPSaveDimension* pDim = aSaveData.GetNewDimensionByName(u"Category"_ustr);
pDim->SetOrientation(css::sheet::DataPilotFieldOrientation_ROW);
pDim = aSaveData.GetNewDimensionByName(u"Value"_ustr);
pDim->SetOrientation(css::sheet::DataPilotFieldOrientation_DATA);
pDim->SetFunction(ScGeneralFunction::SUM);
aDPObject.SetSaveData(aSaveData);
ScDBDocFunc aDBDocFunc(*pDocShell);
bool bResult = aDBDocFunc.CreatePivotTable(aDPObject, true, true);
CPPUNIT_ASSERT(bResult);
// Verify pivot table output on default view - cell E1 should have content
CPPUNIT_ASSERT(!rDocument.GetString(ScAddress(4, 0, nDefaultViewTab)).isEmpty());
// Verify the pivot table output is synced to sheet view
CPPUNIT_ASSERT_EQUAL(rDocument.GetString(ScAddress(4, 0, nDefaultViewTab)),
rDocument.GetString(ScAddress(4, 0, nSheetViewTab)));
CPPUNIT_ASSERT_EQUAL(rDocument.GetString(ScAddress(4, 1, nDefaultViewTab)),
rDocument.GetString(ScAddress(4, 1, nSheetViewTab)));
}
// Create pivot table from sheet view
{
switchToSheetView();
ScDPObject aDPObject(&rDocument);
ScSheetSourceDesc aSheetDesc(&rDocument);
aSheetDesc.SetSourceRange(ScRange(0, 0, nSheetViewTab, 1, 3, nSheetViewTab));
aDPObject.SetSheetDesc(aSheetDesc);
aDPObject.SetOutRange(ScRange(ScAddress(7, 0, nSheetViewTab)));
ScDPSaveData aSaveData;
ScDPSaveDimension* pDim = aSaveData.GetNewDimensionByName(u"Category"_ustr);
pDim->SetOrientation(css::sheet::DataPilotFieldOrientation_ROW);
pDim = aSaveData.GetNewDimensionByName(u"Value"_ustr);
pDim->SetOrientation(css::sheet::DataPilotFieldOrientation_DATA);
pDim->SetFunction(ScGeneralFunction::SUM);
aDPObject.SetSaveData(aSaveData);
ScDBDocFunc aDBDocFunc(*pDocShell);
bool bResult = aDBDocFunc.CreatePivotTable(aDPObject, true, true);
CPPUNIT_ASSERT(bResult);
// Verify pivot table created on default view - cell H1 should have content
CPPUNIT_ASSERT(!rDocument.GetString(ScAddress(7, 0, nDefaultViewTab)).isEmpty());
// Verify the pivot table output is synced to sheet view
CPPUNIT_ASSERT_EQUAL(rDocument.GetString(ScAddress(7, 0, nDefaultViewTab)),
rDocument.GetString(ScAddress(7, 0, nSheetViewTab)));
CPPUNIT_ASSERT_EQUAL(rDocument.GetString(ScAddress(7, 1, nDefaultViewTab)),
rDocument.GetString(ScAddress(7, 1, nSheetViewTab)));
}
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+1 -1
View File
@@ -93,7 +93,7 @@ public:
bool bRecord, bool bApi, bool bAllowMove = false );
bool RemovePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi);
bool CreatePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi);
SC_DLLPUBLIC bool CreatePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi);
bool UpdatePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi);
/**
@@ -21,12 +21,12 @@ class CreatePivotTableOperation : public Operation
{
private:
ScDocShell& mrDocShell;
ScDPObject const& mrDPObj;
ScDPObject const& mrDPObject;
bool runImplementation() override;
public:
CreatePivotTableOperation(ScDocShell& rDocShell, ScDPObject const& rDPObj, bool bRecord,
CreatePivotTableOperation(ScDocShell& rDocShell, ScDPObject const& rDPObject, bool bRecord,
bool bApi);
};
} // end sc namespace
@@ -16,6 +16,7 @@
#include <vcl/weld/Window.hxx>
#include <dpsave.hxx>
#include <dpshttab.hxx>
#include <undodat.hxx>
#include <scresid.hxx>
#include <hints.hxx>
@@ -23,11 +24,11 @@
namespace sc
{
CreatePivotTableOperation::CreatePivotTableOperation(ScDocShell& rDocShell,
ScDPObject const& rDPObj, bool bRecord,
ScDPObject const& rDPObject, bool bRecord,
bool bApi)
: Operation(OperationType::PivotTableCreate, bRecord, bApi)
, mrDocShell(rDocShell)
, mrDPObj(rDPObj)
, mrDPObject(rDPObject)
{
}
@@ -36,55 +37,65 @@ bool CreatePivotTableOperation::runImplementation()
ScDocShellModificator aModificator(mrDocShell);
weld::WaitObject aWait(ScDocShell::GetActiveDialogParent());
if (!checkSheetViewProtection())
return false;
// At least one cell in the output range should be editable. Check in advance.
ScDocument& rDoc = mrDocShell.GetDocument();
if (!rDoc.IsImportingXML()
&& !sc::pivot::isEditable(mrDocShell, ScRange(mrDPObj.GetOutRange().aStart), mbApi))
auto aOutputStartRange = convertRange(ScRange(mrDPObject.GetOutRange().aStart));
if (!rDoc.IsImportingXML() && !sc::pivot::isEditable(mrDocShell, aOutputStartRange, mbApi))
{
return false;
}
ScDocumentUniquePtr pNewUndoDoc;
if (mbRecord && !rDoc.IsUndoEnabled())
mbRecord = false;
// output range must be set at pNewObj
std::unique_ptr<ScDPObject> pDestObj(new ScDPObject(mrDPObj));
// output range must be set at pNewObject
std::unique_ptr<ScDPObject> pDestObject(new ScDPObject(mrDPObject));
ScDPObject& rDestObj = *pDestObj;
ScDPObject& rDestObject = *pDestObject;
// Convert ranges from sheet view to default view
rDestObject.SetOutRange(convertRange(rDestObject.GetOutRange()));
const ScSheetSourceDesc* pSheetDesc = rDestObject.GetSheetDesc();
if (pSheetDesc && !pSheetDesc->HasRangeName())
{
ScSheetSourceDesc aDesc(*pSheetDesc);
aDesc.SetSourceRange(convertRange(aDesc.GetSourceRange()));
rDestObject.SetSheetDesc(aDesc);
}
// #i94570# When changing the output position in the dialog, a new table is created
// with the settings from the old table, including the name.
// So we have to check for duplicate names here (before inserting).
if (rDoc.GetDPCollection()->GetByName(rDestObj.GetName()))
rDestObj.SetName(OUString()); // ignore the invalid name, create a new name below
if (rDoc.GetDPCollection()->GetByName(rDestObject.GetName()))
rDestObject.SetName(OUString()); // ignore the invalid name, create a new name below
// Synchronize groups between linked tables
{
const ScDPDimensionSaveData* pGroups = nullptr;
bool bRefFound = rDoc.GetDPCollection()->GetReferenceGroups(rDestObj, &pGroups);
bool bRefFound = rDoc.GetDPCollection()->GetReferenceGroups(rDestObject, &pGroups);
if (bRefFound)
{
ScDPSaveData* pSaveData = rDestObj.GetSaveData();
ScDPSaveData* pSaveData = rDestObject.GetSaveData();
if (pSaveData)
pSaveData->SetDimensionData(pGroups);
}
}
rDoc.GetDPCollection()->InsertNewTable(std::move(pDestObj));
rDoc.GetDPCollection()->InsertNewTable(std::move(pDestObject));
rDestObj.ReloadGroupTableData();
rDestObj.SyncAllDimensionMembers();
rDestObj.InvalidateData(); // before getting the new output area
rDestObject.ReloadGroupTableData();
rDestObject.SyncAllDimensionMembers();
rDestObject.InvalidateData(); // before getting the new output area
// make sure the table has a name (not set by dialog)
if (rDestObj.GetName().isEmpty())
rDestObj.SetName(rDoc.GetDPCollection()->CreateNewName());
if (rDestObject.GetName().isEmpty())
rDestObject.SetName(rDoc.GetDPCollection()->CreateNewName());
bool bOverflow = false;
ScRange aNewOut = rDestObj.GetNewOutputRange(bOverflow);
ScRange aNewOut = rDestObject.GetNewOutputRange(bOverflow);
if (bOverflow)
{
@@ -132,17 +143,19 @@ bool CreatePivotTableOperation::runImplementation()
if (mbRecord)
sc::pivot::createUndoDoc(pNewUndoDoc, rDoc, aNewOut);
rDestObj.Output(aNewOut.aStart);
rDestObject.Output(aNewOut.aStart);
mrDocShell.PostPaintGridAll(); //! only necessary parts
if (mbRecord)
{
mrDocShell.GetUndoManager()->AddUndoAction(std::make_unique<ScUndoDataPilot>(
mrDocShell, nullptr, std::move(pNewUndoDoc), nullptr, &rDestObj, false));
mrDocShell, nullptr, std::move(pNewUndoDoc), nullptr, &rDestObject, false));
}
syncSheetViews();
// notify API objects
rDoc.BroadcastUno(ScDataPilotModifiedHint(rDestObj.GetName()));
rDoc.BroadcastUno(ScDataPilotModifiedHint(rDestObject.GetName()));
aModificator.SetDocumentModified();
return true;