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( Window
* pParent
, ScViewData
* pData
) :
42 WinBits(WB_BORDER
| WB_3DLOOK
| WB_SCROLL
| WB_RANGESELECT
|
43 WB_MULTISELECT
| WB_DRAG
| WB_SIZEABLE
) ),
44 DropTargetHelper( this ),
45 DragSourceHelper( this ),
47 nMouseClickPageId( TabBar::PAGE_NOT_FOUND
),
48 nSelPageIdByMouse( TabBar::PAGE_NOT_FOUND
),
51 ScDocument
* pDoc
= pViewData
->GetDocument();
55 SCTAB nCount
= pDoc
->GetTableCount();
56 for (SCTAB i
=0; i
<nCount
; i
++)
58 if (pDoc
->IsVisible(i
))
60 if (pDoc
->GetName(i
,aString
))
62 if ( pDoc
->IsScenario(i
) )
63 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
, TPB_SPECIAL
);
65 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
);
66 if ( !pDoc
->IsDefaultTabBgColor(i
) )
68 aTabBgColor
= pDoc
->GetTabBgColor(i
);
69 SetTabBgColor( static_cast<sal_uInt16
>(i
)+1, aTabBgColor
);
75 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
77 SetSizePixel( Size(SC_TABBAR_DEFWIDTH
, 0) );
79 SetSplitHdl( LINK( pViewData
->GetView(), ScTabView
, TabBarResize
) );
84 SetScrollAlwaysEnabled(true);
86 SetScrollAreaContextHdl( LINK( this, ScTabControl
, ShowPageList
) );
89 IMPL_LINK(ScTabControl
, ShowPageList
, const CommandEvent
*, pEvent
)
93 sal_uInt16 nCurPageId
= GetCurPageId();
95 ScDocument
* pDoc
= pViewData
->GetDocument();
96 SCTAB nCount
= pDoc
->GetTableCount();
97 for (SCTAB i
=0; i
<nCount
; ++i
)
99 if (pDoc
->IsVisible(i
))
102 if (pDoc
->GetName(i
, aString
))
104 sal_uInt16 nId
= static_cast<sal_uInt16
>(i
)+1;
105 aPopup
.InsertItem(nId
, aString
, MIB_CHECKABLE
);
106 if (nId
== nCurPageId
)
107 aPopup
.CheckItem(nId
);
112 sal_uInt16 nItemId
= aPopup
.Execute( this, pEvent
->GetMousePosPixel() );
113 SwitchToPageId(nItemId
);
118 ScTabControl::~ScTabControl()
122 sal_uInt16
ScTabControl::GetMaxId() const
124 sal_uInt16 nVisCnt
= GetPageCount();
126 return GetPageId(nVisCnt
-1);
131 SCTAB
ScTabControl::GetPrivatDropPos(const Point
& rPos
)
133 sal_uInt16 nPos
= ShowDropPos(rPos
);
135 SCTAB nRealPos
= static_cast<SCTAB
>(nPos
);
139 ScDocument
* pDoc
= pViewData
->GetDocument();
141 SCTAB nCount
= pDoc
->GetTableCount();
143 sal_uInt16 nViewPos
=0;
145 for (SCTAB i
=0; i
<nCount
; i
++)
147 if (pDoc
->IsVisible(i
))
153 for (j
=i
+1; j
<nCount
; j
++)
155 if (pDoc
->IsVisible(j
))
169 void ScTabControl::MouseButtonDown( const MouseEvent
& rMEvt
)
171 ScModule
* pScMod
= SC_MOD();
172 if ( !pScMod
->IsModalMode() && !pScMod
->IsFormulaMode() && !IsInEditMode() )
175 pViewData
->GetViewShell()->SetActive(); // Appear und SetViewFrame
176 pViewData
->GetView()->ActiveGrabFocus();
179 /* Click into free area -> insert new sheet (like in Draw).
180 Needing clean left click without modifiers (may be context menu).
181 Remember clicks to all pages, to be able to move mouse pointer later. */
182 if( rMEvt
.IsLeft() && (rMEvt
.GetModifier() == 0) )
183 nMouseClickPageId
= GetPageId( rMEvt
.GetPosPixel(), true );
185 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
187 TabBar::MouseButtonDown( rMEvt
);
190 void ScTabControl::MouseButtonUp( const MouseEvent
& rMEvt
)
192 Point aPos
= PixelToLogic( rMEvt
.GetPosPixel() );
194 // mouse button down and up on same page?
195 if( nMouseClickPageId
!= GetPageId( aPos
, true ) )
196 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
198 if (nMouseClickPageId
== TabBar::INSERT_TAB_POS
)
200 // Insert a new sheet at the right end, with default name.
201 ScDocument
* pDoc
= pViewData
->GetDocument();
202 ScModule
* pScMod
= SC_MOD();
203 if (!pDoc
->IsDocEditable() || pScMod
->IsTableLocked())
206 pDoc
->CreateValidTabName(aName
);
207 SCTAB nTabCount
= pDoc
->GetTableCount();
208 pViewData
->GetViewShell()->InsertTable(aName
, nTabCount
);
212 if ( rMEvt
.GetClicks() == 2 && rMEvt
.IsLeft() && nMouseClickPageId
!= 0 && nMouseClickPageId
!= TAB_PAGE_NOTFOUND
)
214 SfxDispatcher
* pDispatcher
= pViewData
->GetViewShell()->GetViewFrame()->GetDispatcher();
215 pDispatcher
->Execute( FID_TAB_MENU_RENAME
, SFX_CALLMODE_SYNCHRON
| SFX_CALLMODE_RECORD
);
219 if( nMouseClickPageId
== 0 )
221 // Click in the area next to the existing tabs:
222 // #i70320# if several sheets are selected, deselect all ecxept the current sheet,
223 // otherwise add new sheet
224 sal_uInt16 nSlot
= ( GetSelectPageCount() > 1 ) ? FID_TAB_DESELECTALL
: FID_INS_TABLE
;
225 SfxDispatcher
* pDispatcher
= pViewData
->GetViewShell()->GetViewFrame()->GetDispatcher();
226 pDispatcher
->Execute( nSlot
, SFX_CALLMODE_SYNCHRON
| SFX_CALLMODE_RECORD
);
227 // forget page ID, to be really sure that the dialog is not called twice
228 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
231 TabBar::MouseButtonUp( rMEvt
);
234 void ScTabControl::Select()
236 /* Remember last clicked page ID. */
237 nSelPageIdByMouse
= nMouseClickPageId
;
238 /* Reset nMouseClickPageId, so that next Select() call may invalidate
239 nSelPageIdByMouse (i.e. if called from keyboard). */
240 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
242 ScModule
* pScMod
= SC_MOD();
243 ScDocument
* pDoc
= pViewData
->GetDocument();
244 ScMarkData
& rMark
= pViewData
->GetMarkData();
245 SCTAB nCount
= pDoc
->GetTableCount();
248 if ( pScMod
->IsTableLocked() ) // darf jetzt nicht umgeschaltet werden ?
250 // den alten Zustand des TabControls wiederherstellen:
252 for (i
=0; i
<nCount
; i
++)
253 SelectPage( static_cast<sal_uInt16
>(i
)+1, rMark
.GetTableSelect(i
) );
254 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
259 sal_uInt16 nCurId
= GetCurPageId();
260 if (!nCurId
) return; // kann vorkommen, wenn bei Excel-Import alles versteckt ist
261 sal_uInt16 nPage
= nCurId
- 1;
263 // OLE-inplace deaktivieren
264 if ( nPage
!= static_cast<sal_uInt16
>(pViewData
->GetTabNo()) )
265 pViewData
->GetView()->DrawMarkListHasChanged();
267 // InputEnterHandler nur wenn nicht Referenzeingabe
269 bool bRefMode
= pScMod
->IsFormulaMode();
271 pScMod
->InputEnterHandler();
273 for (i
=0; i
<nCount
; i
++)
274 rMark
.SelectTable( i
, IsPageSelected(static_cast<sal_uInt16
>(i
)+1) );
276 SfxDispatcher
& rDisp
= pViewData
->GetDispatcher();
277 if (rDisp
.IsLocked())
278 pViewData
->GetView()->SetTabNo( static_cast<SCTAB
>(nPage
) );
281 // Tabelle fuer Basic ist 1-basiert
282 SfxUInt16Item
aItem( SID_CURRENTTAB
, nPage
+ 1 );
283 rDisp
.Execute( SID_CURRENTTAB
, SFX_CALLMODE_SLOT
| SFX_CALLMODE_RECORD
,
284 &aItem
, (void*) NULL
);
287 SfxBindings
& rBind
= pViewData
->GetBindings();
288 rBind
.Invalidate( FID_FILL_TAB
);
289 rBind
.Invalidate( FID_TAB_DESELECTALL
);
291 rBind
.Invalidate( FID_INS_TABLE
);
292 rBind
.Invalidate( FID_TAB_APPEND
);
293 rBind
.Invalidate( FID_TAB_MOVE
);
294 rBind
.Invalidate( FID_TAB_RENAME
);
295 rBind
.Invalidate( FID_DELETE_TABLE
);
296 rBind
.Invalidate( FID_TABLE_SHOW
);
297 rBind
.Invalidate( FID_TABLE_HIDE
);
298 rBind
.Invalidate( FID_TAB_SET_TAB_BG_COLOR
);
300 // SetReference nur wenn der Konsolidieren-Dialog offen ist
301 // (fuer Referenzen ueber mehrere Tabellen)
302 // bei anderen gibt das nur unnoetiges Gezappel
304 if ( bRefMode
&& pViewData
->GetRefType() == SC_REFTYPE_REF
)
305 if ( pViewData
->GetViewShell()->GetViewFrame()->HasChildWindow(SID_OPENDLG_CONSOLIDATE
) )
308 pViewData
->GetRefStartX(), pViewData
->GetRefStartY(), pViewData
->GetRefStartZ(),
309 pViewData
->GetRefEndX(), pViewData
->GetRefEndY(), pViewData
->GetRefEndZ() );
310 pScMod
->SetReference( aRange
, pDoc
, &rMark
);
311 pScMod
->EndReference(); // wegen Auto-Hide
315 void ScTabControl::UpdateInputContext()
317 ScDocument
* pDoc
= pViewData
->GetDocument();
318 WinBits nStyle
= GetStyle();
319 if (pDoc
->GetDocumentShell()->IsReadOnly())
320 // no insert sheet tab for readonly doc.
321 SetStyle((nStyle
& ~WB_INSERTTAB
));
323 SetStyle((nStyle
| WB_INSERTTAB
));
326 void ScTabControl::UpdateStatus()
328 ScDocument
* pDoc
= pViewData
->GetDocument();
329 ScMarkData
& rMark
= pViewData
->GetMarkData();
330 bool bActive
= pViewData
->IsActive();
332 SCTAB nCount
= pDoc
->GetTableCount();
335 SCTAB nMaxCnt
= std::max( nCount
, static_cast<SCTAB
>(GetMaxId()) );
338 bool bModified
= false; // Tabellen-Namen
339 for (i
=0; i
<nMaxCnt
&& !bModified
; i
++)
341 if (pDoc
->IsVisible(i
))
343 pDoc
->GetName(i
,aString
);
344 aTabBgColor
= pDoc
->GetTabBgColor(i
);
348 aString
= OUString();
351 if ( !aString
.equals(GetPageText(static_cast<sal_uInt16
>(i
)+1)) || (GetTabBgColor(static_cast<sal_uInt16
>(i
)+1) != aTabBgColor
) )
358 for (i
=0; i
<nCount
; i
++)
360 if (pDoc
->IsVisible(i
))
362 if (pDoc
->GetName(i
,aString
))
364 if ( pDoc
->IsScenario(i
) )
365 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
, TPB_SPECIAL
);
367 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
);
368 if ( !pDoc
->IsDefaultTabBgColor(i
) )
370 aTabBgColor
= pDoc
->GetTabBgColor(i
);
371 SetTabBgColor( static_cast<sal_uInt16
>(i
)+1, aTabBgColor
);
377 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
381 bModified
= false; // Selektion
382 for (i
=0; i
<nMaxCnt
&& !bModified
; i
++)
383 if ( rMark
.GetTableSelect(i
) != (bool) IsPageSelected(static_cast<sal_uInt16
>(i
)+1) )
386 // #i99576# the following loop is mis-optimized on unxsoli4 and the reason
387 // why this file is in NOOPTFILES.
389 for (i
=0; i
<nCount
; i
++)
390 SelectPage( static_cast<sal_uInt16
>(i
)+1, rMark
.GetTableSelect(i
) );
397 void ScTabControl::SetSheetLayoutRTL( bool bSheetRTL
)
399 SetEffectiveRTL( bSheetRTL
);
400 nSelPageIdByMouse
= TabBar::PAGE_NOT_FOUND
;
403 void ScTabControl::SwitchToPageId(sal_uInt16 nId
)
407 bool bAlreadySelected
= IsPageSelected( nId
);
408 //make the clicked page the current one
410 //change the selection when the current one is not already
411 //selected or part of a multi selection
412 if(!bAlreadySelected
)
414 sal_uInt16 nCount
= GetMaxId();
416 for (sal_uInt16 i
=1; i
<=nCount
; i
++)
417 SelectPage( i
, i
==nId
);
423 void ScTabControl::Command( const CommandEvent
& rCEvt
)
425 ScModule
* pScMod
= SC_MOD();
426 ScTabViewShell
* pViewSh
= pViewData
->GetViewShell();
427 bool bDisable
= pScMod
->IsFormulaMode() || pScMod
->IsModalMode();
429 // ViewFrame erstmal aktivieren (Bug 19493):
430 pViewSh
->SetActive();
432 sal_uInt16 nCmd
= rCEvt
.GetCommand();
433 if ( nCmd
== COMMAND_CONTEXTMENU
)
437 // #i18735# select the page that is under the mouse cursor
438 // if multiple tables are selected and the one under the cursor
439 // is not part of them then unselect them
440 sal_uInt16 nId
= GetPageId( rCEvt
.GetMousePosPixel() );
443 // #i52073# OLE inplace editing has to be stopped before showing the sheet tab context menu
444 pViewSh
->DeactivateOle();
447 // get Dispatcher from ViewData (ViewFrame) instead of Shell (Frame), so it can't be null
448 pViewData
->GetDispatcher().ExecutePopup( ScResId(RID_POPUP_TAB
) );
453 void ScTabControl::StartDrag( sal_Int8
/* nAction */, const Point
& rPosPixel
)
455 ScModule
* pScMod
= SC_MOD();
456 bool bDisable
= pScMod
->IsFormulaMode() || pScMod
->IsModalMode();
460 Region
aRegion( Rectangle(0,0,0,0) );
461 CommandEvent
aCEvt( rPosPixel
, COMMAND_STARTDRAG
, true ); // needed for StartDrag
462 if (TabBar::StartDrag( aCEvt
, aRegion
))
467 void ScTabControl::DoDrag( const Region
& /* rRegion */ )
469 ScDocShell
* pDocSh
= pViewData
->GetDocShell();
470 ScDocument
* pDoc
= pDocSh
->GetDocument();
472 SCTAB nTab
= pViewData
->GetTabNo();
473 ScRange
aTabRange( 0, 0, nTab
, MAXCOL
, MAXROW
, nTab
);
474 ScMarkData aTabMark
= pViewData
->GetMarkData();
475 aTabMark
.ResetMark(); // doesn't change marked table information
476 aTabMark
.SetMarkArea( aTabRange
);
478 ScDocument
* pClipDoc
= new ScDocument( SCDOCMODE_CLIP
);
479 ScClipParam
aClipParam(aTabRange
, false);
480 pDoc
->CopyToClip(aClipParam
, pClipDoc
, &aTabMark
, false);
482 TransferableObjectDescriptor aObjDesc
;
483 pDocSh
->FillTransferableObjectDescriptor( aObjDesc
);
484 aObjDesc
.maDisplayName
= pDocSh
->GetMedium()->GetURLObject().GetURLNoPass();
485 // maSize is set in ScTransferObj ctor
487 ScTransferObj
* pTransferObj
= new ScTransferObj( pClipDoc
, aObjDesc
);
488 com::sun::star::uno::Reference
<com::sun::star::datatransfer::XTransferable
> xTransferable( pTransferObj
);
490 pTransferObj
->SetDragSourceFlags( SC_DROP_TABLE
);
492 pTransferObj
->SetDragSource( pDocSh
, aTabMark
);
494 Window
* pWindow
= pViewData
->GetActiveWin();
495 SC_MOD()->SetDragObject( pTransferObj
, NULL
); // for internal D&D
496 pTransferObj
->StartDrag( pWindow
, DND_ACTION_COPYMOVE
| DND_ACTION_LINK
);
499 static sal_uInt16
lcl_DocShellNr( ScDocument
* pDoc
)
501 sal_uInt16 nShellCnt
= 0;
502 SfxObjectShell
* pShell
= SfxObjectShell::GetFirst();
505 if ( pShell
->Type() == TYPE(ScDocShell
) )
507 if ( ((ScDocShell
*)pShell
)->GetDocument() == pDoc
)
512 pShell
= SfxObjectShell::GetNext( *pShell
);
515 OSL_FAIL("Dokument nicht gefunden");
519 sal_Int8
ScTabControl::ExecuteDrop( const ExecuteDropEvent
& rEvt
)
523 ScDocument
* pDoc
= pViewData
->GetDocument();
524 const ScDragData
& rData
= SC_MOD()->GetDragData();
525 if ( rData
.pCellTransfer
&& ( rData
.pCellTransfer
->GetDragSourceFlags() & SC_DROP_TABLE
) &&
526 rData
.pCellTransfer
->GetSourceDocument() == pDoc
)
528 // moving of tables within the document
529 SCTAB nPos
= GetPrivatDropPos( rEvt
.maPosPixel
);
532 if ( nPos
== rData
.pCellTransfer
->GetVisibleTab() && rEvt
.mnAction
== DND_ACTION_MOVE
)
534 // #i83005# do nothing - don't move to the same position
535 // (too easily triggered unintentionally, and might take a long time in large documents)
539 if ( !pDoc
->GetChangeTrack() && pDoc
->IsDocEditable() )
541 //! use table selection from the tab control where dragging was started?
542 pViewData
->GetView()->MoveTable( lcl_DocShellNr(pDoc
), nPos
, rEvt
.mnAction
!= DND_ACTION_MOVE
);
544 rData
.pCellTransfer
->SetDragWasInternal(); // don't delete
553 sal_Int8
ScTabControl::AcceptDrop( const AcceptDropEvent
& rEvt
)
555 if ( rEvt
.mbLeaving
)
559 return rEvt
.mnAction
;
562 const ScDocument
* pDoc
= pViewData
->GetDocument();
563 const ScDragData
& rData
= SC_MOD()->GetDragData();
564 if ( rData
.pCellTransfer
&& ( rData
.pCellTransfer
->GetDragSourceFlags() & SC_DROP_TABLE
) &&
565 rData
.pCellTransfer
->GetSourceDocument() == pDoc
)
567 // moving of tables within the document
568 if ( !pDoc
->GetChangeTrack() && pDoc
->IsDocEditable() )
570 ShowDropPos( rEvt
.maPosPixel
);
571 return rEvt
.mnAction
;
574 else // switch sheets for all formats
576 SwitchPage( rEvt
.maPosPixel
); // switch sheet after timeout
577 return 0; // nothing can be dropped here
583 bool ScTabControl::StartRenaming()
585 if ( pViewData
->GetDocument()->IsDocEditable() )
591 TabBarAllowRenamingReturnCode
ScTabControl::AllowRenaming()
593 ScTabViewShell
* pViewSh
= pViewData
->GetViewShell();
594 OSL_ENSURE( pViewSh
, "pViewData->GetViewShell()" );
596 TabBarAllowRenamingReturnCode nRet
= TABBAR_RENAMING_CANCEL
;
597 sal_uInt16 nId
= GetEditPageId();
600 SCTAB nTab
= nId
- 1;
601 OUString aNewName
= GetEditText();
602 bool bDone
= pViewSh
->RenameTable( aNewName
, nTab
);
604 nRet
= TABBAR_RENAMING_YES
;
605 else if ( bErrorShown
)
607 // if the error message from this TabControl is currently visible,
608 // don't end edit mode now, to avoid problems when returning to
609 // the other call (showing the error) - this should not happen
610 OSL_FAIL("ScTabControl::AllowRenaming: nested calls");
611 nRet
= TABBAR_RENAMING_NO
;
613 else if ( Application::IsInModalMode() )
615 // don't show error message above any modal dialog
616 // instead cancel renaming without error message
617 nRet
= TABBAR_RENAMING_CANCEL
;
622 pViewSh
->ErrorMessage( STR_INVALIDTABNAME
);
624 nRet
= TABBAR_RENAMING_NO
;
630 void ScTabControl::EndRenaming()
633 pViewData
->GetView()->ActiveGrabFocus();
636 void ScTabControl::Mirror()
639 if( nSelPageIdByMouse
!= TabBar::PAGE_NOT_FOUND
)
641 Rectangle
aRect( GetPageRect( GetCurPageId() ) );
642 if( !aRect
.IsEmpty() )
643 SetPointerPosPixel( aRect
.Center() );
644 nSelPageIdByMouse
= TabBar::PAGE_NOT_FOUND
; // only once after a Select()
648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */