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 <LayerTabBar.hxx>
21 #include <svx/svdlayer.hxx>
22 #include <svx/svdpagv.hxx>
23 #include <vcl/commandevent.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/weld.hxx>
26 #include <sfx2/dispatch.hxx>
27 #include <sfx2/viewfrm.hxx>
28 
29 #include <helpids.h>
30 #include <app.hrc>
31 #include <strings.hrc>
32 
33 #include <DrawViewShell.hxx>
34 #include <View.hxx>
35 #include <drawdoc.hxx>
36 #include <sdresid.hxx>
37 #include <unokywds.hxx>
38 #include <DrawDocShell.hxx>
39 #include <drawview.hxx>
40 #include <undolayer.hxx>
41 
42 namespace sd {
43 
44 /**
45  * default constructor
46  */
LayerTabBar(DrawViewShell * pViewSh,vcl::Window * pParent)47 LayerTabBar::LayerTabBar(DrawViewShell* pViewSh, vcl::Window* pParent)
48     : TabBar( pParent, WinBits( WB_BORDER | WB_3DLOOK | WB_SCROLL ) ),
49     DropTargetHelper( this ),
50     pDrViewSh(pViewSh)
51 {
52     EnableEditMode();
53     SetSizePixel(Size(0, 0));
54     SetMaxPageWidth( 150 );
55     SetHelpId( HID_SD_TABBAR_LAYERS );
56 }
57 
~LayerTabBar()58 LayerTabBar::~LayerTabBar()
59 {
60     disposeOnce();
61 }
62 
dispose()63 void LayerTabBar::dispose()
64 {
65     DropTargetHelper::dispose();
66     TabBar::dispose();
67 }
68 
convertToLocalizedName(const OUString & rName)69 OUString LayerTabBar::convertToLocalizedName(const OUString& rName)
70 {
71     if ( rName == sUNO_LayerName_background )
72         return SdResId( STR_LAYER_BCKGRND );
73 
74     if ( rName == sUNO_LayerName_background_objects )
75         return SdResId( STR_LAYER_BCKGRNDOBJ );
76 
77     if ( rName == sUNO_LayerName_layout )
78         return SdResId( STR_LAYER_LAYOUT );
79 
80     if ( rName == sUNO_LayerName_controls )
81         return SdResId( STR_LAYER_CONTROLS );
82 
83     if ( rName == sUNO_LayerName_measurelines )
84         return SdResId( STR_LAYER_MEASURELINES );
85 
86     return rName;
87 }
88 
89 // Use a method name, that is specific to LayerTabBar to make code better readable
GetLayerName(sal_uInt16 nPageId) const90 OUString LayerTabBar::GetLayerName(sal_uInt16 nPageId) const
91 {
92     return GetAuxiliaryText(nPageId);
93 }
94 
SetLayerName(sal_uInt16 nPageId,const OUString & rText)95 void LayerTabBar::SetLayerName( sal_uInt16 nPageId, const OUString& rText )
96 {
97     SetAuxiliaryText(nPageId, rText);
98 }
99 
100 // Here "Page" is a tab in the LayerTabBar.
InsertPage(sal_uInt16 nPageId,const OUString & rText,TabBarPageBits nBits,sal_uInt16 nPos)101 void LayerTabBar::InsertPage( sal_uInt16 nPageId, const OUString& rText,
102                                 TabBarPageBits nBits, sal_uInt16 nPos)
103 {
104     OUString sLocalizedName(convertToLocalizedName(rText));
105     TabBar::InsertPage(nPageId, sLocalizedName, nBits, nPos );
106     SetLayerName(nPageId, rText);
107 }
108 
SetPageText(sal_uInt16 nPageId,const OUString & rText)109 void LayerTabBar::SetPageText( sal_uInt16 nPageId, const OUString& rText )
110 {
111     OUString sLocalizedName(convertToLocalizedName(rText));
112     SetLayerName(nPageId, rText);
113     TabBar::SetPageText(nPageId, sLocalizedName);
114 }
115 
IsLocalizedNameOfStandardLayer(std::u16string_view rName)116 bool LayerTabBar::IsLocalizedNameOfStandardLayer(std::u16string_view rName)
117 {
118     return (   rName == SdResId(STR_LAYER_LAYOUT)
119             || rName == SdResId(STR_LAYER_CONTROLS)
120             || rName == SdResId(STR_LAYER_MEASURELINES)
121             || rName == SdResId(STR_LAYER_BCKGRND)
122             || rName == SdResId(STR_LAYER_BCKGRNDOBJ) );
123 }
124 
IsRealNameOfStandardLayer(std::u16string_view rName)125 bool LayerTabBar::IsRealNameOfStandardLayer(std::u16string_view rName)
126 {
127     return (   rName == sUNO_LayerName_layout
128             || rName == sUNO_LayerName_controls
129             || rName == sUNO_LayerName_measurelines
130             || rName == sUNO_LayerName_background
131             || rName == sUNO_LayerName_background_objects );
132 }
133 
Select()134 void LayerTabBar::Select()
135 {
136     SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
137     pDispatcher->Execute(SID_SWITCHLAYER, SfxCallMode::ASYNCHRON);
138 }
139 
MouseButtonDown(const MouseEvent & rMEvt)140 void LayerTabBar::MouseButtonDown(const MouseEvent& rMEvt)
141 {
142     bool bSetPageID=false;
143 
144     if (rMEvt.IsLeft())
145     {
146         Point aPosPixel = rMEvt.GetPosPixel();
147         sal_uInt16 aTabId = GetPageId( PixelToLogic(aPosPixel) );
148         if (aTabId == 0)
149         {
150             SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
151             pDispatcher->Execute(SID_INSERTLAYER, SfxCallMode::SYNCHRON);
152 
153             bSetPageID=true;
154         }
155         else if (rMEvt.IsMod2())
156         {
157             // direct editing of tab text
158             // make sure the clicked tab is the current tab otherwise Edit() acts on the wrong tab
159             if ( aTabId != GetCurPageId())
160             {
161                 MouseEvent aSyntheticEvent (rMEvt.GetPosPixel(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0);
162                 TabBar::MouseButtonDown(aSyntheticEvent);
163             }
164         }
165         else if (rMEvt.IsMod1() || rMEvt.IsShift())
166         {
167             // keyboard Shortcuts to change layer attributes
168 
169             OUString aName(GetLayerName(aTabId));
170             SdrPageView* pPV = pDrViewSh->GetView()->GetSdrPageView();
171 
172             // Save old state
173 
174             bool bOldPrintable = pPV->IsLayerPrintable(aName);
175             bool bOldVisible = pPV->IsLayerVisible(aName);
176             bool bOldLocked = pPV->IsLayerLocked(aName);
177 
178             bool bNewPrintable = bOldPrintable;
179             bool bNewVisible = bOldVisible;
180             bool bNewLocked = bOldLocked;
181 
182             if (rMEvt.IsMod1() && rMEvt.IsShift())
183             {
184                 // Shift+Ctrl: Toggle between layer printable / not printable
185                 bNewPrintable = !bOldPrintable;
186                 pPV->SetLayerPrintable(aName, bNewPrintable);
187             }
188             else if (rMEvt.IsShift())
189             {
190                 // Shift: Toggle between layer visible / hidden
191                 bNewVisible = !bOldVisible;
192                 pPV->SetLayerVisible(aName, bNewVisible);
193             }
194             else // if (rMEvt.IsMod1())
195             {
196                 // Ctrl: Toggle between layer locked / unlocked
197                 bNewLocked = !bOldLocked;
198                 pPV->SetLayerLocked(aName, bNewLocked);
199             }
200 
201             pDrViewSh->ResetActualLayer();
202 
203             // Add Undo action
204 
205             ::sd::View* pView = pDrViewSh->GetView();
206             DrawView* pDrView = dynamic_cast<DrawView*>(pView);
207 
208             SdDrawDocument& rDoc = pView->GetDoc();
209             SdrLayer* pLayer = rDoc.GetLayerAdmin().GetLayer(aName);
210 
211             if (pLayer)
212             {
213                 assert (pDrView && "Change layer attribute undo action is only working with a SdDrawView");
214                 if(pDrView)
215                 {
216                     SfxUndoManager* pManager = rDoc.GetDocSh()->GetUndoManager();
217                     std::unique_ptr<SdLayerModifyUndoAction> pAction(new SdLayerModifyUndoAction(
218                         &rDoc,
219                         pLayer,
220                         aName,
221                         pLayer->GetTitle(),
222                         pLayer->GetDescription(),
223                         bOldVisible,
224                         bOldLocked,
225                         bOldPrintable,
226                         aName,
227                         pLayer->GetTitle(),
228                         pLayer->GetDescription(),
229                         bNewVisible,
230                         bNewLocked,
231                         bNewPrintable
232                         ));
233                     pManager->AddUndoAction(std::move(pAction));
234                 }
235             }
236 
237             // Mark document changed
238 
239             pView->GetDoc().SetChanged();
240         }
241     }
242 
243     // If you insert a new layer you must not call TabBar::MouseButtonDown(rMEvt);
244     // because you want to activate the new layer
245     if( !bSetPageID )
246         TabBar::MouseButtonDown(rMEvt);
247 }
248 
DoubleClick()249 void LayerTabBar::DoubleClick()
250 {
251     if (GetCurPageId() != 0)
252     {
253         SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
254         pDispatcher->Execute( SID_MODIFYLAYER, SfxCallMode::SYNCHRON );
255     }
256 }
257 
258 /**
259  * AcceptDrop-Event
260  */
261 
AcceptDrop(const AcceptDropEvent & rEvt)262 sal_Int8 LayerTabBar::AcceptDrop( const AcceptDropEvent& rEvt )
263 {
264     sal_Int8 nRet = DND_ACTION_NONE;
265 
266     if( rEvt.mbLeaving )
267         EndSwitchPage();
268 
269     if( !pDrViewSh->GetDocSh()->IsReadOnly() )
270     {
271         Point         aPos( PixelToLogic( rEvt.maPosPixel ) );
272         OUString      sLayerName( GetLayerName(GetPageId(aPos)) );
273         SdrLayerID    nLayerId = pDrViewSh->GetView()->GetDoc().GetLayerAdmin().GetLayerID(sLayerName);
274 
275         nRet = pDrViewSh->AcceptDrop( rEvt, *this, nullptr, SDRPAGE_NOTFOUND, nLayerId );
276 
277         SwitchPage( aPos );
278     }
279 
280     return nRet;
281 }
282 
283 /**
284  * ExecuteDrop-Event
285  */
ExecuteDrop(const ExecuteDropEvent & rEvt)286 sal_Int8 LayerTabBar::ExecuteDrop( const ExecuteDropEvent& rEvt )
287 {
288     Point         aPos( PixelToLogic(rEvt.maPosPixel) );
289     OUString      sLayerName( GetLayerName(GetPageId(aPos)) );
290     SdrLayerID    nLayerId = pDrViewSh->GetView()->GetDoc().GetLayerAdmin().GetLayerID(sLayerName);
291 
292     sal_Int8        nRet = pDrViewSh->ExecuteDrop( rEvt, *this, nullptr, SDRPAGE_NOTFOUND, nLayerId );
293 
294     EndSwitchPage();
295 
296     return nRet;
297 
298 }
299 
Command(const CommandEvent & rCEvt)300 void  LayerTabBar::Command(const CommandEvent& rCEvt)
301 {
302     if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
303     {
304         SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
305         pDispatcher->ExecutePopup("layertab");
306     }
307 }
308 
StartRenaming()309 bool LayerTabBar::StartRenaming()
310 {
311     bool bOK = true;
312     OUString aLayerName = GetLayerName( GetEditPageId() );
313 
314     if ( IsRealNameOfStandardLayer(aLayerName))
315     {
316         // It is not allowed to change these names
317         bOK = false;
318     }
319     else
320     {
321         ::sd::View* pView = pDrViewSh->GetView();
322 
323         if ( pView->IsTextEdit() )
324         {
325             pView->SdrEndTextEdit();
326         }
327     }
328 
329     return bOK;
330 }
331 
AllowRenaming()332 TabBarAllowRenamingReturnCode LayerTabBar::AllowRenaming()
333 {
334     bool bOK = true;
335 
336     // Check if names already exists
337     ::sd::View* pView = pDrViewSh->GetView();
338     SdDrawDocument& rDoc = pView->GetDoc();
339     OUString aLayerName = pView->GetActiveLayer();
340     SdrLayerAdmin& rLayerAdmin = rDoc.GetLayerAdmin();
341     OUString aNewName( GetEditText() );
342 
343     if (aNewName.isEmpty() ||
344         (rLayerAdmin.GetLayer( aNewName ) && aLayerName != aNewName) )
345     {
346         // Name already exists.
347         std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pDrViewSh->GetViewFrame()->GetFrameWeld(),
348                                                    VclMessageType::Warning, VclButtonsType::Ok,
349                                                    SdResId(STR_WARN_NAME_DUPLICATE)));
350         xWarn->run();
351         bOK = false;
352     }
353 
354     if (bOK)
355     {
356         if ( IsLocalizedNameOfStandardLayer(aNewName) || IsRealNameOfStandardLayer(aNewName) )
357         {
358             // Standard layer names may not be changed.
359             bOK = false;
360         }
361     }
362 
363     return bOK ? TABBAR_RENAMING_YES : TABBAR_RENAMING_NO;
364 }
365 
EndRenaming()366 void LayerTabBar::EndRenaming()
367 {
368     if( IsEditModeCanceled() )
369         return;
370 
371     ::sd::View* pView = pDrViewSh->GetView();
372     DrawView* pDrView = dynamic_cast<DrawView*>( pView  );
373 
374     SdDrawDocument& rDoc = pView->GetDoc();
375     OUString aLayerName = pView->GetActiveLayer();
376     SdrLayerAdmin& rLayerAdmin = rDoc.GetLayerAdmin();
377     SdrLayer* pLayer = rLayerAdmin.GetLayer(aLayerName);
378 
379     if (!pLayer)
380         return;
381 
382     OUString aNewName( GetEditText() );
383     assert (pDrView && "Rename layer undo action is only working with a SdDrawView");
384     if( pDrView )
385     {
386         SfxUndoManager* pManager = rDoc.GetDocSh()->GetUndoManager();
387         std::unique_ptr<SdLayerModifyUndoAction> pAction(new SdLayerModifyUndoAction(
388             &rDoc,
389             pLayer,
390             aLayerName,
391             pLayer->GetTitle(),
392             pLayer->GetDescription(),
393             pDrView->IsLayerVisible(aLayerName),
394             pDrView->IsLayerLocked(aLayerName),
395             pDrView->IsLayerPrintable(aLayerName),
396             aNewName,
397             pLayer->GetTitle(),
398             pLayer->GetDescription(),
399             pDrView->IsLayerVisible(aLayerName),
400             pDrView->IsLayerLocked(aLayerName),
401             pDrView->IsLayerPrintable(aLayerName)
402             ));
403         pManager->AddUndoAction( std::move(pAction) );
404     }
405 
406     // First notify View since SetName() calls ResetActualLayer() and
407     // the View then already has to know the Layer
408     pView->SetActiveLayer(aNewName);
409     pLayer->SetName(aNewName);
410     rDoc.SetChanged();
411 }
412 
ActivatePage()413 void LayerTabBar::ActivatePage()
414 {
415     if (pDrViewSh!=nullptr)
416     {
417 
418         SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher();
419         pDispatcher->Execute(SID_SWITCHLAYER, SfxCallMode::ASYNCHRON);
420     }
421 }
422 
SendActivatePageEvent()423 void LayerTabBar::SendActivatePageEvent()
424 {
425     CallEventListeners (VclEventId::TabbarPageActivated,
426         reinterpret_cast<void*>(GetCurPageId()));
427 }
428 
SendDeactivatePageEvent()429 void LayerTabBar::SendDeactivatePageEvent()
430 {
431     CallEventListeners (VclEventId::TabbarPageDeactivated,
432         reinterpret_cast<void*>(GetCurPageId()));
433 }
434 
435 } // end of namespace sd
436 
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
438