fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / chart2 / source / controller / main / SelectionHelper.cxx
blobc6da54051ce9d6cc47975df80bdcbc3cff132657
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 "macros.hxx"
23 #include "DiagramHelper.hxx"
24 #include "ChartModelHelper.hxx"
26 #include <svx/svdpage.hxx>
27 #include <svx/svditer.hxx>
28 #include "svx/obj3d.hxx"
29 #include <svx/svdopath.hxx>
30 #include <vcl/svapp.hxx>
31 #include <osl/mutex.hxx>
32 #include <basegfx/point/b2dpoint.hxx>
33 #include <com/sun/star/beans/XPropertySet.hpp>
35 namespace chart
37 using namespace ::com::sun::star;
39 namespace
42 OUString lcl_getObjectName( SdrObject* pObj )
44 if(pObj)
45 return pObj->GetName();
46 return OUString();
49 void impl_selectObject( SdrObject* pObjectToSelect, DrawViewWrapper& rDrawViewWrapper )
51 SolarMutexGuard aSolarGuard;
53 if(pObjectToSelect)
55 SelectionHelper aSelectionHelper( pObjectToSelect );
56 SdrObject* pMarkObj = aSelectionHelper.getObjectToMark();
57 rDrawViewWrapper.setMarkHandleProvider(&aSelectionHelper);
58 rDrawViewWrapper.MarkObject(pMarkObj);
59 rDrawViewWrapper.setMarkHandleProvider(NULL);
63 }//anonymous namespace
65 bool Selection::hasSelection()
67 return m_aSelectedOID.isValid();
70 OUString Selection::getSelectedCID()
72 return m_aSelectedOID.getObjectCID();
75 uno::Reference< drawing::XShape > Selection::getSelectedAdditionalShape()
77 return m_aSelectedOID.getAdditionalShape();
80 bool Selection::setSelection( const OUString& rCID )
82 if ( !rCID.equals( m_aSelectedOID.getObjectCID() ) )
84 m_aSelectedOID = ObjectIdentifier( rCID );
85 return true;
87 return false;
90 bool Selection::setSelection( const uno::Reference< drawing::XShape >& xShape )
92 if ( !( xShape == m_aSelectedOID.getAdditionalShape() ) )
94 clearSelection();
95 m_aSelectedOID = ObjectIdentifier( xShape );
96 return true;
98 return false;
101 void Selection::clearSelection()
103 m_aSelectedOID = ObjectIdentifier();
104 m_aSelectedOID_beforeMouseDown = ObjectIdentifier();
105 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
108 bool Selection::maybeSwitchSelectionAfterSingleClickWasEnsured()
110 if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid()
111 && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing != m_aSelectedOID )
113 m_aSelectedOID = m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing;
114 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
115 return true;
117 return false;
120 void Selection::resetPossibleSelectionAfterSingleClickWasEnsured()
122 if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() )
124 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
128 void Selection::remindSelectionBeforeMouseDown()
130 m_aSelectedOID_beforeMouseDown = m_aSelectedOID;
133 bool Selection::isSelectionDifferentFromBeforeMouseDown() const
135 return ( m_aSelectedOID != m_aSelectedOID_beforeMouseDown );
138 void Selection::applySelection( DrawViewWrapper* pDrawViewWrapper )
140 if( pDrawViewWrapper )
143 SolarMutexGuard aSolarGuard;
144 pDrawViewWrapper->UnmarkAll();
146 SdrObject* pObjectToSelect = 0;
147 if ( m_aSelectedOID.isAutoGeneratedObject() )
149 pObjectToSelect = pDrawViewWrapper->getNamedSdrObject( m_aSelectedOID.getObjectCID() );
151 else if( m_aSelectedOID.isAdditionalShape() )
153 pObjectToSelect = DrawViewWrapper::getSdrObject( m_aSelectedOID.getAdditionalShape() );
156 impl_selectObject( pObjectToSelect, *pDrawViewWrapper );
160 void Selection::adaptSelectionToNewPos( const Point& rMousePos, DrawViewWrapper* pDrawViewWrapper
161 , bool bIsRightMouse, bool bWaitingForDoubleClick )
163 if( pDrawViewWrapper )
165 //do not toggel multiclick selection if right clicked on the selected object or waiting for double click
166 bool bAllowMultiClickSelectionChange = !bIsRightMouse && !bWaitingForDoubleClick;
168 ObjectIdentifier aLastSelectedObject( m_aSelectedOID );
170 SolarMutexGuard aSolarGuard;
172 //bAllowMultiClickSelectionChange==true -> a second click on the same object can lead to a changed selection (e.g. series -> single data point)
174 //get object to select:
176 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
178 //the search for the object to select starts with the hit object deepest in the grouping hierarchy (a leaf in the tree)
179 //further we travel along the grouping hierarchy from child to parent
180 SdrObject* pNewObj = pDrawViewWrapper->getHitObject(rMousePos);
181 m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) );//name of pNewObj
183 //ignore handle only objects for hit test
184 while( pNewObj && m_aSelectedOID.getObjectCID().match( "HandlesOnly" ) )
186 pNewObj->SetMarkProtect(true);
187 pNewObj = pDrawViewWrapper->getHitObject(rMousePos);
188 m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) );
191 //accept only named objects while searching for the object to select
192 //this call may change m_aSelectedOID
193 if ( SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, true ) )
195 //if the so far found object is a multi click object further steps are necessary
196 while( ObjectIdentifier::isMultiClickObject( m_aSelectedOID.getObjectCID() ) )
198 bool bSameObjectAsLastSelected = ( aLastSelectedObject == m_aSelectedOID );
199 if( bSameObjectAsLastSelected )
201 //if the same child is clicked again don't go up further
202 break;
204 if ( ObjectIdentifier::areSiblings( aLastSelectedObject.getObjectCID(), m_aSelectedOID.getObjectCID() ) )
206 //if a sibling of the last selected object is clicked don't go up further
207 break;
209 ObjectIdentifier aLastChild = m_aSelectedOID;
210 if ( !SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, false ) )
212 //take the one found so far
213 break;
215 //if the last selected object is found don't go up further
216 //but take the last child if selection change is allowed
217 if ( aLastSelectedObject == m_aSelectedOID )
219 if( bAllowMultiClickSelectionChange )
221 m_aSelectedOID = aLastChild;
223 else
224 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = aLastChild;
225 break;
229 OSL_ENSURE(m_aSelectedOID.isValid(), "somehow lost selected object");
231 else
233 //maybe an additional shape was hit
234 if ( pNewObj )
236 m_aSelectedOID = ObjectIdentifier( uno::Reference< drawing::XShape >( pNewObj->getUnoShape(), uno::UNO_QUERY ) );
238 else
240 m_aSelectedOID = ObjectIdentifier();
244 if ( !m_aSelectedOID.isAdditionalShape() )
246 OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) );//@todo read CID from model
248 if ( !m_aSelectedOID.isAutoGeneratedObject() )
250 m_aSelectedOID = ObjectIdentifier( aPageCID );
253 //check whether the diagram was hit but not selected (e.g. because it has no filling):
254 OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
255 OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, OUString() ) );//@todo read CID from model
256 bool bBackGroundHit = m_aSelectedOID.getObjectCID().equals( aPageCID ) || m_aSelectedOID.getObjectCID().equals( aWallCID ) || !m_aSelectedOID.isAutoGeneratedObject();
257 if( bBackGroundHit )
259 //todo: if more than one diagram is available in future do check the list of all diagrams here
260 SdrObject* pDiagram = pDrawViewWrapper->getNamedSdrObject( aDiagramCID );
261 if( pDiagram )
263 if( DrawViewWrapper::IsObjectHit( pDiagram, rMousePos ) )
265 m_aSelectedOID = ObjectIdentifier( aDiagramCID );
269 //check whether the legend was hit but not selected (e.g. because it has no filling):
270 if( bBackGroundHit || m_aSelectedOID.getObjectCID().equals( aDiagramCID ) )
272 OUString aLegendCID( ObjectIdentifier::createClassifiedIdentifierForParticle( ObjectIdentifier::createParticleForLegend(0,0) ) );//@todo read CID from model
273 SdrObject* pLegend = pDrawViewWrapper->getNamedSdrObject( aLegendCID );
274 if( pLegend )
276 if( DrawViewWrapper::IsObjectHit( pLegend, rMousePos ) )
278 m_aSelectedOID = ObjectIdentifier( aLegendCID );
285 if ( bIsRightMouse && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() )
287 m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
292 bool Selection::isResizeableObjectSelected()
294 ObjectType eObjectType = m_aSelectedOID.getObjectType();
295 switch( eObjectType )
297 case OBJECTTYPE_DIAGRAM:
298 case OBJECTTYPE_DIAGRAM_WALL:
299 case OBJECTTYPE_SHAPE:
300 case OBJECTTYPE_LEGEND:
301 return true;
302 default:
303 return false;
307 bool Selection::isRotateableObjectSelected( const uno::Reference< frame::XModel >& xChartModel )
309 return SelectionHelper::isRotateableObject( m_aSelectedOID.getObjectCID(), xChartModel );
312 bool Selection::isDragableObjectSelected()
314 return m_aSelectedOID.isDragableObject();
317 bool Selection::isAdditionalShapeSelected() const
319 return m_aSelectedOID.isAdditionalShape();
322 bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject
323 , OUString& rOutName
324 , bool bGivenObjectMayBeResult )
326 SolarMutexGuard aSolarGuard;
327 //find the deepest named group
328 SdrObject* pObj = pInOutObject;
329 OUString aName;
330 if( bGivenObjectMayBeResult )
331 aName = lcl_getObjectName( pObj );
333 while( pObj && !ObjectIdentifier::isCID( aName ) )
335 SdrObjList* pObjList = pObj->GetObjList();
336 if( !pObjList )
337 return false;
338 SdrObject* pOwner = pObjList->GetOwnerObj();
339 if( !pOwner )
340 return false;
341 pObj = pOwner;
342 aName = lcl_getObjectName( pObj );
345 if(!pObj)
346 return false;
347 if(aName.isEmpty())
348 return false;
350 pInOutObject = pObj;
351 rOutName = aName;
352 return true;
355 bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject
356 , ObjectIdentifier& rOutObject
357 , bool bGivenObjectMayBeResult )
359 OUString aName;
360 if ( findNamedParent( pInOutObject, aName, bGivenObjectMayBeResult ) )
362 rOutObject = ObjectIdentifier( aName );
363 return true;
365 return false;
368 bool SelectionHelper::isDragableObjectHitTwice( const Point& rMPos
369 , const OUString& rNameOfSelectedObject
370 , const DrawViewWrapper& rDrawViewWrapper )
372 if(rNameOfSelectedObject.isEmpty())
373 return false;
374 if( !ObjectIdentifier::isDragableObject(rNameOfSelectedObject) )
375 return false;
376 SolarMutexGuard aSolarGuard;
377 SdrObject* pObj = rDrawViewWrapper.getNamedSdrObject( rNameOfSelectedObject );
378 if( !DrawViewWrapper::IsObjectHit( pObj, rMPos ) )
379 return false;
380 return true;
383 OUString SelectionHelper::getHitObjectCID(
384 const Point& rMPos,
385 DrawViewWrapper& rDrawViewWrapper,
386 bool bGetDiagramInsteadOf_Wall )
388 // //- solar mutex
389 SolarMutexGuard aSolarGuard;
390 OUString aRet;
392 SdrObject* pNewObj = rDrawViewWrapper.getHitObject(rMPos);
393 aRet = lcl_getObjectName( pNewObj );//name of pNewObj
395 //ignore handle only objects for hit test
396 while( pNewObj && aRet.match("HandlesOnly") )
398 pNewObj->SetMarkProtect(true);
399 pNewObj = rDrawViewWrapper.getHitObject(rMPos);
400 aRet = lcl_getObjectName( pNewObj );
403 //accept only named objects while searching for the object to select
404 if( !findNamedParent( pNewObj, aRet, true ) )
406 aRet.clear();
409 OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) );//@todo read CID from model
410 //get page when nothing was hit
411 if( aRet.isEmpty() && !pNewObj )
413 aRet = aPageCID;
416 //get diagram instead wall or page if hit inside diagram
417 if( !aRet.isEmpty() )
419 if( aRet.equals( aPageCID ) )
421 OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
422 //todo: if more than one diagram is available in future do check the list of all diagrams here
423 SdrObject* pDiagram = rDrawViewWrapper.getNamedSdrObject( aDiagramCID );
424 if( pDiagram )
426 if( DrawViewWrapper::IsObjectHit( pDiagram, rMPos ) )
428 aRet = aDiagramCID;
432 else if( bGetDiagramInsteadOf_Wall )
434 OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, OUString() ) );//@todo read CID from model
436 if( aRet.equals( aWallCID ) )
438 OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
439 aRet = aDiagramCID;
444 return aRet;
445 // \\- solar mutex
448 bool SelectionHelper::isRotateableObject( const OUString& rCID
449 , const uno::Reference< frame::XModel >& xChartModel )
451 if( !ObjectIdentifier::isRotateableObject( rCID ) )
452 return false;
454 sal_Int32 nDimensionCount = DiagramHelper::getDimension( ChartModelHelper::findDiagram( xChartModel ) );
456 if( nDimensionCount == 3 )
457 return true;
458 return false;
461 SelectionHelper::SelectionHelper( SdrObject* pSelectedObj )
462 : m_pSelectedObj( pSelectedObj ), m_pMarkObj(NULL)
466 SelectionHelper::~SelectionHelper()
470 bool SelectionHelper::getFrameDragSingles()
472 bool bFrameDragSingles = true;//true == green == surrounding handles
473 if( m_pSelectedObj && m_pSelectedObj->ISA(E3dObject) )
474 bFrameDragSingles = false;
475 return bFrameDragSingles;
478 SdrObject* SelectionHelper::getMarkHandlesObject( SdrObject* pObj )
480 if(!pObj)
481 return 0;
482 OUString aName( lcl_getObjectName( pObj ) );
483 if( aName.match("MarkHandles") || aName.match("HandlesOnly") )
484 return pObj;
485 if( !aName.isEmpty() )//dont't get the markhandles of a different object
486 return 0;
488 //search for a child with name "MarkHandles" or "HandlesOnly"
489 SolarMutexGuard aSolarGuard;
490 SdrObjList* pSubList = pObj->GetSubList();
491 if(pSubList)
493 SdrObjListIter aIterator(*pSubList, IM_FLAT);
494 while (aIterator.IsMore())
496 SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() );
497 if( pMarkHandles )
498 return pMarkHandles;
501 return 0;
504 SdrObject* SelectionHelper::getObjectToMark()
506 //return the selected object itself
507 //or a specific other object if that exsists
508 SdrObject* pObj = m_pSelectedObj;
509 m_pMarkObj = pObj;
511 //search for a child with name "MarkHandles" or "HandlesOnly"
512 if(pObj)
514 SolarMutexGuard aSolarGuard;
515 SdrObjList* pSubList = pObj->GetSubList();
516 if(pSubList)
518 SdrObjListIter aIterator(*pSubList, IM_FLAT);
519 while (aIterator.IsMore())
521 SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() );
522 if( pMarkHandles )
524 m_pMarkObj = pMarkHandles;
525 break;
530 return m_pMarkObj;
533 E3dScene* SelectionHelper::getSceneToRotate( SdrObject* pObj )
535 //search whether the object or one of its children is a 3D object
536 //if so, return the accessory 3DScene
538 E3dObject* pRotateable = 0;
540 if(pObj)
542 pRotateable = dynamic_cast<E3dObject*>(pObj);
543 if( !pRotateable )
545 SolarMutexGuard aSolarGuard;
546 SdrObjList* pSubList = pObj->GetSubList();
547 if(pSubList)
549 SdrObjListIter aIterator(*pSubList, IM_DEEPWITHGROUPS);
550 while( aIterator.IsMore() && !pRotateable )
552 SdrObject* pSubObj = aIterator.Next();
553 pRotateable = dynamic_cast<E3dObject*>(pSubObj);
559 E3dScene* pScene = 0;
560 if(pRotateable)
562 SolarMutexGuard aSolarGuard;
563 pScene = pRotateable->GetScene();
565 return pScene;
569 bool SelectionHelper::getMarkHandles( SdrHdlList& rHdlList )
571 SolarMutexGuard aSolarGuard;
573 //@todo -> more flexible handle creation
574 //2 scenarios possible:
575 //1. add an additional invisible shape as a child to the selected object
576 //this child needs to be named somehow and handles need to be generated therefrom ...
577 //or 2. offer a central service per view where renderer and so can register for handle creation for a special shape
578 //.. or 3. feature from drawinglayer to create handles for each shape ... (bad performance ... ?) ?
580 //scenario 1 is now used:
581 //if a child with name MarkHandles exsists
582 //this child is marked instead of the logical selected object
585 //if a special mark object was found
586 //that object should be used for marking only
587 if( m_pMarkObj != m_pSelectedObj)
588 return false;
590 //if a special mark object was found
591 //that object should be used to create handles from
592 if( m_pMarkObj && m_pMarkObj != m_pSelectedObj)
594 rHdlList.Clear();
595 if( m_pMarkObj->ISA(SdrPathObj) )
597 //if th object is a polygon
598 //from each point a handle is generated
599 const ::basegfx::B2DPolyPolygon& rPolyPolygon = static_cast<SdrPathObj*>(m_pMarkObj)->GetPathPoly();
600 for( sal_uInt32 nN = 0L; nN < rPolyPolygon.count(); nN++)
602 const ::basegfx::B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(nN));
603 for( sal_uInt32 nM = 0L; nM < aPolygon.count(); nM++)
605 const ::basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(nM));
606 SdrHdl* pHdl = new SdrHdl(Point(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY())), HDL_POLY);
607 rHdlList.AddHdl(pHdl);
610 return true;
612 else
613 return false; //use the special MarkObject for marking
616 //@todo:
617 //add and document good marking defaults ...
619 rHdlList.Clear();
621 SdrObject* pObj = m_pSelectedObj;
622 if(!pObj)
623 return false;
624 SdrObjList* pSubList = pObj->GetSubList();
625 if( !pSubList )//no group object !pObj->IsGroupObject()
626 return false;
628 OUString aName( lcl_getObjectName( pObj ) );
629 ObjectType eObjectType( ObjectIdentifier::getObjectType( aName ) );
630 if( OBJECTTYPE_DATA_POINT == eObjectType
631 || OBJECTTYPE_DATA_LABEL == eObjectType
632 || OBJECTTYPE_LEGEND_ENTRY == eObjectType
633 || OBJECTTYPE_AXIS_UNITLABEL == eObjectType )
635 return false;
638 SdrObjListIter aIterator(*pSubList, IM_FLAT);
640 while (aIterator.IsMore())
642 SdrObject* pSubObj = aIterator.Next();
643 if( OBJECTTYPE_DATA_SERIES == eObjectType )
645 OUString aSubName( lcl_getObjectName( pSubObj ) );
646 ObjectType eSubObjectType( ObjectIdentifier::getObjectType( aSubName ) );
647 if( eSubObjectType!=OBJECTTYPE_DATA_POINT )
648 return false;
651 Point aPos = pSubObj->GetCurrentBoundRect().Center();
652 SdrHdl* pHdl = new SdrHdl(aPos,HDL_POLY);
653 rHdlList.AddHdl(pHdl);
655 return true;
658 } //namespace chart
660 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */