/src/libreoffice/sc/source/ui/view/drawvie4.cxx
Line | Count | Source |
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 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <svx/svditer.hxx> |
21 | | #include <svx/svdograf.hxx> |
22 | | #include <svx/svdogrp.hxx> |
23 | | #include <svx/svdoole2.hxx> |
24 | | #include <svx/svdundo.hxx> |
25 | | #include <sfx2/docfile.hxx> |
26 | | #include <tools/urlobj.hxx> |
27 | | #include <toolkit/helper/vclunohelper.hxx> |
28 | | #include <sal/log.hxx> |
29 | | |
30 | | #include <drawview.hxx> |
31 | | #include <global.hxx> |
32 | | #include <drwlayer.hxx> |
33 | | #include <viewdata.hxx> |
34 | | #include <document.hxx> |
35 | | #include <docsh.hxx> |
36 | | #include <drwtrans.hxx> |
37 | | #include <transobj.hxx> |
38 | | #include <drawutil.hxx> |
39 | | #include <scmod.hxx> |
40 | | #include <globstr.hrc> |
41 | | #include <scresid.hxx> |
42 | | #include <gridwin.hxx> |
43 | | #include <userdat.hxx> |
44 | | |
45 | | #include <com/sun/star/embed/NoVisualAreaSizeException.hpp> |
46 | | #include <com/sun/star/embed/Aspects.hpp> |
47 | | #include <com/sun/star/embed/XEmbeddedObject.hpp> |
48 | | #include <com/sun/star/chart2/XChartTypeContainer.hpp> |
49 | | #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> |
50 | | #include <com/sun/star/chart2/XDataSeriesContainer.hpp> |
51 | | #include <com/sun/star/chart2/XChartDocument.hpp> |
52 | | #include <comphelper/diagnose_ex.hxx> |
53 | | |
54 | | using namespace com::sun::star; |
55 | | |
56 | | Point aDragStartDiff; |
57 | | |
58 | | void ScDrawView::BeginDrag( vcl::Window* pWindow, const Point& rStartPos ) |
59 | 0 | { |
60 | 0 | const SdrMarkList& rMarkList = GetMarkedObjectList(); |
61 | 0 | if ( rMarkList.GetMarkCount() == 0 ) |
62 | 0 | return; |
63 | | |
64 | 0 | BrkAction(); |
65 | |
|
66 | 0 | tools::Rectangle aMarkedRect = GetAllMarkedRect(); |
67 | |
|
68 | 0 | aDragStartDiff = rStartPos - aMarkedRect.TopLeft(); |
69 | |
|
70 | 0 | bool bAnyOle, bOneOle; |
71 | 0 | CheckOle( rMarkList, bAnyOle, bOneOle ); |
72 | |
|
73 | 0 | ScDocShellRef aDragShellRef; |
74 | 0 | if (bAnyOle) |
75 | 0 | { |
76 | 0 | aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately |
77 | 0 | aDragShellRef->DoInitNew(); |
78 | 0 | } |
79 | 0 | ScDrawLayer::SetGlobalDrawPersist( aDragShellRef.get() ); |
80 | 0 | std::unique_ptr<SdrModel> pModel(CreateMarkedObjModel()); |
81 | 0 | ScDrawLayer::SetGlobalDrawPersist(nullptr); |
82 | | |
83 | | // Charts now always copy their data in addition to the source reference, so |
84 | | // there's no need to call SchDLL::Update for the charts in the clipboard doc. |
85 | | // Update with the data (including NumberFormatter) from the live document would |
86 | | // also store the NumberFormatter in the clipboard chart (#88749#) |
87 | |
|
88 | 0 | ScDocShell* pDocSh = rViewData.GetDocShell(); |
89 | |
|
90 | 0 | TransferableObjectDescriptor aObjDesc; |
91 | 0 | pDocSh->FillTransferableObjectDescriptor( aObjDesc ); |
92 | 0 | aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass(); |
93 | | // maSize is set in ScDrawTransferObj ctor |
94 | |
|
95 | 0 | rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pModel), *pDocSh, std::move(aObjDesc) ); |
96 | |
|
97 | 0 | pTransferObj->SetDrawPersist(aDragShellRef); // keep persist for ole objects alive |
98 | 0 | pTransferObj->SetDragSource( this ); // copies selection |
99 | |
|
100 | 0 | ScModule::get()->SetDragObject(nullptr, pTransferObj.get()); // for internal D&D |
101 | 0 | pTransferObj->StartDrag( pWindow, DND_ACTION_COPYMOVE | DND_ACTION_LINK ); |
102 | 0 | } |
103 | | |
104 | | namespace { |
105 | | |
106 | | void getRangeFromDataSource( uno::Reference< chart2::data::XDataSource > const & xDataSource, std::vector<OUString>& rRangeRep) |
107 | 0 | { |
108 | 0 | const uno::Sequence<uno::Reference<chart2::data::XLabeledDataSequence> > xSeqs = xDataSource->getDataSequences(); |
109 | 0 | for (const uno::Reference<chart2::data::XLabeledDataSequence>& xLS : xSeqs) |
110 | 0 | { |
111 | 0 | uno::Reference<chart2::data::XDataSequence> xSeq = xLS->getValues(); |
112 | 0 | if (xSeq.is()) |
113 | 0 | { |
114 | 0 | OUString aRep = xSeq->getSourceRangeRepresentation(); |
115 | 0 | rRangeRep.push_back(aRep); |
116 | 0 | } |
117 | 0 | xSeq = xLS->getLabel(); |
118 | 0 | if (xSeq.is()) |
119 | 0 | { |
120 | 0 | OUString aRep = xSeq->getSourceRangeRepresentation(); |
121 | 0 | rRangeRep.push_back(aRep); |
122 | 0 | } |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | | void getRangeFromErrorBar(const uno::Reference< chart2::XChartDocument >& rChartDoc, std::vector<OUString>& rRangeRep) |
127 | 0 | { |
128 | 0 | uno::Reference <chart2::XDiagram > xDiagram = rChartDoc->getFirstDiagram(); |
129 | 0 | if(!xDiagram.is()) |
130 | 0 | return; |
131 | | |
132 | 0 | uno::Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY); |
133 | 0 | if(!xCooSysContainer.is()) |
134 | 0 | return; |
135 | | |
136 | 0 | const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems()); |
137 | 0 | for(const auto& rCooSys : xCooSysSequence) |
138 | 0 | { |
139 | 0 | uno::Reference< chart2::XChartTypeContainer > xChartTypeContainer( rCooSys, uno::UNO_QUERY); |
140 | 0 | if(!xChartTypeContainer.is()) |
141 | 0 | continue; |
142 | | |
143 | 0 | const uno::Sequence< uno::Reference< chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() ); |
144 | 0 | for(const auto& rChartType : xChartTypeSequence) |
145 | 0 | { |
146 | 0 | uno::Reference< chart2::XDataSeriesContainer > xDataSequenceContainer( rChartType, uno::UNO_QUERY); |
147 | 0 | if(!xDataSequenceContainer.is()) |
148 | 0 | continue; |
149 | | |
150 | 0 | const uno::Sequence< uno::Reference< chart2::XDataSeries > > xSeriesSequence( xDataSequenceContainer->getDataSeries() ); |
151 | 0 | for(const uno::Reference<chart2::XDataSeries>& xSeries : xSeriesSequence) |
152 | 0 | { |
153 | 0 | uno::Reference< beans::XPropertySet > xPropSet( xSeries, uno::UNO_QUERY); |
154 | 0 | uno::Reference< chart2::data::XDataSource > xErrorBarY; |
155 | 0 | xPropSet->getPropertyValue(u"ErrorBarY"_ustr) >>= xErrorBarY; |
156 | 0 | if(xErrorBarY.is()) |
157 | 0 | getRangeFromDataSource(xErrorBarY, rRangeRep); |
158 | 0 | uno::Reference< chart2::data::XDataSource > xErrorBarX; |
159 | 0 | xPropSet->getPropertyValue(u"ErrorBarX"_ustr) >>= xErrorBarX; |
160 | 0 | if(xErrorBarX.is()) |
161 | 0 | getRangeFromDataSource(xErrorBarX, rRangeRep); |
162 | 0 | } |
163 | 0 | } |
164 | 0 | } |
165 | 0 | } |
166 | | |
167 | | void getRangeFromOle2Object(const SdrOle2Obj& rObj, std::vector<OUString>& rRangeRep) |
168 | 0 | { |
169 | 0 | if (!rObj.IsChart()) |
170 | | // not a chart object. |
171 | 0 | return; |
172 | | |
173 | 0 | const uno::Reference<embed::XEmbeddedObject>& xObj = rObj.GetObjRef(); |
174 | 0 | if (!xObj.is()) |
175 | 0 | return; |
176 | | |
177 | 0 | uno::Reference<chart2::XChartDocument> xChartDoc(xObj->getComponent(), uno::UNO_QUERY); |
178 | 0 | if (!xChartDoc.is()) |
179 | 0 | return; |
180 | | |
181 | 0 | if(xChartDoc->hasInternalDataProvider()) |
182 | 0 | return; |
183 | | |
184 | 0 | getRangeFromErrorBar(xChartDoc, rRangeRep); |
185 | |
|
186 | 0 | uno::Reference<chart2::data::XDataSource> xDataSource(xChartDoc, uno::UNO_QUERY); |
187 | 0 | if (!xDataSource.is()) |
188 | 0 | return; |
189 | | |
190 | | // Get all data sources used in this chart. |
191 | 0 | getRangeFromDataSource(xDataSource, rRangeRep); |
192 | |
|
193 | 0 | return; |
194 | 0 | } |
195 | | |
196 | | // Get all cell ranges that are referenced by the selected chart objects. |
197 | | void getOleSourceRanges(const SdrMarkList& rMarkList, bool& rAnyOle, bool& rOneOle, std::vector<ScRange>* pRanges = nullptr, const ScDocument* pDoc = nullptr ) |
198 | 0 | { |
199 | 0 | bool bCalcSourceRanges = pRanges && pDoc; |
200 | 0 | std::vector<OUString> aRangeReps; |
201 | 0 | rAnyOle = rOneOle = false; |
202 | 0 | const size_t nCount = rMarkList.GetMarkCount(); |
203 | 0 | for (size_t i=0; i<nCount; ++i) |
204 | 0 | { |
205 | 0 | SdrMark* pMark = rMarkList.GetMark(i); |
206 | 0 | if ( !pMark ) |
207 | 0 | continue; |
208 | | |
209 | 0 | SdrObject* pObj = pMark->GetMarkedSdrObj(); |
210 | 0 | if ( !pObj ) |
211 | 0 | continue; |
212 | | |
213 | 0 | SdrObjKind nSdrObjKind = pObj->GetObjIdentifier(); |
214 | 0 | if (nSdrObjKind == SdrObjKind::OLE2) |
215 | 0 | { |
216 | 0 | rAnyOle = true; |
217 | 0 | rOneOle = (nCount == 1); |
218 | 0 | if ( bCalcSourceRanges ) |
219 | 0 | getRangeFromOle2Object( static_cast<const SdrOle2Obj&>( *pObj ), aRangeReps ); |
220 | 0 | else |
221 | 0 | break; |
222 | 0 | } |
223 | 0 | else if ( dynamic_cast<const SdrObjGroup*>( pObj) != nullptr ) |
224 | 0 | { |
225 | 0 | SdrObjListIter aIter( *pObj, SdrIterMode::DeepNoGroups ); |
226 | 0 | SdrObject* pSubObj = aIter.Next(); |
227 | 0 | while (pSubObj) |
228 | 0 | { |
229 | 0 | if ( pSubObj->GetObjIdentifier() == SdrObjKind::OLE2 ) |
230 | 0 | { |
231 | 0 | rAnyOle = true; |
232 | | // rOneOle remains false - a group isn't treated like a single OLE object |
233 | 0 | if ( !bCalcSourceRanges ) |
234 | 0 | return; |
235 | | |
236 | 0 | getRangeFromOle2Object( static_cast<const SdrOle2Obj&>( *pSubObj ), aRangeReps ); |
237 | 0 | } |
238 | 0 | pSubObj = aIter.Next(); |
239 | 0 | } |
240 | 0 | } |
241 | 0 | } |
242 | | |
243 | 0 | if (!bCalcSourceRanges) |
244 | 0 | return; |
245 | | |
246 | | // Compile all range representation strings into ranges. |
247 | 0 | for (const auto& rRangeRep : aRangeReps) |
248 | 0 | { |
249 | 0 | ScRangeList aRange; |
250 | 0 | ScAddress aAddr; |
251 | 0 | if (aRange.Parse(rRangeRep, *pDoc, pDoc->GetAddressConvention()) & ScRefFlags::VALID) |
252 | 0 | { |
253 | 0 | pRanges->insert(pRanges->end(), aRange.begin(), aRange.end()); |
254 | 0 | } |
255 | 0 | else if (aAddr.Parse(rRangeRep, *pDoc, pDoc->GetAddressConvention()) & ScRefFlags::VALID) |
256 | 0 | pRanges->push_back(ScRange(aAddr)); |
257 | 0 | } |
258 | |
|
259 | 0 | return; |
260 | 0 | } |
261 | | |
262 | | class InsertTabIndex |
263 | | { |
264 | | std::vector<SCTAB>& mrTabs; |
265 | | public: |
266 | 0 | explicit InsertTabIndex(std::vector<SCTAB>& rTabs) : mrTabs(rTabs) {} |
267 | | void operator() (const ScRange& rRange) |
268 | 0 | { |
269 | 0 | mrTabs.push_back(rRange.aStart.Tab()); |
270 | 0 | } |
271 | | }; |
272 | | |
273 | | class CopyRangeData |
274 | | { |
275 | | ScDocument& mrSrc; |
276 | | ScDocument& mrDest; |
277 | | public: |
278 | 0 | CopyRangeData(ScDocument& rSrc, ScDocument& rDest) : mrSrc(rSrc), mrDest(rDest) {} |
279 | | |
280 | | void operator() (const ScRange& rRange) |
281 | 0 | { |
282 | 0 | OUString aTabName; |
283 | 0 | mrSrc.GetName(rRange.aStart.Tab(), aTabName); |
284 | |
|
285 | 0 | SCTAB nTab; |
286 | 0 | if (!mrDest.GetTable(aTabName, nTab)) |
287 | | // Sheet by this name doesn't exist. |
288 | 0 | return; |
289 | | |
290 | 0 | mrSrc.CopyStaticToDocument(rRange, nTab, mrDest); |
291 | 0 | } |
292 | | }; |
293 | | |
294 | | void copyChartRefDataToClipDoc(ScDocument& rSrcDoc, ScDocument& rClipDoc, const std::vector<ScRange>& rRanges) |
295 | 0 | { |
296 | | // Get a list of referenced table indices. |
297 | 0 | std::vector<SCTAB> aTabs; |
298 | 0 | std::for_each(rRanges.begin(), rRanges.end(), InsertTabIndex(aTabs)); |
299 | 0 | std::sort(aTabs.begin(), aTabs.end()); |
300 | 0 | aTabs.erase(std::unique(aTabs.begin(), aTabs.end()), aTabs.end()); |
301 | | |
302 | | // Get table names. |
303 | 0 | if (aTabs.empty()) |
304 | 0 | return; |
305 | | |
306 | | // Create sheets only for referenced source sheets. |
307 | 0 | OUString aName; |
308 | 0 | std::vector<SCTAB>::const_iterator it = aTabs.begin(), itEnd = aTabs.end(); |
309 | 0 | if (!rSrcDoc.GetName(*it, aName)) |
310 | 0 | return; |
311 | | |
312 | 0 | rClipDoc.SetTabNameOnLoad(0, aName); // document initially has one sheet. |
313 | |
|
314 | 0 | for (++it; it != itEnd; ++it) |
315 | 0 | { |
316 | 0 | if (!rSrcDoc.GetName(*it, aName)) |
317 | 0 | return; |
318 | | |
319 | 0 | rClipDoc.AppendTabOnLoad(aName); |
320 | 0 | } |
321 | | |
322 | 0 | std::for_each(rRanges.begin(), rRanges.end(), CopyRangeData(rSrcDoc, rClipDoc)); |
323 | 0 | } |
324 | | |
325 | | } |
326 | | |
327 | | void ScDrawView::CheckOle( const SdrMarkList& rMarkList, bool& rAnyOle, bool& rOneOle ) |
328 | 0 | { |
329 | 0 | getOleSourceRanges( rMarkList, rAnyOle, rOneOle ); |
330 | 0 | } |
331 | | |
332 | | void ScDrawView::DoCopy() |
333 | 0 | { |
334 | 0 | const SdrMarkList& rMarkList = GetMarkedObjectList(); |
335 | 0 | std::vector<ScRange> aRanges; |
336 | 0 | bool bAnyOle = false, bOneOle = false; |
337 | 0 | getOleSourceRanges( rMarkList, bAnyOle, bOneOle, &aRanges, &rDoc ); |
338 | | |
339 | | // update ScGlobal::xDrawClipDocShellRef |
340 | 0 | ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) ); |
341 | 0 | if (ScGlobal::xDrawClipDocShellRef.is() && !aRanges.empty()) |
342 | 0 | { |
343 | | // Copy data referenced by the chart objects to the draw clip |
344 | | // document. We need to do this before CreateMarkedObjModel() below. |
345 | 0 | ScDocShellRef xDocSh = ScGlobal::xDrawClipDocShellRef; |
346 | 0 | ScDocument& rClipDoc = xDocSh->GetDocument(); |
347 | 0 | copyChartRefDataToClipDoc(rDoc, rClipDoc, aRanges); |
348 | 0 | } |
349 | 0 | std::unique_ptr<SdrModel> pModel(CreateMarkedObjModel()); |
350 | 0 | ScDrawLayer::SetGlobalDrawPersist(nullptr); |
351 | | |
352 | | // Charts now always copy their data in addition to the source reference, so |
353 | | // there's no need to call SchDLL::Update for the charts in the clipboard doc. |
354 | | // Update with the data (including NumberFormatter) from the live document would |
355 | | // also store the NumberFormatter in the clipboard chart (#88749#) |
356 | |
|
357 | 0 | ScDocShell* pDocSh = rViewData.GetDocShell(); |
358 | |
|
359 | 0 | TransferableObjectDescriptor aObjDesc; |
360 | 0 | pDocSh->FillTransferableObjectDescriptor( aObjDesc ); |
361 | 0 | aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass(); |
362 | | // maSize is set in ScDrawTransferObj ctor |
363 | |
|
364 | 0 | rtl::Reference<ScDrawTransferObj> pTransferObj(new ScDrawTransferObj( std::move(pModel), *pDocSh, std::move(aObjDesc) )); |
365 | |
|
366 | 0 | if ( ScGlobal::xDrawClipDocShellRef.is() ) |
367 | 0 | { |
368 | 0 | pTransferObj->SetDrawPersist( ScGlobal::xDrawClipDocShellRef ); // keep persist for ole objects alive |
369 | 0 | } |
370 | |
|
371 | 0 | pTransferObj->CopyToClipboard( rViewData.GetActiveWin() ); // system clipboard |
372 | 0 | } |
373 | | |
374 | | uno::Reference<datatransfer::XTransferable> ScDrawView::CopyToTransferable() |
375 | 0 | { |
376 | 0 | bool bAnyOle, bOneOle; |
377 | 0 | const SdrMarkList& rMarkList = GetMarkedObjectList(); |
378 | 0 | CheckOle( rMarkList, bAnyOle, bOneOle ); |
379 | | |
380 | | // update ScGlobal::xDrawClipDocShellRef |
381 | 0 | ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) ); |
382 | 0 | std::unique_ptr<SdrModel> pModel( CreateMarkedObjModel() ); |
383 | 0 | ScDrawLayer::SetGlobalDrawPersist(nullptr); |
384 | | |
385 | | // Charts now always copy their data in addition to the source reference, so |
386 | | // there's no need to call SchDLL::Update for the charts in the clipboard doc. |
387 | | // Update with the data (including NumberFormatter) from the live document would |
388 | | // also store the NumberFormatter in the clipboard chart (#88749#) |
389 | | // lcl_RefreshChartData( pModel, rViewData.GetDocument() ); |
390 | |
|
391 | 0 | ScDocShell* pDocSh = rViewData.GetDocShell(); |
392 | |
|
393 | 0 | TransferableObjectDescriptor aObjDesc; |
394 | 0 | pDocSh->FillTransferableObjectDescriptor( aObjDesc ); |
395 | 0 | aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass(); |
396 | | // maSize is set in ScDrawTransferObj ctor |
397 | |
|
398 | 0 | rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pModel), *pDocSh, std::move(aObjDesc) ); |
399 | |
|
400 | 0 | if ( ScGlobal::xDrawClipDocShellRef.is() ) |
401 | 0 | { |
402 | 0 | pTransferObj->SetDrawPersist( ScGlobal::xDrawClipDocShellRef ); // keep persist for ole objects alive |
403 | 0 | } |
404 | |
|
405 | 0 | return pTransferObj; |
406 | 0 | } |
407 | | |
408 | | // Calculate correction for 100%, regardless of current settings |
409 | | |
410 | | void ScDrawView::CalcNormScale( double& rFractX, double& rFractY ) const |
411 | 0 | { |
412 | 0 | double nPPTX = ScGlobal::nScreenPPTX; |
413 | 0 | double nPPTY = ScGlobal::nScreenPPTY; |
414 | |
|
415 | 0 | nPPTX /= rViewData.GetDocShell()->GetOutputFactor(); |
416 | |
|
417 | 0 | SCCOL nEndCol = 0; |
418 | 0 | SCROW nEndRow = 0; |
419 | 0 | rDoc.GetTableArea( nTab, nEndCol, nEndRow ); |
420 | 0 | if (nEndCol<20) |
421 | 0 | nEndCol = 20; |
422 | 0 | if (nEndRow<20) |
423 | 0 | nEndRow = 1000; |
424 | |
|
425 | 0 | double fZoom(1.0); |
426 | 0 | ScDrawUtil::CalcScale( rDoc, nTab, 0,0, nEndCol,nEndRow, pDev, fZoom, fZoom, |
427 | 0 | nPPTX, nPPTY, rFractX,rFractY ); |
428 | 0 | } |
429 | | |
430 | | void ScDrawView::SetMarkedOriginalSize() |
431 | 0 | { |
432 | 0 | std::unique_ptr<SdrUndoGroup> pUndoGroup(new SdrUndoGroup(GetModel())); |
433 | |
|
434 | 0 | const SdrMarkList& rMarkList = GetMarkedObjectList(); |
435 | 0 | tools::Long nDone = 0; |
436 | 0 | const size_t nCount = rMarkList.GetMarkCount(); |
437 | 0 | for (size_t i=0; i<nCount; ++i) |
438 | 0 | { |
439 | 0 | SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj(); |
440 | 0 | SdrObjKind nIdent = pObj->GetObjIdentifier(); |
441 | 0 | bool bDo = false; |
442 | 0 | Size aOriginalSize; |
443 | 0 | if (nIdent == SdrObjKind::OLE2) |
444 | 0 | { |
445 | | // TODO/LEAN: working with visual area can switch object to running state |
446 | 0 | uno::Reference < embed::XEmbeddedObject > xObj = static_cast<SdrOle2Obj*>(pObj)->GetObjRef(); |
447 | 0 | if ( xObj.is() ) // NULL for an invalid object that couldn't be loaded |
448 | 0 | { |
449 | 0 | sal_Int64 nAspect = static_cast<SdrOle2Obj*>(pObj)->GetAspect(); |
450 | |
|
451 | 0 | if ( nAspect == embed::Aspects::MSOLE_ICON ) |
452 | 0 | { |
453 | 0 | MapMode aMapMode( MapUnit::Map100thMM ); |
454 | 0 | aOriginalSize = static_cast<SdrOle2Obj*>(pObj)->GetOrigObjSize( &aMapMode ); |
455 | 0 | bDo = true; |
456 | 0 | } |
457 | 0 | else |
458 | 0 | { |
459 | 0 | MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( static_cast<SdrOle2Obj*>(pObj)->GetAspect() ) ); |
460 | 0 | try |
461 | 0 | { |
462 | 0 | awt::Size aSz = xObj->getVisualAreaSize( static_cast<SdrOle2Obj*>(pObj)->GetAspect() ); |
463 | 0 | aOriginalSize = OutputDevice::LogicToLogic( |
464 | 0 | Size( aSz.Width, aSz.Height ), |
465 | 0 | MapMode(aUnit), |
466 | 0 | MapMode(MapUnit::Map100thMM)); |
467 | 0 | bDo = true; |
468 | 0 | } catch( embed::NoVisualAreaSizeException& ) |
469 | 0 | { |
470 | 0 | TOOLS_WARN_EXCEPTION("sc.ui", "Can't get the original size of the object!" ); |
471 | 0 | } |
472 | 0 | } |
473 | 0 | } |
474 | 0 | } |
475 | 0 | else if (nIdent == SdrObjKind::Graphic) |
476 | 0 | { |
477 | 0 | const SdrGrafObj* pSdrGrafObj = static_cast<const SdrGrafObj*>(pObj); |
478 | |
|
479 | 0 | MapMode aSourceMap = pSdrGrafObj->GetGraphic().GetPrefMapMode(); |
480 | 0 | MapMode aDestMap( MapUnit::Map100thMM ); |
481 | 0 | if (aSourceMap.GetMapUnit() == MapUnit::MapPixel) |
482 | 0 | { |
483 | | // consider pixel correction, so that the bitmap is correct on the screen |
484 | 0 | double fNormScaleX, fNormScaleY; |
485 | 0 | CalcNormScale( fNormScaleX, fNormScaleY ); |
486 | 0 | aDestMap.SetScaleX(fNormScaleX); |
487 | 0 | aDestMap.SetScaleY(fNormScaleY); |
488 | 0 | } |
489 | 0 | aOriginalSize = pSdrGrafObj->getOriginalSize(); |
490 | 0 | bDo = true; |
491 | 0 | } |
492 | | |
493 | 0 | if ( bDo ) |
494 | 0 | { |
495 | 0 | tools::Rectangle aDrawRect = pObj->GetLogicRect(); |
496 | |
|
497 | 0 | if (aDrawRect.GetWidth() && aDrawRect.GetHeight()) |
498 | 0 | { |
499 | 0 | pUndoGroup->AddAction( std::make_unique<SdrUndoGeoObj>( *pObj ) ); |
500 | 0 | pObj->Resize( aDrawRect.TopLeft(), double( aOriginalSize.Width() ) / aDrawRect.GetWidth(), |
501 | 0 | double( aOriginalSize.Height() ) / aDrawRect.GetHeight() ); |
502 | 0 | ++nDone; |
503 | 0 | } |
504 | 0 | } |
505 | 0 | } |
506 | | |
507 | 0 | if (nDone) |
508 | 0 | { |
509 | 0 | pUndoGroup->SetComment(ScResId( STR_UNDO_ORIGINALSIZE )); |
510 | 0 | ScDocShell* pDocSh = rViewData.GetDocShell(); |
511 | 0 | pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup)); |
512 | 0 | pDocSh->SetDrawModified(); |
513 | 0 | } |
514 | 0 | } |
515 | | |
516 | | void ScDrawView::FitToCellSize() |
517 | 0 | { |
518 | 0 | const SdrMarkList& rMarkList = GetMarkedObjectList(); |
519 | |
|
520 | 0 | if (rMarkList.GetMarkCount() != 1) |
521 | 0 | { |
522 | 0 | SAL_WARN("sc.ui", "Fit to cell only works with one graphic!"); |
523 | 0 | return; |
524 | 0 | } |
525 | | |
526 | 0 | SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); |
527 | |
|
528 | 0 | ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObj); |
529 | 0 | if (aAnchorType != SCA_CELL && aAnchorType != SCA_CELL_RESIZE) |
530 | 0 | { |
531 | 0 | SAL_WARN("sc.ui", "Fit to cell only works with cell anchored graphics!"); |
532 | 0 | return; |
533 | 0 | } |
534 | | |
535 | 0 | ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pObj); |
536 | 0 | if (!pObjData) |
537 | 0 | { |
538 | 0 | SAL_WARN("sc.ui", "Missing ScDrawObjData!"); |
539 | 0 | return; |
540 | 0 | } |
541 | | |
542 | 0 | std::unique_ptr<SdrUndoGroup> pUndoGroup(new SdrUndoGroup(GetModel())); |
543 | 0 | tools::Rectangle aGraphicRect = pObj->GetSnapRect(); |
544 | 0 | tools::Rectangle aCellRect = ScDrawLayer::GetCellRect( rDoc, pObjData->maStart, true); |
545 | | |
546 | | // For graphic objects, we want to keep the aspect ratio |
547 | 0 | if (pObj->shouldKeepAspectRatio()) |
548 | 0 | { |
549 | 0 | tools::Long nWidth = aGraphicRect.GetWidth(); |
550 | 0 | assert(nWidth && "div-by-zero"); |
551 | 0 | double fScaleX = static_cast<double>(aCellRect.GetWidth()) / static_cast<double>(nWidth); |
552 | 0 | tools::Long nHeight = aGraphicRect.GetHeight(); |
553 | 0 | assert(nHeight && "div-by-zero"); |
554 | 0 | double fScaleY = static_cast<double>(aCellRect.GetHeight()) / static_cast<double>(nHeight); |
555 | 0 | double fScaleMin = std::min(fScaleX, fScaleY); |
556 | |
|
557 | 0 | aCellRect.setWidth(static_cast<double>(aGraphicRect.GetWidth()) * fScaleMin); |
558 | 0 | aCellRect.setHeight(static_cast<double>(aGraphicRect.GetHeight()) * fScaleMin); |
559 | 0 | } |
560 | |
|
561 | 0 | pUndoGroup->AddAction( std::make_unique<SdrUndoGeoObj>( *pObj ) ); |
562 | 0 | if (pObj->GetObjIdentifier() == SdrObjKind::CustomShape) |
563 | 0 | pObj->AdjustToMaxRect(aCellRect); |
564 | 0 | else |
565 | 0 | pObj->SetSnapRect(aCellRect); |
566 | |
|
567 | 0 | pUndoGroup->SetComment(ScResId( STR_UNDO_FITCELLSIZE )); |
568 | 0 | ScDocShell* pDocSh = rViewData.GetDocShell(); |
569 | 0 | pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup)); |
570 | |
|
571 | 0 | } |
572 | | |
573 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |