Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / ui / view / tabcont.cxx
blobb9c837c400c261233feea8786a128907173277d4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
27 #include "docsh.hxx"
28 #include "scmod.hxx"
29 #include "scresid.hxx"
30 #include "sc.hrc"
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)
42 , pViewData(pData)
43 , nMouseClickPageId(TabBar::PAGE_NOT_FOUND)
44 , nSelPageIdByMouse(TabBar::PAGE_NOT_FOUND)
45 , bErrorShown(false)
47 ScDocument* pDoc = pViewData->GetDocument();
49 OUString aString;
50 Color aTabBgColor;
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 );
60 else
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 ) );
77 EnableEditMode();
78 UpdateInputContext();
80 SetScrollAlwaysEnabled(false);
82 SetScrollAreaContextHdl( LINK( this, ScTabControl, ShowPageList ) );
85 IMPL_LINK_TYPED(ScTabControl, ShowPageList, const CommandEvent &, rEvent, void)
87 PopupMenu aPopup;
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))
97 OUString aString;
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();
119 if (nVisCnt)
120 return GetPageId(nVisCnt-1);
122 return 0;
125 SCTAB ScTabControl::GetPrivatDropPos(const Point& rPos )
127 sal_uInt16 nPos = ShowDropPos(rPos);
129 SCTAB nRealPos = static_cast<SCTAB>(nPos);
131 if(nPos !=0 )
133 ScDocument* pDoc = pViewData->GetDocument();
135 SCTAB nCount = pDoc->GetTableCount();
137 sal_uInt16 nViewPos=0;
138 nRealPos = nCount;
139 for (SCTAB i=0; i<nCount; i++)
141 if (pDoc->IsVisible(i))
143 nViewPos++;
144 if(nViewPos==nPos)
146 SCTAB j;
147 for (j=i+1; j<nCount; j++)
149 if (pDoc->IsVisible(j))
151 break;
154 nRealPos =j;
155 break;
160 return nRealPos ;
163 void ScTabControl::MouseButtonDown( const MouseEvent& rMEvt )
165 ScModule* pScMod = SC_MOD();
166 if ( !pScMod->IsModalMode() && !pScMod->IsFormulaMode() && !IsInEditMode() )
168 // activate View
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 );
191 return;
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())
217 return;
218 OUString aName;
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();
236 SCTAB i;
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 );
246 return;
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();
260 if (!bRefMode)
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) );
269 else
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) )
300 ScRange aRange(
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));
315 else
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();
326 SCTAB i;
327 OUString aString;
328 SCTAB nMaxCnt = std::max( nCount, static_cast<SCTAB>(GetMaxId()) );
329 Color aTabBgColor;
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);
339 else
341 aString.clear();
344 if ( !aString.equals(GetPageText(static_cast<sal_uInt16>(i)+1)) || (GetTabBgColor(static_cast<sal_uInt16>(i)+1) != aTabBgColor) )
345 bModified = true;
348 if (bModified)
350 Clear();
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 );
359 else
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 );
372 if (bActive)
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) )
377 bModified = true;
379 if ( bModified )
380 for (i=0; i<nCount; i++)
381 SelectPage( static_cast<sal_uInt16>(i)+1, rMark.GetTableSelect(i) );
383 else
388 void ScTabControl::SetSheetLayoutRTL( bool bSheetRTL )
390 SetEffectiveRTL( bSheetRTL );
391 nSelPageIdByMouse = TabBar::PAGE_NOT_FOUND;
394 void ScTabControl::SwitchToPageId(sal_uInt16 nId)
396 if (nId)
398 bool bAlreadySelected = IsPageSelected( nId );
399 //make the clicked page the current one
400 SetCurPageId( nId );
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 );
409 Select();
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() );
429 SwitchToPageId(nId);
431 // #i52073# OLE inplace editing has to be stopped before showing the sheet tab context menu
432 pViewSh->DeactivateOle();
434 // Popup-Menu:
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();
445 if (!bDisable)
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 ))
450 DoDrag( 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();
492 while ( pShell )
494 if ( dynamic_cast<const ScDocShell *>(pShell) != nullptr )
496 if ( &static_cast<ScDocShell*>(pShell)->GetDocument() == pDoc )
497 return nShellCnt;
499 ++nShellCnt;
501 pShell = SfxObjectShell::GetNext( *pShell );
504 OSL_FAIL("Document not found");
505 return 0;
508 sal_Int8 ScTabControl::ExecuteDrop( const ExecuteDropEvent& rEvt )
510 EndSwitchPage();
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 );
519 HideDropPos();
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)
526 else
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 )
546 EndSwitchPage();
547 HideDropPos();
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
569 return 0;
572 bool ScTabControl::StartRenaming()
574 if ( pViewData->GetDocument()->IsDocEditable() )
575 return true;
576 else
577 return false;
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();
587 if ( nId )
589 SCTAB nTab = nId - 1;
590 OUString aNewName = GetEditText();
591 bool bDone = pViewSh->RenameTable( aNewName, nTab );
592 if ( bDone )
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;
608 else
610 bErrorShown = true;
611 pViewSh->ErrorMessage( STR_INVALIDTABNAME );
612 bErrorShown = false;
613 nRet = TABBAR_RENAMING_NO;
616 return nRet;
619 void ScTabControl::EndRenaming()
621 if ( HasFocus() )
622 pViewData->GetView()->ActiveGrabFocus();
625 void ScTabControl::Mirror()
627 TabBar::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: */