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"
37 // STATIC DATA -----------------------------------------------------------
39 //==================================================================
41 ScTabControl::ScTabControl( Window
* pParent
, ScViewData
* pData
) :
43 WinBits(WB_BORDER
| WB_3DLOOK
| WB_SCROLL
| WB_RANGESELECT
|
44 WB_MULTISELECT
| WB_DRAG
| WB_SIZEABLE
) ),
45 DropTargetHelper( this ),
46 DragSourceHelper( this ),
48 nMouseClickPageId( TabBar::PAGE_NOT_FOUND
),
49 nSelPageIdByMouse( TabBar::PAGE_NOT_FOUND
),
52 ScDocument
* pDoc
= pViewData
->GetDocument();
56 SCTAB nCount
= pDoc
->GetTableCount();
57 for (SCTAB i
=0; i
<nCount
; i
++)
59 if (pDoc
->IsVisible(i
))
61 if (pDoc
->GetName(i
,aString
))
63 if ( pDoc
->IsScenario(i
) )
64 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
, TPB_SPECIAL
);
66 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
);
67 if ( !pDoc
->IsDefaultTabBgColor(i
) )
69 aTabBgColor
= pDoc
->GetTabBgColor(i
);
70 SetTabBgColor( static_cast<sal_uInt16
>(i
)+1, aTabBgColor
);
76 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
78 SetSizePixel( Size(SC_TABBAR_DEFWIDTH
, 0) );
80 SetSplitHdl( LINK( pViewData
->GetView(), ScTabView
, TabBarResize
) );
86 ScTabControl::~ScTabControl()
90 sal_uInt16
ScTabControl::GetMaxId() const
92 sal_uInt16 nVisCnt
= GetPageCount();
94 return GetPageId(nVisCnt
-1);
99 SCTAB
ScTabControl::GetPrivatDropPos(const Point
& rPos
)
101 sal_uInt16 nPos
= ShowDropPos(rPos
);
103 SCTAB nRealPos
= static_cast<SCTAB
>(nPos
);
107 ScDocument
* pDoc
= pViewData
->GetDocument();
109 SCTAB nCount
= pDoc
->GetTableCount();
111 sal_uInt16 nViewPos
=0;
113 for (SCTAB i
=0; i
<nCount
; i
++)
115 if (pDoc
->IsVisible(i
))
121 for (j
=i
+1; j
<nCount
; j
++)
123 if (pDoc
->IsVisible(j
))
137 void ScTabControl::MouseButtonDown( const MouseEvent
& rMEvt
)
139 ScModule
* pScMod
= SC_MOD();
140 if ( !pScMod
->IsModalMode() && !pScMod
->IsFormulaMode() && !IsInEditMode() )
143 pViewData
->GetViewShell()->SetActive(); // Appear und SetViewFrame
144 pViewData
->GetView()->ActiveGrabFocus();
147 /* Click into free area -> insert new sheet (like in Draw).
148 Needing clean left click without modifiers (may be context menu).
149 Remember clicks to all pages, to be able to move mouse pointer later. */
150 if( rMEvt
.IsLeft() && (rMEvt
.GetModifier() == 0) )
151 nMouseClickPageId
= GetPageId( rMEvt
.GetPosPixel(), true );
153 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
155 TabBar::MouseButtonDown( rMEvt
);
158 void ScTabControl::MouseButtonUp( const MouseEvent
& rMEvt
)
160 Point aPos
= PixelToLogic( rMEvt
.GetPosPixel() );
162 // mouse button down and up on same page?
163 if( nMouseClickPageId
!= GetPageId( aPos
, true ) )
164 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
166 if (nMouseClickPageId
== TabBar::INSERT_TAB_POS
)
168 // Insert a new sheet at the right end, with default name.
169 ScDocument
* pDoc
= pViewData
->GetDocument();
170 ScModule
* pScMod
= SC_MOD();
171 if (!pDoc
->IsDocEditable() || pScMod
->IsTableLocked())
174 pDoc
->CreateValidTabName(aName
);
175 SCTAB nTabCount
= pDoc
->GetTableCount();
176 pViewData
->GetViewShell()->InsertTable(aName
, nTabCount
);
180 if ( rMEvt
.GetClicks() == 2 && rMEvt
.IsLeft() && nMouseClickPageId
!= 0 && nMouseClickPageId
!= TAB_PAGE_NOTFOUND
)
182 SfxDispatcher
* pDispatcher
= pViewData
->GetViewShell()->GetViewFrame()->GetDispatcher();
183 pDispatcher
->Execute( FID_TAB_MENU_RENAME
, SFX_CALLMODE_SYNCHRON
| SFX_CALLMODE_RECORD
);
187 if( nMouseClickPageId
== 0 )
189 // Click in the area next to the existing tabs:
190 // #i70320# if several sheets are selected, deselect all ecxept the current sheet,
191 // otherwise add new sheet
192 sal_uInt16 nSlot
= ( GetSelectPageCount() > 1 ) ? FID_TAB_DESELECTALL
: FID_INS_TABLE
;
193 SfxDispatcher
* pDispatcher
= pViewData
->GetViewShell()->GetViewFrame()->GetDispatcher();
194 pDispatcher
->Execute( nSlot
, SFX_CALLMODE_SYNCHRON
| SFX_CALLMODE_RECORD
);
195 // forget page ID, to be really sure that the dialog is not called twice
196 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
199 TabBar::MouseButtonUp( rMEvt
);
202 void ScTabControl::Select()
204 /* Remember last clicked page ID. */
205 nSelPageIdByMouse
= nMouseClickPageId
;
206 /* Reset nMouseClickPageId, so that next Select() call may invalidate
207 nSelPageIdByMouse (i.e. if called from keyboard). */
208 nMouseClickPageId
= TabBar::PAGE_NOT_FOUND
;
210 ScModule
* pScMod
= SC_MOD();
211 ScDocument
* pDoc
= pViewData
->GetDocument();
212 ScMarkData
& rMark
= pViewData
->GetMarkData();
213 SCTAB nCount
= pDoc
->GetTableCount();
216 if ( pScMod
->IsTableLocked() ) // darf jetzt nicht umgeschaltet werden ?
218 // den alten Zustand des TabControls wiederherstellen:
220 for (i
=0; i
<nCount
; i
++)
221 SelectPage( static_cast<sal_uInt16
>(i
)+1, rMark
.GetTableSelect(i
) );
222 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
227 sal_uInt16 nCurId
= GetCurPageId();
228 if (!nCurId
) return; // kann vorkommen, wenn bei Excel-Import alles versteckt ist
229 sal_uInt16 nPage
= nCurId
- 1;
231 // OLE-inplace deaktivieren
232 if ( nPage
!= static_cast<sal_uInt16
>(pViewData
->GetTabNo()) )
233 pViewData
->GetView()->DrawMarkListHasChanged();
235 // InputEnterHandler nur wenn nicht Referenzeingabe
237 sal_Bool bRefMode
= pScMod
->IsFormulaMode();
239 pScMod
->InputEnterHandler();
241 for (i
=0; i
<nCount
; i
++)
242 rMark
.SelectTable( i
, IsPageSelected(static_cast<sal_uInt16
>(i
)+1) );
244 SfxDispatcher
& rDisp
= pViewData
->GetDispatcher();
245 if (rDisp
.IsLocked())
246 pViewData
->GetView()->SetTabNo( static_cast<SCTAB
>(nPage
) );
249 // Tabelle fuer Basic ist 1-basiert
250 SfxUInt16Item
aItem( SID_CURRENTTAB
, nPage
+ 1 );
251 rDisp
.Execute( SID_CURRENTTAB
, SFX_CALLMODE_SLOT
| SFX_CALLMODE_RECORD
,
252 &aItem
, (void*) NULL
);
255 SfxBindings
& rBind
= pViewData
->GetBindings();
256 rBind
.Invalidate( FID_FILL_TAB
);
257 rBind
.Invalidate( FID_TAB_DESELECTALL
);
259 rBind
.Invalidate( FID_INS_TABLE
);
260 rBind
.Invalidate( FID_TAB_APPEND
);
261 rBind
.Invalidate( FID_TAB_MOVE
);
262 rBind
.Invalidate( FID_TAB_RENAME
);
263 rBind
.Invalidate( FID_DELETE_TABLE
);
264 rBind
.Invalidate( FID_TABLE_SHOW
);
265 rBind
.Invalidate( FID_TABLE_HIDE
);
266 rBind
.Invalidate( FID_TAB_SET_TAB_BG_COLOR
);
268 // SetReference nur wenn der Konsolidieren-Dialog offen ist
269 // (fuer Referenzen ueber mehrere Tabellen)
270 // bei anderen gibt das nur unnoetiges Gezappel
272 if ( bRefMode
&& pViewData
->GetRefType() == SC_REFTYPE_REF
)
273 if ( pViewData
->GetViewShell()->GetViewFrame()->HasChildWindow(SID_OPENDLG_CONSOLIDATE
) )
276 pViewData
->GetRefStartX(), pViewData
->GetRefStartY(), pViewData
->GetRefStartZ(),
277 pViewData
->GetRefEndX(), pViewData
->GetRefEndY(), pViewData
->GetRefEndZ() );
278 pScMod
->SetReference( aRange
, pDoc
, &rMark
);
279 pScMod
->EndReference(); // wegen Auto-Hide
283 void ScTabControl::UpdateInputContext()
285 ScDocument
* pDoc
= pViewData
->GetDocument();
286 WinBits nStyle
= GetStyle();
287 if (pDoc
->GetDocumentShell()->IsReadOnly())
288 // no insert sheet tab for readonly doc.
289 SetStyle((nStyle
& ~WB_INSERTTAB
));
291 SetStyle((nStyle
| WB_INSERTTAB
));
294 void ScTabControl::UpdateStatus()
296 ScDocument
* pDoc
= pViewData
->GetDocument();
297 ScMarkData
& rMark
= pViewData
->GetMarkData();
298 sal_Bool bActive
= pViewData
->IsActive();
300 SCTAB nCount
= pDoc
->GetTableCount();
303 SCTAB nMaxCnt
= std::max( nCount
, static_cast<SCTAB
>(GetMaxId()) );
306 sal_Bool bModified
= false; // Tabellen-Namen
307 for (i
=0; i
<nMaxCnt
&& !bModified
; i
++)
309 if (pDoc
->IsVisible(i
))
311 pDoc
->GetName(i
,aString
);
312 aTabBgColor
= pDoc
->GetTabBgColor(i
);
316 aString
= OUString();
319 if ( !aString
.equals(GetPageText(static_cast<sal_uInt16
>(i
)+1)) || (GetTabBgColor(static_cast<sal_uInt16
>(i
)+1) != aTabBgColor
) )
320 bModified
= sal_True
;
326 for (i
=0; i
<nCount
; i
++)
328 if (pDoc
->IsVisible(i
))
330 if (pDoc
->GetName(i
,aString
))
332 if ( pDoc
->IsScenario(i
) )
333 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
, TPB_SPECIAL
);
335 InsertPage( static_cast<sal_uInt16
>(i
)+1, aString
);
336 if ( !pDoc
->IsDefaultTabBgColor(i
) )
338 aTabBgColor
= pDoc
->GetTabBgColor(i
);
339 SetTabBgColor( static_cast<sal_uInt16
>(i
)+1, aTabBgColor
);
345 SetCurPageId( static_cast<sal_uInt16
>(pViewData
->GetTabNo()) + 1 );
349 bModified
= false; // Selektion
350 for (i
=0; i
<nMaxCnt
&& !bModified
; i
++)
351 if ( rMark
.GetTableSelect(i
) != (bool) IsPageSelected(static_cast<sal_uInt16
>(i
)+1) )
352 bModified
= sal_True
;
354 // #i99576# the following loop is mis-optimized on unxsoli4 and the reason
355 // why this file is in NOOPTFILES.
357 for (i
=0; i
<nCount
; i
++)
358 SelectPage( static_cast<sal_uInt16
>(i
)+1, rMark
.GetTableSelect(i
) );
365 void ScTabControl::SetSheetLayoutRTL( sal_Bool bSheetRTL
)
367 SetEffectiveRTL( bSheetRTL
);
368 nSelPageIdByMouse
= TabBar::PAGE_NOT_FOUND
;
372 void ScTabControl::Command( const CommandEvent
& rCEvt
)
374 ScModule
* pScMod
= SC_MOD();
375 ScTabViewShell
* pViewSh
= pViewData
->GetViewShell();
376 sal_Bool bDisable
= pScMod
->IsFormulaMode() || pScMod
->IsModalMode();
378 // ViewFrame erstmal aktivieren (Bug 19493):
379 pViewSh
->SetActive();
381 sal_uInt16 nCmd
= rCEvt
.GetCommand();
382 if ( nCmd
== COMMAND_CONTEXTMENU
)
386 // #i18735# select the page that is under the mouse cursor
387 // if multiple tables are selected and the one under the cursor
388 // is not part of them then unselect them
389 sal_uInt16 nId
= GetPageId( rCEvt
.GetMousePosPixel() );
392 sal_Bool bAlreadySelected
= IsPageSelected( nId
);
393 //make the clicked page the current one
395 //change the selection when the current one is not already
396 //selected or part of a multi selection
397 if(!bAlreadySelected
)
399 sal_uInt16 nCount
= GetMaxId();
401 for (sal_uInt16 i
=1; i
<=nCount
; i
++)
402 SelectPage( i
, i
==nId
);
407 // #i52073# OLE inplace editing has to be stopped before showing the sheet tab context menu
408 pViewSh
->DeactivateOle();
411 // get Dispatcher from ViewData (ViewFrame) instead of Shell (Frame), so it can't be null
412 pViewData
->GetDispatcher().ExecutePopup( ScResId(RID_POPUP_TAB
) );
417 void ScTabControl::StartDrag( sal_Int8
/* nAction */, const Point
& rPosPixel
)
419 ScModule
* pScMod
= SC_MOD();
420 sal_Bool bDisable
= pScMod
->IsFormulaMode() || pScMod
->IsModalMode();
424 Region
aRegion( Rectangle(0,0,0,0) );
425 CommandEvent
aCEvt( rPosPixel
, COMMAND_STARTDRAG
, sal_True
); // needed for StartDrag
426 if (TabBar::StartDrag( aCEvt
, aRegion
))
431 void ScTabControl::DoDrag( const Region
& /* rRegion */ )
433 ScDocShell
* pDocSh
= pViewData
->GetDocShell();
434 ScDocument
* pDoc
= pDocSh
->GetDocument();
436 SCTAB nTab
= pViewData
->GetTabNo();
437 ScRange
aTabRange( 0, 0, nTab
, MAXCOL
, MAXROW
, nTab
);
438 ScMarkData aTabMark
= pViewData
->GetMarkData();
439 aTabMark
.ResetMark(); // doesn't change marked table information
440 aTabMark
.SetMarkArea( aTabRange
);
442 ScDocument
* pClipDoc
= new ScDocument( SCDOCMODE_CLIP
);
443 ScClipParam
aClipParam(aTabRange
, false);
444 pDoc
->CopyToClip(aClipParam
, pClipDoc
, &aTabMark
, false);
446 TransferableObjectDescriptor aObjDesc
;
447 pDocSh
->FillTransferableObjectDescriptor( aObjDesc
);
448 aObjDesc
.maDisplayName
= pDocSh
->GetMedium()->GetURLObject().GetURLNoPass();
449 // maSize is set in ScTransferObj ctor
451 ScTransferObj
* pTransferObj
= new ScTransferObj( pClipDoc
, aObjDesc
);
452 com::sun::star::uno::Reference
<com::sun::star::datatransfer::XTransferable
> xTransferable( pTransferObj
);
454 pTransferObj
->SetDragSourceFlags( SC_DROP_TABLE
);
456 pTransferObj
->SetDragSource( pDocSh
, aTabMark
);
458 Window
* pWindow
= pViewData
->GetActiveWin();
459 SC_MOD()->SetDragObject( pTransferObj
, NULL
); // for internal D&D
460 pTransferObj
->StartDrag( pWindow
, DND_ACTION_COPYMOVE
| DND_ACTION_LINK
);
463 static sal_uInt16
lcl_DocShellNr( ScDocument
* pDoc
)
465 sal_uInt16 nShellCnt
= 0;
466 SfxObjectShell
* pShell
= SfxObjectShell::GetFirst();
469 if ( pShell
->Type() == TYPE(ScDocShell
) )
471 if ( ((ScDocShell
*)pShell
)->GetDocument() == pDoc
)
476 pShell
= SfxObjectShell::GetNext( *pShell
);
479 OSL_FAIL("Dokument nicht gefunden");
483 sal_Int8
ScTabControl::ExecuteDrop( const ExecuteDropEvent
& rEvt
)
487 ScDocument
* pDoc
= pViewData
->GetDocument();
488 const ScDragData
& rData
= SC_MOD()->GetDragData();
489 if ( rData
.pCellTransfer
&& ( rData
.pCellTransfer
->GetDragSourceFlags() & SC_DROP_TABLE
) &&
490 rData
.pCellTransfer
->GetSourceDocument() == pDoc
)
492 // moving of tables within the document
493 SCTAB nPos
= GetPrivatDropPos( rEvt
.maPosPixel
);
496 if ( nPos
== rData
.pCellTransfer
->GetVisibleTab() && rEvt
.mnAction
== DND_ACTION_MOVE
)
498 // #i83005# do nothing - don't move to the same position
499 // (too easily triggered unintentionally, and might take a long time in large documents)
503 if ( !pDoc
->GetChangeTrack() && pDoc
->IsDocEditable() )
505 //! use table selection from the tab control where dragging was started?
506 pViewData
->GetView()->MoveTable( lcl_DocShellNr(pDoc
), nPos
, rEvt
.mnAction
!= DND_ACTION_MOVE
);
508 rData
.pCellTransfer
->SetDragWasInternal(); // don't delete
517 sal_Int8
ScTabControl::AcceptDrop( const AcceptDropEvent
& rEvt
)
519 if ( rEvt
.mbLeaving
)
523 return rEvt
.mnAction
;
526 const ScDocument
* pDoc
= pViewData
->GetDocument();
527 const ScDragData
& rData
= SC_MOD()->GetDragData();
528 if ( rData
.pCellTransfer
&& ( rData
.pCellTransfer
->GetDragSourceFlags() & SC_DROP_TABLE
) &&
529 rData
.pCellTransfer
->GetSourceDocument() == pDoc
)
531 // moving of tables within the document
532 if ( !pDoc
->GetChangeTrack() && pDoc
->IsDocEditable() )
534 ShowDropPos( rEvt
.maPosPixel
);
535 return rEvt
.mnAction
;
538 else // switch sheets for all formats
540 SwitchPage( rEvt
.maPosPixel
); // switch sheet after timeout
541 return 0; // nothing can be dropped here
547 long ScTabControl::StartRenaming()
549 if ( pViewData
->GetDocument()->IsDocEditable() )
550 return TABBAR_RENAMING_YES
;
552 return TABBAR_RENAMING_NO
;
555 long ScTabControl::AllowRenaming()
557 ScTabViewShell
* pViewSh
= pViewData
->GetViewShell();
558 OSL_ENSURE( pViewSh
, "pViewData->GetViewShell()" );
560 long nRet
= TABBAR_RENAMING_CANCEL
;
561 sal_uInt16 nId
= GetEditPageId();
564 SCTAB nTab
= nId
- 1;
565 String aNewName
= GetEditText();
566 sal_Bool bDone
= pViewSh
->RenameTable( aNewName
, nTab
);
568 nRet
= TABBAR_RENAMING_YES
;
569 else if ( bErrorShown
)
571 // if the error message from this TabControl is currently visible,
572 // don't end edit mode now, to avoid problems when returning to
573 // the other call (showing the error) - this should not happen
574 OSL_FAIL("ScTabControl::AllowRenaming: nested calls");
575 nRet
= TABBAR_RENAMING_NO
;
577 else if ( Application::IsInModalMode() )
579 // don't show error message above any modal dialog
580 // instead cancel renaming without error message
581 nRet
= TABBAR_RENAMING_CANCEL
;
585 bErrorShown
= sal_True
;
586 pViewSh
->ErrorMessage( STR_INVALIDTABNAME
);
588 nRet
= TABBAR_RENAMING_NO
;
594 void ScTabControl::EndRenaming()
597 pViewData
->GetView()->ActiveGrabFocus();
600 void ScTabControl::Mirror()
603 if( nSelPageIdByMouse
!= TabBar::PAGE_NOT_FOUND
)
605 Rectangle
aRect( GetPageRect( GetCurPageId() ) );
606 if( !aRect
.IsEmpty() )
607 SetPointerPosPixel( aRect
.Center() );
608 nSelPageIdByMouse
= TabBar::PAGE_NOT_FOUND
; // only once after a Select()
614 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */