1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <sfx2/viewfrm.hxx>
21 #include <sfx2/dispatch.hxx>
22 #include <sfx2/docfile.hxx>
23 #include <tools/urlobj.hxx>
24 #include <vcl/svapp.hxx>
25 #include "tabcont.hxx"
26 #include "tabvwsh.hxx"
29 #include "scresid.hxx"
31 #include "globstr.hrc"
32 #include "transobj.hxx"
33 #include "clipparam.hxx"
34 #include "dragdata.hxx"
35 #include "markdata.hxx"
36 #include <gridwin.hxx>
38 ScTabControl::ScTabControl( vcl::Window
* pParent
, ScViewData
* pData
)
39 : TabBar(pParent
, WB_3DLOOK
| WB_MINSCROLL
| WB_SCROLL
| WB_RANGESELECT
| WB_MULTISELECT
| WB_DRAG
)
40 , DropTargetHelper(this)
41 , DragSourceHelper(this)
43 , nMouseClickPageId(TabBar::PAGE_NOT_FOUND
)
44 , nSelPageIdByMouse(TabBar::PAGE_NOT_FOUND
)
47 ScDocument
* pDoc
= pViewData
->GetDocument();
51 SCTAB nCount
= pDoc
->GetTableCount();
52 for (SCTAB i
=0; i
<nCount
; i
++)
54 if (pDoc
->IsVisible(i
))
56 if (pDoc
->GetName(i
,aString
))
58 if ( pDoc
->IsScenario(i
) )
59 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
, TPB_SPECIAL
);
61 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
);
62 if ( !pDoc
->IsDefaultTabBgColor(i
) )
64 aTabBgColor
= pDoc
->GetTabBgColor(i
);
65 SetTabBgColor( static_cast<sal_uInt16
>(i
)+1, aTabBgColor
);
71 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
73 SetSizePixel( Size(SC_TABBAR_DEFWIDTH
, 0) );
75 SetSplitHdl( LINK( pViewData
->GetView(), ScTabView
, TabBarResize
) );
80 SetScrollAlwaysEnabled(false);
82 SetScrollAreaContextHdl( LINK( this, ScTabControl
, ShowPageList
) );
85 IMPL_LINK_TYPED(ScTabControl
, ShowPageList
, const CommandEvent
&, rEvent
, void)
89 sal_uInt16 nCurPageId
= GetCurPageId();
91 ScDocument
* pDoc
= pViewData
->GetDocument();
92 SCTAB nCount
= pDoc
->GetTableCount();
93 for (SCTAB i
=0; i
<nCount
; ++i
)
95 if (pDoc
->IsVisible(i
))
98 if (pDoc
->GetName(i
, aString
))
100 sal_uInt16 nId
= static_cast<sal_uInt16
>(i
)+1;
101 aPopup
.InsertItem(nId
, aString
, MenuItemBits::CHECKABLE
);
102 if (nId
== nCurPageId
)
103 aPopup
.CheckItem(nId
);
108 sal_uInt16 nItemId
= aPopup
.Execute( this, rEvent
.GetMousePosPixel() );
109 SwitchToPageId(nItemId
);
112 ScTabControl::~ScTabControl()
116 sal_uInt16
ScTabControl::GetMaxId() const
118 sal_uInt16 nVisCnt
= GetPageCount();
120 return GetPageId(nVisCnt
-1);
125 SCTAB
ScTabControl::GetPrivatDropPos(const Point
& rPos
)
127 sal_uInt16 nPos
= ShowDropPos(rPos
);
129 SCTAB nRealPos
= static_cast<SCTAB
>(nPos
);
133 ScDocument
* pDoc
= pViewData
->GetDocument();
135 SCTAB nCount
= pDoc
->GetTableCount();
137 sal_uInt16 nViewPos
=0;
139 for (SCTAB i
=0; i
<nCount
; i
++)
141 if (pDoc
->IsVisible(i
))
147 for (j
=i
+1; j
<nCount
; j
++)
149 if (pDoc
->IsVisible(j
))
163 void ScTabControl::MouseButtonDown( const MouseEvent
& rMEvt
)
165 ScModule
* pScMod
= SC_MOD();
166 if ( !pScMod
->IsModalMode() && !pScMod
->IsFormulaMode() && !IsInEditMode() )
169 pViewData
->GetViewShell()->SetActive(); // Appear and SetViewFrame
170 pViewData
->GetView()->ActiveGrabFocus();
173 if (rMEvt
.IsLeft() && rMEvt
.GetModifier() == 0)
174 nMouseClickPageId
= GetPageId(rMEvt
.GetPosPixel());
176 TabBar::MouseButtonDown( rMEvt
);
179 void ScTabControl::MouseButtonUp( const MouseEvent
& rMEvt
)
181 Point aPos
= PixelToLogic( rMEvt
.GetPosPixel() );
183 // mouse button down and up on same page?
184 if( nMouseClickPageId
!= GetPageId(aPos
))
185 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
187 if ( rMEvt
.GetClicks() == 2 && rMEvt
.IsLeft() && nMouseClickPageId
!= 0 && nMouseClickPageId
!= TAB_PAGE_NOTFOUND
)
189 SfxDispatcher
* pDispatcher
= pViewData
->GetViewShell()->GetViewFrame()->GetDispatcher();
190 pDispatcher
->Execute( FID_TAB_MENU_RENAME
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
);
194 if( nMouseClickPageId
== 0 )
196 // Click in the area next to the existing tabs:
197 // #i70320# if several sheets are selected, deselect all except the current sheet,
198 // otherwise add new sheet
199 sal_uInt16 nSlot
= ( GetSelectPageCount() > 1 ) ? FID_TAB_DESELECTALL
: FID_INS_TABLE
;
200 SfxDispatcher
* pDispatcher
= pViewData
->GetViewShell()->GetViewFrame()->GetDispatcher();
201 pDispatcher
->Execute( nSlot
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
);
202 // forget page ID, to be really sure that the dialog is not called twice
203 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
206 TabBar::MouseButtonUp( rMEvt
);
209 void ScTabControl::AddTabClick()
211 TabBar::AddTabClick();
213 // Insert a new sheet at the right end, with default name.
214 ScDocument
* pDoc
= pViewData
->GetDocument();
215 ScModule
* pScMod
= SC_MOD();
216 if (!pDoc
->IsDocEditable() || pScMod
->IsTableLocked())
219 pDoc
->CreateValidTabName(aName
);
220 SCTAB nTabCount
= pDoc
->GetTableCount();
221 pViewData
->GetViewShell()->InsertTable(aName
, nTabCount
);
224 void ScTabControl::Select()
226 /* Remember last clicked page ID. */
227 nSelPageIdByMouse
= nMouseClickPageId
;
228 /* Reset nMouseClickPageId, so that next Select() call may invalidate
229 nSelPageIdByMouse (i.e. if called from keyboard). */
230 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
232 ScModule
* pScMod
= SC_MOD();
233 ScDocument
* pDoc
= pViewData
->GetDocument();
234 ScMarkData
& rMark
= pViewData
->GetMarkData();
235 SCTAB nCount
= pDoc
->GetTableCount();
238 if ( pScMod
->IsTableLocked() ) // may not be switched now ?
240 // restore the old state of TabControls
242 for (i
=0; i
<nCount
; i
++)
243 SelectPage( static_cast<sal_uInt16
>(i
)+1, rMark
.GetTableSelect(i
) );
244 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
249 sal_uInt16 nCurId
= GetCurPageId();
250 if (!nCurId
) return; // for Excel import it can happen that everything is hidden
251 sal_uInt16 nPage
= nCurId
- 1;
253 // OLE-inplace deactivate
254 if ( nPage
!= static_cast<sal_uInt16
>(pViewData
->GetTabNo()) )
255 pViewData
->GetView()->DrawMarkListHasChanged();
257 // InputEnterHandler onlw when not reference input
259 bool bRefMode
= pScMod
->IsFormulaMode();
261 pScMod
->InputEnterHandler();
263 for (i
=0; i
<nCount
; i
++)
264 rMark
.SelectTable( i
, IsPageSelected(static_cast<sal_uInt16
>(i
)+1) );
266 SfxDispatcher
& rDisp
= pViewData
->GetDispatcher();
267 if (rDisp
.IsLocked())
268 pViewData
->GetView()->SetTabNo( static_cast<SCTAB
>(nPage
) );
271 // sheet for basic is 1-based
272 SfxUInt16Item
aItem( SID_CURRENTTAB
, nPage
+ 1 );
273 rDisp
.ExecuteList(SID_CURRENTTAB
,
274 SfxCallMode::SLOT
| SfxCallMode::RECORD
, { &aItem
});
277 SfxBindings
& rBind
= pViewData
->GetBindings();
278 rBind
.Invalidate( FID_FILL_TAB
);
279 rBind
.Invalidate( FID_TAB_DESELECTALL
);
281 rBind
.Invalidate( FID_INS_TABLE
);
282 rBind
.Invalidate( FID_TAB_APPEND
);
283 rBind
.Invalidate( FID_TAB_MOVE
);
284 rBind
.Invalidate( FID_TAB_RENAME
);
285 rBind
.Invalidate( FID_DELETE_TABLE
);
286 rBind
.Invalidate( FID_TABLE_SHOW
);
287 rBind
.Invalidate( FID_TABLE_HIDE
);
288 rBind
.Invalidate( FID_TAB_SET_TAB_BG_COLOR
);
290 // Recalculate status bar functions.
291 rBind
.Invalidate( SID_TABLE_CELL
);
293 // SetReference onlw when the consolidate dialog is open
294 // (for referenzes over multiple sheets)
295 // for others this is only needed fidgeting
297 if ( bRefMode
&& pViewData
->GetRefType() == SC_REFTYPE_REF
)
298 if ( pViewData
->GetViewShell()->GetViewFrame()->HasChildWindow(SID_OPENDLG_CONSOLIDATE
) )
301 pViewData
->GetRefStartX(), pViewData
->GetRefStartY(), pViewData
->GetRefStartZ(),
302 pViewData
->GetRefEndX(), pViewData
->GetRefEndY(), pViewData
->GetRefEndZ() );
303 pScMod
->SetReference( aRange
, pDoc
, &rMark
);
304 pScMod
->EndReference(); // due to Auto-Hide
308 void ScTabControl::UpdateInputContext()
310 ScDocument
* pDoc
= pViewData
->GetDocument();
311 WinBits nStyle
= GetStyle();
312 if (pDoc
->GetDocumentShell()->IsReadOnly())
313 // no insert sheet tab for readonly doc.
314 SetStyle((nStyle
& ~WB_INSERTTAB
));
316 SetStyle((nStyle
| WB_INSERTTAB
));
319 void ScTabControl::UpdateStatus()
321 ScDocument
* pDoc
= pViewData
->GetDocument();
322 ScMarkData
& rMark
= pViewData
->GetMarkData();
323 bool bActive
= pViewData
->IsActive();
325 SCTAB nCount
= pDoc
->GetTableCount();
328 SCTAB nMaxCnt
= std::max( nCount
, static_cast<SCTAB
>(GetMaxId()) );
331 bool bModified
= false; // sheet name
332 for (i
=0; i
<nMaxCnt
&& !bModified
; i
++)
334 if (pDoc
->IsVisible(i
))
336 pDoc
->GetName(i
,aString
);
337 aTabBgColor
= pDoc
->GetTabBgColor(i
);
344 if ( !aString
.equals(GetPageText(static_cast<sal_uInt16
>(i
)+1)) || (GetTabBgColor(static_cast<sal_uInt16
>(i
)+1) != aTabBgColor
) )
351 for (i
=0; i
<nCount
; i
++)
353 if (pDoc
->IsVisible(i
))
355 if (pDoc
->GetName(i
,aString
))
357 if ( pDoc
->IsScenario(i
) )
358 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
, TPB_SPECIAL
);
360 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
);
361 if ( !pDoc
->IsDefaultTabBgColor(i
) )
363 aTabBgColor
= pDoc
->GetTabBgColor(i
);
364 SetTabBgColor( static_cast<sal_uInt16
>(i
)+1, aTabBgColor
);
370 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
374 bModified
= false; // selection
375 for (i
=0; i
<nMaxCnt
&& !bModified
; i
++)
376 if ( rMark
.GetTableSelect(i
) != (bool) IsPageSelected(static_cast<sal_uInt16
>(i
)+1) )
380 for (i
=0; i
<nCount
; i
++)
381 SelectPage( static_cast<sal_uInt16
>(i
)+1, rMark
.GetTableSelect(i
) );
388 void ScTabControl::SetSheetLayoutRTL( bool bSheetRTL
)
390 SetEffectiveRTL( bSheetRTL
);
391 nSelPageIdByMouse
= TabBar::PAGE_NOT_FOUND
;
394 void ScTabControl::SwitchToPageId(sal_uInt16 nId
)
398 bool bAlreadySelected
= IsPageSelected( nId
);
399 //make the clicked page the current one
401 //change the selection when the current one is not already
402 //selected or part of a multi selection
403 if(!bAlreadySelected
)
405 sal_uInt16 nCount
= GetMaxId();
407 for (sal_uInt16 i
=1; i
<=nCount
; i
++)
408 SelectPage( i
, i
==nId
);
414 void ScTabControl::Command( const CommandEvent
& rCEvt
)
416 ScModule
* pScMod
= SC_MOD();
417 ScTabViewShell
* pViewSh
= pViewData
->GetViewShell();
418 bool bDisable
= pScMod
->IsFormulaMode() || pScMod
->IsModalMode();
420 // first activate ViewFrame (Bug 19493):
421 pViewSh
->SetActive();
423 if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
&& !bDisable
)
425 // #i18735# select the page that is under the mouse cursor
426 // if multiple tables are selected and the one under the cursor
427 // is not part of them then unselect them
428 sal_uInt16 nId
= GetPageId( rCEvt
.GetMousePosPixel() );
431 // #i52073# OLE inplace editing has to be stopped before showing the sheet tab context menu
432 pViewSh
->DeactivateOle();
435 // get Dispatcher from ViewData (ViewFrame) instead of Shell (Frame), so it can't be null
436 pViewData
->GetDispatcher().ExecutePopup( "sheettab" );
440 void ScTabControl::StartDrag( sal_Int8
/* nAction */, const Point
& rPosPixel
)
442 ScModule
* pScMod
= SC_MOD();
443 bool bDisable
= pScMod
->IsFormulaMode() || pScMod
->IsModalMode();
447 vcl::Region
aRegion( Rectangle(0,0,0,0) );
448 CommandEvent
aCEvt( rPosPixel
, CommandEventId::StartDrag
, true ); // needed for StartDrag
449 if (TabBar::StartDrag( aCEvt
, aRegion
))
454 void ScTabControl::DoDrag( const vcl::Region
& /* rRegion */ )
456 ScDocShell
* pDocSh
= pViewData
->GetDocShell();
457 ScDocument
& rDoc
= pDocSh
->GetDocument();
459 SCTAB nTab
= pViewData
->GetTabNo();
460 ScRange
aTabRange( 0, 0, nTab
, MAXCOL
, MAXROW
, nTab
);
461 ScMarkData aTabMark
= pViewData
->GetMarkData();
462 aTabMark
.ResetMark(); // doesn't change marked table information
463 aTabMark
.SetMarkArea( aTabRange
);
465 ScDocument
* pClipDoc
= new ScDocument( SCDOCMODE_CLIP
);
466 ScClipParam
aClipParam(aTabRange
, false);
467 rDoc
.CopyToClip(aClipParam
, pClipDoc
, &aTabMark
, false, false);
469 TransferableObjectDescriptor aObjDesc
;
470 pDocSh
->FillTransferableObjectDescriptor( aObjDesc
);
471 aObjDesc
.maDisplayName
= pDocSh
->GetMedium()->GetURLObject().GetURLNoPass();
472 // maSize is set in ScTransferObj ctor
474 ScTransferObj
* pTransferObj
= new ScTransferObj( pClipDoc
, aObjDesc
);
475 css::uno::Reference
<css::datatransfer::XTransferable
> xTransferable( pTransferObj
);
477 pTransferObj
->SetDragSourceFlags( SC_DROP_TABLE
);
479 pTransferObj
->SetDragSource( pDocSh
, aTabMark
);
481 pTransferObj
->SetSourceCursorPos( pViewData
->GetCurX(), pViewData
->GetCurY() );
483 vcl::Window
* pWindow
= pViewData
->GetActiveWin();
484 SC_MOD()->SetDragObject( pTransferObj
, nullptr ); // for internal D&D
485 pTransferObj
->StartDrag( pWindow
, DND_ACTION_COPYMOVE
| DND_ACTION_LINK
);
488 static sal_uInt16
lcl_DocShellNr( ScDocument
* pDoc
)
490 sal_uInt16 nShellCnt
= 0;
491 SfxObjectShell
* pShell
= SfxObjectShell::GetFirst();
494 if ( dynamic_cast<const ScDocShell
*>(pShell
) != nullptr )
496 if ( &static_cast<ScDocShell
*>(pShell
)->GetDocument() == pDoc
)
501 pShell
= SfxObjectShell::GetNext( *pShell
);
504 OSL_FAIL("Document not found");
508 sal_Int8
ScTabControl::ExecuteDrop( const ExecuteDropEvent
& rEvt
)
512 ScDocument
* pDoc
= pViewData
->GetDocument();
513 const ScDragData
& rData
= SC_MOD()->GetDragData();
514 if ( rData
.pCellTransfer
&& ( rData
.pCellTransfer
->GetDragSourceFlags() & SC_DROP_TABLE
) &&
515 rData
.pCellTransfer
->GetSourceDocument() == pDoc
)
517 // moving of tables within the document
518 SCTAB nPos
= GetPrivatDropPos( rEvt
.maPosPixel
);
521 if ( nPos
== rData
.pCellTransfer
->GetVisibleTab() && rEvt
.mnAction
== DND_ACTION_MOVE
)
523 // #i83005# do nothing - don't move to the same position
524 // (too easily triggered unintentionally, and might take a long time in large documents)
528 if ( !pDoc
->GetChangeTrack() && pDoc
->IsDocEditable() )
530 //! use table selection from the tab control where dragging was started?
531 pViewData
->GetView()->MoveTable( lcl_DocShellNr(pDoc
), nPos
, rEvt
.mnAction
!= DND_ACTION_MOVE
);
533 rData
.pCellTransfer
->SetDragWasInternal(); // don't delete
534 return DND_ACTION_COPY
;
539 return DND_ACTION_NONE
;
542 sal_Int8
ScTabControl::AcceptDrop( const AcceptDropEvent
& rEvt
)
544 if ( rEvt
.mbLeaving
)
548 return rEvt
.mnAction
;
551 const ScDocument
* pDoc
= pViewData
->GetDocument();
552 const ScDragData
& rData
= SC_MOD()->GetDragData();
553 if ( rData
.pCellTransfer
&& ( rData
.pCellTransfer
->GetDragSourceFlags() & SC_DROP_TABLE
) &&
554 rData
.pCellTransfer
->GetSourceDocument() == pDoc
)
556 // moving of tables within the document
557 if ( !pDoc
->GetChangeTrack() && pDoc
->IsDocEditable() )
559 ShowDropPos( rEvt
.maPosPixel
);
560 return rEvt
.mnAction
;
563 else // switch sheets for all formats
565 SwitchPage( rEvt
.maPosPixel
); // switch sheet after timeout
566 return 0; // nothing can be dropped here
572 bool ScTabControl::StartRenaming()
574 if ( pViewData
->GetDocument()->IsDocEditable() )
580 TabBarAllowRenamingReturnCode
ScTabControl::AllowRenaming()
582 ScTabViewShell
* pViewSh
= pViewData
->GetViewShell();
583 OSL_ENSURE( pViewSh
, "pViewData->GetViewShell()" );
585 TabBarAllowRenamingReturnCode nRet
= TABBAR_RENAMING_CANCEL
;
586 sal_uInt16 nId
= GetEditPageId();
589 SCTAB nTab
= nId
- 1;
590 OUString aNewName
= GetEditText();
591 bool bDone
= pViewSh
->RenameTable( aNewName
, nTab
);
593 nRet
= TABBAR_RENAMING_YES
;
594 else if ( bErrorShown
)
596 // if the error message from this TabControl is currently visible,
597 // don't end edit mode now, to avoid problems when returning to
598 // the other call (showing the error) - this should not happen
599 OSL_FAIL("ScTabControl::AllowRenaming: nested calls");
600 nRet
= TABBAR_RENAMING_NO
;
602 else if ( Application::IsInModalMode() )
604 // don't show error message above any modal dialog
605 // instead cancel renaming without error message
606 nRet
= TABBAR_RENAMING_CANCEL
;
611 pViewSh
->ErrorMessage( STR_INVALIDTABNAME
);
613 nRet
= TABBAR_RENAMING_NO
;
619 void ScTabControl::EndRenaming()
622 pViewData
->GetView()->ActiveGrabFocus();
625 void ScTabControl::Mirror()
628 if( nSelPageIdByMouse
!= TabBar::PAGE_NOT_FOUND
)
630 Rectangle
aRect( GetPageRect( GetCurPageId() ) );
631 if( !aRect
.IsEmpty() )
632 SetPointerPosPixel( aRect
.Center() );
633 nSelPageIdByMouse
= TabBar::PAGE_NOT_FOUND
; // only once after a Select()
637 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */