Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / chart2 / source / controller / main / SelectionHelper.cxx
blob9be4ae4e35040b9f8fcfe4ca152dd56e64cc0982
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <SelectionHelper.hxx>
21 #include <ObjectIdentifier.hxx>
22 #include <DiagramHelper.hxx>
23 #include <ChartModelHelper.hxx>
25 #include <svx/svdpage.hxx>
26 #include <svx/svditer.hxx>
27 #include <svx/obj3d.hxx>
28 #include <svx/svdopath.hxx>
29 #include <vcl/svapp.hxx>
30 #include <basegfx/point/b2dpoint.hxx>
31 #include <com/sun/star/beans/XPropertySet.hpp>
33 namespace chart
35 using namespace ::com::sun::star;
37 namespace
40 OUString lcl_getObjectName( SdrObject const * pObj )
42 if(pObj)
43 return pObj->GetName();
44 return OUString();
47 void impl_selectObject( SdrObject* pObjectToSelect, DrawViewWrapper& rDrawViewWrapper )
49 SolarMutexGuard aSolarGuard;
51 if(pObjectToSelect)
53 SelectionHelper aSelectionHelper( pObjectToSelect );
54 SdrObject* pMarkObj = aSelectionHelper.getObjectToMark();
55 rDrawViewWrapper.setMarkHandleProvider(&aSelectionHelper);
56 rDrawViewWrapper.MarkObject(pMarkObj);
57 rDrawViewWrapper.setMarkHandleProvider(nullptr);
61 }//anonymous namespace
63 bool Selection::hasSelection()
65 return m_aSelectedOID.isValid();
68 OUString const & Selection::getSelectedCID()
70 return m_aSelectedOID.getObjectCID();
73 uno::Reference< drawing::XShape > const & Selection::getSelectedAdditionalShape()
75 return m_aSelectedOID.getAdditionalShape();
78 bool Selection::setSelection( const OUString& rCID )
80 if ( rCID != m_aSelectedOID.getObjectCID() )
82 m_aSelectedOID = ObjectIdentifier( rCID );
83 return true;
85 return false;
88 bool Selection::setSelection( const uno::Reference< drawing::XShape >& xShape )
90 if ( !( xShape == m_aSelectedOID.getAdditionalShape() ) )
92 clearSelection();
93 m_aSelectedOID = ObjectIdentifier( xShape );
94 return true;
96 return false;
99 void Selection::clearSelection()
101 m_aSelectedOID = ObjectIdentifier();
102 m_aSelectedOID_beforeMouseDown = ObjectIdentifier();
103 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
106 bool Selection::maybeSwitchSelectionAfterSingleClickWasEnsured()
108 if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid()
109 && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing != m_aSelectedOID )
111 m_aSelectedOID = m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing;
112 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
113 return true;
115 return false;
118 void Selection::resetPossibleSelectionAfterSingleClickWasEnsured()
120 if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() )
122 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
126 void Selection::remindSelectionBeforeMouseDown()
128 m_aSelectedOID_beforeMouseDown = m_aSelectedOID;
131 bool Selection::isSelectionDifferentFromBeforeMouseDown() const
133 return ( m_aSelectedOID != m_aSelectedOID_beforeMouseDown );
136 void Selection::applySelection( DrawViewWrapper* pDrawViewWrapper )
138 if( pDrawViewWrapper )
141 SolarMutexGuard aSolarGuard;
142 pDrawViewWrapper->UnmarkAll();
144 SdrObject* pObjectToSelect = nullptr;
145 if ( m_aSelectedOID.isAutoGeneratedObject() )
147 pObjectToSelect = pDrawViewWrapper->getNamedSdrObject( m_aSelectedOID.getObjectCID() );
149 else if( m_aSelectedOID.isAdditionalShape() )
151 pObjectToSelect = DrawViewWrapper::getSdrObject( m_aSelectedOID.getAdditionalShape() );
154 impl_selectObject( pObjectToSelect, *pDrawViewWrapper );
158 void Selection::adaptSelectionToNewPos( const Point& rMousePos, DrawViewWrapper const * pDrawViewWrapper
159 , bool bIsRightMouse, bool bWaitingForDoubleClick )
161 if( pDrawViewWrapper )
163 //do not toggle multiclick selection if right clicked on the selected object or waiting for double click
164 bool bAllowMultiClickSelectionChange = !bIsRightMouse && !bWaitingForDoubleClick;
166 ObjectIdentifier aLastSelectedObject( m_aSelectedOID );
168 SolarMutexGuard aSolarGuard;
170 //bAllowMultiClickSelectionChange==true -> a second click on the same object can lead to a changed selection (e.g. series -> single data point)
172 //get object to select:
174 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
176 //the search for the object to select starts with the hit object deepest in the grouping hierarchy (a leaf in the tree)
177 //further we travel along the grouping hierarchy from child to parent
178 SdrObject* pNewObj = pDrawViewWrapper->getHitObject(rMousePos);
179 m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) );//name of pNewObj
181 //ignore handle only objects for hit test
182 while( pNewObj && m_aSelectedOID.getObjectCID().match( "HandlesOnly" ) )
184 pNewObj->SetMarkProtect(true);
185 pNewObj = pDrawViewWrapper->getHitObject(rMousePos);
186 m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) );
189 //accept only named objects while searching for the object to select
190 //this call may change m_aSelectedOID
191 if ( SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, true ) )
193 //if the so far found object is a multi click object further steps are necessary
194 while( ObjectIdentifier::isMultiClickObject( m_aSelectedOID.getObjectCID() ) )
196 bool bSameObjectAsLastSelected = ( aLastSelectedObject == m_aSelectedOID );
197 if( bSameObjectAsLastSelected )
199 //if the same child is clicked again don't go up further
200 break;
202 if ( ObjectIdentifier::areSiblings( aLastSelectedObject.getObjectCID(), m_aSelectedOID.getObjectCID() ) )
204 //if a sibling of the last selected object is clicked don't go up further
205 break;
207 ObjectIdentifier aLastChild = m_aSelectedOID;
208 if ( !SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, false ) )
210 //take the one found so far
211 break;
213 //if the last selected object is found don't go up further
214 //but take the last child if selection change is allowed
215 if ( aLastSelectedObject == m_aSelectedOID )
217 if( bAllowMultiClickSelectionChange )
219 m_aSelectedOID = aLastChild;
221 else
222 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = aLastChild;
223 break;
227 OSL_ENSURE(m_aSelectedOID.isValid(), "somehow lost selected object");
229 else
231 //maybe an additional shape was hit
232 if ( pNewObj )
234 m_aSelectedOID = ObjectIdentifier( uno::Reference< drawing::XShape >( pNewObj->getUnoShape(), uno::UNO_QUERY ) );
236 else
238 m_aSelectedOID = ObjectIdentifier();
242 if ( !m_aSelectedOID.isAdditionalShape() )
244 OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) );//@todo read CID from model
246 if ( !m_aSelectedOID.isAutoGeneratedObject() )
248 m_aSelectedOID = ObjectIdentifier( aPageCID );
251 //check whether the diagram was hit but not selected (e.g. because it has no filling):
252 OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
253 OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, OUString() ) );//@todo read CID from model
254 bool bBackGroundHit = m_aSelectedOID.getObjectCID() == aPageCID || m_aSelectedOID.getObjectCID() == aWallCID || !m_aSelectedOID.isAutoGeneratedObject();
255 if( bBackGroundHit )
257 //todo: if more than one diagram is available in future do check the list of all diagrams here
258 SdrObject* pDiagram = pDrawViewWrapper->getNamedSdrObject( aDiagramCID );
259 if( pDiagram )
261 if( DrawViewWrapper::IsObjectHit( pDiagram, rMousePos ) )
263 m_aSelectedOID = ObjectIdentifier( aDiagramCID );
267 //check whether the legend was hit but not selected (e.g. because it has no filling):
268 if( bBackGroundHit || m_aSelectedOID.getObjectCID() == aDiagramCID )
270 OUString aLegendCID( ObjectIdentifier::createClassifiedIdentifierForParticle( ObjectIdentifier::createParticleForLegend(nullptr) ) );//@todo read CID from model
271 SdrObject* pLegend = pDrawViewWrapper->getNamedSdrObject( aLegendCID );
272 if( pLegend )
274 if( DrawViewWrapper::IsObjectHit( pLegend, rMousePos ) )
276 m_aSelectedOID = ObjectIdentifier( aLegendCID );
283 if ( bIsRightMouse && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() )
285 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
290 bool Selection::isResizeableObjectSelected()
292 ObjectType eObjectType = m_aSelectedOID.getObjectType();
293 switch( eObjectType )
295 case OBJECTTYPE_DIAGRAM:
296 case OBJECTTYPE_DIAGRAM_WALL:
297 case OBJECTTYPE_SHAPE:
298 case OBJECTTYPE_LEGEND:
299 return true;
300 default:
301 return false;
305 bool Selection::isRotateableObjectSelected( const uno::Reference< frame::XModel >& xChartModel )
307 return SelectionHelper::isRotateableObject( m_aSelectedOID.getObjectCID(), xChartModel );
310 bool Selection::isDragableObjectSelected()
312 return m_aSelectedOID.isDragableObject();
315 bool Selection::isAdditionalShapeSelected() const
317 return m_aSelectedOID.isAdditionalShape();
320 bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject
321 , OUString& rOutName
322 , bool bGivenObjectMayBeResult )
324 SolarMutexGuard aSolarGuard;
325 //find the deepest named group
326 SdrObject* pObj = pInOutObject;
327 OUString aName;
328 if( bGivenObjectMayBeResult )
329 aName = lcl_getObjectName( pObj );
331 while( pObj && !ObjectIdentifier::isCID( aName ) )
333 SdrObjList* pObjList = pObj->getParentOfSdrObject();
334 if( !pObjList )
335 return false;
336 SdrObject* pOwner = pObjList->getSdrObjectFromSdrObjList();
337 if( !pOwner )
338 return false;
339 pObj = pOwner;
340 aName = lcl_getObjectName( pObj );
343 if(!pObj)
344 return false;
345 if(aName.isEmpty())
346 return false;
348 pInOutObject = pObj;
349 rOutName = aName;
350 return true;
353 bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject
354 , ObjectIdentifier& rOutObject
355 , bool bGivenObjectMayBeResult )
357 OUString aName;
358 if ( findNamedParent( pInOutObject, aName, bGivenObjectMayBeResult ) )
360 rOutObject = ObjectIdentifier( aName );
361 return true;
363 return false;
366 bool SelectionHelper::isDragableObjectHitTwice( const Point& rMPos
367 , const OUString& rNameOfSelectedObject
368 , const DrawViewWrapper& rDrawViewWrapper )
370 if(rNameOfSelectedObject.isEmpty())
371 return false;
372 if( !ObjectIdentifier::isDragableObject(rNameOfSelectedObject) )
373 return false;
374 SolarMutexGuard aSolarGuard;
375 SdrObject* pObj = rDrawViewWrapper.getNamedSdrObject( rNameOfSelectedObject );
376 return DrawViewWrapper::IsObjectHit( pObj, rMPos );
379 OUString SelectionHelper::getHitObjectCID(
380 const Point& rMPos,
381 DrawViewWrapper const & rDrawViewWrapper,
382 bool bGetDiagramInsteadOf_Wall )
384 SolarMutexGuard aSolarGuard;
385 OUString aRet;
387 SdrObject* pNewObj = rDrawViewWrapper.getHitObject(rMPos);
388 aRet = lcl_getObjectName( pNewObj );//name of pNewObj
390 //ignore handle only objects for hit test
391 while( pNewObj && aRet.match("HandlesOnly") )
393 pNewObj->SetMarkProtect(true);
394 pNewObj = rDrawViewWrapper.getHitObject(rMPos);
395 aRet = lcl_getObjectName( pNewObj );
398 //accept only named objects while searching for the object to select
399 if( !findNamedParent( pNewObj, aRet, true ) )
401 aRet.clear();
404 OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) );//@todo read CID from model
405 //get page when nothing was hit
406 if( aRet.isEmpty() && !pNewObj )
408 aRet = aPageCID;
411 //get diagram instead wall or page if hit inside diagram
412 if( !aRet.isEmpty() )
414 if( aRet == aPageCID )
416 OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
417 //todo: if more than one diagram is available in future do check the list of all diagrams here
418 SdrObject* pDiagram = rDrawViewWrapper.getNamedSdrObject( aDiagramCID );
419 if( pDiagram )
421 if( DrawViewWrapper::IsObjectHit( pDiagram, rMPos ) )
423 aRet = aDiagramCID;
427 else if( bGetDiagramInsteadOf_Wall )
429 OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, OUString() ) );//@todo read CID from model
431 if( aRet == aWallCID )
433 OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
434 aRet = aDiagramCID;
439 return aRet;
440 // \\- solar mutex
443 bool SelectionHelper::isRotateableObject( const OUString& rCID
444 , const uno::Reference< frame::XModel >& xChartModel )
446 if( !ObjectIdentifier::isRotateableObject( rCID ) )
447 return false;
449 sal_Int32 nDimensionCount = DiagramHelper::getDimension( ChartModelHelper::findDiagram( xChartModel ) );
451 return nDimensionCount == 3;
454 SelectionHelper::SelectionHelper( SdrObject* pSelectedObj )
455 : m_pSelectedObj( pSelectedObj ), m_pMarkObj(nullptr)
459 SelectionHelper::~SelectionHelper()
463 bool SelectionHelper::getFrameDragSingles()
465 bool bFrameDragSingles = true;//true == green == surrounding handles
466 if( m_pSelectedObj && dynamic_cast<const E3dObject*>( m_pSelectedObj) != nullptr )
467 bFrameDragSingles = false;
468 return bFrameDragSingles;
471 SdrObject* SelectionHelper::getMarkHandlesObject( SdrObject* pObj )
473 if(!pObj)
474 return nullptr;
475 OUString aName( lcl_getObjectName( pObj ) );
476 if( aName.match("MarkHandles") || aName.match("HandlesOnly") )
477 return pObj;
478 if( !aName.isEmpty() )//don't get the markhandles of a different object
479 return nullptr;
481 //search for a child with name "MarkHandles" or "HandlesOnly"
482 SolarMutexGuard aSolarGuard;
483 SdrObjList* pSubList = pObj->GetSubList();
484 if(pSubList)
486 SdrObjListIter aIterator(pSubList, SdrIterMode::Flat);
487 while (aIterator.IsMore())
489 SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() );
490 if( pMarkHandles )
491 return pMarkHandles;
494 return nullptr;
497 SdrObject* SelectionHelper::getObjectToMark()
499 //return the selected object itself
500 //or a specific other object if that exsists
501 SdrObject* pObj = m_pSelectedObj;
502 m_pMarkObj = pObj;
504 //search for a child with name "MarkHandles" or "HandlesOnly"
505 if(pObj)
507 SolarMutexGuard aSolarGuard;
508 SdrObjList* pSubList = pObj->GetSubList();
509 if(pSubList)
511 SdrObjListIter aIterator(pSubList, SdrIterMode::Flat);
512 while (aIterator.IsMore())
514 SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() );
515 if( pMarkHandles )
517 m_pMarkObj = pMarkHandles;
518 break;
523 return m_pMarkObj;
526 E3dScene* SelectionHelper::getSceneToRotate( SdrObject* pObj )
528 //search whether the object or one of its children is a 3D object
529 //if so, return the accessory 3DScene
531 E3dObject* pRotateable = nullptr;
533 if(pObj)
535 pRotateable = dynamic_cast<E3dObject*>(pObj);
536 if( !pRotateable )
538 SolarMutexGuard aSolarGuard;
539 SdrObjList* pSubList = pObj->GetSubList();
540 if(pSubList)
542 SdrObjListIter aIterator(pSubList, SdrIterMode::DeepWithGroups);
543 while( aIterator.IsMore() && !pRotateable )
545 SdrObject* pSubObj = aIterator.Next();
546 pRotateable = dynamic_cast<E3dObject*>(pSubObj);
552 E3dScene* pScene = nullptr;
553 if(pRotateable)
555 SolarMutexGuard aSolarGuard;
556 pScene = pRotateable->GetScene();
558 return pScene;
562 bool SelectionHelper::getMarkHandles( SdrHdlList& rHdlList )
564 SolarMutexGuard aSolarGuard;
566 //@todo -> more flexible handle creation
567 //2 scenarios possible:
568 //1. add an additional invisible shape as a child to the selected object
569 //this child needs to be named somehow and handles need to be generated therefrom ...
570 //or 2. offer a central service per view where renderer and so can register for handle creation for a special shape
571 //.. or 3. feature from drawinglayer to create handles for each shape ... (bad performance ... ?) ?
573 //scenario 1 is now used:
574 //if a child with name MarkHandles exsists
575 //this child is marked instead of the logical selected object
578 //if a special mark object was found
579 //that object should be used for marking only
580 if( m_pMarkObj != m_pSelectedObj)
581 return false;
583 //if a special mark object was found
584 //that object should be used to create handles from
585 if( m_pMarkObj && m_pMarkObj != m_pSelectedObj)
587 rHdlList.Clear();
588 if( dynamic_cast<const SdrPathObj*>( m_pMarkObj) != nullptr )
590 //if th object is a polygon
591 //from each point a handle is generated
592 const ::basegfx::B2DPolyPolygon& rPolyPolygon = static_cast<SdrPathObj*>(m_pMarkObj)->GetPathPoly();
593 for( sal_uInt32 nN = 0; nN < rPolyPolygon.count(); nN++)
595 const ::basegfx::B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(nN));
596 for( sal_uInt32 nM = 0; nM < aPolygon.count(); nM++)
598 const ::basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(nM));
599 SdrHdl* pHdl = new SdrHdl(Point(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY())), SdrHdlKind::Poly);
600 rHdlList.AddHdl(pHdl);
603 return true;
605 else
606 return false; //use the special MarkObject for marking
609 //@todo:
610 //add and document good marking defaults ...
612 rHdlList.Clear();
614 SdrObject* pObj = m_pSelectedObj;
615 if(!pObj)
616 return false;
617 SdrObjList* pSubList = pObj->GetSubList();
618 if( !pSubList )//no group object !pObj->IsGroupObject()
619 return false;
621 OUString aName( lcl_getObjectName( pObj ) );
622 ObjectType eObjectType( ObjectIdentifier::getObjectType( aName ) );
623 if( eObjectType == OBJECTTYPE_DATA_POINT
624 || eObjectType == OBJECTTYPE_DATA_LABEL
625 || eObjectType == OBJECTTYPE_LEGEND_ENTRY
626 || eObjectType == OBJECTTYPE_AXIS_UNITLABEL )
628 return false;
631 SdrObjListIter aIterator(pSubList, SdrIterMode::Flat);
633 while (aIterator.IsMore())
635 SdrObject* pSubObj = aIterator.Next();
636 if( eObjectType == OBJECTTYPE_DATA_SERIES )
638 OUString aSubName( lcl_getObjectName( pSubObj ) );
639 ObjectType eSubObjectType( ObjectIdentifier::getObjectType( aSubName ) );
640 if( eSubObjectType!=OBJECTTYPE_DATA_POINT )
641 return false;
644 Point aPos = pSubObj->GetCurrentBoundRect().Center();
645 SdrHdl* pHdl = new SdrHdl(aPos,SdrHdlKind::Poly);
646 rHdlList.AddHdl(pHdl);
648 return true;
651 } //namespace chart
653 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */