Bump version to 4.3-4
[LibreOffice.git] / sc / source / ui / view / tabcont.cxx
blobe6092771e0f204a854bd48248f48d369f0d88492
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 // STATIC DATA -----------------------------------------------------------
40 ScTabControl::ScTabControl( Window* pParent, ScViewData* pData ) :
41 TabBar( pParent,
42 WinBits(WB_BORDER | WB_3DLOOK | WB_SCROLL | WB_RANGESELECT |
43 WB_MULTISELECT | WB_DRAG | WB_SIZEABLE) ),
44 DropTargetHelper( this ),
45 DragSourceHelper( this ),
46 pViewData( pData ),
47 nMouseClickPageId( TabBar::PAGE_NOT_FOUND ),
48 nSelPageIdByMouse( TabBar::PAGE_NOT_FOUND ),
49 bErrorShown( false )
51 ScDocument* pDoc = pViewData->GetDocument();
53 OUString aString;
54 Color aTabBgColor;
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 );
64 else
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 ) );
81 EnableEditMode();
82 UpdateInputContext();
84 SetScrollAlwaysEnabled(true);
86 SetScrollAreaContextHdl( LINK( this, ScTabControl, ShowPageList ) );
89 IMPL_LINK(ScTabControl, ShowPageList, const CommandEvent *, pEvent)
91 PopupMenu aPopup;
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))
101 OUString aString;
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);
115 return 0;
118 ScTabControl::~ScTabControl()
122 sal_uInt16 ScTabControl::GetMaxId() const
124 sal_uInt16 nVisCnt = GetPageCount();
125 if (nVisCnt)
126 return GetPageId(nVisCnt-1);
128 return 0;
131 SCTAB ScTabControl::GetPrivatDropPos(const Point& rPos )
133 sal_uInt16 nPos = ShowDropPos(rPos);
135 SCTAB nRealPos = static_cast<SCTAB>(nPos);
137 if(nPos !=0 )
139 ScDocument* pDoc = pViewData->GetDocument();
141 SCTAB nCount = pDoc->GetTableCount();
143 sal_uInt16 nViewPos=0;
144 nRealPos = nCount;
145 for (SCTAB i=0; i<nCount; i++)
147 if (pDoc->IsVisible(i))
149 nViewPos++;
150 if(nViewPos==nPos)
152 SCTAB j;
153 for (j=i+1; j<nCount; j++)
155 if (pDoc->IsVisible(j))
157 break;
160 nRealPos =j;
161 break;
166 return nRealPos ;
169 void ScTabControl::MouseButtonDown( const MouseEvent& rMEvt )
171 ScModule* pScMod = SC_MOD();
172 if ( !pScMod->IsModalMode() && !pScMod->IsFormulaMode() && !IsInEditMode() )
174 // View aktivieren
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 );
184 else
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())
204 return;
205 OUString aName;
206 pDoc->CreateValidTabName(aName);
207 SCTAB nTabCount = pDoc->GetTableCount();
208 pViewData->GetViewShell()->InsertTable(aName, nTabCount);
209 return;
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 );
216 return;
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();
246 SCTAB i;
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 );
256 return;
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();
270 if (!bRefMode)
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) );
279 else
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) )
307 ScRange aRange(
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));
322 else
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();
333 SCTAB i;
334 OUString aString;
335 SCTAB nMaxCnt = std::max( nCount, static_cast<SCTAB>(GetMaxId()) );
336 Color aTabBgColor;
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);
346 else
348 aString = OUString();
351 if ( !aString.equals(GetPageText(static_cast<sal_uInt16>(i)+1)) || (GetTabBgColor(static_cast<sal_uInt16>(i)+1) != aTabBgColor) )
352 bModified = true;
355 if (bModified)
357 Clear();
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 );
366 else
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 );
379 if (bActive)
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) )
384 bModified = true;
386 // #i99576# the following loop is mis-optimized on unxsoli4 and the reason
387 // why this file is in NOOPTFILES.
388 if ( bModified )
389 for (i=0; i<nCount; i++)
390 SelectPage( static_cast<sal_uInt16>(i)+1, rMark.GetTableSelect(i) );
392 else
397 void ScTabControl::SetSheetLayoutRTL( bool bSheetRTL )
399 SetEffectiveRTL( bSheetRTL );
400 nSelPageIdByMouse = TabBar::PAGE_NOT_FOUND;
403 void ScTabControl::SwitchToPageId(sal_uInt16 nId)
405 if (nId)
407 bool bAlreadySelected = IsPageSelected( nId );
408 //make the clicked page the current one
409 SetCurPageId( nId );
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 );
418 Select();
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 )
435 if (!bDisable)
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() );
441 SwitchToPageId(nId);
443 // #i52073# OLE inplace editing has to be stopped before showing the sheet tab context menu
444 pViewSh->DeactivateOle();
446 // Popup-Menu:
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();
458 if (!bDisable)
460 Region aRegion( Rectangle(0,0,0,0) );
461 CommandEvent aCEvt( rPosPixel, COMMAND_STARTDRAG, true ); // needed for StartDrag
462 if (TabBar::StartDrag( aCEvt, aRegion ))
463 DoDrag( 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();
503 while ( pShell )
505 if ( pShell->Type() == TYPE(ScDocShell) )
507 if ( ((ScDocShell*)pShell)->GetDocument() == pDoc )
508 return nShellCnt;
510 ++nShellCnt;
512 pShell = SfxObjectShell::GetNext( *pShell );
515 OSL_FAIL("Dokument nicht gefunden");
516 return 0;
519 sal_Int8 ScTabControl::ExecuteDrop( const ExecuteDropEvent& rEvt )
521 EndSwitchPage();
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 );
530 HideDropPos();
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)
537 else
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
545 return sal_True;
550 return 0;
553 sal_Int8 ScTabControl::AcceptDrop( const AcceptDropEvent& rEvt )
555 if ( rEvt.mbLeaving )
557 EndSwitchPage();
558 HideDropPos();
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
580 return 0;
583 bool ScTabControl::StartRenaming()
585 if ( pViewData->GetDocument()->IsDocEditable() )
586 return true;
587 else
588 return false;
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();
598 if ( nId )
600 SCTAB nTab = nId - 1;
601 OUString aNewName = GetEditText();
602 bool bDone = pViewSh->RenameTable( aNewName, nTab );
603 if ( bDone )
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;
619 else
621 bErrorShown = true;
622 pViewSh->ErrorMessage( STR_INVALIDTABNAME );
623 bErrorShown = false;
624 nRet = TABBAR_RENAMING_NO;
627 return nRet;
630 void ScTabControl::EndRenaming()
632 if ( HasFocus() )
633 pViewData->GetView()->ActiveGrabFocus();
636 void ScTabControl::Mirror()
638 TabBar::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: */