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 // STATIC DATA -----------------------------------------------------------
40 ScTabControl::ScTabControl( vcl::Window
* pParent
, ScViewData
* pData
)
41 : TabBar(pParent
, WB_3DLOOK
| WB_MINSCROLL
| WB_SCROLL
| WB_RANGESELECT
| WB_MULTISELECT
| WB_DRAG
)
42 , DropTargetHelper(this)
43 , DragSourceHelper(this)
45 , nMouseClickPageId(TabBar::PAGE_NOT_FOUND
)
46 , nSelPageIdByMouse(TabBar::PAGE_NOT_FOUND
)
49 ScDocument
* pDoc
= pViewData
->GetDocument();
53 SCTAB nCount
= pDoc
->GetTableCount();
54 for (SCTAB i
=0; i
<nCount
; i
++)
56 if (pDoc
->IsVisible(i
))
58 if (pDoc
->GetName(i
,aString
))
60 if ( pDoc
->IsScenario(i
) )
61 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
, TPB_SPECIAL
);
63 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
);
64 if ( !pDoc
->IsDefaultTabBgColor(i
) )
66 aTabBgColor
= pDoc
->GetTabBgColor(i
);
67 SetTabBgColor( static_cast<sal_uInt16
>(i
)+1, aTabBgColor
);
73 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
75 SetSizePixel( Size(SC_TABBAR_DEFWIDTH
, 0) );
77 SetSplitHdl( LINK( pViewData
->GetView(), ScTabView
, TabBarResize
) );
82 SetScrollAlwaysEnabled(false);
84 SetScrollAreaContextHdl( LINK( this, ScTabControl
, ShowPageList
) );
87 IMPL_LINK(ScTabControl
, ShowPageList
, const CommandEvent
*, pEvent
)
91 sal_uInt16 nCurPageId
= GetCurPageId();
93 ScDocument
* pDoc
= pViewData
->GetDocument();
94 SCTAB nCount
= pDoc
->GetTableCount();
95 for (SCTAB i
=0; i
<nCount
; ++i
)
97 if (pDoc
->IsVisible(i
))
100 if (pDoc
->GetName(i
, aString
))
102 sal_uInt16 nId
= static_cast<sal_uInt16
>(i
)+1;
103 aPopup
.InsertItem(nId
, aString
, MenuItemBits::CHECKABLE
);
104 if (nId
== nCurPageId
)
105 aPopup
.CheckItem(nId
);
110 sal_uInt16 nItemId
= aPopup
.Execute( this, pEvent
->GetMousePosPixel() );
111 SwitchToPageId(nItemId
);
116 ScTabControl::~ScTabControl()
120 sal_uInt16
ScTabControl::GetMaxId() const
122 sal_uInt16 nVisCnt
= GetPageCount();
124 return GetPageId(nVisCnt
-1);
129 SCTAB
ScTabControl::GetPrivatDropPos(const Point
& rPos
)
131 sal_uInt16 nPos
= ShowDropPos(rPos
);
133 SCTAB nRealPos
= static_cast<SCTAB
>(nPos
);
137 ScDocument
* pDoc
= pViewData
->GetDocument();
139 SCTAB nCount
= pDoc
->GetTableCount();
141 sal_uInt16 nViewPos
=0;
143 for (SCTAB i
=0; i
<nCount
; i
++)
145 if (pDoc
->IsVisible(i
))
151 for (j
=i
+1; j
<nCount
; j
++)
153 if (pDoc
->IsVisible(j
))
167 void ScTabControl::MouseButtonDown( const MouseEvent
& rMEvt
)
169 ScModule
* pScMod
= SC_MOD();
170 if ( !pScMod
->IsModalMode() && !pScMod
->IsFormulaMode() && !IsInEditMode() )
173 pViewData
->GetViewShell()->SetActive(); // Appear und SetViewFrame
174 pViewData
->GetView()->ActiveGrabFocus();
177 if (rMEvt
.IsLeft() && rMEvt
.GetModifier() == 0)
178 nMouseClickPageId
= GetPageId(rMEvt
.GetPosPixel());
180 TabBar::MouseButtonDown( rMEvt
);
183 void ScTabControl::MouseButtonUp( const MouseEvent
& rMEvt
)
185 Point aPos
= PixelToLogic( rMEvt
.GetPosPixel() );
187 // mouse button down and up on same page?
188 if( nMouseClickPageId
!= GetPageId(aPos
))
189 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
191 if ( rMEvt
.GetClicks() == 2 && rMEvt
.IsLeft() && nMouseClickPageId
!= 0 && nMouseClickPageId
!= TAB_PAGE_NOTFOUND
)
193 SfxDispatcher
* pDispatcher
= pViewData
->GetViewShell()->GetViewFrame()->GetDispatcher();
194 pDispatcher
->Execute( FID_TAB_MENU_RENAME
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
);
198 if( nMouseClickPageId
== 0 )
200 // Click in the area next to the existing tabs:
201 // #i70320# if several sheets are selected, deselect all ecxept the current sheet,
202 // otherwise add new sheet
203 sal_uInt16 nSlot
= ( GetSelectPageCount() > 1 ) ? FID_TAB_DESELECTALL
: FID_INS_TABLE
;
204 SfxDispatcher
* pDispatcher
= pViewData
->GetViewShell()->GetViewFrame()->GetDispatcher();
205 pDispatcher
->Execute( nSlot
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
);
206 // forget page ID, to be really sure that the dialog is not called twice
207 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
210 TabBar::MouseButtonUp( rMEvt
);
213 void ScTabControl::AddTabClick()
215 TabBar::AddTabClick();
217 // Insert a new sheet at the right end, with default name.
218 ScDocument
* pDoc
= pViewData
->GetDocument();
219 ScModule
* pScMod
= SC_MOD();
220 if (!pDoc
->IsDocEditable() || pScMod
->IsTableLocked())
223 pDoc
->CreateValidTabName(aName
);
224 SCTAB nTabCount
= pDoc
->GetTableCount();
225 pViewData
->GetViewShell()->InsertTable(aName
, nTabCount
);
228 void ScTabControl::Select()
230 /* Remember last clicked page ID. */
231 nSelPageIdByMouse
= nMouseClickPageId
;
232 /* Reset nMouseClickPageId, so that next Select() call may invalidate
233 nSelPageIdByMouse (i.e. if called from keyboard). */
234 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
236 ScModule
* pScMod
= SC_MOD();
237 ScDocument
* pDoc
= pViewData
->GetDocument();
238 ScMarkData
& rMark
= pViewData
->GetMarkData();
239 SCTAB nCount
= pDoc
->GetTableCount();
242 if ( pScMod
->IsTableLocked() ) // darf jetzt nicht umgeschaltet werden ?
244 // den alten Zustand des TabControls wiederherstellen:
246 for (i
=0; i
<nCount
; i
++)
247 SelectPage( static_cast<sal_uInt16
>(i
)+1, rMark
.GetTableSelect(i
) );
248 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
253 sal_uInt16 nCurId
= GetCurPageId();
254 if (!nCurId
) return; // kann vorkommen, wenn bei Excel-Import alles versteckt ist
255 sal_uInt16 nPage
= nCurId
- 1;
257 // OLE-inplace deaktivieren
258 if ( nPage
!= static_cast<sal_uInt16
>(pViewData
->GetTabNo()) )
259 pViewData
->GetView()->DrawMarkListHasChanged();
261 // InputEnterHandler nur wenn nicht Referenzeingabe
263 bool bRefMode
= pScMod
->IsFormulaMode();
265 pScMod
->InputEnterHandler();
267 for (i
=0; i
<nCount
; i
++)
268 rMark
.SelectTable( i
, IsPageSelected(static_cast<sal_uInt16
>(i
)+1) );
270 SfxDispatcher
& rDisp
= pViewData
->GetDispatcher();
271 if (rDisp
.IsLocked())
272 pViewData
->GetView()->SetTabNo( static_cast<SCTAB
>(nPage
) );
275 // Tabelle fuer Basic ist 1-basiert
276 SfxUInt16Item
aItem( SID_CURRENTTAB
, nPage
+ 1 );
277 rDisp
.Execute( SID_CURRENTTAB
, SfxCallMode::SLOT
| SfxCallMode::RECORD
,
278 &aItem
, (void*) NULL
);
281 SfxBindings
& rBind
= pViewData
->GetBindings();
282 rBind
.Invalidate( FID_FILL_TAB
);
283 rBind
.Invalidate( FID_TAB_DESELECTALL
);
285 rBind
.Invalidate( FID_INS_TABLE
);
286 rBind
.Invalidate( FID_TAB_APPEND
);
287 rBind
.Invalidate( FID_TAB_MOVE
);
288 rBind
.Invalidate( FID_TAB_RENAME
);
289 rBind
.Invalidate( FID_DELETE_TABLE
);
290 rBind
.Invalidate( FID_TABLE_SHOW
);
291 rBind
.Invalidate( FID_TABLE_HIDE
);
292 rBind
.Invalidate( FID_TAB_SET_TAB_BG_COLOR
);
294 // SetReference nur wenn der Konsolidieren-Dialog offen ist
295 // (fuer Referenzen ueber mehrere Tabellen)
296 // bei anderen gibt das nur unnoetiges Gezappel
298 if ( bRefMode
&& pViewData
->GetRefType() == SC_REFTYPE_REF
)
299 if ( pViewData
->GetViewShell()->GetViewFrame()->HasChildWindow(SID_OPENDLG_CONSOLIDATE
) )
302 pViewData
->GetRefStartX(), pViewData
->GetRefStartY(), pViewData
->GetRefStartZ(),
303 pViewData
->GetRefEndX(), pViewData
->GetRefEndY(), pViewData
->GetRefEndZ() );
304 pScMod
->SetReference( aRange
, pDoc
, &rMark
);
305 pScMod
->EndReference(); // wegen Auto-Hide
309 void ScTabControl::UpdateInputContext()
311 ScDocument
* pDoc
= pViewData
->GetDocument();
312 WinBits nStyle
= GetStyle();
313 if (pDoc
->GetDocumentShell()->IsReadOnly())
314 // no insert sheet tab for readonly doc.
315 SetStyle((nStyle
& ~WB_INSERTTAB
));
317 SetStyle((nStyle
| WB_INSERTTAB
));
320 void ScTabControl::UpdateStatus()
322 ScDocument
* pDoc
= pViewData
->GetDocument();
323 ScMarkData
& rMark
= pViewData
->GetMarkData();
324 bool bActive
= pViewData
->IsActive();
326 SCTAB nCount
= pDoc
->GetTableCount();
329 SCTAB nMaxCnt
= std::max( nCount
, static_cast<SCTAB
>(GetMaxId()) );
332 bool bModified
= false; // Tabellen-Namen
333 for (i
=0; i
<nMaxCnt
&& !bModified
; i
++)
335 if (pDoc
->IsVisible(i
))
337 pDoc
->GetName(i
,aString
);
338 aTabBgColor
= pDoc
->GetTabBgColor(i
);
345 if ( !aString
.equals(GetPageText(static_cast<sal_uInt16
>(i
)+1)) || (GetTabBgColor(static_cast<sal_uInt16
>(i
)+1) != aTabBgColor
) )
352 for (i
=0; i
<nCount
; i
++)
354 if (pDoc
->IsVisible(i
))
356 if (pDoc
->GetName(i
,aString
))
358 if ( pDoc
->IsScenario(i
) )
359 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
, TPB_SPECIAL
);
361 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
);
362 if ( !pDoc
->IsDefaultTabBgColor(i
) )
364 aTabBgColor
= pDoc
->GetTabBgColor(i
);
365 SetTabBgColor( static_cast<sal_uInt16
>(i
)+1, aTabBgColor
);
371 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
375 bModified
= false; // Selektion
376 for (i
=0; i
<nMaxCnt
&& !bModified
; i
++)
377 if ( rMark
.GetTableSelect(i
) != (bool) IsPageSelected(static_cast<sal_uInt16
>(i
)+1) )
381 for (i
=0; i
<nCount
; i
++)
382 SelectPage( static_cast<sal_uInt16
>(i
)+1, rMark
.GetTableSelect(i
) );
389 void ScTabControl::SetSheetLayoutRTL( bool bSheetRTL
)
391 SetEffectiveRTL( bSheetRTL
);
392 nSelPageIdByMouse
= TabBar::PAGE_NOT_FOUND
;
395 void ScTabControl::SwitchToPageId(sal_uInt16 nId
)
399 bool bAlreadySelected
= IsPageSelected( nId
);
400 //make the clicked page the current one
402 //change the selection when the current one is not already
403 //selected or part of a multi selection
404 if(!bAlreadySelected
)
406 sal_uInt16 nCount
= GetMaxId();
408 for (sal_uInt16 i
=1; i
<=nCount
; i
++)
409 SelectPage( i
, i
==nId
);
415 void ScTabControl::Command( const CommandEvent
& rCEvt
)
417 ScModule
* pScMod
= SC_MOD();
418 ScTabViewShell
* pViewSh
= pViewData
->GetViewShell();
419 bool bDisable
= pScMod
->IsFormulaMode() || pScMod
->IsModalMode();
421 // ViewFrame erstmal aktivieren (Bug 19493):
422 pViewSh
->SetActive();
424 if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
&& !bDisable
)
426 // #i18735# select the page that is under the mouse cursor
427 // if multiple tables are selected and the one under the cursor
428 // is not part of them then unselect them
429 sal_uInt16 nId
= GetPageId( rCEvt
.GetMousePosPixel() );
432 // #i52073# OLE inplace editing has to be stopped before showing the sheet tab context menu
433 pViewSh
->DeactivateOle();
436 // get Dispatcher from ViewData (ViewFrame) instead of Shell (Frame), so it can't be null
437 pViewData
->GetDispatcher().ExecutePopup( ScResId(RID_POPUP_TAB
) );
441 void ScTabControl::StartDrag( sal_Int8
/* nAction */, const Point
& rPosPixel
)
443 ScModule
* pScMod
= SC_MOD();
444 bool bDisable
= pScMod
->IsFormulaMode() || pScMod
->IsModalMode();
448 vcl::Region
aRegion( Rectangle(0,0,0,0) );
449 CommandEvent
aCEvt( rPosPixel
, CommandEventId::StartDrag
, true ); // needed for StartDrag
450 if (TabBar::StartDrag( aCEvt
, aRegion
))
455 void ScTabControl::DoDrag( const vcl::Region
& /* rRegion */ )
457 ScDocShell
* pDocSh
= pViewData
->GetDocShell();
458 ScDocument
& rDoc
= pDocSh
->GetDocument();
460 SCTAB nTab
= pViewData
->GetTabNo();
461 ScRange
aTabRange( 0, 0, nTab
, MAXCOL
, MAXROW
, nTab
);
462 ScMarkData aTabMark
= pViewData
->GetMarkData();
463 aTabMark
.ResetMark(); // doesn't change marked table information
464 aTabMark
.SetMarkArea( aTabRange
);
466 ScDocument
* pClipDoc
= new ScDocument( SCDOCMODE_CLIP
);
467 ScClipParam
aClipParam(aTabRange
, false);
468 rDoc
.CopyToClip(aClipParam
, pClipDoc
, &aTabMark
, false);
470 TransferableObjectDescriptor aObjDesc
;
471 pDocSh
->FillTransferableObjectDescriptor( aObjDesc
);
472 aObjDesc
.maDisplayName
= pDocSh
->GetMedium()->GetURLObject().GetURLNoPass();
473 // maSize is set in ScTransferObj ctor
475 ScTransferObj
* pTransferObj
= new ScTransferObj( pClipDoc
, aObjDesc
);
476 com::sun::star::uno::Reference
<com::sun::star::datatransfer::XTransferable
> xTransferable( pTransferObj
);
478 pTransferObj
->SetDragSourceFlags( SC_DROP_TABLE
);
480 pTransferObj
->SetDragSource( pDocSh
, aTabMark
);
482 vcl::Window
* pWindow
= pViewData
->GetActiveWin();
483 SC_MOD()->SetDragObject( pTransferObj
, NULL
); // for internal D&D
484 pTransferObj
->StartDrag( pWindow
, DND_ACTION_COPYMOVE
| DND_ACTION_LINK
);
487 static sal_uInt16
lcl_DocShellNr( ScDocument
* pDoc
)
489 sal_uInt16 nShellCnt
= 0;
490 SfxObjectShell
* pShell
= SfxObjectShell::GetFirst();
493 if ( pShell
->Type() == TYPE(ScDocShell
) )
495 if ( &static_cast<ScDocShell
*>(pShell
)->GetDocument() == pDoc
)
500 pShell
= SfxObjectShell::GetNext( *pShell
);
503 OSL_FAIL("Dokument nicht gefunden");
507 sal_Int8
ScTabControl::ExecuteDrop( const ExecuteDropEvent
& rEvt
)
511 ScDocument
* pDoc
= pViewData
->GetDocument();
512 const ScDragData
& rData
= SC_MOD()->GetDragData();
513 if ( rData
.pCellTransfer
&& ( rData
.pCellTransfer
->GetDragSourceFlags() & SC_DROP_TABLE
) &&
514 rData
.pCellTransfer
->GetSourceDocument() == pDoc
)
516 // moving of tables within the document
517 SCTAB nPos
= GetPrivatDropPos( rEvt
.maPosPixel
);
520 if ( nPos
== rData
.pCellTransfer
->GetVisibleTab() && rEvt
.mnAction
== DND_ACTION_MOVE
)
522 // #i83005# do nothing - don't move to the same position
523 // (too easily triggered unintentionally, and might take a long time in large documents)
527 if ( !pDoc
->GetChangeTrack() && pDoc
->IsDocEditable() )
529 //! use table selection from the tab control where dragging was started?
530 pViewData
->GetView()->MoveTable( lcl_DocShellNr(pDoc
), nPos
, rEvt
.mnAction
!= DND_ACTION_MOVE
);
532 rData
.pCellTransfer
->SetDragWasInternal(); // don't delete
533 return DND_ACTION_COPY
;
538 return DND_ACTION_NONE
;
541 sal_Int8
ScTabControl::AcceptDrop( const AcceptDropEvent
& rEvt
)
543 if ( rEvt
.mbLeaving
)
547 return rEvt
.mnAction
;
550 const ScDocument
* pDoc
= pViewData
->GetDocument();
551 const ScDragData
& rData
= SC_MOD()->GetDragData();
552 if ( rData
.pCellTransfer
&& ( rData
.pCellTransfer
->GetDragSourceFlags() & SC_DROP_TABLE
) &&
553 rData
.pCellTransfer
->GetSourceDocument() == pDoc
)
555 // moving of tables within the document
556 if ( !pDoc
->GetChangeTrack() && pDoc
->IsDocEditable() )
558 ShowDropPos( rEvt
.maPosPixel
);
559 return rEvt
.mnAction
;
562 else // switch sheets for all formats
564 SwitchPage( rEvt
.maPosPixel
); // switch sheet after timeout
565 return 0; // nothing can be dropped here
571 bool ScTabControl::StartRenaming()
573 if ( pViewData
->GetDocument()->IsDocEditable() )
579 TabBarAllowRenamingReturnCode
ScTabControl::AllowRenaming()
581 ScTabViewShell
* pViewSh
= pViewData
->GetViewShell();
582 OSL_ENSURE( pViewSh
, "pViewData->GetViewShell()" );
584 TabBarAllowRenamingReturnCode nRet
= TABBAR_RENAMING_CANCEL
;
585 sal_uInt16 nId
= GetEditPageId();
588 SCTAB nTab
= nId
- 1;
589 OUString aNewName
= GetEditText();
590 bool bDone
= pViewSh
->RenameTable( aNewName
, nTab
);
592 nRet
= TABBAR_RENAMING_YES
;
593 else if ( bErrorShown
)
595 // if the error message from this TabControl is currently visible,
596 // don't end edit mode now, to avoid problems when returning to
597 // the other call (showing the error) - this should not happen
598 OSL_FAIL("ScTabControl::AllowRenaming: nested calls");
599 nRet
= TABBAR_RENAMING_NO
;
601 else if ( Application::IsInModalMode() )
603 // don't show error message above any modal dialog
604 // instead cancel renaming without error message
605 nRet
= TABBAR_RENAMING_CANCEL
;
610 pViewSh
->ErrorMessage( STR_INVALIDTABNAME
);
612 nRet
= TABBAR_RENAMING_NO
;
618 void ScTabControl::EndRenaming()
621 pViewData
->GetView()->ActiveGrabFocus();
624 void ScTabControl::Mirror()
627 if( nSelPageIdByMouse
!= TabBar::PAGE_NOT_FOUND
)
629 Rectangle
aRect( GetPageRect( GetCurPageId() ) );
630 if( !aRect
.IsEmpty() )
631 SetPointerPosPixel( aRect
.Center() );
632 nSelPageIdByMouse
= TabBar::PAGE_NOT_FOUND
; // only once after a Select()
636 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */