bump product version to 4.1.6.2
[LibreOffice.git] / sc / source / ui / view / tabcont.cxx
blob4fce1138d80db9ab6753295e82c68d125029da47
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"
37 // STATIC DATA -----------------------------------------------------------
39 //==================================================================
41 ScTabControl::ScTabControl( Window* pParent, ScViewData* pData ) :
42 TabBar( pParent,
43 WinBits(WB_BORDER | WB_3DLOOK | WB_SCROLL | WB_RANGESELECT |
44 WB_MULTISELECT | WB_DRAG | WB_SIZEABLE) ),
45 DropTargetHelper( this ),
46 DragSourceHelper( this ),
47 pViewData( pData ),
48 nMouseClickPageId( TabBar::PAGE_NOT_FOUND ),
49 nSelPageIdByMouse( TabBar::PAGE_NOT_FOUND ),
50 bErrorShown( false )
52 ScDocument* pDoc = pViewData->GetDocument();
54 OUString aString;
55 Color aTabBgColor;
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 );
65 else
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 ) );
82 EnableEditMode();
83 UpdateInputContext();
86 ScTabControl::~ScTabControl()
90 sal_uInt16 ScTabControl::GetMaxId() const
92 sal_uInt16 nVisCnt = GetPageCount();
93 if (nVisCnt)
94 return GetPageId(nVisCnt-1);
96 return 0;
99 SCTAB ScTabControl::GetPrivatDropPos(const Point& rPos )
101 sal_uInt16 nPos = ShowDropPos(rPos);
103 SCTAB nRealPos = static_cast<SCTAB>(nPos);
105 if(nPos !=0 )
107 ScDocument* pDoc = pViewData->GetDocument();
109 SCTAB nCount = pDoc->GetTableCount();
111 sal_uInt16 nViewPos=0;
112 nRealPos = nCount;
113 for (SCTAB i=0; i<nCount; i++)
115 if (pDoc->IsVisible(i))
117 nViewPos++;
118 if(nViewPos==nPos)
120 SCTAB j;
121 for (j=i+1; j<nCount; j++)
123 if (pDoc->IsVisible(j))
125 break;
128 nRealPos =j;
129 break;
134 return nRealPos ;
137 void ScTabControl::MouseButtonDown( const MouseEvent& rMEvt )
139 ScModule* pScMod = SC_MOD();
140 if ( !pScMod->IsModalMode() && !pScMod->IsFormulaMode() && !IsInEditMode() )
142 // View aktivieren
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 );
152 else
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())
172 return;
173 OUString aName;
174 pDoc->CreateValidTabName(aName);
175 SCTAB nTabCount = pDoc->GetTableCount();
176 pViewData->GetViewShell()->InsertTable(aName, nTabCount);
177 return;
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 );
184 return;
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();
214 SCTAB i;
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 );
224 return;
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();
238 if (!bRefMode)
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) );
247 else
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) )
275 ScRange aRange(
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));
290 else
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();
301 SCTAB i;
302 OUString aString;
303 SCTAB nMaxCnt = std::max( nCount, static_cast<SCTAB>(GetMaxId()) );
304 Color aTabBgColor;
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);
314 else
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;
323 if (bModified)
325 Clear();
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 );
334 else
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 );
347 if (bActive)
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.
356 if ( bModified )
357 for (i=0; i<nCount; i++)
358 SelectPage( static_cast<sal_uInt16>(i)+1, rMark.GetTableSelect(i) );
360 else
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 )
384 if (!bDisable)
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() );
390 if (nId)
392 sal_Bool bAlreadySelected = IsPageSelected( nId );
393 //make the clicked page the current one
394 SetCurPageId( nId );
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 );
403 Select();
407 // #i52073# OLE inplace editing has to be stopped before showing the sheet tab context menu
408 pViewSh->DeactivateOle();
410 // Popup-Menu:
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();
422 if (!bDisable)
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 ))
427 DoDrag( 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();
467 while ( pShell )
469 if ( pShell->Type() == TYPE(ScDocShell) )
471 if ( ((ScDocShell*)pShell)->GetDocument() == pDoc )
472 return nShellCnt;
474 ++nShellCnt;
476 pShell = SfxObjectShell::GetNext( *pShell );
479 OSL_FAIL("Dokument nicht gefunden");
480 return 0;
483 sal_Int8 ScTabControl::ExecuteDrop( const ExecuteDropEvent& rEvt )
485 EndSwitchPage();
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 );
494 HideDropPos();
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)
501 else
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
509 return sal_True;
514 return 0;
517 sal_Int8 ScTabControl::AcceptDrop( const AcceptDropEvent& rEvt )
519 if ( rEvt.mbLeaving )
521 EndSwitchPage();
522 HideDropPos();
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
544 return 0;
547 long ScTabControl::StartRenaming()
549 if ( pViewData->GetDocument()->IsDocEditable() )
550 return TABBAR_RENAMING_YES;
551 else
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();
562 if ( nId )
564 SCTAB nTab = nId - 1;
565 String aNewName = GetEditText();
566 sal_Bool bDone = pViewSh->RenameTable( aNewName, nTab );
567 if ( bDone )
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;
583 else
585 bErrorShown = sal_True;
586 pViewSh->ErrorMessage( STR_INVALIDTABNAME );
587 bErrorShown = false;
588 nRet = TABBAR_RENAMING_NO;
591 return nRet;
594 void ScTabControl::EndRenaming()
596 if ( HasFocus() )
597 pViewData->GetView()->ActiveGrabFocus();
600 void ScTabControl::Mirror()
602 TabBar::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: */