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 <com/sun/star/embed/EmbedMisc.hpp>
21 #include <com/sun/star/embed/XEmbeddedObject.hpp>
22 
23 #include <editeng/eeitem.hxx>
24 #include <editeng/sizeitem.hxx>
25 #include <svx/svdpagv.hxx>
26 #include <svx/xdef.hxx>
27 #include <sfx2/objsh.hxx>
28 #include <sfx2/viewfrm.hxx>
29 #include <svl/ptitem.hxx>
30 #include <svx/svdobj.hxx>
31 #include <svx/svdouno.hxx>
32 #include <svx/extrusionbar.hxx>
33 #include <svx/fontworkbar.hxx>
34 #include <svx/sidebar/SelectionChangeHandler.hxx>
35 #include <svx/sidebar/SelectionAnalyzer.hxx>
36 #include <svx/sidebar/ContextChangeEventMultiplexer.hxx>
37 
38 #include <drawsh.hxx>
39 #include <drawview.hxx>
40 #include <viewdata.hxx>
41 #include <sc.hrc>
42 #include <tabvwsh.hxx>
43 #include <document.hxx>
44 #include <drwlayer.hxx>
45 #include <userdat.hxx>
46 #include <drtxtob.hxx>
47 #include <gridwin.hxx>
48 #include <svx/svdoole2.hxx>
49 
50 using namespace com::sun::star;
51 
ScDrawShell(ScViewData * pData)52 ScDrawShell::ScDrawShell( ScViewData* pData ) :
53     SfxShell(pData->GetViewShell()),
54     pViewData( pData ),
55     mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler(
56             [this] () { return this->GetSidebarContextName(); },
57             GetFrame()->GetFrame().GetController(),
58             vcl::EnumContext::Context::Cell))
59 {
60     SetPool( &pViewData->GetScDrawView()->GetModel()->GetItemPool() );
61     SfxUndoManager* pMgr = pViewData->GetSfxDocShell()->GetUndoManager();
62     SetUndoManager( pMgr );
63     if ( !pViewData->GetDocument()->IsUndoEnabled() )
64     {
65         pMgr->SetMaxUndoActionCount( 0 );
66     }
67     SetName("Drawing");
68 
69     mpSelectionChangeHandler->Connect();
70 }
71 
~ScDrawShell()72 ScDrawShell::~ScDrawShell()
73 {
74     mpSelectionChangeHandler->Disconnect();
75 }
76 
GetState(SfxItemSet & rSet)77 void ScDrawShell::GetState( SfxItemSet& rSet )          // Conditions / Toggles
78 {
79     ScDrawView* pView    = pViewData->GetScDrawView();
80     SdrDragMode eMode    = pView->GetDragMode();
81 
82     rSet.Put( SfxBoolItem( SID_OBJECT_ROTATE, eMode == SdrDragMode::Rotate ) );
83     rSet.Put( SfxBoolItem( SID_OBJECT_MIRROR, eMode == SdrDragMode::Mirror ) );
84     rSet.Put( SfxBoolItem( SID_BEZIER_EDIT, !pView->IsFrameDragSingles() ) );
85 
86     sal_uInt16 nFWId = ScGetFontWorkId();
87     SfxViewFrame* pViewFrm = pViewData->GetViewShell()->GetViewFrame();
88     rSet.Put(SfxBoolItem(SID_FONTWORK, pViewFrm->HasChildWindow(nFWId)));
89 
90         // Notes always default to Page anchor.
91     bool bDisableAnchor = false;
92     const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
93     if ( rMarkList.GetMarkCount() == 1 )
94     {
95         SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
96         if( ScDrawLayer::IsNoteCaption( pObj ) )
97         {
98             bDisableAnchor = true;
99             rSet.DisableItem( SID_ANCHOR_PAGE );
100             rSet.DisableItem( SID_ANCHOR_CELL );
101             rSet.DisableItem( SID_ANCHOR_CELL_RESIZE );
102         }
103     }
104 
105     if ( !bDisableAnchor )
106     {
107         switch( pView->GetAnchorType() )
108         {
109         case SCA_PAGE:
110             rSet.Put( SfxBoolItem( SID_ANCHOR_PAGE, true ) );
111             rSet.Put( SfxBoolItem( SID_ANCHOR_CELL, false ) );
112             rSet.Put( SfxBoolItem( SID_ANCHOR_CELL_RESIZE, false ) );
113         break;
114 
115         case SCA_CELL:
116             rSet.Put( SfxBoolItem( SID_ANCHOR_PAGE, false ) );
117             rSet.Put( SfxBoolItem( SID_ANCHOR_CELL, true ) );
118             rSet.Put( SfxBoolItem( SID_ANCHOR_CELL_RESIZE, false ) );
119         break;
120 
121         case SCA_CELL_RESIZE:
122             rSet.Put( SfxBoolItem( SID_ANCHOR_PAGE, false ) );
123             rSet.Put( SfxBoolItem( SID_ANCHOR_CELL, false ) );
124             rSet.Put( SfxBoolItem( SID_ANCHOR_CELL_RESIZE, true ) );
125         break;
126 
127         default:
128             rSet.Put( SfxBoolItem( SID_ANCHOR_PAGE, false ) );
129             rSet.Put( SfxBoolItem( SID_ANCHOR_CELL, false ) );
130             rSet.Put( SfxBoolItem( SID_ANCHOR_CELL_RESIZE, false ) );
131         break;
132         }
133     }
134 }
135 
GetDrawFuncState(SfxItemSet & rSet)136 void ScDrawShell::GetDrawFuncState( SfxItemSet& rSet )      // disable functions
137 {
138     ScDrawView* pView = pViewData->GetScDrawView();
139 
140     //  call IsMirrorAllowed first to make sure ForcePossibilities (and thus CheckMarked)
141     //  is called before GetMarkCount, so the nMarkCount value is valid for the rest of this method.
142     if (!pView->IsMirrorAllowed(true,true))
143     {
144         rSet.DisableItem( SID_MIRROR_HORIZONTAL );
145         rSet.DisableItem( SID_MIRROR_VERTICAL );
146         rSet.DisableItem( SID_FLIP_HORIZONTAL );
147         rSet.DisableItem( SID_FLIP_VERTICAL );
148     }
149 
150     if (pViewData->GetViewShell()->isContentExtractionLocked())
151     {
152         rSet.DisableItem(SID_COPY);
153         rSet.DisableItem(SID_CUT);
154     }
155 
156     const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
157     const size_t nMarkCount = rMarkList.GetMarkCount();
158 
159     if ( nMarkCount <= 1 || !pView->IsGroupPossible() )
160         rSet.DisableItem( SID_GROUP );
161     if ( nMarkCount == 0 || !pView->IsUnGroupPossible() )
162         rSet.DisableItem( SID_UNGROUP );
163     if ( nMarkCount != 1 || !pView->IsGroupEnterPossible() )
164         rSet.DisableItem( SID_ENTER_GROUP );
165     if ( !pView->IsGroupEntered() )
166         rSet.DisableItem( SID_LEAVE_GROUP );
167 
168     if ( nMarkCount <= 1 )                      // Nothing or only one object selected
169     {
170             //  alignment
171         rSet.DisableItem( SID_OBJECT_ALIGN_LEFT );      // no alignment on the side
172         rSet.DisableItem( SID_OBJECT_ALIGN_CENTER );
173         rSet.DisableItem( SID_OBJECT_ALIGN_RIGHT );
174         rSet.DisableItem( SID_OBJECT_ALIGN_UP );
175         rSet.DisableItem( SID_OBJECT_ALIGN_MIDDLE );
176         rSet.DisableItem( SID_OBJECT_ALIGN_DOWN );
177         rSet.DisableItem( SID_OBJECT_ALIGN );
178 
179         // pseudo slots for Format menu
180         rSet.DisableItem( SID_ALIGN_ANY_LEFT );
181         rSet.DisableItem( SID_ALIGN_ANY_HCENTER );
182         rSet.DisableItem( SID_ALIGN_ANY_RIGHT );
183         rSet.DisableItem( SID_ALIGN_ANY_TOP );
184         rSet.DisableItem( SID_ALIGN_ANY_VCENTER );
185         rSet.DisableItem( SID_ALIGN_ANY_BOTTOM );
186     }
187 
188     // do not change layer of form controls
189     // #i83729# do not change layer of cell notes (on internal layer)
190     if ( !nMarkCount || pView->HasMarkedControl() || pView->HasMarkedInternal() )
191     {
192         rSet.DisableItem( SID_OBJECT_HEAVEN );
193         rSet.DisableItem( SID_OBJECT_HELL );
194     }
195     else
196     {
197         if(AreAllObjectsOnLayer(SC_LAYER_FRONT,rMarkList))
198         {
199             rSet.DisableItem( SID_OBJECT_HEAVEN );
200         }
201         else if(AreAllObjectsOnLayer(SC_LAYER_BACK,rMarkList))
202         {
203             rSet.DisableItem( SID_OBJECT_HELL );
204         }
205     }
206 
207     bool bCanRename = false;
208     if ( nMarkCount > 1 )
209     {
210         // no hypelink options for a selected group
211         rSet.DisableItem( SID_DRAW_HLINK_EDIT );
212         rSet.DisableItem( SID_DRAW_HLINK_DELETE );
213         rSet.DisableItem( SID_OPEN_HYPERLINK );
214         // Fit to cell only works with a single graphic
215         rSet.DisableItem( SID_FITCELLSIZE );
216     }
217     else if ( nMarkCount == 1 )
218     {
219         SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
220         ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( pObj );
221         if ( !pInfo || pInfo->GetHlink().isEmpty() )
222         {
223             rSet.DisableItem( SID_DRAW_HLINK_DELETE );
224             rSet.DisableItem( SID_OPEN_HYPERLINK );
225         }
226         SdrLayerID nLayerID = pObj->GetLayer();
227         if ( nLayerID != SC_LAYER_INTERN )
228             bCanRename = true;                          // #i51351# anything except internal objects can be renamed
229 
230         // #91929#; don't show original size entry if not possible
231         sal_uInt16 nObjType = pObj->GetObjIdentifier();
232         if ( nObjType == OBJ_OLE2 )
233         {
234             SdrOle2Obj* pOleObj = static_cast<SdrOle2Obj*>(rMarkList.GetMark( 0 )->GetMarkedSdrObj());
235             if (pOleObj->GetObjRef().is() &&
236                 (pOleObj->GetObjRef()->getStatus( pOleObj->GetAspect() ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE) )
237                 //TODO/LATER: why different slots in Draw and Calc?
238                 rSet.DisableItem(SID_ORIGINALSIZE);
239         }
240         else if ( nObjType == OBJ_CAPTION )
241         {
242             if ( nLayerID == SC_LAYER_INTERN )
243             {
244                 // SdrCaptionObj() Notes cannot be cut/copy in isolation from
245                 // their cells.
246                 rSet.DisableItem( SID_CUT );
247                 rSet.DisableItem( SID_COPY );
248                 // Notes always default to Page anchor.
249                 rSet.DisableItem( SID_ANCHOR_TOGGLE );
250                 rSet.DisableItem( SID_ANCHOR_MENU );
251             }
252         }
253 
254         // Fit to cell is only available for cell anchored graphics obviously
255         if (pView->GetAnchorType() != SCA_CELL &&
256             pView->GetAnchorType() != SCA_CELL_RESIZE)
257             rSet.DisableItem( SID_FITCELLSIZE );
258     }
259     if ( !bCanRename )
260     {
261         // #i68101#
262         rSet.DisableItem( SID_RENAME_OBJECT );
263         rSet.DisableItem( SID_TITLE_DESCRIPTION_OBJECT );
264     }
265 
266     if ( !nMarkCount )                          // nothing selected
267     {
268             //  Arrangement
269         rSet.DisableItem( SID_FRAME_UP );
270         rSet.DisableItem( SID_FRAME_DOWN );
271         rSet.DisableItem( SID_FRAME_TO_TOP );
272         rSet.DisableItem( SID_FRAME_TO_BOTTOM );
273             //  Clipboard / delete
274         rSet.DisableItem( SID_DELETE );
275         rSet.DisableItem( SID_DELETE_CONTENTS );
276         rSet.DisableItem( SID_CUT );
277         rSet.DisableItem( SID_COPY );
278             //  other
279         rSet.DisableItem( SID_ANCHOR_TOGGLE );
280         rSet.DisableItem( SID_ANCHOR_MENU );
281         rSet.DisableItem( SID_ORIGINALSIZE );
282         rSet.DisableItem( SID_FITCELLSIZE );
283         rSet.DisableItem( SID_ATTR_TRANSFORM );
284     }
285 
286     if ( rSet.GetItemState( SID_ENABLE_HYPHENATION ) != SfxItemState::UNKNOWN )
287     {
288         SfxItemSet aAttrs( pView->GetModel()->GetItemPool() );
289         pView->GetAttributes( aAttrs );
290         if( aAttrs.GetItemState( EE_PARA_HYPHENATE ) >= SfxItemState::DEFAULT )
291         {
292             bool bValue = aAttrs.Get( EE_PARA_HYPHENATE ).GetValue();
293             rSet.Put( SfxBoolItem( SID_ENABLE_HYPHENATION, bValue ) );
294         }
295     }
296 
297     svx::ExtrusionBar::getState( pView, rSet );
298     svx::FontworkBar::getState( pView, rSet );
299 }
300 
301 //          Attributes for Drawing-Objects
302 
GetDrawAttrState(SfxItemSet & rSet)303 void ScDrawShell::GetDrawAttrState( SfxItemSet& rSet )
304 {
305     Point       aMousePos   = pViewData->GetMousePosPixel();
306     vcl::Window*     pWindow     = pViewData->GetActiveWin();
307     ScDrawView* pDrView     = pViewData->GetScDrawView();
308     Point       aPos        = pWindow->PixelToLogic(aMousePos);
309     bool        bHasMarked  = pDrView->AreObjectsMarked();
310 
311     if( bHasMarked )
312     {
313         rSet.Put( pDrView->GetAttrFromMarked(false), false );
314     }
315     else
316     {
317         rSet.Put( pDrView->GetDefaultAttr() );
318     }
319 
320     SdrPageView* pPV = pDrView->GetSdrPageView();
321     if ( pPV )
322     {
323         // #i52073# when a sheet with an active OLE object is deleted,
324         // the slot state is queried without an active page view
325 
326         //  Items for position and size (see ScGridWindow::UpdateStatusPosSize, #108137#)
327 
328         // #i34458# The SvxSizeItem in SID_TABLE_CELL is no longer needed by
329         // SvxPosSizeStatusBarControl, it's enough to have it in SID_ATTR_SIZE.
330 
331         bool bActionItem = false;
332         if ( pDrView->IsAction() )              // action rectangle
333         {
334             tools::Rectangle aRect;
335             pDrView->TakeActionRect( aRect );
336             if ( !aRect.IsEmpty() )
337             {
338                 pPV->LogicToPagePos(aRect);
339                 rSet.Put( SfxPointItem( SID_ATTR_POSITION, aRect.TopLeft() ) );
340                 Size aSize( aRect.Right() - aRect.Left(), aRect.Bottom() - aRect.Top() );
341                 rSet.Put( SvxSizeItem( SID_ATTR_SIZE, aSize ) );
342                 bActionItem = true;
343             }
344         }
345         if ( !bActionItem )
346         {
347             if ( pDrView->AreObjectsMarked() )      // selected objects
348             {
349                 tools::Rectangle aRect = pDrView->GetAllMarkedRect();
350                 pPV->LogicToPagePos(aRect);
351                 rSet.Put( SfxPointItem( SID_ATTR_POSITION, aRect.TopLeft() ) );
352                 Size aSize( aRect.Right() - aRect.Left(), aRect.Bottom() - aRect.Top() );
353                 rSet.Put( SvxSizeItem( SID_ATTR_SIZE, aSize ) );
354             }
355             else                                // mouse position
356             {
357                 // aPos is initialized above
358                 pPV->LogicToPagePos(aPos);
359                 rSet.Put( SfxPointItem( SID_ATTR_POSITION, aPos ) );
360                 rSet.Put( SvxSizeItem( SID_ATTR_SIZE, Size( 0, 0 ) ) );
361             }
362         }
363     }
364 }
365 
GetAttrFuncState(SfxItemSet & rSet)366 void ScDrawShell::GetAttrFuncState(SfxItemSet &rSet)
367 {
368     //  Disable dialogs for Draw-attributes if necessary
369 
370     ScDrawView* pDrView = pViewData->GetScDrawView();
371     SfxItemSet aViewSet = pDrView->GetAttrFromMarked(false);
372     const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
373     const size_t nMarkCount = rMarkList.GetMarkCount();
374     bool bShowArea = true, bShowMeasure = true;
375 
376     for ( size_t i = 0; i < nMarkCount && i < 50; ++i )
377     {
378         SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
379         sal_uInt16 nObjType = pObj->GetObjIdentifier();
380 
381         if ( nObjType != OBJ_MEASURE )
382             bShowMeasure = false;
383 
384         // If marked object is 2D, disable format area command.
385         if ( nObjType == OBJ_PLIN     ||
386              nObjType == OBJ_LINE     ||
387              nObjType == OBJ_PATHLINE ||
388              nObjType == OBJ_FREELINE ||
389              nObjType == OBJ_EDGE     ||
390              nObjType == OBJ_CARC     ||
391              bShowMeasure )
392             bShowArea = false;
393 
394         if ( !bShowArea && !bShowMeasure )
395             break;
396     }
397 
398     if ( !bShowArea )
399         rSet.DisableItem( SID_ATTRIBUTES_AREA );
400 
401     if ( !bShowMeasure )
402         rSet.DisableItem( SID_MEASURE_DLG );
403 
404     if ( aViewSet.GetItemState( XATTR_LINESTYLE ) == SfxItemState::DEFAULT )
405     {
406         rSet.DisableItem( SID_ATTRIBUTES_LINE );
407         rSet.DisableItem( SID_ATTR_LINEEND_STYLE );     // Tbx-Controller
408     }
409 
410     if ( aViewSet.GetItemState( XATTR_FILLSTYLE ) == SfxItemState::DEFAULT )
411         rSet.DisableItem( SID_ATTRIBUTES_AREA );
412 }
413 
AreAllObjectsOnLayer(SdrLayerID nLayerNo,const SdrMarkList & rMark)414 bool ScDrawShell::AreAllObjectsOnLayer(SdrLayerID nLayerNo,const SdrMarkList& rMark)
415 {
416     bool bResult=true;
417     const size_t nCount = rMark.GetMarkCount();
418     for (size_t i=0; i<nCount; ++i)
419     {
420         SdrObject* pObj = rMark.GetMark(i)->GetMarkedSdrObj();
421         if ( dynamic_cast<const SdrUnoObj*>( pObj) ==  nullptr )
422         {
423             if(nLayerNo!=pObj->GetLayer())
424             {
425                 bResult=false;
426                 break;
427             }
428         }
429     }
430     return bResult;
431 }
432 
GetDrawAttrStateForIFBX(SfxItemSet & rSet)433 void ScDrawShell::GetDrawAttrStateForIFBX( SfxItemSet& rSet )
434 {
435     ScDrawView* pView = pViewData->GetScDrawView();
436     const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
437 
438     if( rMarkList.GetMark(0) != nullptr )
439     {
440         SfxItemSet aNewAttr(pView->GetGeoAttrFromMarked());
441         rSet.Put(aNewAttr, false);
442     }
443 }
444 
Activate(const bool)445 void ScDrawShell::Activate (const bool)
446 {
447     ContextChangeEventMultiplexer::NotifyContextChange(
448         GetFrame()->GetFrame().GetController(),
449         vcl::EnumContext::GetContextEnum(
450             GetSidebarContextName()));
451 }
452 
GetSidebarContextName()453 const OUString & ScDrawShell::GetSidebarContextName()
454 {
455     return vcl::EnumContext::GetContextName(
456         svx::sidebar::SelectionAnalyzer::GetContextForSelection_SC(
457             GetDrawView()->GetMarkedObjectList()));
458 }
459 
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
461