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 <officecfg/Office/Calc.hxx>
21 #include <rangelst.hxx>
22 #include <scitems.hxx>
24 #include <editeng/editview.hxx>
25 #include <svx/fmshell.hxx>
26 #include <svx/sdr/overlay/overlaymanager.hxx>
27 #include <svx/svdoole2.hxx>
28 #include <sfx2/bindings.hxx>
29 #include <sfx2/lokhelper.hxx>
30 #include <sfx2/viewfrm.hxx>
31 #include <vcl/cursor.hxx>
32 #include <vcl/uitest/logger.hxx>
33 #include <vcl/uitest/eventdescription.hxx>
34 #include <sal/log.hxx>
35 #include <osl/diagnose.h>
37 #include <IAnyRefDialog.hxx>
38 #include <tabview.hxx>
39 #include <tabvwsh.hxx>
41 #include <gridwin.hxx>
42 #include <olinewin.hxx>
43 #include <overlayobject.hxx>
44 #include <colrowba.hxx>
45 #include <tabcont.hxx>
48 #include <viewutil.hxx>
49 #include <editutil.hxx>
50 #include <inputhdl.hxx>
51 #include <inputwin.hxx>
52 #include <validat.hxx>
53 #include <inputopt.hxx>
54 #include <rfindlst.hxx>
55 #include <hiranges.hxx>
56 #include <viewuno.hxx>
57 #include <dpobject.hxx>
58 #include <seltrans.hxx>
59 #include <fillinfo.hxx>
60 #include <rangeutl.hxx>
62 #include <tabprotection.hxx>
63 #include <spellcheckcontext.hxx>
64 #include <markdata.hxx>
65 #include <formula/FormulaCompiler.hxx>
66 #include <comphelper/lok.hxx>
67 #include <comphelper/scopeguard.hxx>
68 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
73 #include <com/sun/star/chart2/data/HighlightedRange.hpp>
78 ScRange
lcl_getSubRangeByIndex( const ScRange
& rRange
, sal_Int32 nIndex
)
80 ScAddress
aResult( rRange
.aStart
);
82 SCCOL nWidth
= rRange
.aEnd
.Col() - rRange
.aStart
.Col() + 1;
83 SCROW nHeight
= rRange
.aEnd
.Row() - rRange
.aStart
.Row() + 1;
84 SCTAB nDepth
= rRange
.aEnd
.Tab() - rRange
.aStart
.Tab() + 1;
85 if( (nWidth
> 0) && (nHeight
> 0) && (nDepth
> 0) )
87 // row by row from first to last sheet
88 sal_Int32 nArea
= nWidth
* nHeight
;
89 aResult
.IncCol( static_cast< SCCOL
>( nIndex
% nWidth
) );
90 aResult
.IncRow( static_cast< SCROW
>( (nIndex
% nArea
) / nWidth
) );
91 aResult
.IncTab( static_cast< SCTAB
>( nIndex
/ nArea
) );
92 if( !rRange
.Contains( aResult
) )
93 aResult
= rRange
.aStart
;
96 return ScRange( aResult
);
99 } // anonymous namespace
101 using namespace com::sun::star
;
103 ScExtraEditViewManager::~ScExtraEditViewManager()
105 DBG_ASSERT(nTotalWindows
== 0, "ScExtraEditViewManager dtor: some out window has not yet been removed!");
108 inline void ScExtraEditViewManager::Add(SfxViewShell
* pViewShell
, ScSplitPos eWhich
)
110 Apply
<Adder
>(pViewShell
, eWhich
);
113 inline void ScExtraEditViewManager::Remove(SfxViewShell
* pViewShell
, ScSplitPos eWhich
)
115 Apply
<Remover
>(pViewShell
, eWhich
);
119 template<ScExtraEditViewManager::ModifierTagType ModifierTag
>
120 void ScExtraEditViewManager::Apply(SfxViewShell
* pViewShell
, ScSplitPos eWhich
)
122 ScTabViewShell
* pOtherViewShell
= dynamic_cast<ScTabViewShell
*>(pViewShell
);
123 if (pOtherViewShell
== nullptr || pOtherViewShell
== mpThisViewShell
)
126 mpOtherEditView
= pOtherViewShell
->GetViewData().GetEditView(eWhich
);
127 if (mpOtherEditView
!= nullptr)
129 for (int i
= 0; i
< 4; ++i
)
131 ScGridWindow
* pWin
= mpGridWin
[i
].get();
134 Modifier
<ModifierTag
>(pWin
);
140 template<ScExtraEditViewManager::ModifierTagType ModifierTag
>
141 void ScExtraEditViewManager::Modifier(ScGridWindow
* /*pWin*/)
144 SAL_WARN("sc", "ScExtraEditViewManager::Modifier<ModifierTag>: non-specialized version should not be invoked.");
148 void ScExtraEditViewManager::Modifier
<ScExtraEditViewManager::Adder
>(ScGridWindow
* pWin
)
150 if (mpOtherEditView
->AddOtherViewWindow(pWin
))
155 void ScExtraEditViewManager::Modifier
<ScExtraEditViewManager::Remover
>(ScGridWindow
* pWin
)
157 if (mpOtherEditView
->RemoveOtherViewWindow(pWin
))
161 // --- public functions
163 void ScTabView::ClickCursor( SCCOL nPosX
, SCROW nPosY
, bool bControl
)
165 ScDocument
& rDoc
= aViewData
.GetDocument();
166 SCTAB nTab
= aViewData
.GetTabNo();
167 rDoc
.SkipOverlapped(nPosX
, nPosY
, nTab
);
169 ScModule
* mod
= ScModule::get();
170 bool bRefMode
= mod
->IsFormulaMode();
179 InitRefMode( nPosX
, nPosY
, nTab
, SC_REFTYPE_REF
);
183 DoneBlockMode( bControl
);
184 aViewData
.ResetOldCursor();
185 SetCursor( nPosX
, nPosY
);
189 void ScTabView::UpdateAutoFillMark(bool bFromPaste
)
191 // single selection or cursor
193 ScMarkType eMarkType
= aViewData
.GetSimpleArea(aMarkRange
);
194 bool bMarked
= eMarkType
== SC_MARK_SIMPLE
|| eMarkType
== SC_MARK_SIMPLE_FILTERED
;
196 for (sal_uInt16 i
= 0; i
< 4; i
++)
198 if (pGridWin
[i
] && pGridWin
[i
]->IsVisible())
199 pGridWin
[i
]->UpdateAutoFillMark( bMarked
, aMarkRange
);
202 for (sal_uInt16 i
= 0; i
< 2; i
++)
204 if (pColBar
[i
] && pColBar
[i
]->IsVisible())
205 pColBar
[i
]->SetMark( bMarked
, aMarkRange
.aStart
.Col(), aMarkRange
.aEnd
.Col() );
206 if (pRowBar
[i
] && pRowBar
[i
]->IsVisible())
207 pRowBar
[i
]->SetMark( bMarked
, aMarkRange
.aStart
.Row(), aMarkRange
.aEnd
.Row() );
210 // selection transfer object is checked together with AutoFill marks,
211 // because it has the same requirement of a single continuous block.
213 CheckSelectionTransfer(); // update selection transfer object
216 void ScTabView::FakeButtonUp( ScSplitPos eWhich
)
218 if (pGridWin
[eWhich
])
219 pGridWin
[eWhich
]->FakeButtonUp();
222 void ScTabView::HideAllCursors()
224 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
226 if (pWin
&& pWin
->IsVisible())
228 vcl::Cursor
* pCur
= pWin
->GetCursor();
229 if (pCur
&& pCur
->IsVisible())
236 void ScTabView::ShowAllCursors()
238 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
240 if (pWin
&& pWin
->IsVisible())
243 pWin
->CursorChanged();
248 void ScTabView::ShowCursor()
250 pGridWin
[aViewData
.GetActivePart()]->ShowCursor();
251 pGridWin
[aViewData
.GetActivePart()]->CursorChanged();
254 void ScTabView::InvalidateAttribs()
256 SfxBindings
& rBindings
= aViewData
.GetBindings();
258 rBindings
.Invalidate( SID_STYLE_APPLY
);
259 rBindings
.Invalidate( SID_STYLE_FAMILY2
);
260 rBindings
.Invalidate( SID_STYLE_FAMILY3
);
262 rBindings
.Invalidate( SID_ATTR_CHAR_FONT
);
263 rBindings
.Invalidate( SID_ATTR_CHAR_FONTHEIGHT
);
264 rBindings
.Invalidate( SID_ATTR_CHAR_COLOR
);
266 rBindings
.Invalidate( SID_ATTR_CHAR_WEIGHT
);
267 rBindings
.Invalidate( SID_ATTR_CHAR_POSTURE
);
268 rBindings
.Invalidate( SID_ATTR_CHAR_UNDERLINE
);
269 rBindings
.Invalidate( SID_ULINE_VAL_NONE
);
270 rBindings
.Invalidate( SID_ULINE_VAL_SINGLE
);
271 rBindings
.Invalidate( SID_ULINE_VAL_DOUBLE
);
272 rBindings
.Invalidate( SID_ULINE_VAL_DOTTED
);
274 rBindings
.Invalidate( SID_ATTR_CHAR_OVERLINE
);
276 rBindings
.Invalidate( SID_ATTR_CHAR_KERNING
);
277 rBindings
.Invalidate( SID_SET_SUPER_SCRIPT
);
278 rBindings
.Invalidate( SID_SET_SUB_SCRIPT
);
279 rBindings
.Invalidate( SID_ATTR_CHAR_STRIKEOUT
);
280 rBindings
.Invalidate( SID_ATTR_CHAR_SHADOWED
);
282 rBindings
.Invalidate( SID_ATTR_PARA_ADJUST_LEFT
);
283 rBindings
.Invalidate( SID_ATTR_PARA_ADJUST_RIGHT
);
284 rBindings
.Invalidate( SID_ATTR_PARA_ADJUST_BLOCK
);
285 rBindings
.Invalidate( SID_ATTR_PARA_ADJUST_CENTER
);
286 rBindings
.Invalidate( SID_NUMBER_TYPE_FORMAT
);
288 rBindings
.Invalidate( SID_ALIGNLEFT
);
289 rBindings
.Invalidate( SID_ALIGNRIGHT
);
290 rBindings
.Invalidate( SID_ALIGNBLOCK
);
291 rBindings
.Invalidate( SID_ALIGNCENTERHOR
);
293 rBindings
.Invalidate( SID_ALIGNTOP
);
294 rBindings
.Invalidate( SID_ALIGNBOTTOM
);
295 rBindings
.Invalidate( SID_ALIGNCENTERVER
);
297 rBindings
.Invalidate( SID_SCATTR_CELLPROTECTION
);
299 // stuff for sidebar panels
301 rBindings
.Invalidate( SID_H_ALIGNCELL
);
302 rBindings
.Invalidate( SID_V_ALIGNCELL
);
303 rBindings
.Invalidate( SID_ATTR_ALIGN_INDENT
);
304 rBindings
.Invalidate( SID_FRAME_LINECOLOR
);
305 rBindings
.Invalidate( SID_FRAME_LINESTYLE
);
306 rBindings
.Invalidate( SID_ATTR_BORDER_OUTER
);
307 rBindings
.Invalidate( SID_ATTR_BORDER_INNER
);
308 rBindings
.Invalidate( SID_ATTR_BORDER_DIAG_TLBR
);
309 rBindings
.Invalidate( SID_ATTR_BORDER_DIAG_BLTR
);
310 rBindings
.Invalidate( SID_NUMBER_TYPE_FORMAT
);
313 rBindings
.Invalidate( SID_BACKGROUND_COLOR
);
315 rBindings
.Invalidate( SID_ATTR_ALIGN_LINEBREAK
);
316 rBindings
.Invalidate( SID_NUMBER_FORMAT
);
318 rBindings
.Invalidate( SID_TEXTDIRECTION_LEFT_TO_RIGHT
);
319 rBindings
.Invalidate( SID_TEXTDIRECTION_TOP_TO_BOTTOM
);
320 rBindings
.Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT
);
321 rBindings
.Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT
);
323 // pseudo slots for Format menu
324 rBindings
.Invalidate( SID_ALIGN_ANY_HDEFAULT
);
325 rBindings
.Invalidate( SID_ALIGN_ANY_LEFT
);
326 rBindings
.Invalidate( SID_ALIGN_ANY_HCENTER
);
327 rBindings
.Invalidate( SID_ALIGN_ANY_RIGHT
);
328 rBindings
.Invalidate( SID_ALIGN_ANY_JUSTIFIED
);
329 rBindings
.Invalidate( SID_ALIGN_ANY_VDEFAULT
);
330 rBindings
.Invalidate( SID_ALIGN_ANY_TOP
);
331 rBindings
.Invalidate( SID_ALIGN_ANY_VCENTER
);
332 rBindings
.Invalidate( SID_ALIGN_ANY_BOTTOM
);
334 rBindings
.Invalidate( SID_NUMBER_CURRENCY
);
335 rBindings
.Invalidate( SID_NUMBER_SCIENTIFIC
);
336 rBindings
.Invalidate( SID_NUMBER_DATE
);
337 rBindings
.Invalidate( SID_NUMBER_CURRENCY
);
338 rBindings
.Invalidate( SID_NUMBER_PERCENT
);
339 rBindings
.Invalidate( SID_NUMBER_TWODEC
);
340 rBindings
.Invalidate( SID_NUMBER_TIME
);
341 rBindings
.Invalidate( SID_NUMBER_STANDARD
);
342 rBindings
.Invalidate( SID_NUMBER_THOUSANDS
);
347 void collectUIInformation(std::map
<OUString
, OUString
>&& aParameters
)
349 EventDescription aDescription
;
350 aDescription
.aID
= "grid_window";
351 aDescription
.aAction
= "SELECT";
352 aDescription
.aParameters
= std::move(aParameters
);
353 aDescription
.aParent
= "MainWindow";
354 aDescription
.aKeyWord
= "ScGridWinUIObject";
356 UITestLogger::getInstance().logEvent(aDescription
);
361 // SetCursor - Cursor, set, draw, update InputWin
363 // Optimising breaks the functionality
365 void ScTabView::SetCursor( SCCOL nPosX
, SCROW nPosY
, bool bNew
)
367 SCCOL nOldX
= aViewData
.GetCurX();
368 SCROW nOldY
= aViewData
.GetCurY();
370 // DeactivateIP only for MarkListHasChanged
372 // FIXME: this is to limit the number of rows handled in the Online
373 // to 1000; this will be removed again when the performance
374 // bottlenecks are sorted out
375 if (comphelper::LibreOfficeKit::isActive())
376 nPosY
= std::min(nPosY
, MAXTILEDROW
);
378 if ( !(nPosX
!= nOldX
|| nPosY
!= nOldY
|| bNew
) )
384 ScTabViewShell
* pViewShell
= aViewData
.GetViewShell();
385 bool bRefMode
= pViewShell
&& pViewShell
->IsRefInputMode();
386 if ( aViewData
.HasEditView( aViewData
.GetActivePart() ) && !bRefMode
) // 23259 or so
393 aViewData
.SetCurX( nPosX
);
394 aViewData
.SetCurY( nPosY
);
402 OUString aCurrAddress
= ScAddress(nPosX
,nPosY
,0).GetColRowString();
403 collectUIInformation({{"CELL", aCurrAddress
}});
405 if (!comphelper::LibreOfficeKit::isActive())
408 if (nPosX
<= aViewData
.GetMaxTiledCol() - 10 && nPosY
<= aViewData
.GetMaxTiledRow() - 25)
411 ScDocument
& rDoc
= aViewData
.GetDocument();
412 ScDocShell
* pDocSh
= aViewData
.GetDocShell();
413 ScModelObj
* pModelObj
= pDocSh
? pDocSh
->GetModel() : nullptr;
416 aOldSize
= pModelObj
->getDocumentSize();
418 if (nPosX
> aViewData
.GetMaxTiledCol() - 10)
419 aViewData
.SetMaxTiledCol(std::min
<SCCOL
>(std::max(nPosX
, aViewData
.GetMaxTiledCol()) + 10, rDoc
.MaxCol()));
421 if (nPosY
> aViewData
.GetMaxTiledRow() - 25)
422 aViewData
.SetMaxTiledRow(std::min
<SCROW
>(std::max(nPosY
, aViewData
.GetMaxTiledRow()) + 25, MAXTILEDROW
));
426 aNewSize
= pModelObj
->getDocumentSize();
433 ScGridWindow
* pGridWindow
= aViewData
.GetActiveWin();
436 Size
aNewSizePx(aNewSize
.Width() * aViewData
.GetPPTX(), aNewSize
.Height() * aViewData
.GetPPTY());
437 if (aNewSizePx
!= pGridWindow
->GetOutputSizePixel())
438 pGridWindow
->SetOutputSizePixel(aNewSizePx
);
442 if (aOldSize
== aNewSize
)
445 // New area extended to the right of the sheet after last column
446 // including overlapping area with aNewRowArea
447 tools::Rectangle
aNewColArea(aOldSize
.getWidth(), 0, aNewSize
.getWidth(), aNewSize
.getHeight());
448 // New area extended to the bottom of the sheet after last row
449 // excluding overlapping area with aNewColArea
450 tools::Rectangle
aNewRowArea(0, aOldSize
.getHeight(), aOldSize
.getWidth(), aNewSize
.getHeight());
452 // Only invalidate if spreadsheet extended to the right
453 if (aNewColArea
.getOpenWidth())
455 SfxLokHelper::notifyInvalidation(aViewData
.GetViewShell(), &aNewColArea
);
458 // Only invalidate if spreadsheet extended to the bottom
459 if (aNewRowArea
.getOpenHeight())
461 SfxLokHelper::notifyInvalidation(aViewData
.GetViewShell(), &aNewRowArea
);
464 // Provide size in the payload, so clients don't have to
465 // call lok::Document::getDocumentSize().
466 std::stringstream ss
;
467 ss
<< aNewSize
.Width() << ", " << aNewSize
.Height();
468 OString
sSize( ss
.str() );
469 ScModelObj
* pModel
= comphelper::getFromUnoTunnel
<ScModelObj
>(aViewData
.GetViewShell()->GetCurrentDocument());
470 SfxLokHelper::notifyDocumentSizeChanged(aViewData
.GetViewShell(), sSize
, pModel
, false);
473 static bool lcl_IsRefDlgActive(SfxViewFrame
& rViewFrm
)
475 ScModule
* pScMod
= ScModule::get();
476 if (!pScMod
->IsRefDialogOpen())
479 auto nDlgId
= pScMod
->GetCurRefDlgId();
480 if (!rViewFrm
.HasChildWindow(nDlgId
))
483 SfxChildWindow
* pChild
= rViewFrm
.GetChildWindow(nDlgId
);
487 auto xDlgController
= pChild
->GetController();
488 if (!xDlgController
|| !xDlgController
->getDialog()->get_visible())
491 IAnyRefDialog
* pRefDlg
= dynamic_cast<IAnyRefDialog
*>(xDlgController
.get());
492 return pRefDlg
&& pRefDlg
->IsRefInputMode();
495 void ScTabView::CheckSelectionTransfer()
497 if ( !aViewData
.IsActive() ) // only for active view
500 ScModule
* pScMod
= ScModule::get();
501 ScSelectionTransferObj
* pOld
= pScMod
->GetSelectionTransfer();
502 rtl::Reference
<ScSelectionTransferObj
> pNew
= ScSelectionTransferObj::CreateFromView( this );
506 // create new selection
511 pScMod
->SetSelectionTransfer( pNew
.get() );
513 // tdf#124975/tdf#136242 changing the calc selection can trigger removal of the
514 // selection of an open RefDlg dialog, so don't inform the
515 // desktop clipboard of the changed selection if that dialog is open
516 if (!lcl_IsRefDlgActive(aViewData
.GetViewShell()->GetViewFrame()))
517 pNew
->CopyToPrimarySelection(); // may delete pOld
519 // Log the selection change
520 ScMarkData
& rMark
= aViewData
.GetMarkData();
521 if (rMark
.IsMarked())
523 const ScRange
& aMarkRange
= rMark
.GetMarkArea();
524 OUString aStartAddress
= aMarkRange
.aStart
.GetColRowString();
525 OUString aEndAddress
= aMarkRange
.aEnd
.GetColRowString();
526 collectUIInformation({{"RANGE", aStartAddress
+ ":" + aEndAddress
}});
530 // update input row / menus
531 // CursorPosChanged calls SelectionChanged
532 // SelectionChanged calls CellContentChanged
534 void ScTabView::CellContentChanged()
536 SfxBindings
& rBindings
= aViewData
.GetBindings();
538 rBindings
.Invalidate( SID_ATTR_SIZE
); // -> show error message
539 rBindings
.Invalidate( SID_THESAURUS
);
540 rBindings
.Invalidate( SID_HYPERLINK_GETLINK
);
541 rBindings
.Invalidate( SID_ROWCOL_SELCOUNT
);
543 InvalidateAttribs(); // attributes updates
545 aViewData
.GetViewShell()->UpdateInputHandler();
548 void ScTabView::SetTabProtectionSymbol( SCTAB nTab
, const bool bProtect
)
550 pTabControl
->SetProtectionSymbol( static_cast<sal_uInt16
>(nTab
)+1, bProtect
);
553 void ScTabView::SelectionChanged(bool bFromPaste
)
555 SfxViewFrame
& rViewFrame
= aViewData
.GetViewShell()->GetViewFrame();
556 uno::Reference
<frame::XController
> xController
= rViewFrame
.GetFrame().GetController();
557 if (xController
.is())
559 ScTabViewObj
* pImp
= dynamic_cast<ScTabViewObj
*>( xController
.get() );
561 pImp
->SelectionChanged();
564 UpdateAutoFillMark(bFromPaste
); // also calls CheckSelectionTransfer
566 SfxBindings
& rBindings
= aViewData
.GetBindings();
568 rBindings
.Invalidate( SID_CURRENTCELL
); // -> Navigator
569 rBindings
.Invalidate( SID_AUTO_FILTER
); // -> Menu
570 rBindings
.Invalidate( FID_NOTE_VISIBLE
);
571 rBindings
.Invalidate( FID_SHOW_NOTE
);
572 rBindings
.Invalidate( FID_HIDE_NOTE
);
573 rBindings
.Invalidate( FID_SHOW_ALL_NOTES
);
574 rBindings
.Invalidate( FID_HIDE_ALL_NOTES
);
575 rBindings
.Invalidate( SID_TOGGLE_NOTES
);
576 rBindings
.Invalidate( SID_DELETE_NOTE
);
577 rBindings
.Invalidate( SID_ROWCOL_SELCOUNT
);
579 // functions than may need to be disabled
581 rBindings
.Invalidate( FID_INS_ROWBRK
);
582 rBindings
.Invalidate( FID_INS_COLBRK
);
583 rBindings
.Invalidate( FID_DEL_ROWBRK
);
584 rBindings
.Invalidate( FID_DEL_COLBRK
);
585 rBindings
.Invalidate( FID_MERGE_ON
);
586 rBindings
.Invalidate( FID_MERGE_OFF
);
587 rBindings
.Invalidate( FID_MERGE_TOGGLE
);
588 rBindings
.Invalidate( SID_AUTOFILTER_HIDE
);
589 rBindings
.Invalidate( SID_UNFILTER
);
590 rBindings
.Invalidate( SID_REIMPORT_DATA
);
591 rBindings
.Invalidate( SID_REFRESH_DBAREA
);
592 rBindings
.Invalidate( SID_OUTLINE_SHOW
);
593 rBindings
.Invalidate( SID_OUTLINE_HIDE
);
594 rBindings
.Invalidate( SID_OUTLINE_REMOVE
);
595 rBindings
.Invalidate( FID_FILL_TO_BOTTOM
);
596 rBindings
.Invalidate( FID_FILL_TO_RIGHT
);
597 rBindings
.Invalidate( FID_FILL_TO_TOP
);
598 rBindings
.Invalidate( FID_FILL_TO_LEFT
);
599 rBindings
.Invalidate( FID_FILL_SERIES
);
600 rBindings
.Invalidate( SID_SCENARIOS
);
601 rBindings
.Invalidate( SID_AUTOFORMAT
);
602 rBindings
.Invalidate( SID_OPENDLG_TABOP
);
603 rBindings
.Invalidate( SID_DATA_SELECT
);
605 rBindings
.Invalidate( SID_CUT
);
606 rBindings
.Invalidate( SID_COPY
);
607 rBindings
.Invalidate( SID_PASTE
);
608 rBindings
.Invalidate( SID_PASTE_SPECIAL
);
609 rBindings
.Invalidate( SID_PASTE_UNFORMATTED
);
610 rBindings
.Invalidate( SID_COPYDELETE
);
612 rBindings
.Invalidate( FID_INS_ROW
);
613 rBindings
.Invalidate( FID_INS_COLUMN
);
614 rBindings
.Invalidate( FID_INS_ROWS_BEFORE
);
615 rBindings
.Invalidate( FID_INS_COLUMNS_BEFORE
);
616 rBindings
.Invalidate( FID_INS_ROWS_AFTER
);
617 rBindings
.Invalidate( FID_INS_COLUMNS_AFTER
);
618 rBindings
.Invalidate( FID_INS_CELL
);
619 rBindings
.Invalidate( FID_INS_CELLSDOWN
);
620 rBindings
.Invalidate( FID_INS_CELLSRIGHT
);
622 rBindings
.Invalidate( FID_CHG_COMMENT
);
624 // only due to protect cell:
626 rBindings
.Invalidate( SID_CELL_FORMAT_RESET
);
627 rBindings
.Invalidate( SID_DELETE
);
628 rBindings
.Invalidate( SID_DELETE_CONTENTS
);
629 rBindings
.Invalidate( FID_DELETE_CELL
);
630 rBindings
.Invalidate( FID_CELL_FORMAT
);
631 rBindings
.Invalidate( SID_ENABLE_HYPHENATION
);
632 rBindings
.Invalidate( SID_INSERT_POSTIT
);
633 rBindings
.Invalidate( SID_CHARMAP
);
634 rBindings
.Invalidate( SID_OPENDLG_FUNCTION
);
635 rBindings
.Invalidate( FID_VALIDATION
);
636 rBindings
.Invalidate( SID_EXTERNAL_SOURCE
);
637 rBindings
.Invalidate( SID_TEXT_TO_COLUMNS
);
638 rBindings
.Invalidate( SID_SORT_ASCENDING
);
639 rBindings
.Invalidate( SID_SORT_DESCENDING
);
640 rBindings
.Invalidate( SID_SELECT_UNPROTECTED_CELLS
);
641 if (!comphelper::LibreOfficeKit::isActive())
642 rBindings
.Invalidate( SID_LANGUAGE_STATUS
);
644 if (aViewData
.GetViewShell()->HasAccessibilityObjects())
645 aViewData
.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccCursorChanged
));
647 CellContentChanged();
650 void ScTabView::CursorPosChanged()
652 bool bRefMode
= ScModule::get()->IsFormulaMode();
653 if ( !bRefMode
) // check that RefMode works when switching sheets
654 aViewData
.GetDocShell()->Broadcast( SfxHint( SfxHintId::ScKillEditView
) );
656 // Broadcast, so that other Views of the document also switch
658 ScDocument
& rDocument
= aViewData
.GetDocument();
659 bool bDataPilot
= rDocument
.HasDataPilotAtPosition(aViewData
.GetCurPos());
660 aViewData
.GetViewShell()->SetPivotShell(bDataPilot
);
664 bool bSparkline
= rDocument
.HasSparkline(aViewData
.GetCurPos());
665 aViewData
.GetViewShell()->SetSparklineShell(bSparkline
);
668 // UpdateInputHandler now in CellContentChanged
672 aViewData
.SetTabStartCol( SC_TABSTART_NONE
);
677 Point
calcHintWindowPosition(
678 const Point
& rCellPos
, const Size
& rCellSize
, const Size
& rFrameWndSize
, const Size
& rHintWndSize
)
680 const tools::Long nMargin
= 20;
682 tools::Long nMLeft
= rCellPos
.X();
683 tools::Long nMRight
= rFrameWndSize
.Width() - rCellPos
.X() - rCellSize
.Width();
684 tools::Long nMTop
= rCellPos
.Y();
685 tools::Long nMBottom
= rFrameWndSize
.Height() - rCellPos
.Y() - rCellSize
.Height();
687 // First, see if we can fit the entire hint window in the visible region.
689 if (nMRight
- nMargin
>= rHintWndSize
.Width())
691 // Right margin is wide enough.
692 if (rFrameWndSize
.Height() >= rHintWndSize
.Height())
694 // The frame has enough height. Take it.
695 Point aPos
= rCellPos
;
696 aPos
.AdjustX(rCellSize
.Width() + nMargin
);
697 if (aPos
.Y() + rHintWndSize
.Height() > rFrameWndSize
.Height())
699 // Push the hint window up a bit to make it fit.
700 aPos
.setY( rFrameWndSize
.Height() - rHintWndSize
.Height() );
706 if (nMBottom
- nMargin
>= rHintWndSize
.Height())
708 // Bottom margin is high enough.
709 if (rFrameWndSize
.Width() >= rHintWndSize
.Width())
711 // The frame has enough width. Take it.
712 Point aPos
= rCellPos
;
713 aPos
.AdjustY(rCellSize
.Height() + nMargin
);
714 if (aPos
.X() + rHintWndSize
.Width() > rFrameWndSize
.Width())
716 // Move the hint window to the left to make it fit.
717 aPos
.setX( rFrameWndSize
.Width() - rHintWndSize
.Width() );
723 if (nMLeft
- nMargin
>= rHintWndSize
.Width())
725 // Left margin is wide enough.
726 if (rFrameWndSize
.Height() >= rHintWndSize
.Height())
728 // The frame is high enough. Take it.
729 Point aPos
= rCellPos
;
730 aPos
.AdjustX( -(rHintWndSize
.Width() + nMargin
) );
731 if (aPos
.Y() + rHintWndSize
.Height() > rFrameWndSize
.Height())
733 // Push the hint window up a bit to make it fit.
734 aPos
.setY( rFrameWndSize
.Height() - rHintWndSize
.Height() );
740 if (nMTop
- nMargin
>= rHintWndSize
.Height())
742 // Top margin is high enough.
743 if (rFrameWndSize
.Width() >= rHintWndSize
.Width())
745 // The frame is wide enough. Take it.
746 Point aPos
= rCellPos
;
747 aPos
.AdjustY( -(rHintWndSize
.Height() + nMargin
) );
748 if (aPos
.X() + rHintWndSize
.Width() > rFrameWndSize
.Width())
750 // Move the hint window to the left to make it fit.
751 aPos
.setX( rFrameWndSize
.Width() - rHintWndSize
.Width() );
757 // The popup doesn't fit in any direction in its entirety. Do our best.
759 if (nMRight
- nMargin
>= rHintWndSize
.Width())
761 // Right margin is good enough.
762 Point aPos
= rCellPos
;
763 aPos
.AdjustX(nMargin
+ rCellSize
.Width() );
768 if (nMBottom
- nMargin
>= rHintWndSize
.Height())
770 // Bottom margin is good enough.
771 Point aPos
= rCellPos
;
772 aPos
.AdjustY(nMargin
+ rCellSize
.Height() );
777 if (nMLeft
- nMargin
>= rHintWndSize
.Width())
779 // Left margin is good enough.
780 Point aPos
= rCellPos
;
781 aPos
.AdjustX( -(rHintWndSize
.Width() + nMargin
) );
786 if (nMTop
- nMargin
>= rHintWndSize
.Height())
788 // Top margin is good enough.
789 Point aPos
= rCellPos
;
790 aPos
.AdjustY( -(rHintWndSize
.Height() + nMargin
) );
795 // None of the above. Hopeless. At least try not to cover the current
797 Point aPos
= rCellPos
;
798 aPos
.AdjustX(rCellSize
.Width() );
804 void ScTabView::TestHintWindow()
806 // show input help window and list drop-down button for validity
808 mxInputHintOO
.reset();
810 bool bListValButton
= false;
811 ScAddress aListValPos
;
813 ScDocument
& rDoc
= aViewData
.GetDocument();
814 const SfxUInt32Item
* pItem
= rDoc
.GetAttr( aViewData
.GetCurX(),
816 aViewData
.GetTabNo(),
818 if ( pItem
->GetValue() )
820 const ScValidationData
* pData
= rDoc
.GetValidationEntry( pItem
->GetValue() );
821 OSL_ENSURE(pData
,"ValidationData not found");
822 OUString aTitle
, aMessage
;
824 if ( pData
&& pData
->GetInput( aTitle
, aMessage
) && !aMessage
.isEmpty() )
826 ScSplitPos eWhich
= aViewData
.GetActivePart();
827 ScGridWindow
* pWin
= pGridWin
[eWhich
].get();
828 SCCOL nCol
= aViewData
.GetCurX();
829 SCROW nRow
= aViewData
.GetCurY();
830 Point aPos
= aViewData
.GetScrPos( nCol
, nRow
, eWhich
);
831 Size aWinSize
= pWin
->GetOutputSizePixel();
833 if ( nCol
>= aViewData
.GetPosX(WhichH(eWhich
)) &&
834 nRow
>= aViewData
.GetPosY(WhichV(eWhich
)) &&
835 aPos
.X() < aWinSize
.Width() && aPos
.Y() < aWinSize
.Height() )
837 const svtools::ColorConfig
& rColorCfg
= ScModule::get()->GetColorConfig();
838 Color aCommentColor
= rColorCfg
.GetColorValue(svtools::CALCNOTESBACKGROUND
).nColor
;
839 // create HintWindow, determines its size by itself
840 ScOverlayHint
* pOverlay
= new ScOverlayHint(aTitle
, aMessage
, aCommentColor
, pFrameWin
->GetFont());
842 mxInputHintOO
.reset(new sdr::overlay::OverlayObjectList
);
843 mxInputHintOO
->append(std::unique_ptr
<sdr::overlay::OverlayObject
>(pOverlay
));
845 Size aHintWndSize
= pOverlay
->GetSizePixel();
846 tools::Long nCellSizeX
= 0;
847 tools::Long nCellSizeY
= 0;
848 aViewData
.GetMergeSizePixel(nCol
, nRow
, nCellSizeX
, nCellSizeY
);
850 Point aHintPos
= calcHintWindowPosition(
851 aPos
, Size(nCellSizeX
,nCellSizeY
), aWinSize
, aHintWndSize
);
853 pOverlay
->SetPos(pWin
->PixelToLogic(aHintPos
, pWin
->GetDrawMapMode()), pWin
->GetDrawMapMode());
854 for (VclPtr
<ScGridWindow
> & pWindow
: pGridWin
)
858 if (!pWindow
->IsVisible())
860 rtl::Reference
<sdr::overlay::OverlayManager
> xOverlayManager
= pWindow
->getOverlayManager();
861 if (!xOverlayManager
.is())
865 xOverlayManager
->add(*pOverlay
);
866 pWindow
->updateLOKInputHelp(aTitle
, aMessage
);
870 //tdf#92530 if the help tip doesn't fit into its allocated area in a split window
871 //scenario, then because here we place it into the other split windows as well the
872 //missing portions will be displayed in the other split windows to form an apparent
873 //single tip, albeit "under" the split lines
874 Point
aOtherPos(pWindow
->ScreenToOutputPixel(pWin
->OutputToScreenPixel(aHintPos
)));
875 std::unique_ptr
<ScOverlayHint
> pOtherOverlay(new ScOverlayHint(aTitle
, aMessage
, aCommentColor
, pFrameWin
->GetFont()));
876 Point
aFooPos(pWindow
->PixelToLogic(aOtherPos
, pWindow
->GetDrawMapMode()));
877 pOtherOverlay
->SetPos(aFooPos
, pWindow
->GetDrawMapMode());
878 xOverlayManager
->add(*pOtherOverlay
);
879 mxInputHintOO
->append(std::move(pOtherOverlay
));
885 // list drop-down button
886 if ( pData
&& pData
->HasSelectionList() )
888 aListValPos
.Set( aViewData
.GetCurX(), aViewData
.GetCurY(), aViewData
.GetTabNo() );
889 bListValButton
= true;
893 for (VclPtr
<ScGridWindow
> const & pWin
: pGridWin
)
895 if (pWin
&& pWin
->IsVisible())
896 pWin
->UpdateListValPos(bListValButton
, aListValPos
);
900 bool ScTabView::HasHintWindow() const { return mxInputHintOO
!= nullptr; }
902 void ScTabView::RemoveHintWindow()
904 mxInputHintOO
.reset();
907 // find window that should not be over the cursor
908 static weld::Window
* lcl_GetCareWin(SfxViewFrame
& rViewFrm
)
910 //! also spelling ??? (then set the member variables when calling)
913 if (rViewFrm
.HasChildWindow(SID_SEARCH_DLG
))
915 SfxChildWindow
* pChild
= rViewFrm
.GetChildWindow(SID_SEARCH_DLG
);
918 auto xDlgController
= pChild
->GetController();
919 if (xDlgController
&& xDlgController
->getDialog()->get_visible())
920 return xDlgController
->getDialog();
925 if ( rViewFrm
.HasChildWindow(FID_CHG_ACCEPT
) )
927 SfxChildWindow
* pChild
= rViewFrm
.GetChildWindow(FID_CHG_ACCEPT
);
930 auto xDlgController
= pChild
->GetController();
931 if (xDlgController
&& xDlgController
->getDialog()->get_visible())
932 return xDlgController
->getDialog();
939 // adjust screen with respect to cursor position
941 void ScTabView::AlignToCursor( SCCOL nCurX
, SCROW nCurY
, ScFollowMode eMode
,
942 const ScSplitPos
* pWhich
)
944 // now switch active part here
946 ScSplitPos eActive
= aViewData
.GetActivePart();
947 ScHSplitPos eActiveX
= WhichH(eActive
);
948 ScVSplitPos eActiveY
= WhichV(eActive
);
949 bool bHFix
= (aViewData
.GetHSplitMode() == SC_SPLIT_FIX
);
950 bool bVFix
= (aViewData
.GetVSplitMode() == SC_SPLIT_FIX
);
951 if (bHFix
&& eActiveX
== SC_SPLIT_LEFT
&& nCurX
>= aViewData
.GetFixPosX())
953 ActivatePart( (eActiveY
==SC_SPLIT_TOP
) ? SC_SPLIT_TOPRIGHT
: SC_SPLIT_BOTTOMRIGHT
);
954 eActiveX
= SC_SPLIT_RIGHT
;
956 if (bVFix
&& eActiveY
== SC_SPLIT_TOP
&& nCurY
>= aViewData
.GetFixPosY())
958 ActivatePart( (eActiveX
==SC_SPLIT_LEFT
) ? SC_SPLIT_BOTTOMLEFT
: SC_SPLIT_BOTTOMRIGHT
);
959 eActiveY
= SC_SPLIT_BOTTOM
;
964 if ( eMode
!= SC_FOLLOW_NONE
)
970 eAlign
= aViewData
.GetActivePart();
971 ScHSplitPos eAlignX
= WhichH(eAlign
);
972 ScVSplitPos eAlignY
= WhichV(eAlign
);
974 SCCOL nDeltaX
= aViewData
.GetPosX(eAlignX
);
975 SCROW nDeltaY
= aViewData
.GetPosY(eAlignY
);
976 SCCOL nSizeX
= aViewData
.VisibleCellsX(eAlignX
);
977 SCROW nSizeY
= aViewData
.VisibleCellsY(eAlignY
);
979 tools::Long nCellSizeX
;
980 tools::Long nCellSizeY
;
981 if ( nCurX
>= 0 && nCurY
>= 0 )
982 aViewData
.GetMergeSizePixel( nCurX
, nCurY
, nCellSizeX
, nCellSizeY
);
984 nCellSizeX
= nCellSizeY
= 0;
985 Size aScrSize
= aViewData
.GetScrSize();
988 if ( eMode
== SC_FOLLOW_JUMP_END
&& nCurX
> aViewData
.GetRefStartX()
989 && nCurY
> aViewData
.GetRefStartY() )
990 nDenom
= 1; // tdf#154271 Selected cell will be at the bottom corner
991 // to maximize the visible/usable area
993 nDenom
= 2; // Selected cell will be at the center of the screen, so that
994 // it will be visible. This is useful for search results, etc.
995 tools::Long nSpaceX
= ( aScrSize
.Width() - nCellSizeX
) / nDenom
;
996 tools::Long nSpaceY
= ( aScrSize
.Height() - nCellSizeY
) / nDenom
;
997 // nSpaceY: desired start position of cell for FOLLOW_JUMP, modified if dialog interferes
999 bool bForceNew
= false; // force new calculation of JUMP position (vertical only)
1001 // VisibleCellsY == CellsAtY( GetPosY( eWhichY ), 1, eWhichY )
1003 // when for instance a search dialog is open, don't put the cursor behind the dialog
1004 // if possible, put the row with the cursor above or below the dialog
1005 //! not if already completely visible
1007 if ( eMode
== SC_FOLLOW_JUMP
|| eMode
== SC_FOLLOW_JUMP_END
)
1009 weld::Window
* pCare
= lcl_GetCareWin( aViewData
.GetViewShell()->GetViewFrame() );
1012 bool bLimit
= false;
1013 tools::Rectangle aDlgPixel
;
1015 vcl::Window
* pWin
= GetActiveWin();
1016 weld::Window
* pFrame
= pWin
? pWin
->GetFrameWeld() : nullptr;
1017 int x
, y
, width
, height
;
1018 if (pFrame
&& pCare
->get_extents_relative_to(*pFrame
, x
, y
, width
, height
))
1020 aDlgPixel
= tools::Rectangle(Point(x
, y
), Size(width
, height
));
1021 aWinSize
= pWin
->GetOutputSizePixel();
1022 // dos the dialog cover the GridWin?
1023 if ( aDlgPixel
.Right() >= 0 && aDlgPixel
.Left() < aWinSize
.Width() )
1025 if ( nCurX
< nDeltaX
|| nCurX
>= nDeltaX
+nSizeX
||
1026 nCurY
< nDeltaY
|| nCurY
>= nDeltaY
+nSizeY
)
1027 bLimit
= true; // scroll anyway
1030 // cursor is on the screen
1031 Point aStart
= aViewData
.GetScrPos( nCurX
, nCurY
, eAlign
);
1032 tools::Long nCSX
, nCSY
;
1033 aViewData
.GetMergeSizePixel( nCurX
, nCurY
, nCSX
, nCSY
);
1034 tools::Rectangle
aCursor( aStart
, Size( nCSX
, nCSY
) );
1035 if ( aCursor
.Overlaps( aDlgPixel
) )
1036 bLimit
= true; // cell is covered by the dialog
1043 bool bBottom
= false;
1044 tools::Long nTopSpace
= aDlgPixel
.Top();
1045 tools::Long nBotSpace
= aWinSize
.Height() - aDlgPixel
.Bottom();
1046 if ( nBotSpace
> 0 && nBotSpace
> nTopSpace
)
1048 tools::Long nDlgBot
= aDlgPixel
.Bottom();
1051 aViewData
.GetPosFromPixel( 0,nDlgBot
, eAlign
, nWPosX
, nWPosY
);
1052 ++nWPosY
; // below the last affected cell
1054 SCROW nDiff
= nWPosY
- nDeltaY
;
1055 if ( nCurY
>= nDiff
) // position can not be negative
1057 nSpaceY
= nDlgBot
+ ( nBotSpace
- nCellSizeY
) / 2;
1062 if ( !bBottom
&& nTopSpace
> 0 )
1064 nSpaceY
= ( nTopSpace
- nCellSizeY
) / 2;
1071 SCCOL nNewDeltaX
= nDeltaX
;
1072 SCROW nNewDeltaY
= nDeltaY
;
1073 bool bDoLine
= false;
1077 case SC_FOLLOW_JUMP
:
1078 case SC_FOLLOW_JUMP_END
:
1079 if ( nCurX
< nDeltaX
|| nCurX
>= nDeltaX
+nSizeX
)
1081 nNewDeltaX
= nCurX
- aViewData
.CellsAtX( nCurX
, -1, eAlignX
, static_cast<sal_uInt16
>(nSpaceX
) );
1084 nSizeX
= aViewData
.CellsAtX( nNewDeltaX
, 1, eAlignX
);
1086 if ( nCurY
< nDeltaY
|| nCurY
>= nDeltaY
+nSizeY
|| bForceNew
)
1088 nNewDeltaY
= nCurY
- aViewData
.CellsAtY( nCurY
, -1, eAlignY
, static_cast<sal_uInt16
>(nSpaceY
) );
1091 nSizeY
= aViewData
.CellsAtY( nNewDeltaY
, 1, eAlignY
);
1096 case SC_FOLLOW_LINE
:
1101 if ( nCurX
< nDeltaX
|| nCurX
>= nDeltaX
+nSizeX
)
1103 nNewDeltaX
= nDeltaX
+ nCurX
- aViewData
.GetCurX();
1106 nSizeX
= aViewData
.CellsAtX( nNewDeltaX
, 1, eAlignX
);
1108 if ( nCurY
< nDeltaY
|| nCurY
>= nDeltaY
+nSizeY
)
1110 nNewDeltaY
= nDeltaY
+ nCurY
- aViewData
.GetCurY();
1113 nSizeY
= aViewData
.CellsAtY( nNewDeltaY
, 1, eAlignY
);
1116 // like old version of SC_FOLLOW_JUMP:
1118 if ( nCurX
< nNewDeltaX
|| nCurX
>= nNewDeltaX
+nSizeX
)
1120 nNewDeltaX
= nCurX
- (nSizeX
/ 2);
1123 nSizeX
= aViewData
.CellsAtX( nNewDeltaX
, 1, eAlignX
);
1125 if ( nCurY
< nNewDeltaY
|| nCurY
>= nNewDeltaY
+nSizeY
)
1127 nNewDeltaY
= nCurY
- (nSizeY
/ 2);
1130 nSizeY
= aViewData
.CellsAtY( nNewDeltaY
, 1, eAlignY
);
1136 case SC_FOLLOW_NONE
:
1139 OSL_FAIL("Wrong cursor mode");
1143 ScDocument
& rDoc
= aViewData
.GetDocument();
1146 while ( nCurX
>= nNewDeltaX
+nSizeX
)
1148 nNewDeltaX
= nCurX
-nSizeX
+1;
1149 SCTAB nTab
= aViewData
.GetTabNo();
1150 while ( nNewDeltaX
< rDoc
.MaxCol() && !rDoc
.GetColWidth( nNewDeltaX
, nTab
) )
1152 nSizeX
= aViewData
.CellsAtX( nNewDeltaX
, 1, eAlignX
);
1154 while ( nCurY
>= nNewDeltaY
+nSizeY
)
1156 nNewDeltaY
= nCurY
-nSizeY
+1;
1157 SCTAB nTab
= aViewData
.GetTabNo();
1158 while ( nNewDeltaY
< rDoc
.MaxRow() && !rDoc
.GetRowHeight( nNewDeltaY
, nTab
) )
1160 nSizeY
= aViewData
.CellsAtY( nNewDeltaY
, 1, eAlignY
);
1162 if ( nCurX
< nNewDeltaX
)
1164 if ( nCurY
< nNewDeltaY
)
1168 if ( nNewDeltaX
!= nDeltaX
)
1169 nSizeX
= aViewData
.CellsAtX( nNewDeltaX
, 1, eAlignX
);
1170 if (nNewDeltaX
+nSizeX
-1 > rDoc
.MaxCol())
1171 nNewDeltaX
= rDoc
.MaxCol()-nSizeX
+1;
1175 if ( nNewDeltaY
!= nDeltaY
)
1176 nSizeY
= aViewData
.CellsAtY( nNewDeltaY
, 1, eAlignY
);
1177 if (nNewDeltaY
+nSizeY
-1 > rDoc
.MaxRow())
1178 nNewDeltaY
= rDoc
.MaxRow()-nSizeY
+1;
1182 if ( nNewDeltaX
!= nDeltaX
)
1183 ScrollX( nNewDeltaX
- nDeltaX
, eAlignX
);
1184 if ( nNewDeltaY
!= nDeltaY
)
1185 ScrollY( nNewDeltaY
- nDeltaY
, eAlignY
);
1188 // switch active part again
1191 if (eActiveX
== SC_SPLIT_RIGHT
&& nCurX
< aViewData
.GetFixPosX())
1193 ActivatePart( (eActiveY
==SC_SPLIT_TOP
) ? SC_SPLIT_TOPLEFT
: SC_SPLIT_BOTTOMLEFT
);
1194 eActiveX
= SC_SPLIT_LEFT
;
1197 if (eActiveY
== SC_SPLIT_BOTTOM
&& nCurY
< aViewData
.GetFixPosY())
1199 ActivatePart( (eActiveX
==SC_SPLIT_LEFT
) ? SC_SPLIT_TOPLEFT
: SC_SPLIT_TOPRIGHT
);
1203 bool ScTabView::SelMouseButtonDown( const MouseEvent
& rMEvt
)
1208 bool bMod1Locked
= (aViewData
.GetViewShell()->GetLockedModifiers() & KEY_MOD1
) != 0;
1209 aViewData
.SetSelCtrlMouseClick( rMEvt
.IsMod1() || bMod1Locked
);
1213 bMoveIsShift
= rMEvt
.IsShift();
1214 bRet
= pSelEngine
->SelMouseButtonDown( rMEvt
);
1215 bMoveIsShift
= false;
1218 aViewData
.SetSelCtrlMouseClick( false ); // #i3875# *Hack*
1223 // MoveCursor - with adjustment of the view section
1225 void ScTabView::MoveCursorAbs( SCCOL nCurX
, SCROW nCurY
, ScFollowMode eMode
,
1226 bool bShift
, bool bControl
, bool bKeepOld
, bool bKeepSel
)
1229 aViewData
.ResetOldCursor();
1231 ScDocument
& rDoc
= aViewData
.GetDocument();
1233 if( aViewData
.GetViewShell()->GetForceFocusOnCurCell() )
1234 aViewData
.GetViewShell()->SetForceFocusOnCurCell( !rDoc
.ValidColRow(nCurX
, nCurY
) );
1236 if (nCurX
< 0) nCurX
= 0;
1237 if (nCurY
< 0) nCurY
= 0;
1238 if (nCurX
> rDoc
.MaxCol()) nCurX
= rDoc
.MaxCol();
1239 if (nCurY
> rDoc
.MaxRow()) nCurY
= rDoc
.MaxRow();
1241 // FIXME: this is to limit the number of rows handled in the Online
1242 // to 1000; this will be removed again when the performance
1243 // bottlenecks are sorted out
1244 if (comphelper::LibreOfficeKit::isActive())
1245 nCurY
= std::min(nCurY
, MAXTILEDROW
);
1249 // switch of active now in AlignToCursor
1251 AlignToCursor( nCurX
, nCurY
, eMode
);
1255 SetCursor( nCurX
, nCurY
); // keep selection
1257 // If the cursor is in existing selection, it's a cursor movement by
1258 // ENTER or TAB. If not, then it's a new selection during ADD
1261 const ScMarkData
& rMark
= aViewData
.GetMarkData();
1262 ScRangeList aSelList
;
1263 rMark
.FillRangeListWithMarks(&aSelList
, false);
1264 if (!aSelList
.Contains(ScRange(nCurX
, nCurY
, aViewData
.GetTabNo())))
1265 // Cursor not in existing selection. Start a new selection.
1266 DoneBlockMode(true);
1272 // Remove all marked data on cursor movement unless the Shift is
1273 // locked or while editing a formula. It is cheaper to check for
1274 // marks first and then formula mode.
1275 ScMarkData
& rMark
= aViewData
.GetMarkData();
1276 bool bMarked
= rMark
.IsMarked() || rMark
.IsMultiMarked();
1277 if (bMarked
&& !ScModule::get()->IsFormulaMode())
1281 InitOwnBlockMode( ScRange( nCurX
, nCurY
, aViewData
.GetTabNo()));
1286 bool bSame
= ( nCurX
== aViewData
.GetCurX() && nCurY
== aViewData
.GetCurY() );
1287 bMoveIsShift
= bShift
;
1288 pSelEngine
->CursorPosChanging( bShift
, bControl
);
1289 bMoveIsShift
= false;
1290 aFunctionSet
.SetCursorAtCell( nCurX
, nCurY
, false );
1292 // If the cursor has not been moved, the SelectionChanged for canceling the
1293 // selection has to happen here individually:
1302 void ScTabView::MoveCursorRel( SCCOL nMovX
, SCROW nMovY
, ScFollowMode eMode
,
1303 bool bShift
, bool bKeepSel
)
1305 ScDocument
& rDoc
= aViewData
.GetDocument();
1306 SCTAB nTab
= aViewData
.GetTabNo();
1308 bool bSkipProtected
= false, bSkipUnprotected
= false;
1309 const ScTableProtection
* pProtect
= rDoc
.GetTabProtection(nTab
);
1310 if ( pProtect
&& pProtect
->isProtected() )
1312 bSkipProtected
= !pProtect
->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS
);
1313 bSkipUnprotected
= !pProtect
->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS
);
1316 if ( bSkipProtected
&& bSkipUnprotected
)
1323 if ( aViewData
.IsRefMode() )
1325 nOldX
= aViewData
.GetRefEndX();
1326 nOldY
= aViewData
.GetRefEndY();
1327 nCurX
= nOldX
+ nMovX
;
1328 nCurY
= nOldY
+ nMovY
;
1332 nOldX
= aViewData
.GetCurX();
1333 nOldY
= aViewData
.GetCurY();
1334 nCurX
= (nMovX
!= 0) ? nOldX
+nMovX
: aViewData
.GetOldCurX();
1335 nCurY
= (nMovY
!= 0) ? nOldY
+nMovY
: aViewData
.GetOldCurY();
1338 if (nMovX
< 0 && nOldX
== 0)
1339 { // trying to go left from 1st column
1340 if (nMovY
== 0) // done, because no vertical move is requested
1343 if (nMovY
< 0 && nOldY
== 0)
1344 { // trying to go up from 1st row
1345 if (nMovX
== 0) // done, because no horizontal move is requested
1349 aViewData
.ResetOldCursor();
1351 if (nMovX
!= 0 && rDoc
.ValidColRow(nCurX
,nCurY
))
1352 SkipCursorHorizontal(nCurX
, nCurY
, nOldX
, nMovX
);
1354 if (nMovY
!= 0 && rDoc
.ValidColRow(nCurX
,nCurY
))
1355 SkipCursorVertical(nCurX
, nCurY
, nOldY
, nMovY
);
1357 MoveCursorAbs( nCurX
, nCurY
, eMode
, bShift
, false, true, bKeepSel
);
1360 void ScTabView::MoveCursorPage( SCCOL nMovX
, SCROW nMovY
, ScFollowMode eMode
, bool bShift
, bool bKeepSel
)
1364 GetPageMoveEndPosition(nMovX
, nMovY
, nPageX
, nPageY
);
1365 MoveCursorRel( nPageX
, nPageY
, eMode
, bShift
, bKeepSel
);
1368 void ScTabView::MoveCursorArea( SCCOL nMovX
, SCROW nMovY
, ScFollowMode eMode
, bool bShift
, bool bKeepSel
, bool bInteractiveByUser
)
1372 GetAreaMoveEndPosition(nMovX
, nMovY
, eMode
, nNewX
, nNewY
, eMode
, bInteractiveByUser
);
1373 MoveCursorRel(nNewX
, nNewY
, eMode
, bShift
, bKeepSel
);
1376 void ScTabView::MoveCursorEnd( SCCOL nMovX
, SCROW nMovY
, ScFollowMode eMode
, bool bShift
, bool bKeepSel
)
1378 ScDocument
& rDoc
= aViewData
.GetDocument();
1379 SCTAB nTab
= aViewData
.GetTabNo();
1383 aViewData
.GetMoveCursor( nCurX
,nCurY
);
1384 SCCOL nNewX
= nCurX
;
1385 SCROW nNewY
= nCurY
;
1389 if ( nMovX
> 0 || nMovY
> 0 )
1390 rDoc
.GetPrintArea( nTab
, nUsedX
, nUsedY
); // get end
1395 nNewX
=nUsedX
; // last used range
1402 aViewData
.ResetOldCursor();
1403 MoveCursorRel( nNewX
-nCurX
, nNewY
-nCurY
, eMode
, bShift
, bKeepSel
);
1406 void ScTabView::MoveCursorScreen( SCCOL nMovX
, SCROW nMovY
, ScFollowMode eMode
, bool bShift
)
1408 ScDocument
& rDoc
= aViewData
.GetDocument();
1409 SCTAB nTab
= aViewData
.GetTabNo();
1413 aViewData
.GetMoveCursor( nCurX
,nCurY
);
1414 SCCOL nNewX
= nCurX
;
1415 SCROW nNewY
= nCurY
;
1417 ScSplitPos eWhich
= aViewData
.GetActivePart();
1418 SCCOL nPosX
= aViewData
.GetPosX( WhichH(eWhich
) );
1419 SCROW nPosY
= aViewData
.GetPosY( WhichV(eWhich
) );
1421 SCCOL nAddX
= aViewData
.VisibleCellsX( WhichH(eWhich
) );
1424 SCROW nAddY
= aViewData
.VisibleCellsY( WhichV(eWhich
) );
1438 aViewData
.SetOldCursor( nNewX
,nNewY
);
1439 rDoc
.SkipOverlapped(nNewX
, nNewY
, nTab
);
1440 MoveCursorAbs( nNewX
, nNewY
, eMode
, bShift
, false, true );
1443 void ScTabView::MoveCursorEnter( bool bShift
) // bShift -> up/down
1445 const ScInputOptions
& rOpt
= ScModule::get()->GetInputOptions();
1446 if (!rOpt
.GetMoveSelection())
1448 aViewData
.UpdateInputHandler(true);
1454 switch (static_cast<ScDirection
>(rOpt
.GetMoveDir()))
1457 nMoveY
= bShift
? -1 : 1;
1460 nMoveX
= bShift
? -1 : 1;
1463 nMoveY
= bShift
? 1 : -1;
1466 nMoveX
= bShift
? 1 : -1;
1472 aViewData
.GetMoveCursor( nCurX
,nCurY
);
1473 SCCOL nNewX
= nCurX
;
1474 SCROW nNewY
= nCurY
;
1475 SCTAB nTab
= aViewData
.GetTabNo();
1477 ScMarkData
& rMark
= aViewData
.GetMarkData();
1478 ScDocument
& rDoc
= aViewData
.GetDocument();
1480 if (rMark
.IsMarked() || rMark
.IsMultiMarked())
1482 rDoc
.GetNextPos( nNewX
, nNewY
, nTab
, nMoveX
, nMoveY
, true, false, rMark
);
1484 MoveCursorRel( nNewX
- nCurX
, nNewY
- nCurY
, SC_FOLLOW_LINE
, false, true );
1486 // update input line even if cursor was not moved
1487 if ( nNewX
== nCurX
&& nNewY
== nCurY
)
1488 aViewData
.UpdateInputHandler(true);
1492 // After Tab and Enter back to the starting column again.
1493 const SCCOL nTabStartCol
= ((nMoveY
!= 0 && !nMoveX
) ? aViewData
.GetTabStartCol() : SC_TABSTART_NONE
);
1494 rDoc
.GetNextPos( nNewX
, nNewY
, nTab
, nMoveX
, nMoveY
, false, true, rMark
, nTabStartCol
);
1496 MoveCursorRel( nNewX
- nCurX
, nNewY
- nCurY
, SC_FOLLOW_LINE
, false);
1500 bool ScTabView::MoveCursorKeyInput( const KeyEvent
& rKeyEvent
)
1502 const vcl::KeyCode
& rKCode
= rKeyEvent
.GetKeyCode();
1504 enum { MOD_NONE
, MOD_CTRL
, MOD_ALT
, MOD_BOTH
} eModifier
=
1506 (rKCode
.IsMod2() ? MOD_BOTH
: MOD_CTRL
) :
1507 (rKCode
.IsMod2() ? MOD_ALT
: MOD_NONE
);
1509 bool bSel
= rKCode
.IsShift();
1510 sal_uInt16 nCode
= rKCode
.GetCode();
1517 case KEY_LEFT
: nDX
= -1; break;
1518 case KEY_RIGHT
: nDX
= 1; break;
1519 case KEY_UP
: nDY
= -1; break;
1520 case KEY_DOWN
: nDY
= 1; break;
1522 if( nDX
!= 0 || nDY
!= 0 )
1526 case MOD_NONE
: MoveCursorRel( nDX
, nDY
, SC_FOLLOW_LINE
, bSel
); break;
1527 case MOD_CTRL
: MoveCursorArea( nDX
, nDY
, SC_FOLLOW_JUMP
, bSel
); break;
1530 // added to avoid warnings
1533 // always true to suppress changes of col/row size (ALT+CURSOR)
1538 if( (nCode
== KEY_PAGEUP
) || (nCode
== KEY_PAGEDOWN
) )
1540 nDX
= (nCode
== KEY_PAGEUP
) ? -1 : 1;
1543 case MOD_NONE
: MoveCursorPage( 0, static_cast<SCCOLROW
>(nDX
), SC_FOLLOW_FIX
, bSel
); break;
1544 case MOD_ALT
: MoveCursorPage( nDX
, 0, SC_FOLLOW_FIX
, bSel
); break;
1545 case MOD_CTRL
: SelectNextTab( nDX
, false ); break;
1548 // added to avoid warnings
1555 if( (nCode
== KEY_HOME
) || (nCode
== KEY_END
) )
1557 nDX
= (nCode
== KEY_HOME
) ? -1 : 1;
1558 ScFollowMode eMode
= (nCode
== KEY_HOME
) ? SC_FOLLOW_LINE
: SC_FOLLOW_JUMP_END
;
1561 case MOD_NONE
: MoveCursorEnd( nDX
, 0, eMode
, bSel
); break;
1562 case MOD_CTRL
: MoveCursorEnd( nDX
, static_cast<SCCOLROW
>(nDX
), eMode
, bSel
); break;
1565 // added to avoid warnings
1574 // next/previous unprotected cell
1575 void ScTabView::FindNextUnprot( bool bShift
, bool bInSelection
)
1577 short nMove
= bShift
? -1 : 1;
1579 ScMarkData
& rMark
= aViewData
.GetMarkData();
1580 bool bMarked
= bInSelection
&& (rMark
.IsMarked() || rMark
.IsMultiMarked());
1584 aViewData
.GetMoveCursor( nCurX
,nCurY
);
1585 SCCOL nNewX
= nCurX
;
1586 SCROW nNewY
= nCurY
;
1587 SCTAB nTab
= aViewData
.GetTabNo();
1589 ScDocument
& rDoc
= aViewData
.GetDocument();
1590 rDoc
.GetNextPos( nNewX
,nNewY
, nTab
, nMove
,0, bMarked
, true, rMark
);
1592 SCCOL nTabCol
= aViewData
.GetTabStartCol();
1593 if ( nTabCol
== SC_TABSTART_NONE
)
1594 nTabCol
= nCurX
; // back to this column after Enter
1596 MoveCursorRel( nNewX
-nCurX
, nNewY
-nCurY
, SC_FOLLOW_LINE
, false, true );
1598 // TabCol is reset in MoveCursorRel...
1599 aViewData
.SetTabStartCol( nTabCol
);
1602 void ScTabView::MarkColumns()
1607 ScMarkData
& rMark
= aViewData
.GetMarkData();
1608 if (rMark
.IsMarked())
1610 const ScRange
& aMarkRange
= rMark
.GetMarkArea();
1611 nStartCol
= aMarkRange
.aStart
.Col();
1612 nEndCol
= aMarkRange
.aEnd
.Col();
1617 aViewData
.GetMoveCursor( nStartCol
, nDummy
);
1621 SCTAB nTab
= aViewData
.GetTabNo();
1622 ScDocument
& rDoc
= aViewData
.GetDocument();
1624 InitBlockMode( nStartCol
,0, nTab
);
1625 MarkCursor( nEndCol
, rDoc
.MaxRow(), nTab
);
1629 void ScTabView::MarkRows()
1634 ScMarkData
& rMark
= aViewData
.GetMarkData();
1635 if (rMark
.IsMarked())
1637 const ScRange
& aMarkRange
= rMark
.GetMarkArea();
1638 nStartRow
= aMarkRange
.aStart
.Row();
1639 nEndRow
= aMarkRange
.aEnd
.Row();
1644 aViewData
.GetMoveCursor( nDummy
, nStartRow
);
1648 SCTAB nTab
= aViewData
.GetTabNo();
1649 ScDocument
& rDoc
= aViewData
.GetDocument();
1651 InitBlockMode( 0,nStartRow
, nTab
);
1652 MarkCursor( rDoc
.MaxCol(), nEndRow
, nTab
);
1657 void ScTabView::MarkColumns(SCCOL nCol
, sal_Int16 nModifier
)
1659 ScDocument
& rDoc
= aViewData
.GetDocument();
1660 SCCOL nStartCol
= nCol
;
1661 SCTAB nTab
= aViewData
.GetTabNo();
1663 if ((nModifier
& KEY_SHIFT
) == KEY_SHIFT
)
1664 bMoveIsShift
= true;
1666 if (ScModule::get()->IsFormulaMode())
1668 DoneRefMode( nModifier
!= 0 );
1669 InitRefMode( nCol
, 0, nTab
, SC_REFTYPE_REF
);
1670 UpdateRef( nCol
, rDoc
.MaxRow(), nTab
);
1671 bMoveIsShift
= false;
1675 DoneBlockMode( nModifier
!= 0 );
1676 InitBlockMode( nStartCol
, 0, nTab
, true, true);
1677 MarkCursor( nCol
, rDoc
.MaxRow(), nTab
);
1678 bMoveIsShift
= false;
1679 SetCursor( nCol
, 0 );
1684 void ScTabView::MarkRows(SCROW nRow
, sal_Int16 nModifier
)
1686 ScDocument
& rDoc
= aViewData
.GetDocument();
1687 SCROW nStartRow
= nRow
;
1688 SCTAB nTab
= aViewData
.GetTabNo();
1690 if ((nModifier
& KEY_SHIFT
) == KEY_SHIFT
)
1691 bMoveIsShift
= true;
1693 if (ScModule::get()->IsFormulaMode())
1695 DoneRefMode( nModifier
!= 0 );
1696 InitRefMode( 0, nRow
, nTab
, SC_REFTYPE_REF
);
1697 UpdateRef( rDoc
.MaxCol(), nRow
, nTab
);
1698 bMoveIsShift
= false;
1702 DoneBlockMode( nModifier
!= 0 );
1703 InitBlockMode( 0, nStartRow
, nTab
, true, false, true );
1704 MarkCursor( rDoc
.MaxCol(), nRow
, nTab
);
1705 bMoveIsShift
= false;
1706 SetCursor( 0, nRow
);
1711 void ScTabView::HighlightOverlay()
1713 if (!officecfg::Office::Calc::Content::Display::ColumnRowHighlighting::get())
1715 aViewData
.GetHighlightData().ResetMark();
1716 UpdateHighlightOverlay();
1720 ScAddress aCell
= GetViewData().GetCurPos();
1721 SCROW nRow
= aCell
.Row();
1722 SCCOL nCol
= aCell
.Col();
1724 bool nModifier
= false; // modifier key pressed?
1725 DoneBlockModeHighlight( nModifier
);
1726 InitBlockModeHighlight( nCol
, 0, aCell
.Tab(), true, false);
1728 DoneBlockModeHighlight( nModifier
);
1729 InitBlockModeHighlight( 0, nRow
, aCell
.Tab(), false, true );
1732 void ScTabView::MarkDataArea( bool bIncludeCursor
)
1734 ScDocument
& rDoc
= aViewData
.GetDocument();
1735 SCTAB nTab
= aViewData
.GetTabNo();
1736 SCCOL nStartCol
= aViewData
.GetCurX();
1737 SCROW nStartRow
= aViewData
.GetCurY();
1738 SCCOL nEndCol
= nStartCol
;
1739 SCROW nEndRow
= nStartRow
;
1741 rDoc
.GetDataArea( nTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
, bIncludeCursor
, false );
1745 InitBlockMode( nStartCol
, nStartRow
, nTab
);
1746 MarkCursor( nEndCol
, nEndRow
, nTab
);
1752 void ScTabView::MarkMatrixFormula()
1754 ScDocument
& rDoc
= aViewData
.GetDocument();
1755 ScAddress
aCursor( aViewData
.GetCurX(), aViewData
.GetCurY(), aViewData
.GetTabNo() );
1757 if ( rDoc
.GetMatrixFormulaRange( aCursor
, aMatrix
) )
1759 MarkRange( aMatrix
, false ); // cursor is already within the range
1763 void ScTabView::MarkRange( const ScRange
& rRange
, bool bSetCursor
, bool bContinue
)
1765 ScDocument
& rDoc
= aViewData
.GetDocument();
1766 SCTAB nTab
= rRange
.aStart
.Tab();
1770 DoneBlockMode( bContinue
); // bContinue==true -> clear old mark
1771 if (bSetCursor
) // if Cursor is set, also always align
1773 SCCOL nAlignX
= rRange
.aStart
.Col();
1774 SCROW nAlignY
= rRange
.aStart
.Row();
1775 bool bCol
= ( rRange
.aStart
.Col() == 0 && rRange
.aEnd
.Col() == rDoc
.MaxCol() ) && !aViewData
.GetDocument().IsInVBAMode();
1776 bool bRow
= ( rRange
.aStart
.Row() == 0 && rRange
.aEnd
.Row() == rDoc
.MaxRow() );
1778 nAlignX
= aViewData
.GetPosX(WhichH(aViewData
.GetActivePart()));
1780 nAlignY
= aViewData
.GetPosY(WhichV(aViewData
.GetActivePart()));
1781 AlignToCursor( nAlignX
, nAlignY
, SC_FOLLOW_JUMP
);
1783 InitBlockMode( rRange
.aStart
.Col(), rRange
.aStart
.Row(), nTab
);
1784 MarkCursor( rRange
.aEnd
.Col(), rRange
.aEnd
.Row(), nTab
);
1787 SCCOL nPosX
= rRange
.aStart
.Col();
1788 SCROW nPosY
= rRange
.aStart
.Row();
1789 rDoc
.SkipOverlapped(nPosX
, nPosY
, nTab
);
1791 aViewData
.ResetOldCursor();
1792 SetCursor( nPosX
, nPosY
);
1799 void ScTabView::Unmark()
1801 ScMarkData
& rMark
= aViewData
.GetMarkData();
1802 if ( rMark
.IsMarked() || rMark
.IsMultiMarked() )
1806 aViewData
.GetMoveCursor( nCurX
,nCurY
);
1807 MoveCursorAbs( nCurX
, nCurY
, SC_FOLLOW_NONE
, false, false );
1813 void ScTabView::SetMarkData( const ScMarkData
& rNew
)
1816 InitOwnBlockMode( rNew
.GetMarkArea());
1817 aViewData
.GetMarkData() = rNew
;
1822 void ScTabView::MarkDataChanged()
1824 // has to be called after making direct changes to mark data (not via MarkCursor etc)
1826 UpdateSelectionOverlay();
1829 void ScTabView::SelectNextTab( short nDir
, bool bExtendSelection
)
1833 OSL_ENSURE( nDir
==-1 || nDir
==1, "SelectNextTab: invalid value");
1835 ScDocument
& rDoc
= aViewData
.GetDocument();
1836 SCTAB nTab
= aViewData
.GetTabNo();
1837 SCTAB nNextTab
= nTab
;
1838 SCTAB nCount
= rDoc
.GetTableCount();
1846 if (officecfg::Office::Calc::Input::WrapNextPrevSheetTab::get())
1851 if (rDoc
.IsVisible(nNextTab
))
1853 } while (nNextTab
!= nTab
);
1860 if (nNextTab
>= nCount
)
1862 if (officecfg::Office::Calc::Input::WrapNextPrevSheetTab::get())
1867 if (rDoc
.IsVisible(nNextTab
))
1869 } while (nNextTab
!= nTab
);
1871 if (nNextTab
== nTab
)
1874 SetTabNo(nNextTab
, false, bExtendSelection
);
1878 void ScTabView::SelectTabPage( const sal_uInt16 nTab
)
1880 pTabControl
->SwitchToPageId( nTab
);
1883 // SetTabNo - set the displayed sheet
1885 void ScTabView::SetTabNo( SCTAB nTab
, bool bNew
, bool bExtendSelection
, bool bSameTabButMoved
)
1887 if ( !ValidTab(nTab
) )
1889 OSL_FAIL("SetTabNo: invalid sheet");
1893 if (!bNew
&& nTab
== aViewData
.GetTabNo())
1896 // FormShell would like to be informed before the switch
1897 FmFormShell
* pFormSh
= aViewData
.GetViewShell()->GetFormShell();
1900 bool bAllowed
= pFormSh
->PrepareClose();
1903 //! error message? or does FormShell do it?
1904 //! return error flag and cancel actions
1906 return; // FormShell says that it can not be switched
1910 // not InputEnterHandler due to reference input
1912 ScDocument
& rDoc
= aViewData
.GetDocument();
1914 rDoc
.MakeTable( nTab
);
1916 // Update pending row heights before switching the sheet, so Reschedule from the progress bar
1917 // doesn't paint the new sheet with old heights
1918 aViewData
.GetDocShell()->UpdatePendingRowHeights( nTab
);
1920 SCTAB nTabCount
= rDoc
.GetTableCount();
1921 SCTAB nOldPos
= nTab
;
1922 while (!rDoc
.IsVisible(nTab
)) // search for next visible
1924 bool bUp
= (nTab
>=nOldPos
);
1928 if (nTab
>=nTabCount
)
1941 OSL_FAIL("no visible sheets");
1942 rDoc
.SetVisible( 0, true );
1947 // #i71490# Deselect drawing objects before changing the sheet number in view data,
1948 // so the handling of notes still has the sheet selected on which the notes are.
1951 ScModule
* pScMod
= ScModule::get();
1952 bool bRefMode
= pScMod
->IsFormulaMode();
1953 if ( !bRefMode
) // query, so that RefMode works when switching sheet
1956 pSelEngine
->Reset(); // reset all flags, including locked modifiers
1957 aViewData
.SetRefTabNo( nTab
);
1960 ScSplitPos eOldActive
= aViewData
.GetActivePart(); // before switching
1961 bool bFocus
= pGridWin
[eOldActive
] && pGridWin
[eOldActive
]->HasFocus();
1963 aViewData
.SetTabNo( nTab
);
1964 if (mpSpellCheckCxt
)
1965 mpSpellCheckCxt
->setTabNo( nTab
);
1966 // UpdateShow before SetCursor, so that UpdateAutoFillMark finds the correct
1967 // window (is called from SetCursor)
1969 aViewData
.GetView()->TestHintWindow();
1971 SfxBindings
& rBindings
= aViewData
.GetBindings();
1972 ScMarkData
& rMark
= aViewData
.GetMarkData();
1974 bool bAllSelected
= true;
1975 for (SCTAB nSelTab
= 0; nSelTab
< nTabCount
; ++nSelTab
)
1977 if (!rDoc
.IsVisible(nSelTab
) || rMark
.GetTableSelect(nSelTab
))
1979 if (nTab
== nSelTab
)
1980 // This tab is already in selection. Keep the current
1982 bExtendSelection
= true;
1986 bAllSelected
= false;
1987 if (bExtendSelection
)
1988 // We got what we need. No need to stay in the loop.
1992 if (bAllSelected
&& !bNew
)
1993 // #i6327# if all tables are selected, a selection event (#i6330#) will deselect all
1994 // (not if called with bNew to update settings)
1995 bExtendSelection
= false;
1997 if (bExtendSelection
)
1998 rMark
.SelectTable( nTab
, true );
2001 rMark
.SelectOneTable( nTab
);
2002 rBindings
.Invalidate( FID_FILL_TAB
);
2003 rBindings
.Invalidate( FID_TAB_DESELECTALL
);
2006 bool bUnoRefDialog
= pScMod
->IsRefDialogOpen() && pScMod
->GetCurRefDlgId() == WID_SIMPLE_REF
;
2008 // recalc zoom-dependent values (before TabChanged, before UpdateEditViewPos)
2012 if ( bRefMode
) // hide EditView if necessary (after aViewData.SetTabNo !)
2014 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
2016 if (pWin
&& pWin
->IsVisible())
2017 pWin
->UpdateEditViewPos();
2021 TabChanged(bSameTabButMoved
); // DrawView
2022 collectUIInformation({{"TABLE", OUString::number(nTab
)}});
2023 UpdateVisibleRange();
2025 aViewData
.GetViewShell()->WindowChanged(); // if the active window has changed
2026 aViewData
.ResetOldCursor();
2027 SetCursor( aViewData
.GetCurX(), aViewData
.GetCurY(), true );
2029 if ( !bUnoRefDialog
)
2030 aViewData
.GetViewShell()->DisconnectAllClients(); // important for floating frames
2033 // hide / show inplace client
2034 ScClient
* pClient
= static_cast<ScClient
*>(aViewData
.GetViewShell()->GetIPClient());
2035 if ( pClient
&& pClient
->IsObjectInPlaceActive() )
2037 tools::Rectangle aObjArea
= pClient
->GetObjArea();
2038 if ( nTab
== aViewData
.GetRefTabNo() )
2040 // move to its original position
2042 SdrOle2Obj
* pDrawObj
= pClient
->GetDrawObj();
2045 tools::Rectangle aRect
= pDrawObj
->GetLogicRect();
2046 MapMode
aMapMode( MapUnit::Map100thMM
);
2047 Size aOleSize
= pDrawObj
->GetOrigObjSize( &aMapMode
);
2048 aRect
.SetSize( aOleSize
);
2054 // move to an invisible position
2056 aObjArea
.SetPos( Point( 0, -2*aObjArea
.GetHeight() ) );
2058 pClient
->SetObjArea( aObjArea
);
2062 if ( bFocus
&& aViewData
.GetActivePart() != eOldActive
&& !bRefMode
)
2063 ActiveGrabFocus(); // grab focus to the pane that's active now
2067 bool bResize
= false;
2068 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
2069 if (aViewData
.UpdateFixX())
2071 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
2072 if (aViewData
.UpdateFixY())
2078 if ( aViewData
.IsPagebreakMode() )
2079 UpdatePageBreakData(); //! asynchronously ??
2081 // Form Layer must know the visible area of the new sheet
2082 // that is why MapMode must already be correct here
2083 SyncGridWindowMapModeFromDrawMapMode();
2086 // disable invalidations for kit during tab switching
2088 ScTabViewShell
* pViewShell
= aViewData
.GetViewShell();
2089 SfxLokCallbackInterface
* pCallback
= pViewShell
->getLibreOfficeKitViewCallback();
2090 pViewShell
->setLibreOfficeKitViewCallback(nullptr);
2091 comphelper::ScopeGuard
aOutputGuard(
2092 [pViewShell
, pCallback
] {
2093 pViewShell
->setLibreOfficeKitViewCallback(pCallback
);
2102 DoResize( aBorderPos
, aFrameSize
);
2103 rBindings
.Invalidate( SID_DELETE_PRINTAREA
); // Menu
2104 rBindings
.Invalidate( FID_DEL_MANUALBREAKS
);
2105 rBindings
.Invalidate( FID_RESET_PRINTZOOM
);
2106 rBindings
.Invalidate( SID_STATUS_DOCPOS
); // Status bar
2107 rBindings
.Invalidate( SID_ROWCOL_SELCOUNT
); // Status bar
2108 rBindings
.Invalidate( SID_STATUS_PAGESTYLE
); // Status bar
2109 rBindings
.Invalidate( SID_CURRENTTAB
); // Navigator
2110 rBindings
.Invalidate( SID_STYLE_FAMILY2
); // Designer
2111 rBindings
.Invalidate( SID_STYLE_FAMILY4
); // Designer
2112 rBindings
.Invalidate( SID_TABLES_COUNT
);
2114 if (pScMod
->IsRefDialogOpen())
2116 sal_uInt16 nCurRefDlgId
=pScMod
->GetCurRefDlgId();
2117 SfxViewFrame
& rViewFrm
= aViewData
.GetViewShell()->GetViewFrame();
2118 SfxChildWindow
* pChildWnd
= rViewFrm
.GetChildWindow( nCurRefDlgId
);
2121 if (pChildWnd
->GetController())
2123 IAnyRefDialog
* pRefDlg
= dynamic_cast<IAnyRefDialog
*>(pChildWnd
->GetController().get());
2125 pRefDlg
->ViewShellChanged();
2130 OnLibreOfficeKitTabChanged();
2133 void ScTabView::AddWindowToForeignEditView(SfxViewShell
* pViewShell
, ScSplitPos eWhich
)
2135 aExtraEditViewManager
.Add(pViewShell
, eWhich
);
2138 void ScTabView::RemoveWindowFromForeignEditView(SfxViewShell
* pViewShell
, ScSplitPos eWhich
)
2140 aExtraEditViewManager
.Remove(pViewShell
, eWhich
);
2143 void ScTabView::OnLibreOfficeKitTabChanged()
2145 if (!comphelper::LibreOfficeKit::isActive())
2148 ScTabViewShell
* pThisViewShell
= aViewData
.GetViewShell();
2149 SCTAB nThisTabNo
= pThisViewShell
->GetViewData().GetTabNo();
2150 auto lTabSwitch
= [pThisViewShell
, nThisTabNo
] (ScTabViewShell
* pOtherViewShell
)
2152 ScViewData
& rOtherViewData
= pOtherViewShell
->GetViewData();
2153 SCTAB nOtherTabNo
= rOtherViewData
.GetTabNo();
2154 if (nThisTabNo
== nOtherTabNo
)
2156 for (int i
= 0; i
< 4; ++i
)
2158 if (rOtherViewData
.HasEditView(ScSplitPos(i
)))
2160 pThisViewShell
->AddWindowToForeignEditView(pOtherViewShell
, ScSplitPos(i
));
2166 for (int i
= 0; i
< 4; ++i
)
2168 if (rOtherViewData
.HasEditView(ScSplitPos(i
)))
2170 pThisViewShell
->RemoveWindowFromForeignEditView(pOtherViewShell
, ScSplitPos(i
));
2176 SfxLokHelper::forEachOtherView(pThisViewShell
, lTabSwitch
);
2178 pThisViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_HEADER
, "all"_ostr
);
2180 if (pThisViewShell
->GetInputHandler())
2181 pThisViewShell
->GetInputHandler()->UpdateLokReferenceMarks();
2184 // paint functions - only for this View
2186 void ScTabView::MakeEditView( ScEditEngineDefaulter
* pEngine
, SCCOL nCol
, SCROW nRow
)
2191 DrawEnableAnim( false );
2193 EditView
* pSpellingView
= aViewData
.GetSpellingView();
2195 for (sal_uInt16 i
= 0; i
< 4; i
++)
2197 if (pGridWin
[i
] && pGridWin
[i
]->IsVisible() && !aViewData
.HasEditView(ScSplitPos(i
)))
2199 ScHSplitPos eHWhich
= WhichH( static_cast<ScSplitPos
>(i
) );
2200 ScVSplitPos eVWhich
= WhichV( static_cast<ScSplitPos
>(i
) );
2201 SCCOL nScrX
= aViewData
.GetPosX( eHWhich
);
2202 SCROW nScrY
= aViewData
.GetPosY( eVWhich
);
2205 ( nCol
>= nScrX
&& nCol
<= nScrX
+ aViewData
.VisibleCellsX(eHWhich
) - 1 &&
2206 nRow
>= nScrY
&& nRow
<= nScrY
+ aViewData
.VisibleCellsY(eVWhich
) - 1 );
2208 // for the active part, create edit view even if outside the visible area,
2209 // so input isn't lost (and the edit view may be scrolled into the visible area)
2211 // #i26433# during spelling, the spelling view must be active
2212 if ( bPosVisible
|| aViewData
.GetActivePart() == static_cast<ScSplitPos
>(i
) ||
2213 ( pSpellingView
&& aViewData
.GetEditView(static_cast<ScSplitPos
>(i
)) == pSpellingView
) )
2215 pGridWin
[i
]->HideCursor();
2217 pGridWin
[i
]->DeleteCursorOverlay();
2218 pGridWin
[i
]->DeleteAutoFillOverlay();
2219 pGridWin
[i
]->DeleteCopySourceOverlay();
2221 // flush OverlayManager before changing MapMode to text edit
2222 pGridWin
[i
]->flushOverlayManager();
2224 // MapMode must be set after HideCursor
2225 pGridWin
[i
]->SetMapMode(aViewData
.GetLogicMode());
2229 // move the edit view area to the real (possibly negative) position,
2230 // or hide if completely above or left of the window
2231 pGridWin
[i
]->UpdateEditViewPos();
2234 aViewData
.SetEditEngine(static_cast<ScSplitPos
>(i
), pEngine
, pGridWin
[i
], nCol
,
2240 if (aViewData
.GetViewShell()->HasAccessibilityObjects())
2241 aViewData
.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccEnterEditMode
));
2244 void ScTabView::UpdateEditView()
2246 if (aViewData
.GetTabNo() != aViewData
.GetRefTabNo() && ScModule::get()->IsFormulaMode())
2249 ScSplitPos eActive
= aViewData
.GetActivePart();
2250 for (sal_uInt16 i
= 0; i
< 4; i
++)
2252 ScSplitPos eCurrent
= ScSplitPos(i
);
2253 if (aViewData
.HasEditView(eCurrent
))
2255 EditView
* pEditView
= aViewData
.GetEditView(eCurrent
);
2257 tools::Long nRefTabNo
= GetViewData().GetRefTabNo();
2258 tools::Long nX
= GetViewData().GetCurXForTab(nRefTabNo
);
2259 tools::Long nY
= GetViewData().GetCurYForTab(nRefTabNo
);
2261 aViewData
.SetEditEngine(eCurrent
,
2262 static_cast<ScEditEngineDefaulter
*>(&pEditView
->getEditEngine()),
2263 pGridWin
[i
], nX
, nY
);
2264 if (eCurrent
== eActive
)
2265 pEditView
->ShowCursor( false );
2270 void ScTabView::KillEditView( bool bNoPaint
)
2272 SCCOL nCol1
= aViewData
.GetEditStartCol();
2273 SCROW nRow1
= aViewData
.GetEditStartRow();
2274 SCCOL nCol2
= aViewData
.GetEditEndCol();
2275 SCROW nRow2
= aViewData
.GetEditEndRow();
2276 SCTAB nTab
= aViewData
.GetTabNo();
2278 bool bNotifyAcc
= false;
2279 tools::Rectangle aRectangle
[4];
2281 bool bExtended
= nRow1
!= nRow2
; // column is painted to the end anyway
2283 bool bAtCursor
= nCol1
<= aViewData
.GetCurX() &&
2284 nCol2
>= aViewData
.GetCurX() &&
2285 nRow1
== aViewData
.GetCurY();
2286 for (sal_uInt16 i
= 0; i
< 4; i
++)
2288 bPaint
[i
] = aViewData
.HasEditView( static_cast<ScSplitPos
>(i
) );
2293 EditView
* pView
= aViewData
.GetEditView( static_cast<ScSplitPos
>(i
) );
2294 aRectangle
[i
] = pView
->GetInvalidateRect();
2298 // notify accessibility before all things happen
2299 if (bNotifyAcc
&& aViewData
.GetViewShell()->HasAccessibilityObjects())
2300 aViewData
.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccLeaveEditMode
));
2302 aViewData
.ResetEditView();
2303 for (sal_uInt16 i
= 0; i
< 4; i
++)
2305 if (pGridWin
[i
] && bPaint
[i
] && pGridWin
[i
]->IsVisible())
2307 pGridWin
[i
]->ShowCursor();
2309 pGridWin
[i
]->SetMapMode(pGridWin
[i
]->GetDrawMapMode());
2311 const tools::Rectangle
& rInvRect
= aRectangle
[i
];
2313 if (comphelper::LibreOfficeKit::isActive())
2315 pGridWin
[i
]->LogicInvalidatePart(&rInvRect
, nTab
);
2317 // invalidate other views
2318 auto lInvalidateWindows
=
2319 [nTab
, &rInvRect
] (ScTabView
* pTabView
)
2321 for (VclPtr
<ScGridWindow
> const & pWin
: pTabView
->pGridWin
)
2324 pWin
->LogicInvalidatePart(&rInvRect
, nTab
);
2328 SfxLokHelper::forEachOtherView(GetViewData().GetViewShell(), lInvalidateWindows
);
2330 // #i73567# the cell still has to be repainted
2333 const bool bDoPaint
= bExtended
|| (bAtCursor
&& !bNoPaint
);
2334 const bool bDoInvalidate
= !bDoPaint
&& bAtCursor
;
2337 pGridWin
[i
]->Draw( nCol1
, nRow1
, nCol2
, nRow2
, ScUpdateMode::All
);
2338 pGridWin
[i
]->UpdateSelectionOverlay();
2340 else if (bDoInvalidate
)
2342 // tdf#162651 even if !bNoPaint is set, and there will be a
2343 // follow up Draw of the next content, the area blanked out
2344 // by the editview which is being removed still needs to be
2345 // invalidated. The follow-up Draw of the content may be
2346 // optimized to only redraw the area of cells where content
2347 // has changed and will be unaware of what bounds this
2348 // editview grew to during its editing cycle.
2349 pGridWin
[i
]->Invalidate(rInvRect
);
2356 DrawEnableAnim( true );
2358 // GrabFocus always when this View is active and
2359 // when the input row has the focus
2361 bool bGrabFocus
= false;
2362 if (aViewData
.IsActive())
2364 ScInputHandler
* pInputHdl
= ScModule::get()->GetInputHdl();
2367 ScInputWindow
* pInputWin
= pInputHdl
->GetInputWindow();
2368 if (pInputWin
&& pInputWin
->IsInputActive())
2375 // should be done like this, so that Sfx notice it, but it does not work:
2376 //! aViewData.GetViewShell()->GetViewFrame().GetWindow().GrabFocus();
2377 // therefore first like this:
2378 GetActiveWin()->GrabFocus();
2381 // cursor query only after GrabFocus
2383 for (sal_uInt16 i
= 0; i
< 4; i
++)
2385 if (pGridWin
[i
] && pGridWin
[i
]->IsVisible())
2387 vcl::Cursor
* pCur
= pGridWin
[i
]->GetCursor();
2388 if (pCur
&& pCur
->IsVisible())
2393 pGridWin
[i
]->UpdateCursorOverlay();
2394 pGridWin
[i
]->UpdateAutoFillOverlay();
2400 void ScTabView::UpdateFormulas(SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
)
2402 if ( aViewData
.GetDocument().IsAutoCalcShellDisabled() )
2405 for (sal_uInt16 i
= 0; i
< 4; i
++)
2407 if (pGridWin
[i
] && pGridWin
[i
]->IsVisible())
2408 pGridWin
[i
]->UpdateFormulas(nStartCol
, nStartRow
, nEndCol
, nEndRow
);
2411 if ( aViewData
.IsPagebreakMode() )
2412 UpdatePageBreakData(); //! asynchronous
2414 bool bIsTiledRendering
= comphelper::LibreOfficeKit::isActive();
2415 // UpdateHeaderWidth can fit the GridWindow widths to the frame, something
2416 // we don't want in kit-mode where we try and match the GridWindow width
2417 // to the tiled area separately
2418 if (!bIsTiledRendering
)
2419 UpdateHeaderWidth();
2421 // if in edit mode, adjust edit view area because widths/heights may have changed
2422 if ( aViewData
.HasEditView( aViewData
.GetActivePart() ) )
2426 // PaintArea - repaint block
2428 void ScTabView::PaintArea( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
,
2429 ScUpdateMode eMode
, tools::Long nMaxWidthAffectedHintTwip
)
2435 bool bIsTiledRendering
= comphelper::LibreOfficeKit::isActive();
2436 ScDocument
& rDoc
= aViewData
.GetDocument();
2438 PutInOrder( nStartCol
, nEndCol
);
2439 PutInOrder( nStartRow
, nEndRow
);
2441 for (size_t i
= 0; i
< 4; ++i
)
2443 if (!pGridWin
[i
] || !pGridWin
[i
]->IsVisible())
2446 ScHSplitPos eHWhich
= WhichH( static_cast<ScSplitPos
>(i
) );
2447 ScVSplitPos eVWhich
= WhichV( static_cast<ScSplitPos
>(i
) );
2458 if (bIsTiledRendering
)
2460 nLastX
= aViewData
.GetMaxTiledCol();
2461 nLastY
= aViewData
.GetMaxTiledRow();
2466 SCCOL nScrX
= aViewData
.GetPosX( eHWhich
);
2467 SCROW nScrY
= aViewData
.GetPosY( eVWhich
);
2473 if ( eMode
== ScUpdateMode::All
) // for UPDATE_ALL, paint anyway
2474 nCol2
= nScrX
; // (because of extending strings to the right)
2476 bOut
= true; // completely outside the window
2483 nLastX
= nScrX
+ aViewData
.VisibleCellsX( eHWhich
) + 1;
2484 nLastY
= nScrY
+ aViewData
.VisibleCellsY( eVWhich
) + 1;
2499 bool bLayoutRTL
= aViewData
.GetDocument().IsLayoutRTL( aViewData
.GetTabNo() );
2500 tools::Long nLayoutSign
= (!bIsTiledRendering
&& bLayoutRTL
) ? -1 : 1;
2502 Point aStart
= aViewData
.GetScrPos( nCol1
, nRow1
, static_cast<ScSplitPos
>(i
) );
2503 Point aEnd
= aViewData
.GetScrPos( nCol2
+1, nRow2
+1, static_cast<ScSplitPos
>(i
) );
2505 if ( eMode
== ScUpdateMode::All
)
2507 if (nMaxWidthAffectedHintTwip
!= -1)
2509 tools::Long nMaxWidthAffectedHint
= ScViewData::ToPixel(nMaxWidthAffectedHintTwip
, aViewData
.GetPPTX());
2511 // If we know the max text width affected then just invalidate
2512 // the max of the cell width and hint of affected cell width
2513 // (where affected with is in terms of max width of optimal cell
2514 // width for before/after change)
2515 tools::Long nCellWidth
= std::abs(aEnd
.X() - aStart
.X());
2516 aEnd
.setX(aStart
.getX() + std::max(nCellWidth
, nMaxWidthAffectedHint
) * nLayoutSign
);
2520 if (bIsTiledRendering
)
2522 // When a cell content is deleted we have no clue about
2523 // the width of the embedded text.
2524 // Anyway, clients will ask only for tiles that overlaps
2525 // the visible area.
2526 // Remember that wsd expects int and that aEnd.X() is
2527 // in pixels and will be converted in twips, before performing
2528 // the lok callback, so we need to avoid that an overflow occurs.
2529 aEnd
.setX( std::numeric_limits
<int>::max() / 1000 );
2533 aEnd
.setX( bLayoutRTL
? 0 : pGridWin
[i
]->GetOutputSizePixel().Width() );
2537 aEnd
.AdjustX( -nLayoutSign
);
2540 // #i85232# include area below cells (could be done in GetScrPos?)
2541 if ( eMode
== ScUpdateMode::All
&& nRow2
>= rDoc
.MaxRow() && !bIsTiledRendering
)
2542 aEnd
.setY( pGridWin
[i
]->GetOutputSizePixel().Height() );
2544 aStart
.AdjustX( -nLayoutSign
); // include change marks
2545 aStart
.AdjustY( -1 );
2547 bool bMarkClipped
= ScModule::get()->GetColorConfig().GetColorValue(svtools::CALCTEXTOVERFLOW
).bIsVisible
;
2550 // ScColumn::IsEmptyData has to be optimized for this
2551 // (switch to Search() )
2552 //!if ( nCol1 > 0 && !aViewData.GetDocument()->IsBlockEmpty(
2553 //! 0, nRow1, nCol1-1, nRow2.
2554 //! aViewData.GetTabNo() ) )
2555 tools::Long nMarkPixel
= static_cast<tools::Long
>( SC_CLIPMARK_SIZE
* aViewData
.GetPPTX() );
2556 aStart
.AdjustX( -(nMarkPixel
* nLayoutSign
) );
2559 pGridWin
[i
]->Invalidate( pGridWin
[i
]->PixelToLogic( tools::Rectangle( aStart
,aEnd
) ) );
2562 // #i79909# Calling UpdateAllOverlays here isn't necessary and would lead to overlay calls from a timer,
2563 // with a wrong MapMode if editing in a cell (reference input).
2564 // #i80499# Overlays need updates in a lot of cases, e.g. changing row/column size,
2565 // or showing/hiding outlines. TODO: selections in inactive windows are vanishing.
2566 // #i84689# With relative conditional formats, PaintArea may be called often (for each changed cell),
2567 // so UpdateAllOverlays was moved to ScTabViewShell::Notify and is called only if PaintPartFlags::Left/PaintPartFlags::Top
2568 // is set (width or height changed).
2571 void ScTabView::PaintRangeFinderEntry (const ScRangeFindData
* pData
, const SCTAB nTab
)
2573 ScRange aRef
= pData
->aRef
;
2574 aRef
.PutInOrder(); // PutInOrder for the queries below
2576 if ( aRef
.aStart
== aRef
.aEnd
) //! ignore sheet?
2577 aViewData
.GetDocument().ExtendMerge(aRef
);
2579 if (aRef
.aStart
.Tab() < nTab
|| aRef
.aEnd
.Tab() > nTab
)
2582 SCCOL nCol1
= aRef
.aStart
.Col();
2583 SCROW nRow1
= aRef
.aStart
.Row();
2584 SCCOL nCol2
= aRef
.aEnd
.Col();
2585 SCROW nRow2
= aRef
.aEnd
.Row();
2587 // remove -> repaint
2588 // ScUpdateMode::Marks: Invalidate, nothing until end of row
2590 bool bHiddenEdge
= false;
2592 ScDocument
& rDoc
= aViewData
.GetDocument();
2593 while ( nCol1
> 0 && rDoc
.ColHidden(nCol1
, nTab
) )
2598 while ( nCol2
< rDoc
.MaxCol() && rDoc
.ColHidden(nCol2
, nTab
) )
2603 nTmp
= rDoc
.LastVisibleRow(0, nRow1
, nTab
);
2604 if (!rDoc
.ValidRow(nTmp
))
2611 nTmp
= rDoc
.FirstVisibleRow(nRow2
, rDoc
.MaxRow(), nTab
);
2612 if (!rDoc
.ValidRow(nTmp
))
2613 nTmp
= rDoc
.MaxRow();
2620 if ( nCol2
- nCol1
> 1 && nRow2
- nRow1
> 1 && !bHiddenEdge
)
2622 // only along the edges
2623 PaintArea( nCol1
, nRow1
, nCol2
, nRow1
, ScUpdateMode::Marks
);
2624 PaintArea( nCol1
, nRow1
+1, nCol1
, nRow2
-1, ScUpdateMode::Marks
);
2625 PaintArea( nCol2
, nRow1
+1, nCol2
, nRow2
-1, ScUpdateMode::Marks
);
2626 PaintArea( nCol1
, nRow2
, nCol2
, nRow2
, ScUpdateMode::Marks
);
2629 PaintArea( nCol1
, nRow1
, nCol2
, nRow2
, ScUpdateMode::Marks
);
2632 void ScTabView::PaintRangeFinder( tools::Long nNumber
)
2634 ScInputHandler
* pHdl
= ScModule::get()->GetInputHdl(aViewData
.GetViewShell());
2638 ScRangeFindList
* pRangeFinder
= pHdl
->GetRangeFindList();
2639 if ( !(pRangeFinder
&& pRangeFinder
->GetDocName() == aViewData
.GetDocShell()->GetTitle()) )
2642 SCTAB nTab
= aViewData
.GetTabNo();
2643 sal_uInt16 nCount
= static_cast<sal_uInt16
>(pRangeFinder
->Count());
2647 for (sal_uInt16 i
=0; i
<nCount
; i
++)
2648 PaintRangeFinderEntry(&pRangeFinder
->GetObject(i
),nTab
);
2652 sal_uInt16 idx
= nNumber
;
2654 PaintRangeFinderEntry(&pRangeFinder
->GetObject(idx
),nTab
);
2658 // for chart data selection
2660 void ScTabView::AddHighlightRange( const ScRange
& rRange
, const Color
& rColor
)
2662 maHighlightRanges
.emplace_back( rRange
, rColor
);
2664 SCTAB nTab
= aViewData
.GetTabNo();
2665 if ( nTab
>= rRange
.aStart
.Tab() && nTab
<= rRange
.aEnd
.Tab() )
2666 PaintArea( rRange
.aStart
.Col(), rRange
.aStart
.Row(),
2667 rRange
.aEnd
.Col(), rRange
.aEnd
.Row(), ScUpdateMode::Marks
);
2670 void ScTabView::ClearHighlightRanges()
2672 SCTAB nTab
= aViewData
.GetTabNo();
2673 for (ScHighlightEntry
const & rEntry
: maHighlightRanges
)
2675 ScRange aRange
= rEntry
.aRef
;
2676 if ( nTab
>= aRange
.aStart
.Tab() && nTab
<= aRange
.aEnd
.Tab() )
2677 PaintArea( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
2678 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(), ScUpdateMode::Marks
);
2681 maHighlightRanges
.clear();
2684 void ScTabView::DoChartSelection(
2685 const uno::Sequence
< chart2::data::HighlightedRange
> & rHilightRanges
)
2687 ClearHighlightRanges();
2688 const sal_Unicode sep
= ::formula::FormulaCompiler::GetNativeSymbolChar(ocSep
);
2691 std::vector
<ReferenceMark
> aReferenceMarks( nSize
);
2693 for (chart2::data::HighlightedRange
const & rHighlightedRange
: rHilightRanges
)
2695 Color
aSelColor(ColorTransparency
, rHighlightedRange
.PreferredColor
);
2696 ScRangeList aRangeList
;
2697 ScDocument
& rDoc
= aViewData
.GetDocShell()->GetDocument();
2698 if( ScRangeStringConverter::GetRangeListFromString(
2699 aRangeList
, rHighlightedRange
.RangeRepresentation
, rDoc
, rDoc
.GetAddressConvention(), sep
))
2701 size_t nListSize
= aRangeList
.size();
2703 aReferenceMarks
.resize(nSize
);
2705 for ( size_t j
= 0; j
< nListSize
; ++j
)
2707 ScRange
& p
= aRangeList
[j
];
2708 ScRange aTargetRange
;
2709 if( rHighlightedRange
.Index
== - 1 )
2712 AddHighlightRange( aTargetRange
, aSelColor
);
2716 aTargetRange
= lcl_getSubRangeByIndex( p
, rHighlightedRange
.Index
);
2717 AddHighlightRange( aTargetRange
, aSelColor
);
2720 if ( comphelper::LibreOfficeKit::isActive() && aViewData
.GetViewShell() )
2722 aTargetRange
.PutInOrder();
2724 tools::Long nX1
= aTargetRange
.aStart
.Col();
2725 tools::Long nX2
= aTargetRange
.aEnd
.Col();
2726 tools::Long nY1
= aTargetRange
.aStart
.Row();
2727 tools::Long nY2
= aTargetRange
.aEnd
.Row();
2728 tools::Long nTab
= aTargetRange
.aStart
.Tab();
2730 aReferenceMarks
[nIndex
++] = ScInputHandler::GetReferenceMark( aViewData
, aViewData
.GetDocShell(),
2738 if ( comphelper::LibreOfficeKit::isActive() && aViewData
.GetViewShell() )
2739 ScInputHandler::SendReferenceMarks( aViewData
.GetViewShell(), aReferenceMarks
);
2742 void ScTabView::DoDPFieldPopup(std::u16string_view rPivotTableName
, sal_Int32 nDimensionIndex
, Point aPoint
, Size aSize
)
2744 ScDocument
& rDocument
= aViewData
.GetDocShell()->GetDocument();
2745 ScGridWindow
* pWin
= pGridWin
[aViewData
.GetActivePart()].get();
2750 ScDPCollection
* pDPCollection
= rDocument
.GetDPCollection();
2751 ScDPObject
* pDPObject
= pDPCollection
->GetByName(rPivotTableName
);
2755 pDPObject
->BuildAllDimensionMembers();
2757 Point aPos
= pWin
->LogicToPixel(aPoint
);
2758 bool bLOK
= comphelper::LibreOfficeKit::isActive();
2759 Point aScreenPoint
= bLOK
? aPos
: pWin
->OutputToScreenPixel(aPos
);
2760 Size aScreenSize
= pWin
->LogicToPixel(aSize
);
2762 pWin
->DPLaunchFieldPopupMenu(aScreenPoint
, aScreenSize
, nDimensionIndex
, pDPObject
);
2765 // PaintGrid - repaint data range
2767 void ScTabView::PaintGrid()
2769 for (sal_uInt16 i
= 0; i
< 4; i
++)
2771 if (pGridWin
[i
] && pGridWin
[i
]->IsVisible())
2772 pGridWin
[i
]->Invalidate();
2776 // PaintTop - repaint top control elements
2778 void ScTabView::PaintTop()
2780 for (sal_uInt16 i
= 0; i
< 2; i
++)
2783 pColBar
[i
]->Invalidate();
2785 pColOutline
[i
]->Invalidate();
2789 void ScTabView::CreateAnchorHandles(SdrHdlList
& rHdl
, const ScAddress
& rAddress
)
2791 for (sal_uInt16 i
= 0; i
< 4; i
++)
2793 if(pGridWin
[i
] && pGridWin
[i
]->IsVisible())
2794 pGridWin
[i
]->CreateAnchorHandle(rHdl
, rAddress
);
2798 void ScTabView::PaintTopArea( SCCOL nStartCol
, SCCOL nEndCol
)
2800 // pixel position of the left edge
2802 if ( nStartCol
< aViewData
.GetPosX(SC_SPLIT_LEFT
) ||
2803 nStartCol
< aViewData
.GetPosX(SC_SPLIT_RIGHT
) )
2804 aViewData
.RecalcPixPos();
2806 // adjust freeze (UpdateFixX resets HSplitPos)
2808 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
&& nStartCol
< aViewData
.GetFixPosX() )
2809 if (aViewData
.UpdateFixX())
2815 --nStartCol
; //! general ?
2817 ScDocument
& rDoc
= aViewData
.GetDocument();
2818 bool bLayoutRTL
= rDoc
.IsLayoutRTL( aViewData
.GetTabNo() );
2819 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
2821 for (sal_uInt16 i
= 0; i
< 2; i
++)
2823 ScHSplitPos eWhich
= ScHSplitPos(i
);
2824 if (pColBar
[eWhich
])
2826 Size aWinSize
= pColBar
[eWhich
]->GetSizePixel();
2827 tools::Long nStartX
= aViewData
.GetScrPos( nStartCol
, 0, eWhich
).X();
2829 if (nEndCol
>= rDoc
.MaxCol())
2830 nEndX
= bLayoutRTL
? 0 : ( aWinSize
.Width()-1 );
2832 nEndX
= aViewData
.GetScrPos( nEndCol
+1, 0, eWhich
).X() - nLayoutSign
;
2833 if (nStartX
> nEndX
)
2834 std::swap(nStartX
, nEndX
);
2835 pColBar
[eWhich
]->Invalidate(
2836 tools::Rectangle( nStartX
, 0, nEndX
, aWinSize
.Height()-1 ) );
2838 if (pColOutline
[eWhich
])
2839 pColOutline
[eWhich
]->Invalidate();
2843 // PaintLeft - repaint left control elements
2845 void ScTabView::PaintLeft()
2847 for (sal_uInt16 i
= 0; i
< 2; i
++)
2850 pRowBar
[i
]->Invalidate();
2852 pRowOutline
[i
]->Invalidate();
2856 void ScTabView::PaintLeftArea( SCROW nStartRow
, SCROW nEndRow
)
2858 // pixel position of the upper edge
2860 if ( nStartRow
< aViewData
.GetPosY(SC_SPLIT_TOP
) ||
2861 nStartRow
< aViewData
.GetPosY(SC_SPLIT_BOTTOM
) )
2862 aViewData
.RecalcPixPos();
2864 // adjust freeze (UpdateFixY reset VSplitPos)
2866 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
&& nStartRow
< aViewData
.GetFixPosY() )
2867 if (aViewData
.UpdateFixY())
2875 ScDocument
& rDoc
= aViewData
.GetDocument();
2876 for (sal_uInt16 i
= 0; i
< 2; i
++)
2878 ScVSplitPos eWhich
= ScVSplitPos(i
);
2879 if (pRowBar
[eWhich
])
2881 Size aWinSize
= pRowBar
[eWhich
]->GetSizePixel();
2882 tools::Long nStartY
= aViewData
.GetScrPos( 0, nStartRow
, eWhich
).Y();
2884 if (nEndRow
>= rDoc
.MaxRow())
2885 nEndY
= aWinSize
.Height() - 1;
2887 nEndY
= aViewData
.GetScrPos( 0, nEndRow
+1, eWhich
).Y() - 1;
2888 if (nStartY
> nEndY
)
2889 std::swap(nStartY
, nEndY
);
2890 pRowBar
[eWhich
]->Invalidate(
2891 tools::Rectangle( 0, nStartY
, aWinSize
.Width()-1, nEndY
) );
2893 if (pRowOutline
[eWhich
])
2894 pRowOutline
[eWhich
]->Invalidate();
2898 bool ScTabView::PaintExtras()
2901 ScDocument
& rDoc
= aViewData
.GetDocument();
2902 SCTAB nTab
= aViewData
.GetTabNo();
2903 if (!rDoc
.HasTable(nTab
)) // sheet is deleted?
2905 SCTAB nCount
= rDoc
.GetTableCount();
2906 aViewData
.SetTabNo(nCount
-1);
2909 pTabControl
->UpdateStatus(); // true = active
2913 void ScTabView::RecalcPPT()
2915 // called after changes that require the PPT values to be recalculated
2916 // (currently from detective operations)
2918 double nOldX
= aViewData
.GetPPTX();
2919 double nOldY
= aViewData
.GetPPTY();
2921 aViewData
.RefreshZoom(); // pre-calculate new PPT values
2923 bool bChangedX
= ( aViewData
.GetPPTX() != nOldX
);
2924 bool bChangedY
= ( aViewData
.GetPPTY() != nOldY
);
2925 if ( !(bChangedX
|| bChangedY
) )
2928 // call view SetZoom (including draw scale, split update etc)
2929 // and paint only if values changed
2931 Fraction aZoomX
= aViewData
.GetZoomX();
2932 Fraction aZoomY
= aViewData
.GetZoomY();
2933 SetZoom( aZoomX
, aZoomY
, false );
2942 void ScTabView::ActivateView( bool bActivate
, bool bFirst
)
2944 if ( bActivate
== aViewData
.IsActive() && !bFirst
)
2946 // no assertion anymore - occurs when previously in Drag&Drop switching over
2947 // to another document
2951 // is only called for MDI-(De)Activate
2952 // aViewData.Activate behind due to cursor show for KillEditView
2953 // don't delete selection - if Activate(false) is set in ViewData,
2954 // then the selection is not displayed
2958 ScModule
* pScMod
= ScModule::get();
2959 bool bRefMode
= pScMod
->IsFormulaMode();
2961 // don't cancel reference input, to allow reference
2962 // to other document
2966 // pass view to GetInputHdl, this view may not be current anymore
2967 ScInputHandler
* pHdl
= pScMod
->GetInputHdl(aViewData
.GetViewShell());
2969 pHdl
->EnterHandler();
2975 aViewData
.Activate(bActivate
);
2977 PaintBlock(false); // repaint, selection after active status
2980 HideAllCursors(); // Cursor
2988 ScSplitPos eWin
= aViewData
.GetActivePart();
2989 OSL_ENSURE( pGridWin
[eWin
], "Corrupted document, not all SplitPos in GridWin" );
2990 if ( !pGridWin
[eWin
] )
2992 eWin
= SC_SPLIT_BOTTOMLEFT
;
2993 if ( !pGridWin
[eWin
] )
2996 for ( i
=0; i
<4; i
++ )
3000 eWin
= static_cast<ScSplitPos
>(i
);
3004 OSL_ENSURE( i
<4, "and BOOM" );
3006 aViewData
.SetActivePart( eWin
);
3009 // do not call GrabFocus from here!
3010 // if the document is processed, then Sfx calls GrabFocus in the window of the shell.
3011 // if it is a mail body for instance, then it can't get the focus
3012 UpdateInputContext();
3015 pGridWin
[aViewData
.GetActivePart()]->ClickExtern();
3018 void ScTabView::ActivatePart( ScSplitPos eWhich
)
3020 ScSplitPos eOld
= aViewData
.GetActivePart();
3021 if ( eOld
== eWhich
)
3024 bInActivatePart
= true;
3026 bool bRefMode
= ScModule::get()->IsFormulaMode();
3028 // the HasEditView call during SetCursor would fail otherwise
3029 if ( aViewData
.HasEditView(eOld
) && !bRefMode
)
3032 ScHSplitPos eOldH
= WhichH(eOld
);
3033 ScVSplitPos eOldV
= WhichV(eOld
);
3034 ScHSplitPos eNewH
= WhichH(eWhich
);
3035 ScVSplitPos eNewV
= WhichV(eWhich
);
3036 bool bTopCap
= pColBar
[eOldH
] && pColBar
[eOldH
]->IsMouseCaptured();
3037 bool bLeftCap
= pRowBar
[eOldV
] && pRowBar
[eOldV
]->IsMouseCaptured();
3039 bool bFocus
= pGridWin
[eOld
]->HasFocus();
3040 bool bCapture
= pGridWin
[eOld
]->IsMouseCaptured();
3042 pGridWin
[eOld
]->ReleaseMouse();
3043 pGridWin
[eOld
]->ClickExtern();
3044 pGridWin
[eOld
]->HideCursor();
3045 pGridWin
[eWhich
]->HideCursor();
3046 aViewData
.SetActivePart( eWhich
);
3048 ScTabViewShell
* pShell
= aViewData
.GetViewShell();
3049 pShell
->WindowChanged();
3051 pSelEngine
->SetWindow(pGridWin
[eWhich
]);
3052 pSelEngine
->SetWhich(eWhich
);
3053 pSelEngine
->SetVisibleArea( tools::Rectangle(Point(), pGridWin
[eWhich
]->GetOutputSizePixel()) );
3055 pGridWin
[eOld
]->MoveMouseStatus(*pGridWin
[eWhich
]);
3057 if ( bCapture
|| pGridWin
[eWhich
]->IsMouseCaptured() )
3059 // tracking instead of CaptureMouse, so it can be cancelled cleanly
3060 // (SelectionEngine calls CaptureMouse for SetWindow)
3061 //! someday SelectionEngine itself should call StartTracking!?!
3062 pGridWin
[eWhich
]->ReleaseMouse();
3063 pGridWin
[eWhich
]->StartTracking();
3066 if ( bTopCap
&& pColBar
[eNewH
] )
3068 pColBar
[eOldH
]->SetIgnoreMove(true);
3069 pColBar
[eNewH
]->SetIgnoreMove(false);
3070 pHdrSelEng
->SetWindow( pColBar
[eNewH
] );
3071 tools::Long nWidth
= pColBar
[eNewH
]->GetOutputSizePixel().Width();
3072 pHdrSelEng
->SetVisibleArea( tools::Rectangle( 0, LONG_MIN
, nWidth
-1, LONG_MAX
) );
3073 pColBar
[eNewH
]->CaptureMouse();
3075 if ( bLeftCap
&& pRowBar
[eNewV
] )
3077 pRowBar
[eOldV
]->SetIgnoreMove(true);
3078 pRowBar
[eNewV
]->SetIgnoreMove(false);
3079 pHdrSelEng
->SetWindow( pRowBar
[eNewV
] );
3080 tools::Long nHeight
= pRowBar
[eNewV
]->GetOutputSizePixel().Height();
3081 pHdrSelEng
->SetVisibleArea( tools::Rectangle( LONG_MIN
, 0, LONG_MAX
, nHeight
-1 ) );
3082 pRowBar
[eNewV
]->CaptureMouse();
3084 aHdrFunc
.SetWhich(eWhich
);
3086 pGridWin
[eOld
]->ShowCursor();
3087 pGridWin
[eWhich
]->ShowCursor();
3089 SfxInPlaceClient
* pClient
= aViewData
.GetViewShell()->GetIPClient();
3090 bool bOleActive
= ( pClient
&& pClient
->IsObjectInPlaceActive() );
3092 // don't switch ViewShell's active window during RefInput, because the focus
3093 // might change, and subsequent SetReference calls wouldn't find the right EditView
3094 if ( !bRefMode
&& !bOleActive
)
3095 aViewData
.GetViewShell()->SetWindow( pGridWin
[eWhich
] );
3097 if ( bFocus
&& !aViewData
.IsAnyFillMode() && !bRefMode
)
3099 // GrabFocus only if previously the other GridWindow had the focus
3100 // (for instance due to search and replace)
3101 pGridWin
[eWhich
]->GrabFocus();
3104 bInActivatePart
= false;
3107 void ScTabView::HideListBox()
3109 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
3112 pWin
->ClickExtern();
3116 void ScTabView::UpdateInputContext()
3118 ScGridWindow
* pWin
= pGridWin
[aViewData
.GetActivePart()].get();
3120 pWin
->UpdateInputContext();
3123 pTabControl
->UpdateInputContext();
3126 // GetGridWidth - width of an output range (for ViewData)
3128 tools::Long
ScTabView::GetGridWidth( ScHSplitPos eWhich
)
3130 // at present only the size of the current pane is synchronized with
3131 // the size of the visible area in Online;
3132 // as a workaround we use the same width for all panes independently
3133 // from the eWhich value
3134 if (comphelper::LibreOfficeKit::isActive())
3136 ScGridWindow
* pGridWindow
= aViewData
.GetActiveWin();
3138 return pGridWindow
->GetSizePixel().Width();
3141 ScSplitPos eGridWhich
= ( eWhich
== SC_SPLIT_LEFT
) ? SC_SPLIT_BOTTOMLEFT
: SC_SPLIT_BOTTOMRIGHT
;
3142 if (pGridWin
[eGridWhich
])
3143 return pGridWin
[eGridWhich
]->GetSizePixel().Width();
3148 // GetGridHeight - height of an output range (for ViewData)
3150 tools::Long
ScTabView::GetGridHeight( ScVSplitPos eWhich
)
3152 // at present only the size of the current pane is synchronized with
3153 // the size of the visible area in Online;
3154 // as a workaround we use the same height for all panes independently
3155 // from the eWhich value
3156 if (comphelper::LibreOfficeKit::isActive())
3158 ScGridWindow
* pGridWindow
= aViewData
.GetActiveWin();
3160 return pGridWindow
->GetSizePixel().Height();
3163 ScSplitPos eGridWhich
= ( eWhich
== SC_SPLIT_TOP
) ? SC_SPLIT_TOPLEFT
: SC_SPLIT_BOTTOMLEFT
;
3164 if (pGridWin
[eGridWhich
])
3165 return pGridWin
[eGridWhich
]->GetSizePixel().Height();
3170 void ScTabView::UpdateInputLine()
3172 ScModule::get()->InputEnterHandler();
3175 void ScTabView::SyncGridWindowMapModeFromDrawMapMode()
3177 // AW: Discussed with NN if there is a reason that new map mode was only set for one window,
3178 // but is not. Setting only on one window causes the first repaint to have the old mapMode
3179 // in three of four views, so the overlay will save the wrong content e.g. when zooming out.
3180 // Changing to setting map mode at all windows.
3181 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
3185 pWin
->SetMapMode(pWin
->GetDrawMapMode());
3189 void ScTabView::ZoomChanged()
3191 ScInputHandler
* pHdl
= ScModule::get()->GetInputHdl(aViewData
.GetViewShell());
3193 pHdl
->SetRefScale( aViewData
.GetZoomX(), aViewData
.GetZoomY() );
3199 SyncGridWindowMapModeFromDrawMapMode();
3204 InterpretVisible(); // have everything calculated before painting
3206 SfxBindings
& rBindings
= aViewData
.GetBindings();
3207 rBindings
.Invalidate( SID_ATTR_ZOOM
);
3208 rBindings
.Invalidate( SID_ATTR_ZOOMSLIDER
);
3209 rBindings
.Invalidate(SID_ZOOM_IN
);
3210 rBindings
.Invalidate(SID_ZOOM_OUT
);
3214 // To not change too much, use pWin here
3215 ScGridWindow
* pWin
= pGridWin
[aViewData
.GetActivePart()].get();
3217 if ( pWin
&& aViewData
.HasEditView( aViewData
.GetActivePart() ) )
3219 // flush OverlayManager before changing the MapMode
3220 pWin
->flushOverlayManager();
3222 // make sure the EditView's position and size are updated
3223 // with the right (logic, not drawing) MapMode
3224 pWin
->SetMapMode( aViewData
.GetLogicMode() );
3229 void ScTabView::CheckNeedsRepaint()
3231 for (sal_uInt16 i
= 0; i
< 4; i
++)
3233 if (pGridWin
[i
] && pGridWin
[i
]->IsVisible())
3234 pGridWin
[i
]->CheckNeedsRepaint();
3238 bool ScTabView::NeedsRepaint()
3240 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
3242 if (pWin
&& pWin
->IsVisible() && pWin
->NeedsRepaint())
3248 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */