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
21 #include <svx/svdmrkv.hxx>
22 #include <svx/svdetc.hxx>
23 #include <svx/svdoedge.hxx>
24 #include <svx/svdpagv.hxx>
25 #include <svx/svdpage.hxx>
26 #include "svddrgm1.hxx"
27
28
29 // Point Selection
30
31
HasMarkablePoints() const32 bool SdrMarkView::HasMarkablePoints() const
33 {
34 ForceUndirtyMrkPnt();
35 bool bRet=false;
36 if (!ImpIsFrameHandles()) {
37 const size_t nMarkCount=GetMarkedObjectCount();
38 if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
39 for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
40 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
41 const SdrObject* pObj=pM->GetMarkedSdrObj();
42 bRet=pObj->IsPolyObj();
43 }
44 }
45 }
46 return bRet;
47 }
48
GetMarkablePointCount() const49 sal_Int32 SdrMarkView::GetMarkablePointCount() const
50 {
51 ForceUndirtyMrkPnt();
52 sal_Int32 nCount=0;
53 if (!ImpIsFrameHandles()) {
54 const size_t nMarkCount=GetMarkedObjectCount();
55 if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
56 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
57 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
58 const SdrObject* pObj=pM->GetMarkedSdrObj();
59 if (pObj->IsPolyObj()) {
60 nCount+=pObj->GetPointCount();
61 }
62 }
63 }
64 }
65 return nCount;
66 }
67
HasMarkedPoints() const68 bool SdrMarkView::HasMarkedPoints() const
69 {
70 ForceUndirtyMrkPnt();
71 bool bRet=false;
72 if (!ImpIsFrameHandles()) {
73 const size_t nMarkCount=GetMarkedObjectCount();
74 if (nMarkCount<=static_cast<size_t>(mnFrameHandlesLimit)) {
75 for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
76 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
77 const SdrUShortCont& rPts = pM->GetMarkedPoints();
78 bRet = !rPts.empty();
79 }
80 }
81 }
82 return bRet;
83 }
84
IsPointMarkable(const SdrHdl & rHdl) const85 bool SdrMarkView::IsPointMarkable(const SdrHdl& rHdl) const
86 {
87 return !ImpIsFrameHandles() && !rHdl.IsPlusHdl() && rHdl.GetKind()!=SdrHdlKind::Glue && rHdl.GetKind()!=SdrHdlKind::SmartTag && rHdl.GetObj()!=nullptr && rHdl.GetObj()->IsPolyObj();
88 }
89
MarkPointHelper(SdrHdl * pHdl,SdrMark * pMark,bool bUnmark)90 bool SdrMarkView::MarkPointHelper(SdrHdl* pHdl, SdrMark* pMark, bool bUnmark)
91 {
92 return ImpMarkPoint( pHdl, pMark, bUnmark );
93 }
94
ImpMarkPoint(SdrHdl * pHdl,SdrMark * pMark,bool bUnmark)95 bool SdrMarkView::ImpMarkPoint(SdrHdl* pHdl, SdrMark* pMark, bool bUnmark)
96 {
97 if (pHdl==nullptr || pHdl->IsPlusHdl() || pHdl->GetKind()==SdrHdlKind::Glue)
98 return false;
99
100 if (pHdl->IsSelected() != bUnmark)
101 return false;
102
103 SdrObject* pObj=pHdl->GetObj();
104 if (pObj==nullptr || !pObj->IsPolyObj())
105 return false;
106
107 if (pMark==nullptr)
108 {
109 const size_t nMarkNum=TryToFindMarkedObject(pObj);
110 if (nMarkNum==SAL_MAX_SIZE)
111 return false;
112 pMark=GetSdrMarkByIndex(nMarkNum);
113 }
114 const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
115 SdrUShortCont& rPts=pMark->GetMarkedPoints();
116 if (!bUnmark)
117 {
118 rPts.insert(static_cast<sal_uInt16>(nHdlNum));
119 }
120 else
121 {
122 SdrUShortCont::const_iterator it = rPts.find( static_cast<sal_uInt16>(nHdlNum) );
123 if (it != rPts.end())
124 {
125 rPts.erase(it);
126 }
127 else
128 {
129 return false; // error case!
130 }
131 }
132
133 pHdl->SetSelected(!bUnmark);
134 if (!mbPlusHdlAlways)
135 {
136 if (!bUnmark)
137 {
138 SdrHdlList plusList(nullptr);
139 pObj->AddToPlusHdlList(plusList, *pHdl);
140 sal_uInt32 nCount(plusList.GetHdlCount());
141 for (sal_uInt32 i=0; i<nCount; i++)
142 {
143 SdrHdl* pPlusHdl=plusList.GetHdl(i);
144 pPlusHdl->SetObj(pObj);
145 pPlusHdl->SetPageView(pMark->GetPageView());
146 pPlusHdl->SetPlusHdl(true);
147 }
148 plusList.MoveTo(maHdlList);
149 }
150 else
151 {
152 for (size_t i = maHdlList.GetHdlCount(); i>0;)
153 {
154 --i;
155 SdrHdl* pPlusHdl=maHdlList.GetHdl(i);
156 if (pPlusHdl->IsPlusHdl() && pPlusHdl->GetSourceHdlNum()==nHdlNum)
157 {
158 maHdlList.RemoveHdl(i);
159 }
160 }
161 }
162 }
163
164 maHdlList.Sort();
165
166 return true;
167 }
168
169
MarkPoint(SdrHdl & rHdl,bool bUnmark)170 bool SdrMarkView::MarkPoint(SdrHdl& rHdl, bool bUnmark)
171 {
172 ForceUndirtyMrkPnt();
173 bool bRet=false;
174 const SdrObject* pObj=rHdl.GetObj();
175 if (IsPointMarkable(rHdl) && rHdl.IsSelected()==bUnmark) {
176 const size_t nMarkNum=TryToFindMarkedObject(pObj);
177 if (nMarkNum!=SAL_MAX_SIZE) {
178 SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
179 if (ImpMarkPoint(&rHdl,pM,bUnmark)) {
180 MarkListHasChanged();
181 bRet=true;
182 }
183 }
184 }
185
186 return bRet;
187 }
188
MarkPoints(const tools::Rectangle * pRect,bool bUnmark)189 bool SdrMarkView::MarkPoints(const tools::Rectangle* pRect, bool bUnmark)
190 {
191 ForceUndirtyMrkPnt();
192 bool bChgd=false;
193 SortMarkedObjects();
194 const SdrObject* pObj0=nullptr;
195 const SdrPageView* pPV0=nullptr;
196 SdrMark* pM=nullptr;
197 maHdlList.Sort();
198 const size_t nHdlCnt=maHdlList.GetHdlCount();
199 for (size_t nHdlNum=nHdlCnt; nHdlNum>0;) {
200 --nHdlNum;
201 SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
202 if (IsPointMarkable(*pHdl) && pHdl->IsSelected()==bUnmark) {
203 const SdrObject* pObj=pHdl->GetObj();
204 const SdrPageView* pPV=pHdl->GetPageView();
205 if (pObj!=pObj0 || pPV!=pPV0 || pM==nullptr) { // This section is for optimization,
206 const size_t nMarkNum=TryToFindMarkedObject(pObj); // so ImpMarkPoint() doesn't always
207 if (nMarkNum!=SAL_MAX_SIZE) { // have to search the object in the MarkList.
208 pM=GetSdrMarkByIndex(nMarkNum);
209 pObj0=pObj;
210 pPV0=pPV;
211 } else {
212 #ifdef DBG_UTIL
213 if (pObj->IsInserted()) {
214 OSL_FAIL("SdrMarkView::MarkPoints(const Rectangle* pRect): Selected object not found.");
215 }
216 #endif
217 pM=nullptr;
218 }
219 }
220 Point aPos(pHdl->GetPos());
221 if (pM!=nullptr && (pRect==nullptr || pRect->IsInside(aPos))) {
222 if (ImpMarkPoint(pHdl,pM,bUnmark)) bChgd=true;
223 }
224 }
225 }
226 if (bChgd) {
227 MarkListHasChanged();
228 }
229
230 return bChgd;
231 }
232
MarkNextPoint()233 void SdrMarkView::MarkNextPoint()
234 {
235 ForceUndirtyMrkPnt();
236 SortMarkedObjects();
237 }
238
GetMarkedPointsRect() const239 const tools::Rectangle& SdrMarkView::GetMarkedPointsRect() const
240 {
241 ForceUndirtyMrkPnt();
242 if (mbMarkedPointsRectsDirty) ImpSetPointsRects();
243 return maMarkedPointsRect;
244 }
245
SetPlusHandlesAlwaysVisible(bool bOn)246 void SdrMarkView::SetPlusHandlesAlwaysVisible(bool bOn)
247 { // TODO: Optimize HandlePaint!
248 ForceUndirtyMrkPnt();
249 if (bOn!=mbPlusHdlAlways) {
250 mbPlusHdlAlways=bOn;
251 SetMarkHandles(nullptr);
252 MarkListHasChanged();
253 }
254 }
255
256
257 // ImpSetPointsRects() is for PolyPoints and GluePoints!
258
259
ImpSetPointsRects() const260 void SdrMarkView::ImpSetPointsRects() const
261 {
262 tools::Rectangle aPnts;
263 tools::Rectangle aGlue;
264 const size_t nHdlCnt=maHdlList.GetHdlCount();
265 for (size_t nHdlNum=0; nHdlNum<nHdlCnt; ++nHdlNum) {
266 const SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
267 SdrHdlKind eKind=pHdl->GetKind();
268 if ((eKind==SdrHdlKind::Poly && pHdl->IsSelected()) || eKind==SdrHdlKind::Glue) {
269 Point aPt(pHdl->GetPos());
270 tools::Rectangle& rR=eKind==SdrHdlKind::Glue ? aGlue : aPnts;
271 if (rR.IsEmpty()) {
272 rR=tools::Rectangle(aPt,aPt);
273 } else {
274 if (aPt.X()<rR.Left ()) rR.SetLeft(aPt.X() );
275 if (aPt.X()>rR.Right ()) rR.SetRight(aPt.X() );
276 if (aPt.Y()<rR.Top ()) rR.SetTop(aPt.Y() );
277 if (aPt.Y()>rR.Bottom()) rR.SetBottom(aPt.Y() );
278 }
279 }
280 }
281 const_cast<SdrMarkView*>(this)->maMarkedPointsRect=aPnts;
282 const_cast<SdrMarkView*>(this)->maMarkedGluePointsRect=aGlue;
283 const_cast<SdrMarkView*>(this)->mbMarkedPointsRectsDirty=false;
284 }
285
286
287 // UndirtyMrkPnt() is for PolyPoints and GluePoints!
288
289
UndirtyMrkPnt() const290 void SdrMarkView::UndirtyMrkPnt() const
291 {
292 bool bChg=false;
293 const size_t nMarkCount=GetMarkedObjectCount();
294 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
295 SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
296 const SdrObject* pObj=pM->GetMarkedSdrObj();
297 // PolyPoints
298 {
299 SdrUShortCont& rPts = pM->GetMarkedPoints();
300 if (pObj->IsPolyObj()) {
301 // Remove invalid selected points, that is, all
302 // entries above the number of points in the object.
303 sal_uInt32 nMax(pObj->GetPointCount());
304
305 SdrUShortCont::const_iterator it = rPts.lower_bound(nMax);
306 if( it != rPts.end() )
307 {
308 rPts.erase(it, rPts.end());
309 bChg = true;
310 }
311 }
312 else
313 {
314 OSL_FAIL("SdrMarkView::UndirtyMrkPnt(): Selected points on an object that is not a PolyObj!");
315 if (!rPts.empty())
316 {
317 rPts.clear();
318 bChg = true;
319 }
320 }
321 }
322
323 // GluePoints
324 {
325 SdrUShortCont& rPts = pM->GetMarkedGluePoints();
326 const SdrGluePointList* pGPL=pObj->GetGluePointList();
327 if (pGPL!=nullptr) {
328 // Remove invalid selected glue points, that is, all entries
329 // (IDs) that aren't contained in the GluePointList of the
330 // object
331 for(SdrUShortCont::const_iterator it = rPts.begin(); it != rPts.end(); )
332 {
333 sal_uInt16 nId=*it;
334 if (pGPL->FindGluePoint(nId)==SDRGLUEPOINT_NOTFOUND) {
335 it = rPts.erase(it);
336 bChg=true;
337 }
338 else
339 ++it;
340 }
341 } else {
342 if (!rPts.empty()) {
343 rPts.clear(); // object doesn't have any glue points (any more)
344 bChg=true;
345 }
346 }
347 }
348 }
349 if (bChg) const_cast<SdrMarkView*>(this)->mbMarkedPointsRectsDirty=true;
350 const_cast<SdrMarkView*>(this)->mbMrkPntDirty=false;
351 }
352
353
HasMarkableGluePoints() const354 bool SdrMarkView::HasMarkableGluePoints() const
355 {
356 bool bRet=false;
357 if (IsGluePointEditMode()) {
358 ForceUndirtyMrkPnt();
359 const size_t nMarkCount=GetMarkedObjectCount();
360 for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
361 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
362 const SdrObject* pObj=pM->GetMarkedSdrObj();
363 const SdrGluePointList* pGPL=pObj->GetGluePointList();
364
365 // #i38892#
366 if(pGPL && pGPL->GetCount())
367 {
368 for(sal_uInt16 a(0); !bRet && a < pGPL->GetCount(); a++)
369 {
370 if((*pGPL)[a].IsUserDefined())
371 {
372 bRet = true;
373 }
374 }
375 }
376 }
377 }
378 return bRet;
379 }
380
HasMarkedGluePoints() const381 bool SdrMarkView::HasMarkedGluePoints() const
382 {
383 ForceUndirtyMrkPnt();
384 bool bRet=false;
385 const size_t nMarkCount=GetMarkedObjectCount();
386 for (size_t nMarkNum=0; nMarkNum<nMarkCount && !bRet; ++nMarkNum) {
387 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
388 const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
389 bRet = !rPts.empty();
390 }
391 return bRet;
392 }
393
MarkGluePoints(const tools::Rectangle * pRect,bool bUnmark)394 bool SdrMarkView::MarkGluePoints(const tools::Rectangle* pRect, bool bUnmark)
395 {
396 if (!IsGluePointEditMode() && !bUnmark) return false;
397 ForceUndirtyMrkPnt();
398 bool bChgd=false;
399 SortMarkedObjects();
400 const size_t nMarkCount=GetMarkedObjectCount();
401 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum) {
402 SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
403 const SdrObject* pObj=pM->GetMarkedSdrObj();
404 const SdrGluePointList* pGPL=pObj->GetGluePointList();
405 SdrUShortCont& rPts = pM->GetMarkedGluePoints();
406 if (bUnmark && pRect==nullptr) { // UnmarkAll
407 if (!rPts.empty()) {
408 rPts.clear();
409 bChgd=true;
410 }
411 } else {
412 if (pGPL!=nullptr) {
413 sal_uInt16 nGluePointCnt=pGPL->GetCount();
414 for (sal_uInt16 nGPNum=0; nGPNum<nGluePointCnt; nGPNum++) {
415 const SdrGluePoint& rGP=(*pGPL)[nGPNum];
416
417 // #i38892#
418 if(rGP.IsUserDefined())
419 {
420 Point aPos(rGP.GetAbsolutePos(*pObj));
421 if (pRect==nullptr || pRect->IsInside(aPos)) {
422 bool bContains = rPts.find( rGP.GetId() ) != rPts.end();
423 if (!bUnmark && !bContains) {
424 bChgd=true;
425 rPts.insert(rGP.GetId());
426 }
427 if (bUnmark && bContains) {
428 bChgd=true;
429 rPts.erase(rGP.GetId());
430 }
431 }
432 }
433 }
434 }
435 }
436 }
437 if (bChgd) {
438 AdjustMarkHdl();
439 MarkListHasChanged();
440 }
441 return bChgd;
442 }
443
PickGluePoint(const Point & rPnt,SdrObject * & rpObj,sal_uInt16 & rnId,SdrPageView * & rpPV) const444 bool SdrMarkView::PickGluePoint(const Point& rPnt, SdrObject*& rpObj, sal_uInt16& rnId, SdrPageView*& rpPV) const
445 {
446 rpObj=nullptr; rpPV=nullptr; rnId=0;
447 if (!IsGluePointEditMode()) return false;
448 OutputDevice* pOut=mpActualOutDev.get();
449 if (pOut==nullptr) pOut=GetFirstOutputDevice();
450 if (pOut==nullptr) return false;
451 SortMarkedObjects();
452 const size_t nMarkCount=GetMarkedObjectCount();
453 size_t nMarkNum=nMarkCount;
454 while (nMarkNum>0) {
455 nMarkNum--;
456 const SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
457 SdrObject* pObj=pM->GetMarkedSdrObj();
458 SdrPageView* pPV=pM->GetPageView();
459 const SdrGluePointList* pGPL=pObj->GetGluePointList();
460 if (pGPL!=nullptr) {
461 sal_uInt16 nNum=pGPL->HitTest(rPnt,*pOut,pObj);
462 if (nNum!=SDRGLUEPOINT_NOTFOUND)
463 {
464 // #i38892#
465 const SdrGluePoint& rCandidate = (*pGPL)[nNum];
466
467 if(rCandidate.IsUserDefined())
468 {
469 rpObj=pObj;
470 rnId=(*pGPL)[nNum].GetId();
471 rpPV=pPV;
472 return true;
473 }
474 }
475 }
476 }
477 return false;
478 }
479
MarkGluePoint(const SdrObject * pObj,sal_uInt16 nId,bool bUnmark)480 bool SdrMarkView::MarkGluePoint(const SdrObject* pObj, sal_uInt16 nId, bool bUnmark)
481 {
482 if (!IsGluePointEditMode()) return false;
483 ForceUndirtyMrkPnt();
484 bool bChgd=false;
485 if (pObj!=nullptr) {
486 const size_t nMarkPos=TryToFindMarkedObject(pObj);
487 if (nMarkPos!=SAL_MAX_SIZE) {
488 SdrMark* pM=GetSdrMarkByIndex(nMarkPos);
489 SdrUShortCont& rPts = pM->GetMarkedGluePoints();
490 bool bContains = rPts.find( nId ) != rPts.end();
491 if (!bUnmark && !bContains) {
492 bChgd=true;
493 rPts.insert(nId);
494 }
495 if (bUnmark && bContains) {
496 bChgd=true;
497 rPts.erase(nId);
498 }
499 } else {
500 // TODO: implement implicit selection of objects
501 }
502 }
503 if (bChgd) {
504 AdjustMarkHdl();
505 MarkListHasChanged();
506 }
507 return bChgd;
508 }
509
IsGluePointMarked(const SdrObject * pObj,sal_uInt16 nId) const510 bool SdrMarkView::IsGluePointMarked(const SdrObject* pObj, sal_uInt16 nId) const
511 {
512 ForceUndirtyMrkPnt();
513 bool bRet=false;
514 const size_t nPos=TryToFindMarkedObject(pObj); // casting to NonConst
515 if (nPos!=SAL_MAX_SIZE) {
516 const SdrMark* pM=GetSdrMarkByIndex(nPos);
517 const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
518 bRet = rPts.find( nId ) != rPts.end();
519 }
520 return bRet;
521 }
522
GetGluePointHdl(const SdrObject * pObj,sal_uInt16 nId) const523 SdrHdl* SdrMarkView::GetGluePointHdl(const SdrObject* pObj, sal_uInt16 nId) const
524 {
525 ForceUndirtyMrkPnt();
526 const size_t nHdlCnt=maHdlList.GetHdlCount();
527 for (size_t nHdlNum=0; nHdlNum<nHdlCnt; ++nHdlNum) {
528 SdrHdl* pHdl=maHdlList.GetHdl(nHdlNum);
529 if (pHdl->GetObj()==pObj &&
530 pHdl->GetKind()==SdrHdlKind::Glue &&
531 pHdl->GetObjHdlNum()==nId ) return pHdl;
532 }
533 return nullptr;
534 }
535
MarkNextGluePoint()536 void SdrMarkView::MarkNextGluePoint()
537 {
538 ForceUndirtyMrkPnt();
539 SortMarkedObjects();
540 }
541
GetMarkedGluePointsRect() const542 const tools::Rectangle& SdrMarkView::GetMarkedGluePointsRect() const
543 {
544 ForceUndirtyMrkPnt();
545 if (mbMarkedPointsRectsDirty) ImpSetPointsRects();
546 return maMarkedGluePointsRect;
547 }
548
549 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
550