summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorAttila Szűcs <attila.szucs@collabora.com>2024-07-25 06:21:35 +0200
committerCaolán McNamara <caolan.mcnamara@collabora.com>2024-10-18 12:49:41 +0200
commit599365d293bb0c0fcc2b5b1183e50fa9b93a8e3f (patch)
tree8d91ace1459c3691f38ad926272dcc44ea49e899 /sw
parent9cb748847f63f73a7a0bbd63d34a5f3ebf789919 (diff)
SW: extract transform charts (using dialog code)
Implemented chart data extraction, and transformation added insert/delete/modify row/column, and the ability to set resize data table setcolumndesc / setrowdesc .. for 1 descriptor, or with multiple descriptor to set set 1 cell value, or set the whole table cells values. it will resize the table, but you can still use partial arrays like "data": [ [ 1,2,3,4 ], [ 2,3,4,5 ], [ 3 ], [ 4,5,6,7 ], [ 2,2,1 ], [ 5,6,7,8 ] ], that means the 3. row 2,3,4th cell will not be overwritten. for insert column, it call codes from DataBrowserModel. (used by dialog code) added tests, fixed a contentcontrol date problem 2. commit (made by Caolan) squashed into 1. commit: WIP hack this to link move stuff from chartcontroller to chartcore and adjust visibility until it links at least Change-Id: I5529f4da33f046eef7e947d755e29486fa966274 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172849 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175121 Tested-by: Jenkins
Diffstat (limited to 'sw')
-rw-r--r--sw/qa/uibase/shells/data/docStructureChartExampleOriginal.odtbin0 -> 35081 bytes
-rw-r--r--sw/qa/uibase/shells/shells.cxx196
-rw-r--r--sw/source/uibase/shells/textsh1.cxx583
-rw-r--r--sw/source/uibase/uno/loktxdoc.cxx139
4 files changed, 917 insertions, 1 deletions
diff --git a/sw/qa/uibase/shells/data/docStructureChartExampleOriginal.odt b/sw/qa/uibase/shells/data/docStructureChartExampleOriginal.odt
new file mode 100644
index 000000000000..da775ecf4aaa
--- /dev/null
+++ b/sw/qa/uibase/shells/data/docStructureChartExampleOriginal.odt
Binary files differ
diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index e4ed7367fc29..28a31a50ed28 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -13,6 +13,9 @@
#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
#include <com/sun/star/text/BibliographyDataType.hpp>
#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart/XChartDataArray.hpp>
#include <sfx2/dispatch.hxx>
#include <sfx2/viewfrm.hxx>
@@ -41,6 +44,8 @@
#include <ndtxt.hxx>
#include <ftnidx.hxx>
#include <txtftn.hxx>
+#include <unotxdoc.hxx>
+#include <tools/json_writer.hxx>
/// Covers sw/source/uibase/shells/ fixes.
class SwUibaseShellsTest : public SwModelTestBase
@@ -583,6 +588,197 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertFieldmarkReadonly)
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), rIDMA.getFieldmarksCount());
}
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDocumentStructureTransformChart)
+{
+ createSwDoc("docStructureChartExampleOriginal.odt");
+ OString aJson = R"json(
+{
+ "Transforms": {
+ "Charts.ByEmbedIndex.0": {
+ "modifyrow.1": [ 19, 15 ],
+ "datayx.3.1": 37,
+ "deleterow.0": "",
+ "deleterow.1": "",
+ "insertrow.0": [ 15, 17 ],
+ "setrowdesc.0": "Paul",
+ "insertrow.2": [ 19, 22 ],
+ "setrowdesc.2": "Barbara",
+ "insertrow.4": [ 29, 27 ],
+ "setrowdesc.4": "Elizabeth",
+ "insertrow.5": [ 14, 26 ],
+ "setrowdesc.5": "William",
+ "insertcolumn.1": [ 1,2,3,4,5,6 ],
+ "insertcolumn.0": [ 2,1,2,1,2,1 ],
+ "insertcolumn.4": [ 7,7,7,7,7,7 ],
+ "setcolumndesc.4": "c4",
+ "setcolumndesc.0": "c0",
+ "setcolumndesc.2": "c2"
+ },
+ "Charts.BySubTitle.Subtitle2": {
+ "deletecolumn.3": ""
+ },
+ "Charts.ByEmbedName.Object3": {
+ "resize": [ 12, 3 ],
+ "setrowdesc":
+ [
+ "United Kingdom",
+ "United States of America",
+ "Canada",
+ "Brazil",
+ "Germany",
+ "India",
+ "Japan",
+ "Sudan",
+ "Norway",
+ "Italy",
+ "France",
+ "Egypt"
+ ],
+ "modifycolumn.0": [ 12, 9, 8, 5, 5, 4, 3, 3, 2, 2, 1, 1],
+ "resize": [ 12, 2 ]
+ },
+ "Charts.ByTitle.Fixed issues": {
+ "data": [ [ 3,1,2 ],
+ [ 2,0,1 ],
+ [ 3,2,0 ],
+ [ 2,1,1 ],
+ [ 4,2,2 ],
+ [ 2,2,1 ],
+ [ 3,2,0,0 ],
+ [ 3,1,2,1 ],
+ [ 3,3,1,0,1 ],
+ [ 2,1,0,1,2 ],
+ [ 4,2,1,2,2,3 ],
+ [ 2,1,0,0,1,4 ],
+ [ 3,2,2,1,3,2 ],
+ [ 4,2,1,1,2,3 ],
+ [ 3,3,2,0,3,5 ],
+ [ 3,3,1,2,2,3 ],
+ [ 5,1,1,1,1,4 ],
+ [ 2,2,2,1,2,3 ] ],
+ "setrowdesc": ["2023.01",".02",".03",".04",".05",".06",".07",".08",".09",".10",".11",".12","2023.01",".02",".03",".04",".05",".06"],
+ "setcolumndesc": ["Jennifer", "Charles", "Thomas", "Maria", "Lisa", "Daniel"]
+ }
+ }
+}
+)json"_ostr;
+
+ //transform
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue(u"DataJson"_ustr,
+ uno::Any(OStringToOUString(aJson, RTL_TEXTENCODING_UTF8))),
+ };
+ dispatchCommand(mxComponent, u".uno:TransformDocumentStructure"_ustr, aArgs);
+
+ // Check transformed values of the 3 chart
+ for (int nShape = 0; nShape < 3; nShape++)
+ {
+ uno::Reference<text::XTextEmbeddedObjectsSupplier> xEOS(mxComponent, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xEOS.is());
+ uno::Reference<container::XIndexAccess> xEmbeddeds(xEOS->getEmbeddedObjects(),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xEmbeddeds.is());
+
+ uno::Reference<beans::XPropertySet> xShapeProps(xEmbeddeds->getByIndex(nShape),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xShapeProps.is());
+
+ uno::Reference<frame::XModel> xDocModel;
+ xShapeProps->getPropertyValue(u"Model"_ustr) >>= xDocModel;
+ CPPUNIT_ASSERT(xDocModel.is());
+
+ uno::Reference<chart2::XChartDocument> xChartDoc(xDocModel, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xChartDoc.is());
+
+ uno::Reference<chart::XChartDataArray> xDataArray(xChartDoc->getDataProvider(),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xDataArray.is());
+
+ switch (nShape)
+ {
+ case 0:
+ {
+ std::vector<std::vector<double>> aValues = {
+ { 2, 15, 1, 7 }, { 1, 19, 2, 7 }, { 2, 19, 3, 7 },
+ { 1, 25, 4, 7 }, { 2, 29, 5, 7 }, { 1, 14, 6, 7 },
+ };
+ // RowDescriptions
+ std::vector<OUString> aRowDescsValues
+ = { u"Paul"_ustr, u"Mary"_ustr, u"Barbara"_ustr,
+ u"David"_ustr, u"Elizabeth"_ustr, u"William"_ustr };
+ // ColumnDescriptions
+ std::vector<OUString> aColDescsValues
+ = { u"c0"_ustr, u"2022"_ustr, u"c2"_ustr, u"c4"_ustr };
+
+ uno::Sequence<uno::Sequence<double>> aData = xDataArray->getData();
+ for (size_t nY = 0; nY < aValues.size(); nY++)
+ {
+ for (size_t nX = 0; nX < aValues[nY].size(); nX++)
+ {
+ CPPUNIT_ASSERT_EQUAL(aData[nY][nX], aValues[nY][nX]);
+ }
+ }
+
+ uno::Sequence<OUString> aColDescs = xDataArray->getColumnDescriptions();
+ for (size_t i = 0; i < aColDescsValues.size(); i++)
+ {
+ CPPUNIT_ASSERT_EQUAL(aColDescs[i], aColDescsValues[i]);
+ }
+ uno::Sequence<OUString> aRowDescs = xDataArray->getRowDescriptions();
+ for (size_t i = 0; i < aRowDescsValues.size(); i++)
+ {
+ CPPUNIT_ASSERT_EQUAL(aRowDescs[i], aRowDescsValues[i]);
+ }
+ }
+ break;
+ case 1:
+ {
+ uno::Sequence<uno::Sequence<double>> aData = xDataArray->getData();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(18), aData.getLength());
+ uno::Sequence<double>* pRows = aData.getArray();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(6), pRows[0].getLength());
+ }
+ break;
+ case 2:
+ {
+ uno::Sequence<uno::Sequence<double>> aData = xDataArray->getData();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(12), aData.getLength());
+ uno::Sequence<double>* pRows = aData.getArray();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), pRows[0].getLength());
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDocumentStructureExtractChart)
+{
+ createSwDoc("docStructureChartExampleOriginal.odt");
+
+ //extract
+ tools::JsonWriter aJsonWriter;
+ std::string_view aCommand(".uno:ExtractDocumentStructure");
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+ OString aExpectedStr
+ = "{ \"DocStructure\": { \"Charts.ByEmbedIndex.0\": { \"name\": \"Object1\", \"title\": "
+ "\"Paid leave days\", \"subtitle\": \"Subtitle2\", \"RowDescriptions\": [ \"James\", "
+ "\"Mary\", \"Patricia\", \"David\"], \"ColumnDescriptions\": [ \"2022\", \"2023\"], "
+ "\"DataValues\": [ \"Row.0\": [ \"22\", \"24\"], \"Row.1\": [ \"18\", \"16\"], "
+ "\"Row.2\": [ \"32\", \"32\"], \"Row.3\": [ \"25\", \"23\"]]}, "
+ "\"Charts.ByEmbedIndex.1\": { \"name\": \"Object2\", \"title\": \"Fixed issues\", "
+ "\"subtitle\": \"Subtitle1\", \"RowDescriptions\": [ \"\"], \"ColumnDescriptions\": [ \" "
+ "\"], \"DataValues\": [ \"Row.0\": [ \"NaN\"]]}, \"Charts.ByEmbedIndex.2\": { \"name\": "
+ "\"Object3\", \"title\": \"Employees from countries\", \"subtitle\": \"Subtitle3\", "
+ "\"RowDescriptions\": [ \"\"], \"ColumnDescriptions\": [ \"Column 1\"], \"DataValues\": "
+ "[ \"Row.0\": [ \"NaN\"]]}}}"_ostr;
+
+ CPPUNIT_ASSERT_EQUAL(aExpectedStr, aJsonWriter.finishAndGetAsOString());
+}
+
CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmarks)
{
// Given a document with two refmarks, one is not interesting the other is a citation:
diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx
index 2ac91aed446c..6d0aebb3e9a5 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -134,6 +134,28 @@
#include <rtl/uri.hxx>
#include <unotxdoc.hxx>
+#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
+#include <com/sun/star/chart2/XInternalDataProvider.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart/XChartDocument.hpp>
+#include <com/sun/star/chart/XChartDataArray.hpp>
+#include <com/sun/star/chart2/XTitle.hpp>
+#include <com/sun/star/chart2/XTitled.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+
+#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
+#include <com/sun/star/chart2/XChartTypeContainer.hpp>
+#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
+#include <com/sun/star/chart2/XChartTypeContainer.hpp>
+#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
+//#include <../../../../chart2/source/controller/inc/ChartController.hxx>
+//#include <DataSeries.hxx>
+
using namespace ::com::sun::star;
using namespace com::sun::star::beans;
using namespace ::com::sun::star::container;
@@ -790,6 +812,109 @@ void DeleteFields(SfxRequest& rReq, SwWrtShell& rWrtSh)
pDoc->DeleteFormatRefMark(pMark);
}
}
+
+bool lcl_ChangeChartColumnCount(const uno::Reference<chart2::XChartDocument>& xChartDoc, sal_Int32 nId,
+ bool bInsert, bool bResize = false)
+{
+ uno::Reference<chart2::XDiagram> xDiagram = xChartDoc->getFirstDiagram();
+ if (!xDiagram.is())
+ return false;
+ uno::Reference<chart2::XCoordinateSystemContainer> xCooSysContainer(xDiagram, uno::UNO_QUERY);
+ if (!xCooSysContainer.is())
+ return false;
+ uno::Sequence<uno::Reference<chart2::XCoordinateSystem>> xCooSysSequence(
+ xCooSysContainer->getCoordinateSystems());
+ if (xCooSysSequence.getLength() <= 0)
+ return false;
+ uno::Reference<chart2::XChartTypeContainer> xChartTypeContainer(xCooSysSequence[0],
+ uno::UNO_QUERY);
+ if (!xChartTypeContainer.is())
+ return false;
+ uno::Sequence<uno::Reference<chart2::XChartType>> xChartTypeSequence(
+ xChartTypeContainer->getChartTypes());
+ if (xChartTypeSequence.getLength() <= 0)
+ return false;
+ uno::Reference<chart2::XDataSeriesContainer> xDSContainer(xChartTypeSequence[0],
+ uno::UNO_QUERY);
+ if (!xDSContainer.is())
+ return false;
+
+ uno::Reference<chart2::XInternalDataProvider> xIDataProvider(xChartDoc->getDataProvider(),
+ uno::UNO_QUERY);
+ if (!xIDataProvider.is())
+ return false;
+
+ uno::Sequence<uno::Reference<chart2::XDataSeries>> aSeriesSeq(xDSContainer->getDataSeries());
+
+ int nSeriesCount = aSeriesSeq.getLength();
+
+ if (bResize)
+ {
+ // Resize is actually some inserts, or deletes
+ if (nId > nSeriesCount)
+ {
+ bInsert = true;
+ }
+ else if (nId < nSeriesCount)
+ {
+ bInsert = false;
+ }
+ else
+ {
+ // Resize to the same size. No change needed
+ return true;
+ }
+ }
+
+ // insert or delete
+ if (bInsert)
+ {
+ // insert
+ if (nId > nSeriesCount && !bResize)
+ return false;
+
+ int nInsertCount = bResize ? nId - nSeriesCount : 1;
+
+ // call dialog code
+ if (bResize)
+ {
+ for (int i = 0; i < nInsertCount; i++)
+ {
+ xIDataProvider->insertDataSeries(nSeriesCount);
+ }
+ return true;
+ }
+
+ xIDataProvider->insertDataSeries(nId);
+ }
+ else
+ {
+ // delete 1 or more columns
+ if (nId >= nSeriesCount)
+ return false;
+ int nDeleteCount = bResize ? nSeriesCount - nId : 1;
+ for (int i = 0; i < nDeleteCount; i++)
+ {
+ xDSContainer->removeDataSeries(aSeriesSeq[nId]);
+ }
+ }
+ return true;
+}
+
+bool lcl_ResizeChartColumns(const uno::Reference<chart2::XChartDocument>& xChartDoc, sal_Int32 nSize)
+{
+ return lcl_ChangeChartColumnCount(xChartDoc, nSize, false, true);
+}
+
+bool lcl_InsertChartColumns(const uno::Reference<chart2::XChartDocument>& xChartDoc, sal_Int32 nId)
+{
+ return lcl_ChangeChartColumnCount(xChartDoc, nId, true);
+}
+
+bool lcl_DeleteChartColumns(const uno::Reference<chart2::XChartDocument>& xChartDoc, sal_Int32 nId)
+{
+ return lcl_ChangeChartColumnCount(xChartDoc, nId, false);
+}
}
void SwTextShell::Execute(SfxRequest &rReq)
@@ -2275,6 +2400,7 @@ void SwTextShell::Execute(SfxRequest &rReq)
std::stringstream aStream(
(std::string(OUStringToOString(aDataJson, RTL_TEXTENCODING_UTF8))));
boost::property_tree::read_json(aStream, aTree);
+ // Todo: try catch - in case of fail: log wrong JSON format
// get the loaded content controls
uno::Reference<text::XContentControlsSupplier> xCCSupplier(
@@ -2296,6 +2422,29 @@ void SwTextShell::Execute(SfxRequest &rReq)
};
std::vector<std::string> aIdTexts = { ".ByIndex.", ".ByTag.", ".ByAlias.", ".ById." };
+ // get charts
+ uno::Reference<text::XTextEmbeddedObjectsSupplier> xEOS(
+ GetView().GetDocShell()->GetModel(), uno::UNO_QUERY);
+ if (!xEOS.is())
+ break;
+ uno::Reference<container::XIndexAccess> xEmbeddeds(xEOS->getEmbeddedObjects(),
+ uno::UNO_QUERY);
+ if (!xEmbeddeds.is())
+ break;
+
+ sal_Int32 nEOcount = xEmbeddeds->getCount();
+
+ enum class ChartFilterType
+ {
+ ERROR = -1,
+ INDEX,
+ NAME,
+ TITLE,
+ SUBTITLE
+ };
+ std::vector<std::string> aIdChartTexts
+ = { ".ByEmbedIndex.", ".ByEmbedName.", ".ByTitle.", ".BySubTitle." };
+
// Iterate through the JSON data loaded into a tree structure
for (const auto& aItem : aTree)
{
@@ -2304,6 +2453,431 @@ void SwTextShell::Execute(SfxRequest &rReq)
// Handle all transformations
for (const auto& aItem2 : aItem.second)
{
+ if (aItem2.first.starts_with("Charts"))
+ {
+ std::string aTextEnd = aItem2.first.substr(6);
+ std::string aValue = "";
+ ChartFilterType iKeyId = ChartFilterType::ERROR;
+ // Find how the chart is identified: ByIndex, ByTitle...
+ for (size_t i = 0; i < aIdChartTexts.size(); i++)
+ {
+ if (aTextEnd.starts_with(aIdChartTexts[i]))
+ {
+ iKeyId = static_cast<ChartFilterType>(i);
+ aValue = aTextEnd.substr(aIdChartTexts[i].length());
+ break;
+ }
+ }
+ if (iKeyId != ChartFilterType::ERROR)
+ {
+ for (int i = 0; i < nEOcount; ++i)
+ {
+ uno::Reference<beans::XPropertySet> xShapeProps(
+ xEmbeddeds->getByIndex(i), uno::UNO_QUERY);
+ if (!xShapeProps.is())
+ continue;
+
+ uno::Reference<frame::XModel> xDocModel;
+ xShapeProps->getPropertyValue(u"Model"_ustr) >>= xDocModel;
+ if (!xDocModel.is())
+ continue;
+
+ uno::Reference<chart2::XChartDocument> xChartDoc(
+ xDocModel, uno::UNO_QUERY);
+ if (!xChartDoc.is())
+ continue;
+
+ uno::Reference<chart2::data::XDataProvider> xDataProvider(
+ xChartDoc->getDataProvider());
+ if (!xDataProvider.is())
+ continue;
+
+ uno::Reference<chart::XChartDataArray> xDataArray(
+ xChartDoc->getDataProvider(), uno::UNO_QUERY);
+ if (!xDataArray.is())
+ continue;
+
+ uno::Reference<chart2::XInternalDataProvider> xIDataProvider(
+ xChartDoc->getDataProvider(), uno::UNO_QUERY);
+ if (!xIDataProvider.is())
+ continue;
+
+ uno::Reference<util::XModifiable> xModi(xDocModel,
+ uno::UNO_QUERY);
+ if (!xModi.is())
+ continue;
+
+ switch (iKeyId)
+ {
+ case ChartFilterType::INDEX:
+ {
+ if (stoi(aValue) != i)
+ continue;
+ }
+ break;
+ case ChartFilterType::NAME:
+ {
+ uno::Reference<container::XNamed> xNamedShape(
+ xEmbeddeds->getByIndex(i), uno::UNO_QUERY);
+ if (xNamedShape.is())
+ {
+ OUString aName;
+ aName = xNamedShape->getName();
+ if (OStringToOUString(aValue, RTL_TEXTENCODING_UTF8)
+ != aName)
+ continue;
+ }
+ }
+ break;
+ case ChartFilterType::TITLE:
+ {
+ uno::Reference<chart2::XTitled> xTitled(
+ xChartDoc, uno::UNO_QUERY_THROW);
+ if (!xTitled.is())
+ continue;
+ uno::Reference<chart2::XTitle> xTitle
+ = xTitled->getTitleObject();
+ if (!xTitle.is())
+ continue;
+
+ OUString aTitle;
+ const uno::Sequence<
+ uno::Reference<chart2::XFormattedString>>
+ aFSSeq = xTitle->getText();
+ for (auto const& fs : aFSSeq)
+ aTitle += fs->getString();
+ if (OStringToOUString(aValue, RTL_TEXTENCODING_UTF8)
+ != aTitle)
+ continue;
+ }
+ break;
+ case ChartFilterType::SUBTITLE:
+ {
+ uno::Reference<chart2::XDiagram> xDiagram
+ = xChartDoc->getFirstDiagram();
+ if (!xDiagram.is())
+ continue;
+
+ uno::Reference<chart2::XTitled> xTitled(
+ xDiagram, uno::UNO_QUERY_THROW);
+ if (!xTitled.is())
+ continue;
+
+ uno::Reference<chart2::XTitle> xSubTitle(
+ xTitled->getTitleObject());
+ if (!xSubTitle.is())
+ continue;
+
+ OUString aSubTitle;
+ const uno::Sequence<
+ uno::Reference<chart2::XFormattedString>>
+ aFSSeq = xSubTitle->getText();
+ for (auto const& fs : aFSSeq)
+ aSubTitle += fs->getString();
+ if (OStringToOUString(aValue, RTL_TEXTENCODING_UTF8)
+ != aSubTitle)
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+
+ // We have a match, this chart need to be transformed
+ // Set all the values (of the chart) what is needed
+
+ // Check if the InternalDataProvider is row or column based.
+ bool bChartUseColumns = false;
+ uno::Sequence<beans::PropertyValue> aArguments(
+ xDataProvider->detectArguments(nullptr));
+ for (sal_Int32 j = 0; j < aArguments.getLength(); ++j)
+ {
+ if (aArguments[j].Name == "DataRowSource")
+ {
+ css::chart::ChartDataRowSource eRowSource;
+ if (aArguments[j].Value >>= eRowSource)
+ bChartUseColumns
+ = (eRowSource
+ == css::chart::ChartDataRowSource_COLUMNS);
+ break;
+ }
+ }
+
+ for (const auto& aItem3 : aItem2.second)
+ {
+ if (aItem3.first.starts_with("deletecolumn.")
+ || aItem3.first.starts_with("deleterow.")
+ || aItem3.first.starts_with("insertcolumn.")
+ || aItem3.first.starts_with("insertrow.")
+ || aItem3.first.starts_with("modifycolumn.")
+ || aItem3.first.starts_with("modifyrow."))
+ {
+ // delete insert, or modify a row, or column
+ // column, or row?
+ bool bSetColumn = (aItem3.first[6] == 'c');
+ int nId = stoi(aItem3.first.substr(bSetColumn ? 13 : 10));
+ bool bDelete = aItem3.first.starts_with("delete");
+ // delete/insert a row/column if needed
+ if (!aItem3.first.starts_with("modify"))
+ {
+ if (bChartUseColumns == bSetColumn)
+ {
+ if (bDelete)
+ {
+ if (!lcl_DeleteChartColumns(xChartDoc, nId))
+ continue;
+ xIDataProvider->deleteSequence(nId);
+ }
+ else
+ {
+ if (!lcl_InsertChartColumns(xChartDoc, nId))
+ continue;
+ }
+ }
+ else
+ {
+ if (bDelete)
+ {
+ xIDataProvider
+ ->deleteDataPointForAllSequences(nId);
+ }
+ else
+ {
+ xIDataProvider
+ ->insertDataPointForAllSequences(nId
+ - 1);
+ }
+ }
+ }
+ // set values also, if needed
+ if (!bDelete && aItem3.second.size() > 0)
+ {
+ uno::Sequence<uno::Sequence<double>> aData
+ = xDataArray->getData();
+ uno::Sequence<double>* pRows = aData.getArray();
+
+ int nIndex = 0;
+ int nX = nId;
+ int nY = nId;
+ for (const auto& aItem4 : aItem3.second)
+ {
+ if (bSetColumn)
+ {
+ nY = nIndex;
+ }
+ else
+ {
+ nX = nIndex;
+ }
+ if (nY < aData.getLength() && nY >= 0
+ && nX < pRows[nY].getLength() && nX >= 0)
+ {
+ double* pCols = pRows[nY].getArray();
+ pCols[nX]
+ = aItem4.second.get_value<double>();
+ }
+ // else log: set invalid cell: index [nY,Nx]
+ nIndex++;
+ }
+
+ xDataArray->setData(aData);
+ }
+ }
+ else if (aItem3.first.starts_with("setrowdesc"))
+ {
+ // set row descriptions
+ uno::Sequence<OUString> aRowDesc
+ = xDataArray->getRowDescriptions();
+ OUString* aRowdata = aRowDesc.getArray();
+
+ if (aItem3.first.starts_with("setrowdesc."))
+ {
+ // set only 1 description
+ int nValue = stoi(aItem3.first.substr(11));
+ if (nValue >= 0 && nValue < aRowDesc.getLength())
+ {
+ aRowdata[nValue] = OStringToOUString(
+ aItem3.second.get_value<std::string>(),
+ RTL_TEXTENCODING_UTF8);
+ }
+ // Todo: else log: wrong index at setcolumndesc.
+ }
+ else
+ {
+ // set an array of description at once
+ int nIndex = 0;
+ for (const auto& aItem4 : aItem3.second)
+ {
+ if (nIndex >= aRowDesc.getLength())
+ {
+ // Todo log: too many parameters
+ break;
+ }
+ aRowdata[nIndex] = OStringToOUString(
+ aItem4.second.get_value<std::string>(),
+ RTL_TEXTENCODING_UTF8);
+ nIndex++;
+ }
+ }
+ xDataArray->setRowDescriptions(aRowDesc);
+ }
+ else if (aItem3.first.starts_with("setcolumndesc"))
+ {
+ // set colimn descriptions
+ uno::Sequence<OUString> aColDesc
+ = xDataArray->getColumnDescriptions();
+ OUString* aColdata = aColDesc.getArray();
+
+ if (aItem3.first.starts_with("setcolumndesc."))
+ {
+ int nValue = stoi(aItem3.first.substr(14));
+ if (nValue >= 0 && nValue < aColDesc.getLength())
+ {
+ aColdata[nValue] = OStringToOUString(
+ aItem3.second.get_value<std::string>(),
+ RTL_TEXTENCODING_UTF8);
+ }
+ // Todo: else log: wrong index at setcolumndesc.
+ }
+ else
+ {
+ int nIndex = 0;
+ for (const auto& aItem4 : aItem3.second)
+ {
+ if (nIndex >= aColDesc.getLength())
+ {
+ // Todo log: too many parameters
+ break;
+ }
+ aColdata[nIndex] = OStringToOUString(
+ aItem4.second.get_value<std::string>(),
+ RTL_TEXTENCODING_UTF8);
+ nIndex++;
+ }
+ }
+ xDataArray->setColumnDescriptions(aColDesc);
+ }
+ else if (aItem3.first.starts_with("resize"))
+ {
+ if (aItem3.second.size() >= 2)
+ {
+ auto aItem4 = aItem3.second.begin();
+ int nY = aItem4->second.get_value<int>();
+ int nX = (++aItem4)->second.get_value<int>();
+
+ if (nX < 1 || nY < 1)
+ {
+ // Todo log: wrong resize argument
+ continue;
+ }
+ // here we need to use the new insert column thing
+ if (!lcl_ResizeChartColumns(xChartDoc, nX))
+ continue;
+
+ uno::Sequence<uno::Sequence<double>> aData
+ = xDataArray->getData();
+ if (aData.getLength() != nY)
+ aData.realloc(nY);
+
+ for (sal_Int32 j = 0; j < nY; ++j)
+ {
+ uno::Sequence<double>* pRows = aData.getArray();
+ // resize row if needed
+ if (pRows[j].getLength() != nX)
+ {
+ pRows[j].realloc(nX);
+ }
+ }
+ xDataArray->setData(aData);
+ }
+ // Todo: else log: not enought parameter for resize
+ }
+ else if (aItem3.first.starts_with("data"))
+ {
+ // set table data values
+ uno::Sequence<uno::Sequence<double>> aData
+ = xDataArray->getData();
+
+ // set only 1 cell data
+ if (aItem3.first.starts_with("datayx."))
+ {
+ int nPoint = aItem3.first.find('.', 7);
+ int nY = stoi(aItem3.first.substr(7, nPoint - 7));
+ int nX = stoi(aItem3.first.substr(nPoint + 1));
+ if (nY < aData.getLength() && nY >= 0)
+ {
+ uno::Sequence<double>* pRows = aData.getArray();
+ if (nX < pRows[nY].getLength() && nX >= 0)
+ {
+ double* pCols = pRows[nY].getArray();
+ pCols[nX]
+ = aItem3.second.get_value<double>();
+ }
+ }
+ }
+ else
+ {
+ // set the whole data table
+ // resize if needed
+ int nRowsCount = aItem3.second.size();
+ int nColsCount = 0;
+
+ for (const auto& aItem4 : aItem3.second)
+ {
+ if (nColsCount
+ < static_cast<int>(aItem4.second.size()))
+ {
+ nColsCount = aItem4.second.size();
+ }
+ }
+
+ if (nColsCount > 0)
+ {
+ // here we need to use the new insert column thing
+ if(!lcl_ResizeChartColumns(xChartDoc, nColsCount))
+ continue;
+
+ if (aData.getLength() != nRowsCount)
+ aData.realloc(nRowsCount);
+
+ // set all the rows
+ sal_Int32 nY = 0;
+ for (const auto& aItem4 : aItem3.second)
+ {
+ uno::Sequence<double>* pRows
+ = aData.getArray();
+ // resize row if needed
+ if (pRows[nY].getLength() != nColsCount)
+ {
+ pRows[nY].realloc(nColsCount);
+ }
+ double* pCols = pRows[nY].getArray();
+ // set all values in the row
+ sal_Int32 nX = 0;
+ for (const auto& aItem5 : aItem4.second)
+ {
+ if (nX >= nColsCount)
+ {
+ break;
+ }
+ pCols[nX]
+ = aItem5.second.get_value<double>();
+ nX++;
+ }
+ nY++;
+ }
+ }
+ }
+ xDataArray->setData(aData);
+ }
+ // Todo: else Log that this chart command was not recognised
+ xModi->setModified(true);
+ }
+ }
+ }
+ // todo: else log chart transfrom not recognised
+ }
+
if (aItem2.first.starts_with("ContentControls"))
{
std::string aTextEnd = aItem2.first.substr(15);
@@ -2482,6 +3056,15 @@ void SwTextShell::Execute(SfxRequest &rReq)
continue;
xContentControlText->setString(aCheckContent);
}
+ else if (aItem3.first == "date")
+ {
+ std::string aDate
+ = aItem3.second.get_value<std::string>();
+ xContentControlProps->setPropertyValue(
+ UNO_NAME_CURRENT_DATE,
+ uno::Any(OStringToOUString(aDate,
+ RTL_TEXTENCODING_UTF8)));
+ }
else if (aItem3.first == "alias")
{
xContentControlProps->setPropertyValue(
diff --git a/sw/source/uibase/uno/loktxdoc.cxx b/sw/source/uibase/uno/loktxdoc.cxx
index 8a29250c5bdd..7db06fe50a09 100644
--- a/sw/source/uibase/uno/loktxdoc.cxx
+++ b/sw/source/uibase/uno/loktxdoc.cxx
@@ -44,6 +44,14 @@
#include <unocontentcontrol.hxx>
#include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
+#include <com/sun/star/chart2/XInternalDataProvider.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart/XChartDocument.hpp>
+#include <com/sun/star/chart/XChartDataArray.hpp>
+#include <com/sun/star/chart2/XTitle.hpp>
+#include <com/sun/star/chart2/XTitled.hpp>
+
using namespace ::com::sun::star;
namespace
@@ -403,7 +411,6 @@ void GetDocStructure(tools::JsonWriter& rJsonWriter, SwDocShell* /*pDocShell*/,
int iCCcount = xContentControls->getCount();
- auto commentsNode = rJsonWriter.startNode("DocStructure");
for (int i = 0; i < iCCcount; ++i)
{
OString aNodeName("ContentControls.ByIndex."_ostr + OString::number(i));
@@ -477,6 +484,9 @@ void GetDocStructure(tools::JsonWriter& rJsonWriter, SwDocShell* /*pDocShell*/,
OUString aDateLanguage;
xContentControlProps->getPropertyValue(UNO_NAME_DATE_LANGUAGE) >>= aDateLanguage;
rJsonWriter.put(UNO_NAME_DATE_LANGUAGE, aDateLanguage);
+ OUString aCurrentDate;
+ xContentControlProps->getPropertyValue(UNO_NAME_CURRENT_DATE) >>= aCurrentDate;
+ rJsonWriter.put(UNO_NAME_CURRENT_DATE, aCurrentDate);
}
break;
case SwContentControlType::PLAIN_TEXT:
@@ -497,6 +507,125 @@ void GetDocStructure(tools::JsonWriter& rJsonWriter, SwDocShell* /*pDocShell*/,
}
}
+void GetDocStructureCharts(tools::JsonWriter& rJsonWriter, SwDocShell* /*pDocShell*/,
+ const std::map<OUString, OUString>& rArguments,
+ uno::Reference<container::XIndexAccess>& xEmbeddeds)
+{
+ auto it = rArguments.find(u"filter"_ustr);
+ if (it != rArguments.end())
+ {
+ // If filter is present but we are filtering not to charts
+ if (!it->second.equals(u"charts"_ustr))
+ return;
+ }
+
+ sal_Int32 nEOcount = xEmbeddeds->getCount();
+
+ for (int i = 0; i < nEOcount; ++i)
+ {
+ uno::Reference<beans::XPropertySet> xShapeProps(xEmbeddeds->getByIndex(i), uno::UNO_QUERY);
+ if (!xShapeProps.is())
+ continue;
+
+ uno::Reference<frame::XModel> xDocModel;
+ xShapeProps->getPropertyValue(u"Model"_ustr) >>= xDocModel;
+ if (!xDocModel.is())
+ continue;
+
+ uno::Reference<chart2::XChartDocument> xChartDoc(xDocModel, uno::UNO_QUERY);
+ if (!xChartDoc.is())
+ continue;
+
+ uno::Reference<chart2::data::XDataProvider> xDataProvider(xChartDoc->getDataProvider());
+ if (!xDataProvider.is())
+ continue;
+
+ uno::Reference<chart::XChartDataArray> xDataArray(xChartDoc->getDataProvider(),
+ uno::UNO_QUERY);
+ if (!xDataArray.is())
+ continue;
+
+ uno::Reference<chart2::XDiagram> xDiagram = xChartDoc->getFirstDiagram();
+ if (!xDiagram.is())
+ continue;
+
+ //we have the chart Data now, we can start to extract it
+ OString aNodeName("Charts.ByEmbedIndex."_ostr + OString::number(i));
+ auto aChartNode = rJsonWriter.startNode(aNodeName);
+
+ //get the object name
+ uno::Reference<container::XNamed> xNamedShape(xEmbeddeds->getByIndex(i), uno::UNO_QUERY);
+ if (xNamedShape.is())
+ {
+ OUString aName;
+ aName = xNamedShape->getName();
+ rJsonWriter.put("name", aName);
+ }
+
+ //get the chart title, if there is one
+ uno::Reference<chart2::XTitled> xTitled(xChartDoc, uno::UNO_QUERY_THROW);
+ if (xTitled.is())
+ {
+ uno::Reference<chart2::XTitle> xTitle = xTitled->getTitleObject();
+ if (xTitle.is())
+ {
+ OUString aTitle;
+ const uno::Sequence<uno::Reference<chart2::XFormattedString>> aFSSeq
+ = xTitle->getText();
+ for (auto const& fs : aFSSeq)
+ aTitle += fs->getString();
+ rJsonWriter.put("title", aTitle);
+ }
+ }
+
+ //get the chart subtitle, if there is one
+ uno::Reference<chart2::XTitled> xSubTitled(xDiagram, uno::UNO_QUERY_THROW);
+ if (xSubTitled.is())
+ {
+ uno::Reference<chart2::XTitle> xSubTitle = xSubTitled->getTitleObject();
+ if (xSubTitle.is())
+ {
+ OUString aSubTitle;
+ const uno::Sequence<uno::Reference<chart2::XFormattedString>> aFSSeq
+ = xSubTitle->getText();
+ for (auto const& fs : aFSSeq)
+ aSubTitle += fs->getString();
+ rJsonWriter.put("subtitle", aSubTitle);
+ }
+ }
+
+ {
+ uno::Sequence<OUString> aRowDesc = xDataArray->getRowDescriptions();
+ auto aRowDescNode = rJsonWriter.startArray("RowDescriptions");
+ for (int j = 0; j < aRowDesc.getLength(); j++)
+ {
+ rJsonWriter.putSimpleValue(aRowDesc[j]);
+ }
+ }
+ {
+ uno::Sequence<OUString> aColDesc = xDataArray->getColumnDescriptions();
+ auto aColDescNode = rJsonWriter.startArray("ColumnDescriptions");
+ for (int j = 0; j < aColDesc.getLength(); j++)
+ {
+ rJsonWriter.putSimpleValue(aColDesc[j]);
+ }
+ }
+ {
+ uno::Sequence<uno::Sequence<double>> aData = xDataArray->getData();
+ auto aDataValuesNode = rJsonWriter.startArray("DataValues");
+ for (int j = 0; j < aData.getLength(); j++)
+ {
+ OString aRowNodeName("Row."_ostr + OString::number(j));
+ auto aRowNode = rJsonWriter.startArray(aRowNodeName);
+ for (int k = 0; k < aData[j].getLength(); k++)
+ {
+ rJsonWriter.putSimpleValue(OUString::number(aData[j][k]));
+ }
+ }
+ }
+ }
+}
+
/// Implements getCommandValues(".uno:Sections").
///
/// Parameters:
@@ -607,6 +736,14 @@ void SwXTextDocument::getCommandValues(tools::JsonWriter& rJsonWriter, std::stri
}
else if (o3tl::starts_with(rCommand, aExtractDocStructure))
{
+ auto commentsNode = rJsonWriter.startNode("DocStructure");
+
+ uno::Reference<container::XIndexAccess> xEmbeddeds(getEmbeddedObjects(), uno::UNO_QUERY);
+ if (xEmbeddeds.is())
+ {
+ GetDocStructureCharts(rJsonWriter, m_pDocShell, aMap, xEmbeddeds);
+ }
+
uno::Reference<container::XIndexAccess> xContentControls = getContentControls();
GetDocStructure(rJsonWriter, m_pDocShell, aMap, xContentControls);
}