1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <memory>
11 #include <com/sun/star/embed/Aspects.hpp>
12 #include <com/sun/star/embed/XEmbeddedObject.hpp>
13 #include <com/sun/star/awt/Size.hpp>
14 #include <com/sun/star/chart/ChartDataRowSource.hpp>
15 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
16 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
17 
18 #include <tools/gen.hxx>
19 #include <svx/svdoole2.hxx>
20 #include <svx/svdpage.hxx>
21 #include <svx/svdundo.hxx>
22 #include <unotools/moduleoptions.hxx>
23 #include <comphelper/propertysequence.hxx>
24 #include <comphelper/classids.hxx>
25 #include <toolkit/helper/vclunohelper.hxx>
26 #include <tools/globname.hxx>
27 #include <svtools/embedhlp.hxx>
28 #include <comphelper/sequence.hxx>
29 #include <vcl/svapp.hxx>
30 
31 #include <TablePivotChart.hxx>
32 #include <TablePivotCharts.hxx>
33 #include <PivotTableDataProvider.hxx>
34 #include <ChartTools.hxx>
35 
36 #include <miscuno.hxx>
37 #include <docsh.hxx>
38 #include <drwlayer.hxx>
39 
40 using namespace css;
41 
42 namespace sc
43 {
44 
45 SC_SIMPLE_SERVICE_INFO(TablePivotCharts, "TablePivotCharts", "com.sun.star.table.TablePivotCharts")
46 
TablePivotCharts(ScDocShell * pDocShell,SCTAB nTab)47 TablePivotCharts::TablePivotCharts(ScDocShell* pDocShell, SCTAB nTab)
48     : m_pDocShell(pDocShell)
49     , m_nTab(nTab)
50 {
51     m_pDocShell->GetDocument().AddUnoObject(*this);
52 }
53 
~TablePivotCharts()54 TablePivotCharts::~TablePivotCharts()
55 {
56     SolarMutexGuard aGuard;
57 
58     if (m_pDocShell)
59         m_pDocShell->GetDocument().RemoveUnoObject(*this);
60 }
61 
Notify(SfxBroadcaster &,const SfxHint & rHint)62 void TablePivotCharts::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& rHint)
63 {
64     if (rHint.GetId() == SfxHintId::Dying)
65         m_pDocShell = nullptr;
66 }
67 
68 // XTablePivotCharts
addNewByName(OUString const & rName,const awt::Rectangle & aRect,OUString const & rDataPilotName)69 void SAL_CALL TablePivotCharts::addNewByName(OUString const & rName,
70                                              const awt::Rectangle& aRect,
71                                              OUString const & rDataPilotName)
72 {
73     SolarMutexGuard aGuard;
74 
75     if (!m_pDocShell)
76         return;
77 
78     ScDocument& rDoc = m_pDocShell->GetDocument();
79     ScDrawLayer* pModel = m_pDocShell->MakeDrawLayer();
80     SdrPage* pPage = pModel->GetPage(sal_uInt16(m_nTab));
81     if (!pPage)
82         return;
83 
84     //  chart can't be inserted if any ole object with that name exists on any table
85     //  (empty string: generate valid name)
86 
87     OUString aName = rName;
88     SCTAB nDummy;
89     if (!aName.isEmpty() && pModel->GetNamedObject(aName, OBJ_OLE2, nDummy))
90     {
91         //  object exists - only RuntimeException is specified
92         throw uno::RuntimeException();
93     }
94 
95     uno::Reference<embed::XEmbeddedObject> xObject;
96 
97     if (SvtModuleOptions().IsChart())
98         xObject = m_pDocShell->GetEmbeddedObjectContainer().CreateEmbeddedObject(SvGlobalName(SO3_SCH_CLASSID).GetByteSequence(), aName);
99 
100     if (!xObject.is())
101             return;
102 
103     Point aRectPos(aRect.X, aRect.Y);
104     bool bLayoutRTL = rDoc.IsLayoutRTL(m_nTab);
105     if ((aRectPos.X() < 0 && !bLayoutRTL) || (aRectPos.X() > 0 && bLayoutRTL))
106         aRectPos.setX( 0 );
107 
108     if (aRectPos.Y() < 0)
109          aRectPos.setY( 0 );
110 
111     Size aRectSize(aRect.Width, aRect.Height);
112     if (aRectSize.Width() <= 0)
113         aRectSize.setWidth( 5000 ); // default size
114 
115     if (aRectSize.Height() <= 0)
116         aRectSize.setHeight( 5000 );
117 
118     ::tools::Rectangle aInsRect(aRectPos, aRectSize);
119 
120     sal_Int64 nAspect(embed::Aspects::MSOLE_CONTENT);
121     MapUnit aMapUnit(VCLUnoHelper::UnoEmbed2VCLMapUnit(xObject->getMapUnit(nAspect)));
122     Size aSize(aInsRect.GetSize());
123     aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aMapUnit));
124     awt::Size aAwtSize;
125     aAwtSize.Width = aSize.Width();
126     aAwtSize.Height = aSize.Height();
127 
128     rtl::Reference<sc::PivotTableDataProvider> pPivotTableDataProvider(new sc::PivotTableDataProvider(rDoc));
129     pPivotTableDataProvider->setPivotTableName(rDataPilotName);
130 
131     uno::Reference<chart2::data::XDataProvider> xDataProvider(pPivotTableDataProvider);
132 
133     uno::Reference<chart2::data::XDataReceiver> xReceiver;
134 
135     if (xObject.is())
136         xReceiver.set(xObject->getComponent(), uno::UNO_QUERY);
137 
138     if (xReceiver.is())
139     {
140         xReceiver->attachDataProvider(xDataProvider);
141 
142         uno::Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY);
143         xReceiver->attachNumberFormatsSupplier(xNumberFormatsSupplier);
144 
145         uno::Sequence<beans::PropertyValue> aArgs( comphelper::InitPropertySequence({
146                     { "CellRangeRepresentation", uno::makeAny(rDataPilotName) },
147                     { "HasCategories", uno::makeAny(true) },
148                     { "DataRowSource", uno::makeAny(chart::ChartDataRowSource_COLUMNS) }
149                 }));
150         xReceiver->setArguments(aArgs);
151     }
152 
153     SdrOle2Obj* pObject = new SdrOle2Obj(
154             *pModel,
155             svt::EmbeddedObjectRef(xObject, embed::Aspects::MSOLE_CONTENT),
156             aName,
157             aInsRect);
158 
159     if (xObject.is())
160         xObject->setVisualAreaSize(nAspect, aAwtSize);
161 
162     pPage->InsertObject(pObject);
163     pModel->AddUndo(std::make_unique<SdrUndoInsertObj>(*pObject));
164 }
165 
removeByName(const OUString & rName)166 void SAL_CALL TablePivotCharts::removeByName(const OUString& rName)
167 {
168     SolarMutexGuard aGuard;
169     SdrOle2Obj* pObject = sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE);
170     if (pObject)
171     {
172         ScDocument& rDoc = m_pDocShell->GetDocument();
173         ScDrawLayer* pModel = rDoc.GetDrawLayer();
174         SdrPage* pPage = pModel->GetPage(sal_uInt16(m_nTab));
175         pModel->AddUndo(std::make_unique<SdrUndoDelObj>(*pObject));
176         pPage->RemoveObject(pObject->GetOrdNum());
177     }
178 }
179 
180 // XIndexAccess
getCount()181 sal_Int32 SAL_CALL TablePivotCharts::getCount()
182 {
183     SolarMutexGuard aGuard;
184     sal_Int32 nCount = 0;
185 
186     if (!m_pDocShell)
187         return nCount;
188 
189     sc::tools::ChartIterator aIterator(m_pDocShell, m_nTab, sc::tools::ChartSourceType::PIVOT_TABLE);
190 
191     SdrOle2Obj* pOleObject = aIterator.next();
192     while (pOleObject)
193     {
194         if (pOleObject->GetObjRef().is())
195             nCount++;
196         pOleObject = aIterator.next();
197     }
198     return nCount;
199 }
200 
getByIndex(sal_Int32 nIndex)201 uno::Any SAL_CALL TablePivotCharts::getByIndex(sal_Int32 nIndex)
202 {
203     SolarMutexGuard aGuard;
204     SdrOle2Obj* pObject = sc::tools::getChartByIndex(m_pDocShell, m_nTab, nIndex,
205                                                      sc::tools::ChartSourceType::PIVOT_TABLE);
206     if (!pObject)
207         throw lang::IndexOutOfBoundsException();
208 
209     OUString aName;
210     uno::Reference<embed::XEmbeddedObject> xObject = pObject->GetObjRef();
211     if (xObject.is())
212         aName = m_pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);
213 
214     if (aName.isEmpty())
215         throw lang::IndexOutOfBoundsException();
216 
217     uno::Reference<table::XTablePivotChart> xChart(new TablePivotChart(m_pDocShell, m_nTab, aName));
218     if (!xChart.is())
219         throw lang::IndexOutOfBoundsException();
220 
221     return uno::makeAny(xChart);
222 }
223 
getElementType()224 uno::Type SAL_CALL TablePivotCharts::getElementType()
225 {
226     SolarMutexGuard aGuard;
227     return cppu::UnoType<table::XTablePivotChart>::get();
228 }
229 
hasElements()230 sal_Bool SAL_CALL TablePivotCharts::hasElements()
231 {
232     SolarMutexGuard aGuard;
233     return getCount() != 0;
234 }
235 
getByName(OUString const & rName)236 uno::Any SAL_CALL TablePivotCharts::getByName(OUString const & rName)
237 {
238     SolarMutexGuard aGuard;
239 
240     if (!sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE))
241         throw container::NoSuchElementException();
242 
243     uno::Reference<table::XTablePivotChart> xChart(new TablePivotChart(m_pDocShell, m_nTab, rName));
244     if (!xChart.is())
245         throw container::NoSuchElementException();
246 
247     return uno::makeAny(xChart);
248 }
249 
getElementNames()250 uno::Sequence<OUString> SAL_CALL TablePivotCharts::getElementNames()
251 {
252     SolarMutexGuard aGuard;
253 
254     std::vector<OUString> aElements;
255     sc::tools::ChartIterator aIterator(m_pDocShell, m_nTab, sc::tools::ChartSourceType::PIVOT_TABLE);
256 
257     SdrOle2Obj* pOleObject = aIterator.next();
258     while (pOleObject)
259     {
260         uno::Reference<embed::XEmbeddedObject> xObject = pOleObject->GetObjRef();
261         if (xObject.is())
262         {
263             OUString aName = m_pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);
264             aElements.push_back(aName);
265         }
266         pOleObject = aIterator.next();
267     }
268     return comphelper::containerToSequence(aElements);
269 }
270 
hasByName(OUString const & rName)271 sal_Bool SAL_CALL TablePivotCharts::hasByName(OUString const & rName)
272 {
273     SolarMutexGuard aGuard;
274 
275     return sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE) != nullptr;
276 }
277 
278 } // end sc namespace
279 
280 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
281