1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <rangelst.hxx>
21 #include <scitems.hxx>
22
23 #include <editeng/editview.hxx>
24 #include <svx/fmshell.hxx>
25 #include <svx/sdr/overlay/overlaymanager.hxx>
26 #include <svx/svdoole2.hxx>
27 #include <sfx2/bindings.hxx>
28 #include <sfx2/lokhelper.hxx>
29 #include <sfx2/viewfrm.hxx>
30 #include <vcl/cursor.hxx>
31 #include <vcl/uitest/logger.hxx>
32 #include <vcl/uitest/eventdescription.hxx>
33 #include <sal/log.hxx>
34 #include <osl/diagnose.h>
35
36 #include <IAnyRefDialog.hxx>
37 #include <tabview.hxx>
38 #include <tabvwsh.hxx>
39 #include <docsh.hxx>
40 #include <gridwin.hxx>
41 #include <olinewin.hxx>
42 #include <overlayobject.hxx>
43 #include <colrowba.hxx>
44 #include <tabcont.hxx>
45 #include <scmod.hxx>
46 #include <sc.hrc>
47 #include <viewutil.hxx>
48 #include <editutil.hxx>
49 #include <inputhdl.hxx>
50 #include <inputwin.hxx>
51 #include <validat.hxx>
52 #include <inputopt.hxx>
53 #include <rfindlst.hxx>
54 #include <hiranges.hxx>
55 #include <viewuno.hxx>
56 #include <dpobject.hxx>
57 #include <seltrans.hxx>
58 #include <fillinfo.hxx>
59 #include <rangeutl.hxx>
60 #include <client.hxx>
61 #include <tabprotection.hxx>
62 #include <spellcheckcontext.hxx>
63 #include <markdata.hxx>
64 #include <formula/FormulaCompiler.hxx>
65 #include <comphelper/lok.hxx>
66 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
67 #include <output.hxx>
68
69 #include <utility>
70
71 #include <com/sun/star/chart2/data/HighlightedRange.hpp>
72
73 namespace
74 {
75
lcl_getSubRangeByIndex(const ScRange & rRange,sal_Int32 nIndex)76 ScRange lcl_getSubRangeByIndex( const ScRange& rRange, sal_Int32 nIndex )
77 {
78 ScAddress aResult( rRange.aStart );
79
80 SCCOL nWidth = rRange.aEnd.Col() - rRange.aStart.Col() + 1;
81 SCROW nHeight = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
82 SCTAB nDepth = rRange.aEnd.Tab() - rRange.aStart.Tab() + 1;
83 if( (nWidth > 0) && (nHeight > 0) && (nDepth > 0) )
84 {
85 // row by row from first to last sheet
86 sal_Int32 nArea = nWidth * nHeight;
87 aResult.IncCol( static_cast< SCCOL >( nIndex % nWidth ) );
88 aResult.IncRow( static_cast< SCROW >( (nIndex % nArea) / nWidth ) );
89 aResult.IncTab( static_cast< SCTAB >( nIndex / nArea ) );
90 if( !rRange.In( aResult ) )
91 aResult = rRange.aStart;
92 }
93
94 return ScRange( aResult );
95 }
96
97 } // anonymous namespace
98
99 using namespace com::sun::star;
100
~ScExtraEditViewManager()101 ScExtraEditViewManager::~ScExtraEditViewManager()
102 {
103 DBG_ASSERT(nTotalWindows == 0, "ScExtraEditViewManager dtor: some out window has not yet been removed!");
104 }
105
Add(SfxViewShell * pViewShell,ScSplitPos eWhich)106 inline void ScExtraEditViewManager::Add(SfxViewShell* pViewShell, ScSplitPos eWhich)
107 {
108 Apply<Adder>(pViewShell, eWhich);
109 }
110
Remove(SfxViewShell * pViewShell,ScSplitPos eWhich)111 inline void ScExtraEditViewManager::Remove(SfxViewShell* pViewShell, ScSplitPos eWhich)
112 {
113 Apply<Remover>(pViewShell, eWhich);
114 }
115
116
117 template<ScExtraEditViewManager::ModifierTagType ModifierTag>
Apply(SfxViewShell * pViewShell,ScSplitPos eWhich)118 void ScExtraEditViewManager::Apply(SfxViewShell* pViewShell, ScSplitPos eWhich)
119 {
120 ScTabViewShell* pOtherViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
121 if (pOtherViewShell == nullptr || pOtherViewShell == mpThisViewShell)
122 return;
123
124 mpOtherEditView = pOtherViewShell->GetViewData().GetEditView(eWhich);
125 if (mpOtherEditView != nullptr)
126 {
127 DBG_ASSERT(mpOtherEditView->GetEditEngine(), "Edit view has no valid engine.");
128 for (int i = 0; i < 4; ++i)
129 {
130 ScGridWindow* pWin = mpGridWin[i].get();
131 if (pWin != nullptr)
132 {
133 Modifier<ModifierTag>(pWin);
134 }
135 }
136 }
137 }
138
139 template<ScExtraEditViewManager::ModifierTagType ModifierTag>
Modifier(ScGridWindow *)140 void ScExtraEditViewManager::Modifier(ScGridWindow* /*pWin*/)
141 {
142 (void)this;
143 SAL_WARN("sc", "ScExtraEditViewManager::Modifier<ModifierTag>: non-specialized version should not be invoked.");
144 }
145
146 template<>
Modifier(ScGridWindow * pWin)147 void ScExtraEditViewManager::Modifier<ScExtraEditViewManager::Adder>(ScGridWindow* pWin)
148 {
149 if (mpOtherEditView->AddOtherViewWindow(pWin))
150 ++nTotalWindows;
151 }
152
153 template<>
Modifier(ScGridWindow * pWin)154 void ScExtraEditViewManager::Modifier<ScExtraEditViewManager::Remover>(ScGridWindow* pWin)
155 {
156 if (mpOtherEditView->RemoveOtherViewWindow(pWin))
157 --nTotalWindows;
158 }
159
160 // --- public functions
161
ClickCursor(SCCOL nPosX,SCROW nPosY,bool bControl)162 void ScTabView::ClickCursor( SCCOL nPosX, SCROW nPosY, bool bControl )
163 {
164 ScDocument& rDoc = aViewData.GetDocument();
165 SCTAB nTab = aViewData.GetTabNo();
166 rDoc.SkipOverlapped(nPosX, nPosY, nTab);
167
168 bool bRefMode = SC_MOD()->IsFormulaMode();
169
170 if ( bRefMode )
171 {
172 DoneRefMode();
173
174 if (bControl)
175 SC_MOD()->AddRefEntry();
176
177 InitRefMode( nPosX, nPosY, nTab, SC_REFTYPE_REF );
178 }
179 else
180 {
181 DoneBlockMode( bControl );
182 aViewData.ResetOldCursor();
183 SetCursor( nPosX, nPosY );
184 }
185 }
186
UpdateAutoFillMark(bool bFromPaste)187 void ScTabView::UpdateAutoFillMark(bool bFromPaste)
188 {
189 // single selection or cursor
190 ScRange aMarkRange;
191 ScMarkType eMarkType = aViewData.GetSimpleArea(aMarkRange);
192 bool bMarked = eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED;
193
194 for (sal_uInt16 i = 0; i < 4; i++)
195 {
196 if (pGridWin[i] && pGridWin[i]->IsVisible())
197 pGridWin[i]->UpdateAutoFillMark( bMarked, aMarkRange );
198 }
199
200 for (sal_uInt16 i = 0; i < 2; i++)
201 {
202 if (pColBar[i] && pColBar[i]->IsVisible())
203 pColBar[i]->SetMark( bMarked, aMarkRange.aStart.Col(), aMarkRange.aEnd.Col() );
204 if (pRowBar[i] && pRowBar[i]->IsVisible())
205 pRowBar[i]->SetMark( bMarked, aMarkRange.aStart.Row(), aMarkRange.aEnd.Row() );
206 }
207
208 // selection transfer object is checked together with AutoFill marks,
209 // because it has the same requirement of a single continuous block.
210 if (!bFromPaste)
211 CheckSelectionTransfer(); // update selection transfer object
212 }
213
FakeButtonUp(ScSplitPos eWhich)214 void ScTabView::FakeButtonUp( ScSplitPos eWhich )
215 {
216 if (pGridWin[eWhich])
217 pGridWin[eWhich]->FakeButtonUp();
218 }
219
HideAllCursors()220 void ScTabView::HideAllCursors()
221 {
222 for (VclPtr<ScGridWindow> & pWin : pGridWin)
223 {
224 if (pWin && pWin->IsVisible())
225 {
226 vcl::Cursor* pCur = pWin->GetCursor();
227 if (pCur && pCur->IsVisible())
228 pCur->Hide();
229 pWin->HideCursor();
230 }
231 }
232 }
233
ShowAllCursors()234 void ScTabView::ShowAllCursors()
235 {
236 for (VclPtr<ScGridWindow> & pWin : pGridWin)
237 {
238 if (pWin && pWin->IsVisible())
239 {
240 pWin->ShowCursor();
241 pWin->CursorChanged();
242 }
243 }
244 }
245
ShowCursor()246 void ScTabView::ShowCursor()
247 {
248 pGridWin[aViewData.GetActivePart()]->ShowCursor();
249 pGridWin[aViewData.GetActivePart()]->CursorChanged();
250 }
251
InvalidateAttribs()252 void ScTabView::InvalidateAttribs()
253 {
254 SfxBindings& rBindings = aViewData.GetBindings();
255
256 rBindings.Invalidate( SID_STYLE_APPLY );
257 rBindings.Invalidate( SID_STYLE_FAMILY2 );
258 // StarCalc knows only paragraph- or cell format templates
259
260 rBindings.Invalidate( SID_ATTR_CHAR_FONT );
261 rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
262 rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
263
264 rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
265 rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
266 rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
267 rBindings.Invalidate( SID_ULINE_VAL_NONE );
268 rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
269 rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
270 rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
271
272 rBindings.Invalidate( SID_ATTR_CHAR_OVERLINE );
273
274 rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
275 rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
276 rBindings.Invalidate( SID_SET_SUB_SCRIPT );
277 rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
278 rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
279
280 rBindings.Invalidate( SID_ATTR_PARA_ADJUST_LEFT );
281 rBindings.Invalidate( SID_ATTR_PARA_ADJUST_RIGHT );
282 rBindings.Invalidate( SID_ATTR_PARA_ADJUST_BLOCK );
283 rBindings.Invalidate( SID_ATTR_PARA_ADJUST_CENTER);
284 rBindings.Invalidate( SID_NUMBER_TYPE_FORMAT);
285
286 rBindings.Invalidate( SID_ALIGNLEFT );
287 rBindings.Invalidate( SID_ALIGNRIGHT );
288 rBindings.Invalidate( SID_ALIGNBLOCK );
289 rBindings.Invalidate( SID_ALIGNCENTERHOR );
290
291 rBindings.Invalidate( SID_ALIGNTOP );
292 rBindings.Invalidate( SID_ALIGNBOTTOM );
293 rBindings.Invalidate( SID_ALIGNCENTERVER );
294
295 rBindings.Invalidate( SID_SCATTR_CELLPROTECTION );
296
297 // stuff for sidebar panels
298 {
299 rBindings.Invalidate( SID_H_ALIGNCELL );
300 rBindings.Invalidate( SID_V_ALIGNCELL );
301 rBindings.Invalidate( SID_ATTR_ALIGN_INDENT );
302 rBindings.Invalidate( SID_FRAME_LINECOLOR );
303 rBindings.Invalidate( SID_FRAME_LINESTYLE );
304 rBindings.Invalidate( SID_ATTR_BORDER_OUTER );
305 rBindings.Invalidate( SID_ATTR_BORDER_INNER );
306 rBindings.Invalidate( SID_ATTR_BORDER_DIAG_TLBR );
307 rBindings.Invalidate( SID_ATTR_BORDER_DIAG_BLTR );
308 rBindings.Invalidate( SID_NUMBER_TYPE_FORMAT );
309 }
310
311 rBindings.Invalidate( SID_BACKGROUND_COLOR );
312
313 rBindings.Invalidate( SID_ATTR_ALIGN_LINEBREAK );
314 rBindings.Invalidate( SID_NUMBER_FORMAT );
315
316 rBindings.Invalidate( SID_TEXTDIRECTION_LEFT_TO_RIGHT );
317 rBindings.Invalidate( SID_TEXTDIRECTION_TOP_TO_BOTTOM );
318 rBindings.Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT );
319 rBindings.Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT );
320
321 // pseudo slots for Format menu
322 rBindings.Invalidate( SID_ALIGN_ANY_HDEFAULT );
323 rBindings.Invalidate( SID_ALIGN_ANY_LEFT );
324 rBindings.Invalidate( SID_ALIGN_ANY_HCENTER );
325 rBindings.Invalidate( SID_ALIGN_ANY_RIGHT );
326 rBindings.Invalidate( SID_ALIGN_ANY_JUSTIFIED );
327 rBindings.Invalidate( SID_ALIGN_ANY_VDEFAULT );
328 rBindings.Invalidate( SID_ALIGN_ANY_TOP );
329 rBindings.Invalidate( SID_ALIGN_ANY_VCENTER );
330 rBindings.Invalidate( SID_ALIGN_ANY_BOTTOM );
331
332 rBindings.Invalidate( SID_NUMBER_CURRENCY );
333 rBindings.Invalidate( SID_NUMBER_SCIENTIFIC );
334 rBindings.Invalidate( SID_NUMBER_DATE );
335 rBindings.Invalidate( SID_NUMBER_CURRENCY );
336 rBindings.Invalidate( SID_NUMBER_PERCENT );
337 rBindings.Invalidate( SID_NUMBER_TWODEC );
338 rBindings.Invalidate( SID_NUMBER_TIME );
339 rBindings.Invalidate( SID_NUMBER_STANDARD );
340 rBindings.Invalidate( SID_NUMBER_THOUSANDS );
341 }
342
343 namespace {
344
collectUIInformation(const std::map<OUString,OUString> & aParameters)345 void collectUIInformation(const std::map<OUString, OUString>& aParameters)
346 {
347 EventDescription aDescription;
348 aDescription.aID = "grid_window";
349 aDescription.aAction = "SELECT";
350 aDescription.aParameters = aParameters;
351 aDescription.aParent = "MainWindow";
352 aDescription.aKeyWord = "ScGridWinUIObject";
353
354 UITestLogger::getInstance().logEvent(aDescription);
355 }
356
357 }
358
359 // SetCursor - Cursor, set, draw, update InputWin
360 // or send reference
361 // Optimising breaks the functionality
362
SetCursor(SCCOL nPosX,SCROW nPosY,bool bNew)363 void ScTabView::SetCursor( SCCOL nPosX, SCROW nPosY, bool bNew )
364 {
365 SCCOL nOldX = aViewData.GetCurX();
366 SCROW nOldY = aViewData.GetCurY();
367
368 // DeactivateIP only for MarkListHasChanged
369
370 // FIXME: this is to limit the number of rows handled in the Online
371 // to 1000; this will be removed again when the performance
372 // bottlenecks are sorted out
373 if (comphelper::LibreOfficeKit::isActive())
374 nPosY = std::min(nPosY, MAXTILEDROW);
375
376 if ( !(nPosX != nOldX || nPosY != nOldY || bNew) )
377 return;
378
379 ScTabViewShell* pViewShell = aViewData.GetViewShell();
380 bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
381 if ( aViewData.HasEditView( aViewData.GetActivePart() ) && !bRefMode ) // 23259 or so
382 {
383 UpdateInputLine();
384 }
385
386 HideAllCursors();
387
388 aViewData.SetCurX( nPosX );
389 aViewData.SetCurY( nPosY );
390
391 ShowAllCursors();
392
393 CursorPosChanged();
394
395 OUString aCurrAddress = ScAddress(nPosX,nPosY,0).GetColRowString();
396 collectUIInformation({{"CELL", aCurrAddress}});
397
398 if (!comphelper::LibreOfficeKit::isActive())
399 return;
400
401 if (nPosX <= aViewData.GetMaxTiledCol() - 10 && nPosY <= aViewData.GetMaxTiledRow() - 25)
402 return;
403
404 ScDocument& rDoc = aViewData.GetDocument();
405 ScDocShell* pDocSh = aViewData.GetDocShell();
406 ScModelObj* pModelObj = pDocSh ? comphelper::getUnoTunnelImplementation<ScModelObj>( pDocSh->GetModel() ) : nullptr;
407 Size aOldSize(0, 0);
408 if (pModelObj)
409 aOldSize = pModelObj->getDocumentSize();
410
411 if (nPosX > aViewData.GetMaxTiledCol() - 10)
412 aViewData.SetMaxTiledCol(std::min<SCCOL>(std::max(nPosX, aViewData.GetMaxTiledCol()) + 10, rDoc.MaxCol()));
413
414 if (nPosY > aViewData.GetMaxTiledRow() - 25)
415 aViewData.SetMaxTiledRow(std::min<SCROW>(std::max(nPosY, aViewData.GetMaxTiledRow()) + 25, MAXTILEDROW));
416
417 Size aNewSize(0, 0);
418 if (pModelObj)
419 aNewSize = pModelObj->getDocumentSize();
420
421 if (!pDocSh)
422 return;
423
424 // New area extended to the right of the sheet after last column
425 // including overlapping area with aNewRowArea
426 tools::Rectangle aNewColArea(aOldSize.getWidth(), 0, aNewSize.getWidth(), aNewSize.getHeight());
427 // New area extended to the bottom of the sheet after last row
428 // excluding overlapping area with aNewColArea
429 tools::Rectangle aNewRowArea(0, aOldSize.getHeight(), aOldSize.getWidth(), aNewSize.getHeight());
430
431 // Only invalidate if spreadsheet extended to the right
432 if (aNewColArea.getWidth())
433 {
434 SfxLokHelper::notifyInvalidation(aViewData.GetViewShell(), aNewColArea.toString());
435 }
436
437 // Only invalidate if spreadsheet extended to the bottom
438 if (aNewRowArea.getHeight())
439 {
440 SfxLokHelper::notifyInvalidation(aViewData.GetViewShell(), aNewRowArea.toString());
441 }
442
443 // Provide size in the payload, so clients don't have to
444 // call lok::Document::getDocumentSize().
445 std::stringstream ss;
446 ss << aNewSize.Width() << ", " << aNewSize.Height();
447 OString sSize = ss.str().c_str();
448 ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(aViewData.GetViewShell()->GetCurrentDocument());
449 SfxLokHelper::notifyDocumentSizeChanged(aViewData.GetViewShell(), sSize, pModel, false);
450 }
451
lcl_IsRefDlgActive(SfxViewFrame * pViewFrm)452 static bool lcl_IsRefDlgActive(SfxViewFrame* pViewFrm)
453 {
454 ScModule* pScMod = SC_MOD();
455 if (!pScMod->IsRefDialogOpen())
456 return false;
457
458 auto nDlgId = pScMod->GetCurRefDlgId();
459 if (!pViewFrm->HasChildWindow(nDlgId))
460 return false;
461
462 SfxChildWindow* pChild = pViewFrm->GetChildWindow(nDlgId);
463 if (!pChild)
464 return false;
465
466 auto xDlgController = pChild->GetController();
467 if (!xDlgController || !xDlgController->getDialog()->get_visible())
468 return false;
469
470 IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(xDlgController.get());
471 return pRefDlg && pRefDlg->IsRefInputMode();
472 }
473
CheckSelectionTransfer()474 void ScTabView::CheckSelectionTransfer()
475 {
476 if ( !aViewData.IsActive() ) // only for active view
477 return;
478
479 ScModule* pScMod = SC_MOD();
480 ScSelectionTransferObj* pOld = pScMod->GetSelectionTransfer();
481 rtl::Reference<ScSelectionTransferObj> pNew = ScSelectionTransferObj::CreateFromView( this );
482 if ( !pNew )
483 return;
484
485 // create new selection
486
487 if (pOld)
488 pOld->ForgetView();
489
490 pScMod->SetSelectionTransfer( pNew.get() );
491
492 // tdf#124975/tdf#136242 changing the calc selection can trigger removal of the
493 // selection of an open RefDlg dialog, so don't inform the
494 // desktop clipboard of the changed selection if that dialog is open
495 if (!lcl_IsRefDlgActive(aViewData.GetViewShell()->GetViewFrame()))
496 pNew->CopyToPrimarySelection(); // may delete pOld
497
498 // Log the selection change
499 ScMarkData& rMark = aViewData.GetMarkData();
500 if (rMark.IsMarked())
501 {
502 ScRange aMarkRange;
503 rMark.GetMarkArea( aMarkRange );
504 OUString aStartAddress = aMarkRange.aStart.GetColRowString();
505 OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
506 collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}});
507 }
508 }
509
510 // update input row / menus
511 // CursorPosChanged calls SelectionChanged
512 // SelectionChanged calls CellContentChanged
513
CellContentChanged()514 void ScTabView::CellContentChanged()
515 {
516 SfxBindings& rBindings = aViewData.GetBindings();
517
518 rBindings.Invalidate( SID_ATTR_SIZE ); // -> show error message
519 rBindings.Invalidate( SID_THESAURUS );
520 rBindings.Invalidate( SID_HYPERLINK_GETLINK );
521 rBindings.Invalidate( SID_ROWCOL_SELCOUNT );
522
523 InvalidateAttribs(); // attributes updates
524
525 aViewData.GetViewShell()->UpdateInputHandler();
526 }
527
SetTabProtectionSymbol(SCTAB nTab,const bool bProtect)528 void ScTabView::SetTabProtectionSymbol( SCTAB nTab, const bool bProtect )
529 {
530 pTabControl->SetProtectionSymbol( static_cast<sal_uInt16>(nTab)+1, bProtect);
531 }
532
SelectionChanged(bool bFromPaste)533 void ScTabView::SelectionChanged(bool bFromPaste)
534 {
535 SfxViewFrame* pViewFrame = aViewData.GetViewShell()->GetViewFrame();
536 if (pViewFrame)
537 {
538 uno::Reference<frame::XController> xController = pViewFrame->GetFrame().GetController();
539 if (xController.is())
540 {
541 ScTabViewObj* pImp = comphelper::getUnoTunnelImplementation<ScTabViewObj>( xController );
542 if (pImp)
543 pImp->SelectionChanged();
544 }
545 }
546
547 UpdateAutoFillMark(bFromPaste); // also calls CheckSelectionTransfer
548
549 SfxBindings& rBindings = aViewData.GetBindings();
550
551 rBindings.Invalidate( SID_CURRENTCELL ); // -> Navigator
552 rBindings.Invalidate( SID_AUTO_FILTER ); // -> Menu
553 rBindings.Invalidate( FID_NOTE_VISIBLE );
554 rBindings.Invalidate( FID_SHOW_NOTE );
555 rBindings.Invalidate( FID_HIDE_NOTE );
556 rBindings.Invalidate( FID_SHOW_ALL_NOTES );
557 rBindings.Invalidate( FID_HIDE_ALL_NOTES );
558 rBindings.Invalidate( SID_TOGGLE_NOTES );
559 rBindings.Invalidate( SID_DELETE_NOTE );
560 rBindings.Invalidate( SID_ROWCOL_SELCOUNT );
561
562 // functions than may need to be disabled
563
564 rBindings.Invalidate( FID_INS_ROWBRK );
565 rBindings.Invalidate( FID_INS_COLBRK );
566 rBindings.Invalidate( FID_DEL_ROWBRK );
567 rBindings.Invalidate( FID_DEL_COLBRK );
568 rBindings.Invalidate( FID_MERGE_ON );
569 rBindings.Invalidate( FID_MERGE_OFF );
570 rBindings.Invalidate( FID_MERGE_TOGGLE );
571 rBindings.Invalidate( SID_AUTOFILTER_HIDE );
572 rBindings.Invalidate( SID_UNFILTER );
573 rBindings.Invalidate( SID_REIMPORT_DATA );
574 rBindings.Invalidate( SID_REFRESH_DBAREA );
575 rBindings.Invalidate( SID_OUTLINE_SHOW );
576 rBindings.Invalidate( SID_OUTLINE_HIDE );
577 rBindings.Invalidate( SID_OUTLINE_REMOVE );
578 rBindings.Invalidate( FID_FILL_TO_BOTTOM );
579 rBindings.Invalidate( FID_FILL_TO_RIGHT );
580 rBindings.Invalidate( FID_FILL_TO_TOP );
581 rBindings.Invalidate( FID_FILL_TO_LEFT );
582 rBindings.Invalidate( FID_FILL_SERIES );
583 rBindings.Invalidate( SID_SCENARIOS );
584 rBindings.Invalidate( SID_AUTOFORMAT );
585 rBindings.Invalidate( SID_OPENDLG_TABOP );
586 rBindings.Invalidate( SID_DATA_SELECT );
587
588 rBindings.Invalidate( SID_CUT );
589 rBindings.Invalidate( SID_COPY );
590 rBindings.Invalidate( SID_PASTE );
591 rBindings.Invalidate( SID_PASTE_SPECIAL );
592 rBindings.Invalidate( SID_PASTE_UNFORMATTED );
593
594 rBindings.Invalidate( FID_INS_ROW );
595 rBindings.Invalidate( FID_INS_COLUMN );
596 rBindings.Invalidate( FID_INS_ROWS_BEFORE );
597 rBindings.Invalidate( FID_INS_COLUMNS_BEFORE );
598 rBindings.Invalidate( FID_INS_ROWS_AFTER );
599 rBindings.Invalidate( FID_INS_COLUMNS_AFTER );
600 rBindings.Invalidate( FID_INS_CELL );
601 rBindings.Invalidate( FID_INS_CELLSDOWN );
602 rBindings.Invalidate( FID_INS_CELLSRIGHT );
603
604 rBindings.Invalidate( FID_CHG_COMMENT );
605
606 // only due to protect cell:
607
608 rBindings.Invalidate( SID_CELL_FORMAT_RESET );
609 rBindings.Invalidate( SID_DELETE );
610 rBindings.Invalidate( SID_DELETE_CONTENTS );
611 rBindings.Invalidate( FID_DELETE_CELL );
612 rBindings.Invalidate( FID_CELL_FORMAT );
613 rBindings.Invalidate( SID_ENABLE_HYPHENATION );
614 rBindings.Invalidate( SID_INSERT_POSTIT );
615 rBindings.Invalidate( SID_CHARMAP );
616 rBindings.Invalidate( SID_OPENDLG_FUNCTION );
617 rBindings.Invalidate( FID_VALIDATION );
618 rBindings.Invalidate( SID_EXTERNAL_SOURCE );
619 rBindings.Invalidate( SID_TEXT_TO_COLUMNS );
620 rBindings.Invalidate( SID_SORT_ASCENDING );
621 rBindings.Invalidate( SID_SORT_DESCENDING );
622 rBindings.Invalidate( SID_SELECT_UNPROTECTED_CELLS );
623
624 if (aViewData.GetViewShell()->HasAccessibilityObjects())
625 aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccCursorChanged));
626
627 CellContentChanged();
628 }
629
CursorPosChanged()630 void ScTabView::CursorPosChanged()
631 {
632 bool bRefMode = SC_MOD()->IsFormulaMode();
633 if ( !bRefMode ) // check that RefMode works when switching sheets
634 aViewData.GetDocShell()->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
635
636 // Broadcast, so that other Views of the document also switch
637
638 ScDocument& rDoc = aViewData.GetDocument();
639 bool bDP = nullptr != rDoc.GetDPAtCursor(
640 aViewData.GetCurX(), aViewData.GetCurY(), aViewData.GetTabNo() );
641 aViewData.GetViewShell()->SetPivotShell(bDP);
642
643 // UpdateInputHandler now in CellContentChanged
644
645 SelectionChanged();
646
647 aViewData.SetTabStartCol( SC_TABSTART_NONE );
648 }
649
650 namespace {
651
calcHintWindowPosition(const Point & rCellPos,const Size & rCellSize,const Size & rFrameWndSize,const Size & rHintWndSize)652 Point calcHintWindowPosition(
653 const Point& rCellPos, const Size& rCellSize, const Size& rFrameWndSize, const Size& rHintWndSize)
654 {
655 const tools::Long nMargin = 20;
656
657 tools::Long nMLeft = rCellPos.X();
658 tools::Long nMRight = rFrameWndSize.Width() - rCellPos.X() - rCellSize.Width();
659 tools::Long nMTop = rCellPos.Y();
660 tools::Long nMBottom = rFrameWndSize.Height() - rCellPos.Y() - rCellSize.Height();
661
662 // First, see if we can fit the entire hint window in the visible region.
663
664 if (nMRight - nMargin >= rHintWndSize.Width())
665 {
666 // Right margin is wide enough.
667 if (rFrameWndSize.Height() >= rHintWndSize.Height())
668 {
669 // The frame has enough height. Take it.
670 Point aPos = rCellPos;
671 aPos.AdjustX(rCellSize.Width() + nMargin );
672 if (aPos.Y() + rHintWndSize.Height() > rFrameWndSize.Height())
673 {
674 // Push the hint window up a bit to make it fit.
675 aPos.setY( rFrameWndSize.Height() - rHintWndSize.Height() );
676 }
677 return aPos;
678 }
679 }
680
681 if (nMBottom - nMargin >= rHintWndSize.Height())
682 {
683 // Bottom margin is high enough.
684 if (rFrameWndSize.Width() >= rHintWndSize.Width())
685 {
686 // The frame has enough width. Take it.
687 Point aPos = rCellPos;
688 aPos.AdjustY(rCellSize.Height() + nMargin );
689 if (aPos.X() + rHintWndSize.Width() > rFrameWndSize.Width())
690 {
691 // Move the hint window to the left to make it fit.
692 aPos.setX( rFrameWndSize.Width() - rHintWndSize.Width() );
693 }
694 return aPos;
695 }
696 }
697
698 if (nMLeft - nMargin >= rHintWndSize.Width())
699 {
700 // Left margin is wide enough.
701 if (rFrameWndSize.Height() >= rHintWndSize.Height())
702 {
703 // The frame is high enough. Take it.
704 Point aPos = rCellPos;
705 aPos.AdjustX( -(rHintWndSize.Width() + nMargin) );
706 if (aPos.Y() + rHintWndSize.Height() > rFrameWndSize.Height())
707 {
708 // Push the hint window up a bit to make it fit.
709 aPos.setY( rFrameWndSize.Height() - rHintWndSize.Height() );
710 }
711 return aPos;
712 }
713 }
714
715 if (nMTop - nMargin >= rHintWndSize.Height())
716 {
717 // Top margin is high enough.
718 if (rFrameWndSize.Width() >= rHintWndSize.Width())
719 {
720 // The frame is wide enough. Take it.
721 Point aPos = rCellPos;
722 aPos.AdjustY( -(rHintWndSize.Height() + nMargin) );
723 if (aPos.X() + rHintWndSize.Width() > rFrameWndSize.Width())
724 {
725 // Move the hint window to the left to make it fit.
726 aPos.setX( rFrameWndSize.Width() - rHintWndSize.Width() );
727 }
728 return aPos;
729 }
730 }
731
732 // The popup doesn't fit in any direction in its entirety. Do our best.
733
734 if (nMRight - nMargin >= rHintWndSize.Width())
735 {
736 // Right margin is good enough.
737 Point aPos = rCellPos;
738 aPos.AdjustX(nMargin + rCellSize.Width() );
739 aPos.setY( 0 );
740 return aPos;
741 }
742
743 if (nMBottom - nMargin >= rHintWndSize.Height())
744 {
745 // Bottom margin is good enough.
746 Point aPos = rCellPos;
747 aPos.AdjustY(nMargin + rCellSize.Height() );
748 aPos.setX( 0 );
749 return aPos;
750 }
751
752 if (nMLeft - nMargin >= rHintWndSize.Width())
753 {
754 // Left margin is good enough.
755 Point aPos = rCellPos;
756 aPos.AdjustX( -(rHintWndSize.Width() + nMargin) );
757 aPos.setY( 0 );
758 return aPos;
759 }
760
761 if (nMTop - nMargin >= rHintWndSize.Height())
762 {
763 // Top margin is good enough.
764 Point aPos = rCellPos;
765 aPos.AdjustY( -(rHintWndSize.Height() + nMargin) );
766 aPos.setX( 0 );
767 return aPos;
768 }
769
770 // None of the above. Hopeless. At least try not to cover the current
771 // cell.
772 Point aPos = rCellPos;
773 aPos.AdjustX(rCellSize.Width() );
774 return aPos;
775 }
776
777 }
778
TestHintWindow()779 void ScTabView::TestHintWindow()
780 {
781 // show input help window and list drop-down button for validity
782
783 mxInputHintOO.reset();
784
785 bool bListValButton = false;
786 ScAddress aListValPos;
787
788 ScDocument& rDoc = aViewData.GetDocument();
789 const SfxUInt32Item* pItem = rDoc.GetAttr( aViewData.GetCurX(),
790 aViewData.GetCurY(),
791 aViewData.GetTabNo(),
792 ATTR_VALIDDATA );
793 if ( pItem->GetValue() )
794 {
795 const ScValidationData* pData = rDoc.GetValidationEntry( pItem->GetValue() );
796 OSL_ENSURE(pData,"ValidationData not found");
797 OUString aTitle, aMessage;
798
799 if ( pData && pData->GetInput( aTitle, aMessage ) && !aMessage.isEmpty() )
800 {
801 ScSplitPos eWhich = aViewData.GetActivePart();
802 ScGridWindow* pWin = pGridWin[eWhich].get();
803 SCCOL nCol = aViewData.GetCurX();
804 SCROW nRow = aViewData.GetCurY();
805 Point aPos = aViewData.GetScrPos( nCol, nRow, eWhich );
806 Size aWinSize = pWin->GetOutputSizePixel();
807 // cursor visible?
808 if ( nCol >= aViewData.GetPosX(WhichH(eWhich)) &&
809 nRow >= aViewData.GetPosY(WhichV(eWhich)) &&
810 aPos.X() < aWinSize.Width() && aPos.Y() < aWinSize.Height() )
811 {
812 const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
813 Color aCommentColor = rColorCfg.GetColorValue(svtools::CALCNOTESBACKGROUND).nColor;
814 // create HintWindow, determines its size by itself
815 ScOverlayHint* pOverlay = new ScOverlayHint(aTitle, aMessage, aCommentColor, pFrameWin->GetFont());
816
817 mxInputHintOO.reset(new sdr::overlay::OverlayObjectList);
818 mxInputHintOO->append(std::unique_ptr<sdr::overlay::OverlayObject>(pOverlay));
819
820 Size aHintWndSize = pOverlay->GetSizePixel();
821 tools::Long nCellSizeX = 0;
822 tools::Long nCellSizeY = 0;
823 aViewData.GetMergeSizePixel(nCol, nRow, nCellSizeX, nCellSizeY);
824
825 Point aHintPos = calcHintWindowPosition(
826 aPos, Size(nCellSizeX,nCellSizeY), aWinSize, aHintWndSize);
827
828 pOverlay->SetPos(pWin->PixelToLogic(aHintPos, pWin->GetDrawMapMode()), pWin->GetDrawMapMode());
829 for (VclPtr<ScGridWindow> & pWindow : pGridWin)
830 {
831 if (!pWindow)
832 continue;
833 if (!pWindow->IsVisible())
834 continue;
835 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = pWindow->getOverlayManager();
836 if (!xOverlayManager.is())
837 continue;
838 if (pWindow == pWin)
839 {
840 xOverlayManager->add(*pOverlay);
841 pWindow->updateLOKInputHelp(aTitle, aMessage);
842 }
843 else
844 {
845 //tdf#92530 if the help tip doesn't fit into its allocated area in a split window
846 //scenario, then because here we place it into the other split windows as well the
847 //missing portions will be displayed in the other split windows to form an apparent
848 //single tip, albeit "under" the split lines
849 Point aOtherPos(pWindow->ScreenToOutputPixel(pWin->OutputToScreenPixel(aHintPos)));
850 std::unique_ptr<ScOverlayHint> pOtherOverlay(new ScOverlayHint(aTitle, aMessage, aCommentColor, pFrameWin->GetFont()));
851 Point aFooPos(pWindow->PixelToLogic(aOtherPos, pWindow->GetDrawMapMode()));
852 pOtherOverlay->SetPos(aFooPos, pWindow->GetDrawMapMode());
853 xOverlayManager->add(*pOtherOverlay);
854 mxInputHintOO->append(std::move(pOtherOverlay));
855 }
856 }
857 }
858 }
859
860 // list drop-down button
861 if ( pData && pData->HasSelectionList() )
862 {
863 aListValPos.Set( aViewData.GetCurX(), aViewData.GetCurY(), aViewData.GetTabNo() );
864 bListValButton = true;
865 }
866 }
867
868 for (VclPtr<ScGridWindow> const & pWin : pGridWin)
869 {
870 if (pWin && pWin->IsVisible())
871 pWin->UpdateListValPos(bListValButton, aListValPos);
872 }
873 }
874
HasHintWindow() const875 bool ScTabView::HasHintWindow() const { return mxInputHintOO != nullptr; }
876
RemoveHintWindow()877 void ScTabView::RemoveHintWindow()
878 {
879 mxInputHintOO.reset();
880 }
881
882 // find window that should not be over the cursor
lcl_GetCareWin(SfxViewFrame * pViewFrm)883 static weld::Window* lcl_GetCareWin(SfxViewFrame* pViewFrm)
884 {
885 //! also spelling ??? (then set the member variables when calling)
886
887 // search & replace
888 if (pViewFrm->HasChildWindow(SID_SEARCH_DLG))
889 {
890 SfxChildWindow* pChild = pViewFrm->GetChildWindow(SID_SEARCH_DLG);
891 if (pChild)
892 {
893 auto xDlgController = pChild->GetController();
894 if (xDlgController && xDlgController->getDialog()->get_visible())
895 return xDlgController->getDialog();
896 }
897 }
898
899 // apply changes
900 if ( pViewFrm->HasChildWindow(FID_CHG_ACCEPT) )
901 {
902 SfxChildWindow* pChild = pViewFrm->GetChildWindow(FID_CHG_ACCEPT);
903 if (pChild)
904 {
905 auto xDlgController = pChild->GetController();
906 if (xDlgController && xDlgController->getDialog()->get_visible())
907 return xDlgController->getDialog();
908 }
909 }
910
911 return nullptr;
912 }
913
914 // adjust screen with respect to cursor position
915
AlignToCursor(SCCOL nCurX,SCROW nCurY,ScFollowMode eMode,const ScSplitPos * pWhich)916 void ScTabView::AlignToCursor( SCCOL nCurX, SCROW nCurY, ScFollowMode eMode,
917 const ScSplitPos* pWhich )
918 {
919 // now switch active part here
920
921 ScSplitPos eActive = aViewData.GetActivePart();
922 ScHSplitPos eActiveX = WhichH(eActive);
923 ScVSplitPos eActiveY = WhichV(eActive);
924 bool bHFix = (aViewData.GetHSplitMode() == SC_SPLIT_FIX);
925 bool bVFix = (aViewData.GetVSplitMode() == SC_SPLIT_FIX);
926 if (bHFix && eActiveX == SC_SPLIT_LEFT && nCurX >= aViewData.GetFixPosX())
927 {
928 ActivatePart( (eActiveY==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT );
929 eActiveX = SC_SPLIT_RIGHT;
930 }
931 if (bVFix && eActiveY == SC_SPLIT_TOP && nCurY >= aViewData.GetFixPosY())
932 {
933 ActivatePart( (eActiveX==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT );
934 eActiveY = SC_SPLIT_BOTTOM;
935 }
936
937 // actual align
938
939 if ( eMode != SC_FOLLOW_NONE )
940 {
941 ScSplitPos eAlign;
942 if (pWhich)
943 eAlign = *pWhich;
944 else
945 eAlign = aViewData.GetActivePart();
946 ScHSplitPos eAlignX = WhichH(eAlign);
947 ScVSplitPos eAlignY = WhichV(eAlign);
948
949 SCCOL nDeltaX = aViewData.GetPosX(eAlignX);
950 SCROW nDeltaY = aViewData.GetPosY(eAlignY);
951 SCCOL nSizeX = aViewData.VisibleCellsX(eAlignX);
952 SCROW nSizeY = aViewData.VisibleCellsY(eAlignY);
953
954 tools::Long nCellSizeX;
955 tools::Long nCellSizeY;
956 if ( nCurX >= 0 && nCurY >= 0 )
957 aViewData.GetMergeSizePixel( nCurX, nCurY, nCellSizeX, nCellSizeY );
958 else
959 nCellSizeX = nCellSizeY = 0;
960 Size aScrSize = aViewData.GetScrSize();
961 tools::Long nSpaceX = ( aScrSize.Width() - nCellSizeX ) / 2;
962 tools::Long nSpaceY = ( aScrSize.Height() - nCellSizeY ) / 2;
963 // nSpaceY: desired start position of cell for FOLLOW_JUMP, modified if dialog interferes
964
965 bool bForceNew = false; // force new calculation of JUMP position (vertical only)
966
967 // VisibleCellsY == CellsAtY( GetPosY( eWhichY ), 1, eWhichY )
968
969 // when for instance a search dialog is open, don't put the cursor behind the dialog
970 // if possible, put the row with the cursor above or below the dialog
971 //! not if already completely visible
972
973 if ( eMode == SC_FOLLOW_JUMP )
974 {
975 weld::Window* pCare = lcl_GetCareWin( aViewData.GetViewShell()->GetViewFrame() );
976 if (pCare)
977 {
978 bool bLimit = false;
979 tools::Rectangle aDlgPixel;
980 Size aWinSize;
981 vcl::Window* pWin = GetActiveWin();
982 weld::Window* pFrame = pWin ? pWin->GetFrameWeld() : nullptr;
983 int x, y, width, height;
984 if (pFrame && pCare->get_extents_relative_to(*pFrame, x, y, width, height))
985 {
986 aDlgPixel = tools::Rectangle(Point(x, y), Size(width, height));
987 aWinSize = pWin->GetOutputSizePixel();
988 // dos the dialog cover the GridWin?
989 if ( aDlgPixel.Right() >= 0 && aDlgPixel.Left() < aWinSize.Width() )
990 {
991 if ( nCurX < nDeltaX || nCurX >= nDeltaX+nSizeX ||
992 nCurY < nDeltaY || nCurY >= nDeltaY+nSizeY )
993 bLimit = true; // scroll anyway
994 else
995 {
996 // cursor is on the screen
997 Point aStart = aViewData.GetScrPos( nCurX, nCurY, eAlign );
998 tools::Long nCSX, nCSY;
999 aViewData.GetMergeSizePixel( nCurX, nCurY, nCSX, nCSY );
1000 tools::Rectangle aCursor( aStart, Size( nCSX, nCSY ) );
1001 if ( aCursor.IsOver( aDlgPixel ) )
1002 bLimit = true; // cell is covered by the dialog
1003 }
1004 }
1005 }
1006
1007 if (bLimit)
1008 {
1009 bool bBottom = false;
1010 tools::Long nTopSpace = aDlgPixel.Top();
1011 tools::Long nBotSpace = aWinSize.Height() - aDlgPixel.Bottom();
1012 if ( nBotSpace > 0 && nBotSpace > nTopSpace )
1013 {
1014 tools::Long nDlgBot = aDlgPixel.Bottom();
1015 SCCOL nWPosX;
1016 SCROW nWPosY;
1017 aViewData.GetPosFromPixel( 0,nDlgBot, eAlign, nWPosX, nWPosY );
1018 ++nWPosY; // below the last affected cell
1019
1020 SCROW nDiff = nWPosY - nDeltaY;
1021 if ( nCurY >= nDiff ) // position can not be negative
1022 {
1023 nSpaceY = nDlgBot + ( nBotSpace - nCellSizeY ) / 2;
1024 bBottom = true;
1025 bForceNew = true;
1026 }
1027 }
1028 if ( !bBottom && nTopSpace > 0 )
1029 {
1030 nSpaceY = ( nTopSpace - nCellSizeY ) / 2;
1031 bForceNew = true;
1032 }
1033 }
1034 }
1035 }
1036
1037 SCCOL nNewDeltaX = nDeltaX;
1038 SCROW nNewDeltaY = nDeltaY;
1039 bool bDoLine = false;
1040
1041 switch (eMode)
1042 {
1043 case SC_FOLLOW_JUMP:
1044 if ( nCurX < nDeltaX || nCurX >= nDeltaX+nSizeX )
1045 {
1046 nNewDeltaX = nCurX - aViewData.CellsAtX( nCurX, -1, eAlignX, static_cast<sal_uInt16>(nSpaceX) );
1047 if (nNewDeltaX < 0)
1048 nNewDeltaX = 0;
1049 nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX );
1050 }
1051 if ( nCurY < nDeltaY || nCurY >= nDeltaY+nSizeY || bForceNew )
1052 {
1053 nNewDeltaY = nCurY - aViewData.CellsAtY( nCurY, -1, eAlignY, static_cast<sal_uInt16>(nSpaceY) );
1054 if (nNewDeltaY < 0)
1055 nNewDeltaY = 0;
1056 nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY );
1057 }
1058 bDoLine = true;
1059 break;
1060
1061 case SC_FOLLOW_LINE:
1062 bDoLine = true;
1063 break;
1064
1065 case SC_FOLLOW_FIX:
1066 if ( nCurX < nDeltaX || nCurX >= nDeltaX+nSizeX )
1067 {
1068 nNewDeltaX = nDeltaX + nCurX - aViewData.GetCurX();
1069 if (nNewDeltaX < 0)
1070 nNewDeltaX = 0;
1071 nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX );
1072 }
1073 if ( nCurY < nDeltaY || nCurY >= nDeltaY+nSizeY )
1074 {
1075 nNewDeltaY = nDeltaY + nCurY - aViewData.GetCurY();
1076 if (nNewDeltaY < 0)
1077 nNewDeltaY = 0;
1078 nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY );
1079 }
1080
1081 // like old version of SC_FOLLOW_JUMP:
1082
1083 if ( nCurX < nNewDeltaX || nCurX >= nNewDeltaX+nSizeX )
1084 {
1085 nNewDeltaX = nCurX - (nSizeX / 2);
1086 if (nNewDeltaX < 0)
1087 nNewDeltaX = 0;
1088 nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX );
1089 }
1090 if ( nCurY < nNewDeltaY || nCurY >= nNewDeltaY+nSizeY )
1091 {
1092 nNewDeltaY = nCurY - (nSizeY / 2);
1093 if (nNewDeltaY < 0)
1094 nNewDeltaY = 0;
1095 nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY );
1096 }
1097
1098 bDoLine = true;
1099 break;
1100
1101 case SC_FOLLOW_NONE:
1102 break;
1103 default:
1104 OSL_FAIL("Wrong cursor mode");
1105 break;
1106 }
1107
1108 ScDocument& rDoc = aViewData.GetDocument();
1109 if (bDoLine)
1110 {
1111 while ( nCurX >= nNewDeltaX+nSizeX )
1112 {
1113 nNewDeltaX = nCurX-nSizeX+1;
1114 SCTAB nTab = aViewData.GetTabNo();
1115 while ( nNewDeltaX < rDoc.MaxCol() && !rDoc.GetColWidth( nNewDeltaX, nTab ) )
1116 ++nNewDeltaX;
1117 nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX );
1118 }
1119 while ( nCurY >= nNewDeltaY+nSizeY )
1120 {
1121 nNewDeltaY = nCurY-nSizeY+1;
1122 SCTAB nTab = aViewData.GetTabNo();
1123 while ( nNewDeltaY < rDoc.MaxRow() && !rDoc.GetRowHeight( nNewDeltaY, nTab ) )
1124 ++nNewDeltaY;
1125 nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY );
1126 }
1127 if ( nCurX < nNewDeltaX )
1128 nNewDeltaX = nCurX;
1129 if ( nCurY < nNewDeltaY )
1130 nNewDeltaY = nCurY;
1131 }
1132
1133 if ( nNewDeltaX != nDeltaX )
1134 nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX );
1135 if (nNewDeltaX+nSizeX-1 > rDoc.MaxCol())
1136 nNewDeltaX = rDoc.MaxCol()-nSizeX+1;
1137 if (nNewDeltaX < 0)
1138 nNewDeltaX = 0;
1139
1140 if ( nNewDeltaY != nDeltaY )
1141 nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY );
1142 if (nNewDeltaY+nSizeY-1 > rDoc.MaxRow())
1143 nNewDeltaY = rDoc.MaxRow()-nSizeY+1;
1144 if (nNewDeltaY < 0)
1145 nNewDeltaY = 0;
1146
1147 if ( nNewDeltaX != nDeltaX )
1148 ScrollX( nNewDeltaX - nDeltaX, eAlignX );
1149 if ( nNewDeltaY != nDeltaY )
1150 ScrollY( nNewDeltaY - nDeltaY, eAlignY );
1151 }
1152
1153 // switch active part again
1154
1155 if (bHFix)
1156 if (eActiveX == SC_SPLIT_RIGHT && nCurX < aViewData.GetFixPosX())
1157 {
1158 ActivatePart( (eActiveY==SC_SPLIT_TOP) ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT );
1159 eActiveX = SC_SPLIT_LEFT;
1160 }
1161 if (bVFix)
1162 if (eActiveY == SC_SPLIT_BOTTOM && nCurY < aViewData.GetFixPosY())
1163 {
1164 ActivatePart( (eActiveX==SC_SPLIT_LEFT) ? SC_SPLIT_TOPLEFT : SC_SPLIT_TOPRIGHT );
1165 }
1166 }
1167
SelMouseButtonDown(const MouseEvent & rMEvt)1168 bool ScTabView::SelMouseButtonDown( const MouseEvent& rMEvt )
1169 {
1170 bool bRet = false;
1171
1172 // #i3875# *Hack*
1173 bool bMod1Locked = (aViewData.GetViewShell()->GetLockedModifiers() & KEY_MOD1) != 0;
1174 aViewData.SetSelCtrlMouseClick( rMEvt.IsMod1() || bMod1Locked );
1175
1176 if ( pSelEngine )
1177 {
1178 bMoveIsShift = rMEvt.IsShift();
1179 bRet = pSelEngine->SelMouseButtonDown( rMEvt );
1180 bMoveIsShift = false;
1181 }
1182
1183 aViewData.SetSelCtrlMouseClick( false ); // #i3875# *Hack*
1184
1185 return bRet;
1186 }
1187
1188 // MoveCursor - with adjustment of the view section
1189
MoveCursorAbs(SCCOL nCurX,SCROW nCurY,ScFollowMode eMode,bool bShift,bool bControl,bool bKeepOld,bool bKeepSel)1190 void ScTabView::MoveCursorAbs( SCCOL nCurX, SCROW nCurY, ScFollowMode eMode,
1191 bool bShift, bool bControl, bool bKeepOld, bool bKeepSel )
1192 {
1193 if (!bKeepOld)
1194 aViewData.ResetOldCursor();
1195
1196 ScDocument& rDoc = aViewData.GetDocument();
1197 // #i123629#
1198 if( aViewData.GetViewShell()->GetForceFocusOnCurCell() )
1199 aViewData.GetViewShell()->SetForceFocusOnCurCell( !rDoc.ValidColRow(nCurX, nCurY) );
1200
1201 if (nCurX < 0) nCurX = 0;
1202 if (nCurY < 0) nCurY = 0;
1203 if (nCurX > rDoc.MaxCol()) nCurX = rDoc.MaxCol();
1204 if (nCurY > rDoc.MaxRow()) nCurY = rDoc.MaxRow();
1205
1206 // FIXME: this is to limit the number of rows handled in the Online
1207 // to 1000; this will be removed again when the performance
1208 // bottlenecks are sorted out
1209 if (comphelper::LibreOfficeKit::isActive())
1210 nCurY = std::min(nCurY, MAXTILEDROW);
1211
1212 HideAllCursors();
1213
1214 // switch of active now in AlignToCursor
1215
1216 AlignToCursor( nCurX, nCurY, eMode );
1217
1218 if (bKeepSel)
1219 {
1220 SetCursor( nCurX, nCurY ); // keep selection
1221
1222 // If the cursor is in existing selection, it's a cursor movement by
1223 // ENTER or TAB. If not, then it's a new selection during ADD
1224 // selection mode.
1225
1226 const ScMarkData& rMark = aViewData.GetMarkData();
1227 ScRangeList aSelList;
1228 rMark.FillRangeListWithMarks(&aSelList, false);
1229 if (!aSelList.In(ScRange(nCurX, nCurY, aViewData.GetTabNo())))
1230 // Cursor not in existing selection. Start a new selection.
1231 DoneBlockMode(true);
1232 }
1233 else
1234 {
1235 if (!bShift)
1236 {
1237 // Remove all marked data on cursor movement unless the Shift is locked.
1238 ScMarkData& rMark = aViewData.GetMarkData();
1239 bool bMarked = rMark.IsMarked() || rMark.IsMultiMarked();
1240 if (bMarked)
1241 {
1242 rMark.ResetMark();
1243 DoneBlockMode();
1244 InitOwnBlockMode();
1245 MarkDataChanged();
1246 }
1247 }
1248
1249 bool bSame = ( nCurX == aViewData.GetCurX() && nCurY == aViewData.GetCurY() );
1250 bMoveIsShift = bShift;
1251 pSelEngine->CursorPosChanging( bShift, bControl );
1252 bMoveIsShift = false;
1253 aFunctionSet.SetCursorAtCell( nCurX, nCurY, false );
1254
1255 // If the cursor has not been moved, the SelectionChanged for canceling the
1256 // selection has to happen here individually:
1257 if (bSame)
1258 SelectionChanged();
1259 }
1260
1261 ShowAllCursors();
1262 TestHintWindow();
1263 }
1264
MoveCursorRel(SCCOL nMovX,SCROW nMovY,ScFollowMode eMode,bool bShift,bool bKeepSel)1265 void ScTabView::MoveCursorRel( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode,
1266 bool bShift, bool bKeepSel )
1267 {
1268 ScDocument& rDoc = aViewData.GetDocument();
1269 SCTAB nTab = aViewData.GetTabNo();
1270
1271 bool bSkipProtected = false, bSkipUnprotected = false;
1272 const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
1273 if ( pProtect && pProtect->isProtected() )
1274 {
1275 bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
1276 bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
1277 }
1278
1279 if ( bSkipProtected && bSkipUnprotected )
1280 return;
1281
1282 SCCOL nOldX;
1283 SCROW nOldY;
1284 SCCOL nCurX;
1285 SCROW nCurY;
1286 if ( aViewData.IsRefMode() )
1287 {
1288 nOldX = aViewData.GetRefEndX();
1289 nOldY = aViewData.GetRefEndY();
1290 nCurX = nOldX + nMovX;
1291 nCurY = nOldY + nMovY;
1292 }
1293 else
1294 {
1295 nOldX = aViewData.GetCurX();
1296 nOldY = aViewData.GetCurY();
1297 nCurX = (nMovX != 0) ? nOldX+nMovX : aViewData.GetOldCurX();
1298 nCurY = (nMovY != 0) ? nOldY+nMovY : aViewData.GetOldCurY();
1299 }
1300
1301 if (nMovX < 0 && nOldX == 0)
1302 { // trying to go left from 1st column
1303 if (nMovY == 0) // done, because no vertical move is requested
1304 return;
1305 }
1306 if (nMovY < 0 && nOldY == 0)
1307 { // trying to go up from 1st row
1308 if (nMovX == 0) // done, because no horizontal move is requested
1309 return;
1310 }
1311
1312 aViewData.ResetOldCursor();
1313
1314 if (nMovX != 0 && rDoc.ValidColRow(nCurX,nCurY))
1315 SkipCursorHorizontal(nCurX, nCurY, nOldX, nMovX);
1316
1317 if (nMovY != 0 && rDoc.ValidColRow(nCurX,nCurY))
1318 SkipCursorVertical(nCurX, nCurY, nOldY, nMovY);
1319
1320 MoveCursorAbs( nCurX, nCurY, eMode, bShift, false, true, bKeepSel );
1321 }
1322
MoveCursorPage(SCCOL nMovX,SCROW nMovY,ScFollowMode eMode,bool bShift,bool bKeepSel)1323 void ScTabView::MoveCursorPage( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift, bool bKeepSel )
1324 {
1325 SCCOL nPageX;
1326 SCROW nPageY;
1327 GetPageMoveEndPosition(nMovX, nMovY, nPageX, nPageY);
1328 MoveCursorRel( nPageX, nPageY, eMode, bShift, bKeepSel );
1329 }
1330
MoveCursorArea(SCCOL nMovX,SCROW nMovY,ScFollowMode eMode,bool bShift,bool bKeepSel)1331 void ScTabView::MoveCursorArea( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift, bool bKeepSel )
1332 {
1333 SCCOL nNewX;
1334 SCROW nNewY;
1335 GetAreaMoveEndPosition(nMovX, nMovY, eMode, nNewX, nNewY, eMode);
1336 MoveCursorRel(nNewX, nNewY, eMode, bShift, bKeepSel);
1337 }
1338
MoveCursorEnd(SCCOL nMovX,SCROW nMovY,ScFollowMode eMode,bool bShift,bool bKeepSel)1339 void ScTabView::MoveCursorEnd( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift, bool bKeepSel )
1340 {
1341 ScDocument& rDoc = aViewData.GetDocument();
1342 SCTAB nTab = aViewData.GetTabNo();
1343
1344 SCCOL nCurX;
1345 SCROW nCurY;
1346 aViewData.GetMoveCursor( nCurX,nCurY );
1347 SCCOL nNewX = nCurX;
1348 SCROW nNewY = nCurY;
1349
1350 SCCOL nUsedX = 0;
1351 SCROW nUsedY = 0;
1352 if ( nMovX > 0 || nMovY > 0 )
1353 rDoc.GetPrintArea( nTab, nUsedX, nUsedY ); // get end
1354
1355 if (nMovX<0)
1356 nNewX=0;
1357 else if (nMovX>0)
1358 nNewX=nUsedX; // last used range
1359
1360 if (nMovY<0)
1361 nNewY=0;
1362 else if (nMovY>0)
1363 nNewY=nUsedY;
1364
1365 aViewData.ResetOldCursor();
1366 MoveCursorRel( nNewX-nCurX, nNewY-nCurY, eMode, bShift, bKeepSel );
1367 }
1368
MoveCursorScreen(SCCOL nMovX,SCROW nMovY,ScFollowMode eMode,bool bShift)1369 void ScTabView::MoveCursorScreen( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift )
1370 {
1371 ScDocument& rDoc = aViewData.GetDocument();
1372 SCTAB nTab = aViewData.GetTabNo();
1373
1374 SCCOL nCurX;
1375 SCROW nCurY;
1376 aViewData.GetMoveCursor( nCurX,nCurY );
1377 SCCOL nNewX = nCurX;
1378 SCROW nNewY = nCurY;
1379
1380 ScSplitPos eWhich = aViewData.GetActivePart();
1381 SCCOL nPosX = aViewData.GetPosX( WhichH(eWhich) );
1382 SCROW nPosY = aViewData.GetPosY( WhichV(eWhich) );
1383
1384 SCCOL nAddX = aViewData.VisibleCellsX( WhichH(eWhich) );
1385 if (nAddX != 0)
1386 --nAddX;
1387 SCROW nAddY = aViewData.VisibleCellsY( WhichV(eWhich) );
1388 if (nAddY != 0)
1389 --nAddY;
1390
1391 if (nMovX<0)
1392 nNewX=nPosX;
1393 else if (nMovX>0)
1394 nNewX=nPosX+nAddX;
1395
1396 if (nMovY<0)
1397 nNewY=nPosY;
1398 else if (nMovY>0)
1399 nNewY=nPosY+nAddY;
1400
1401 aViewData.SetOldCursor( nNewX,nNewY );
1402 rDoc.SkipOverlapped(nNewX, nNewY, nTab);
1403 MoveCursorAbs( nNewX, nNewY, eMode, bShift, false, true );
1404 }
1405
MoveCursorEnter(bool bShift)1406 void ScTabView::MoveCursorEnter( bool bShift ) // bShift -> up/down
1407 {
1408 const ScInputOptions& rOpt = SC_MOD()->GetInputOptions();
1409 if (!rOpt.GetMoveSelection())
1410 {
1411 aViewData.UpdateInputHandler(true);
1412 return;
1413 }
1414
1415 SCCOL nMoveX = 0;
1416 SCROW nMoveY = 0;
1417 switch (static_cast<ScDirection>(rOpt.GetMoveDir()))
1418 {
1419 case DIR_BOTTOM:
1420 nMoveY = bShift ? -1 : 1;
1421 break;
1422 case DIR_RIGHT:
1423 nMoveX = bShift ? -1 : 1;
1424 break;
1425 case DIR_TOP:
1426 nMoveY = bShift ? 1 : -1;
1427 break;
1428 case DIR_LEFT:
1429 nMoveX = bShift ? 1 : -1;
1430 break;
1431 }
1432
1433 SCCOL nCurX;
1434 SCROW nCurY;
1435 aViewData.GetMoveCursor( nCurX,nCurY );
1436 SCCOL nNewX = nCurX;
1437 SCROW nNewY = nCurY;
1438 SCTAB nTab = aViewData.GetTabNo();
1439
1440 ScMarkData& rMark = aViewData.GetMarkData();
1441 ScDocument& rDoc = aViewData.GetDocument();
1442
1443 if (rMark.IsMarked() || rMark.IsMultiMarked())
1444 {
1445 rDoc.GetNextPos( nNewX, nNewY, nTab, nMoveX, nMoveY, true, false, rMark );
1446
1447 MoveCursorRel( nNewX - nCurX, nNewY - nCurY, SC_FOLLOW_LINE, false, true );
1448
1449 // update input line even if cursor was not moved
1450 if ( nNewX == nCurX && nNewY == nCurY )
1451 aViewData.UpdateInputHandler(true);
1452 }
1453 else
1454 {
1455 // After Tab and Enter back to the starting column again.
1456 const SCCOL nTabStartCol = ((nMoveY != 0 && !nMoveX) ? aViewData.GetTabStartCol() : SC_TABSTART_NONE);
1457 rDoc.GetNextPos( nNewX, nNewY, nTab, nMoveX, nMoveY, false, true, rMark, nTabStartCol );
1458
1459 MoveCursorRel( nNewX - nCurX, nNewY - nCurY, SC_FOLLOW_LINE, false);
1460 }
1461 }
1462
MoveCursorKeyInput(const KeyEvent & rKeyEvent)1463 bool ScTabView::MoveCursorKeyInput( const KeyEvent& rKeyEvent )
1464 {
1465 const vcl::KeyCode& rKCode = rKeyEvent.GetKeyCode();
1466
1467 enum { MOD_NONE, MOD_CTRL, MOD_ALT, MOD_BOTH } eModifier =
1468 rKCode.IsMod1() ?
1469 (rKCode.IsMod2() ? MOD_BOTH : MOD_CTRL) :
1470 (rKCode.IsMod2() ? MOD_ALT : MOD_NONE);
1471
1472 bool bSel = rKCode.IsShift();
1473 sal_uInt16 nCode = rKCode.GetCode();
1474
1475 // CURSOR keys
1476 SCCOL nDX = 0;
1477 SCROW nDY = 0;
1478 switch( nCode )
1479 {
1480 case KEY_LEFT: nDX = -1; break;
1481 case KEY_RIGHT: nDX = 1; break;
1482 case KEY_UP: nDY = -1; break;
1483 case KEY_DOWN: nDY = 1; break;
1484 }
1485 if( nDX != 0 || nDY != 0 )
1486 {
1487 switch( eModifier )
1488 {
1489 case MOD_NONE: MoveCursorRel( nDX, nDY, SC_FOLLOW_LINE, bSel ); break;
1490 case MOD_CTRL: MoveCursorArea( nDX, nDY, SC_FOLLOW_JUMP, bSel ); break;
1491 default:
1492 {
1493 // added to avoid warnings
1494 }
1495 }
1496 // always true to suppress changes of col/row size (ALT+CURSOR)
1497 return true;
1498 }
1499
1500 // PAGEUP/PAGEDOWN
1501 if( (nCode == KEY_PAGEUP) || (nCode == KEY_PAGEDOWN) )
1502 {
1503 nDX = (nCode == KEY_PAGEUP) ? -1 : 1;
1504 switch( eModifier )
1505 {
1506 case MOD_NONE: MoveCursorPage( 0, static_cast<SCCOLROW>(nDX), SC_FOLLOW_FIX, bSel ); break;
1507 case MOD_ALT: MoveCursorPage( nDX, 0, SC_FOLLOW_FIX, bSel ); break;
1508 case MOD_CTRL: SelectNextTab( nDX, false ); break;
1509 default:
1510 {
1511 // added to avoid warnings
1512 }
1513 }
1514 return true;
1515 }
1516
1517 // HOME/END
1518 if( (nCode == KEY_HOME) || (nCode == KEY_END) )
1519 {
1520 nDX = (nCode == KEY_HOME) ? -1 : 1;
1521 ScFollowMode eMode = (nCode == KEY_HOME) ? SC_FOLLOW_LINE : SC_FOLLOW_JUMP;
1522 switch( eModifier )
1523 {
1524 case MOD_NONE: MoveCursorEnd( nDX, 0, eMode, bSel ); break;
1525 case MOD_CTRL: MoveCursorEnd( nDX, static_cast<SCCOLROW>(nDX), eMode, bSel ); break;
1526 default:
1527 {
1528 // added to avoid warnings
1529 }
1530 }
1531 return true;
1532 }
1533
1534 return false;
1535 }
1536
1537 // next/previous unprotected cell
FindNextUnprot(bool bShift,bool bInSelection)1538 void ScTabView::FindNextUnprot( bool bShift, bool bInSelection )
1539 {
1540 short nMove = bShift ? -1 : 1;
1541
1542 ScMarkData& rMark = aViewData.GetMarkData();
1543 bool bMarked = bInSelection && (rMark.IsMarked() || rMark.IsMultiMarked());
1544
1545 SCCOL nCurX;
1546 SCROW nCurY;
1547 aViewData.GetMoveCursor( nCurX,nCurY );
1548 SCCOL nNewX = nCurX;
1549 SCROW nNewY = nCurY;
1550 SCTAB nTab = aViewData.GetTabNo();
1551
1552 ScDocument& rDoc = aViewData.GetDocument();
1553 rDoc.GetNextPos( nNewX,nNewY, nTab, nMove,0, bMarked, true, rMark );
1554
1555 SCCOL nTabCol = aViewData.GetTabStartCol();
1556 if ( nTabCol == SC_TABSTART_NONE )
1557 nTabCol = nCurX; // back to this column after Enter
1558
1559 MoveCursorRel( nNewX-nCurX, nNewY-nCurY, SC_FOLLOW_LINE, false, true );
1560
1561 // TabCol is reset in MoveCursorRel...
1562 aViewData.SetTabStartCol( nTabCol );
1563 }
1564
MarkColumns()1565 void ScTabView::MarkColumns()
1566 {
1567 SCCOL nStartCol;
1568 SCCOL nEndCol;
1569
1570 ScMarkData& rMark = aViewData.GetMarkData();
1571 if (rMark.IsMarked())
1572 {
1573 ScRange aMarkRange;
1574 rMark.GetMarkArea( aMarkRange );
1575 nStartCol = aMarkRange.aStart.Col();
1576 nEndCol = aMarkRange.aEnd.Col();
1577 }
1578 else
1579 {
1580 SCROW nDummy;
1581 aViewData.GetMoveCursor( nStartCol, nDummy );
1582 nEndCol=nStartCol;
1583 }
1584
1585 SCTAB nTab = aViewData.GetTabNo();
1586 ScDocument& rDoc = aViewData.GetDocument();
1587 DoneBlockMode();
1588 InitBlockMode( nStartCol,0, nTab );
1589 MarkCursor( nEndCol, rDoc.MaxRow(), nTab );
1590 SelectionChanged();
1591 }
1592
MarkRows()1593 void ScTabView::MarkRows()
1594 {
1595 SCROW nStartRow;
1596 SCROW nEndRow;
1597
1598 ScMarkData& rMark = aViewData.GetMarkData();
1599 if (rMark.IsMarked())
1600 {
1601 ScRange aMarkRange;
1602 rMark.GetMarkArea( aMarkRange );
1603 nStartRow = aMarkRange.aStart.Row();
1604 nEndRow = aMarkRange.aEnd.Row();
1605 }
1606 else
1607 {
1608 SCCOL nDummy;
1609 aViewData.GetMoveCursor( nDummy, nStartRow );
1610 nEndRow=nStartRow;
1611 }
1612
1613 SCTAB nTab = aViewData.GetTabNo();
1614 ScDocument& rDoc = aViewData.GetDocument();
1615 DoneBlockMode();
1616 InitBlockMode( 0,nStartRow, nTab );
1617 MarkCursor( rDoc.MaxCol(), nEndRow, nTab );
1618 SelectionChanged();
1619 }
1620
1621
MarkColumns(SCCOL nCol,sal_Int16 nModifier)1622 void ScTabView::MarkColumns(SCCOL nCol, sal_Int16 nModifier)
1623 {
1624 ScDocument& rDoc = aViewData.GetDocument();
1625 SCCOL nStartCol = nCol;
1626 SCTAB nTab = aViewData.GetTabNo();
1627
1628 if ((nModifier & KEY_SHIFT) == KEY_SHIFT)
1629 bMoveIsShift = true;
1630
1631 DoneBlockMode( nModifier != 0 );
1632 InitBlockMode( nStartCol, 0, nTab, true, true);
1633 MarkCursor( nCol, rDoc.MaxRow(), nTab );
1634 bMoveIsShift = false;
1635 SetCursor( nCol, 0 );
1636 SelectionChanged();
1637 }
1638
MarkRows(SCROW nRow,sal_Int16 nModifier)1639 void ScTabView::MarkRows(SCROW nRow, sal_Int16 nModifier)
1640 {
1641 ScDocument& rDoc = aViewData.GetDocument();
1642 SCROW nStartRow = nRow;
1643 SCTAB nTab = aViewData.GetTabNo();
1644
1645 if ((nModifier & KEY_SHIFT) == KEY_SHIFT)
1646 bMoveIsShift = true;
1647
1648 DoneBlockMode( nModifier != 0 );
1649 InitBlockMode( 0, nStartRow, nTab, true, false, true );
1650 MarkCursor( rDoc.MaxCol(), nRow, nTab );
1651 bMoveIsShift = false;
1652 SetCursor( 0, nRow );
1653 SelectionChanged();
1654 }
1655
MarkDataArea(bool bIncludeCursor)1656 void ScTabView::MarkDataArea( bool bIncludeCursor )
1657 {
1658 ScDocument& rDoc = aViewData.GetDocument();
1659 SCTAB nTab = aViewData.GetTabNo();
1660 SCCOL nStartCol = aViewData.GetCurX();
1661 SCROW nStartRow = aViewData.GetCurY();
1662 SCCOL nEndCol = nStartCol;
1663 SCROW nEndRow = nStartRow;
1664
1665 rDoc.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, bIncludeCursor, false );
1666
1667 HideAllCursors();
1668 DoneBlockMode();
1669 InitBlockMode( nStartCol, nStartRow, nTab );
1670 MarkCursor( nEndCol, nEndRow, nTab );
1671 ShowAllCursors();
1672
1673 SelectionChanged();
1674 }
1675
MarkMatrixFormula()1676 void ScTabView::MarkMatrixFormula()
1677 {
1678 ScDocument& rDoc = aViewData.GetDocument();
1679 ScAddress aCursor( aViewData.GetCurX(), aViewData.GetCurY(), aViewData.GetTabNo() );
1680 ScRange aMatrix;
1681 if ( rDoc.GetMatrixFormulaRange( aCursor, aMatrix ) )
1682 {
1683 MarkRange( aMatrix, false ); // cursor is already within the range
1684 }
1685 }
1686
MarkRange(const ScRange & rRange,bool bSetCursor,bool bContinue)1687 void ScTabView::MarkRange( const ScRange& rRange, bool bSetCursor, bool bContinue )
1688 {
1689 ScDocument& rDoc = aViewData.GetDocument();
1690 SCTAB nTab = rRange.aStart.Tab();
1691 SetTabNo( nTab );
1692
1693 HideAllCursors();
1694 DoneBlockMode( bContinue ); // bContinue==true -> clear old mark
1695 if (bSetCursor) // if Cursor is set, also always align
1696 {
1697 SCCOL nAlignX = rRange.aStart.Col();
1698 SCROW nAlignY = rRange.aStart.Row();
1699 bool bCol = ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() ) && !aViewData.GetDocument().IsInVBAMode();
1700 bool bRow = ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() );
1701 if ( bCol )
1702 nAlignX = aViewData.GetPosX(WhichH(aViewData.GetActivePart()));
1703 if ( bRow )
1704 nAlignY = aViewData.GetPosY(WhichV(aViewData.GetActivePart()));
1705 AlignToCursor( nAlignX, nAlignY, SC_FOLLOW_JUMP );
1706 }
1707 InitBlockMode( rRange.aStart.Col(), rRange.aStart.Row(), nTab );
1708 MarkCursor( rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
1709 if (bSetCursor)
1710 {
1711 SCCOL nPosX = rRange.aStart.Col();
1712 SCROW nPosY = rRange.aStart.Row();
1713 rDoc.SkipOverlapped(nPosX, nPosY, nTab);
1714
1715 aViewData.ResetOldCursor();
1716 SetCursor( nPosX, nPosY );
1717 }
1718 ShowAllCursors();
1719
1720 SelectionChanged();
1721 }
1722
Unmark()1723 void ScTabView::Unmark()
1724 {
1725 ScMarkData& rMark = aViewData.GetMarkData();
1726 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1727 {
1728 SCCOL nCurX;
1729 SCROW nCurY;
1730 aViewData.GetMoveCursor( nCurX,nCurY );
1731 MoveCursorAbs( nCurX, nCurY, SC_FOLLOW_NONE, false, false );
1732
1733 SelectionChanged();
1734 }
1735 }
1736
SetMarkData(const ScMarkData & rNew)1737 void ScTabView::SetMarkData( const ScMarkData& rNew )
1738 {
1739 DoneBlockMode();
1740 InitOwnBlockMode();
1741 aViewData.GetMarkData() = rNew;
1742
1743 MarkDataChanged();
1744 }
1745
MarkDataChanged()1746 void ScTabView::MarkDataChanged()
1747 {
1748 // has to be called after making direct changes to mark data (not via MarkCursor etc)
1749
1750 UpdateSelectionOverlay();
1751 }
1752
SelectNextTab(short nDir,bool bExtendSelection)1753 void ScTabView::SelectNextTab( short nDir, bool bExtendSelection )
1754 {
1755 if (!nDir)
1756 return;
1757 OSL_ENSURE( nDir==-1 || nDir==1, "SelectNextTab: invalid value");
1758
1759 ScDocument& rDoc = aViewData.GetDocument();
1760 SCTAB nTab = aViewData.GetTabNo();
1761 if (nDir<0)
1762 {
1763 if (!nTab)
1764 return;
1765 --nTab;
1766 while (!rDoc.IsVisible(nTab))
1767 {
1768 if (!nTab)
1769 return;
1770 --nTab;
1771 }
1772 }
1773 else
1774 {
1775 SCTAB nCount = rDoc.GetTableCount();
1776 ++nTab;
1777 if (nTab >= nCount)
1778 return;
1779 while (!rDoc.IsVisible(nTab))
1780 {
1781 ++nTab;
1782 if (nTab >= nCount)
1783 return;
1784 }
1785 }
1786
1787 SetTabNo( nTab, false, bExtendSelection );
1788 PaintExtras();
1789 }
1790
SelectTabPage(const sal_uInt16 nTab)1791 void ScTabView::SelectTabPage( const sal_uInt16 nTab )
1792 {
1793 pTabControl->SwitchToPageId( nTab );
1794 }
1795
1796 // SetTabNo - set the displayed sheet
1797
SetTabNo(SCTAB nTab,bool bNew,bool bExtendSelection,bool bSameTabButMoved)1798 void ScTabView::SetTabNo( SCTAB nTab, bool bNew, bool bExtendSelection, bool bSameTabButMoved )
1799 {
1800 if ( !ValidTab(nTab) )
1801 {
1802 OSL_FAIL("SetTabNo: invalid sheet");
1803 return;
1804 }
1805
1806 if ( !(nTab != aViewData.GetTabNo() || bNew) )
1807 return;
1808
1809 // FormShell would like to be informed before the switch
1810 FmFormShell* pFormSh = aViewData.GetViewShell()->GetFormShell();
1811 if (pFormSh)
1812 {
1813 bool bAllowed = pFormSh->PrepareClose();
1814 if (!bAllowed)
1815 {
1816 //! error message? or does FormShell do it?
1817 //! return error flag and cancel actions
1818
1819 return; // FormShell says that it can not be switched
1820 }
1821 }
1822
1823 // not InputEnterHandler due to reference input
1824
1825 ScDocument& rDoc = aViewData.GetDocument();
1826
1827 rDoc.MakeTable( nTab );
1828
1829 // Update pending row heights before switching the sheet, so Reschedule from the progress bar
1830 // doesn't paint the new sheet with old heights
1831 aViewData.GetDocShell()->UpdatePendingRowHeights( nTab );
1832
1833 SCTAB nTabCount = rDoc.GetTableCount();
1834 SCTAB nOldPos = nTab;
1835 while (!rDoc.IsVisible(nTab)) // search for next visible
1836 {
1837 bool bUp = (nTab>=nOldPos);
1838 if (bUp)
1839 {
1840 ++nTab;
1841 if (nTab>=nTabCount)
1842 {
1843 nTab = nOldPos;
1844 bUp = false;
1845 }
1846 }
1847
1848 if (!bUp)
1849 {
1850 if (nTab != 0)
1851 --nTab;
1852 else
1853 {
1854 OSL_FAIL("no visible sheets");
1855 rDoc.SetVisible( 0, true );
1856 }
1857 }
1858 }
1859
1860 // #i71490# Deselect drawing objects before changing the sheet number in view data,
1861 // so the handling of notes still has the sheet selected on which the notes are.
1862 DrawDeselectAll();
1863
1864 ScModule* pScMod = SC_MOD();
1865 bool bRefMode = pScMod->IsFormulaMode();
1866 if ( !bRefMode ) // query, so that RefMode works when switching sheet
1867 {
1868 DoneBlockMode();
1869 pSelEngine->Reset(); // reset all flags, including locked modifiers
1870 aViewData.SetRefTabNo( nTab );
1871 }
1872
1873 ScSplitPos eOldActive = aViewData.GetActivePart(); // before switching
1874 bool bFocus = pGridWin[eOldActive] && pGridWin[eOldActive]->HasFocus();
1875
1876 aViewData.SetTabNo( nTab );
1877 if (mpSpellCheckCxt)
1878 mpSpellCheckCxt->setTabNo( nTab );
1879 // UpdateShow before SetCursor, so that UpdateAutoFillMark finds the correct
1880 // window (is called from SetCursor)
1881 UpdateShow();
1882
1883 SfxBindings& rBindings = aViewData.GetBindings();
1884 ScMarkData& rMark = aViewData.GetMarkData();
1885
1886 bool bAllSelected = true;
1887 for (SCTAB nSelTab = 0; nSelTab < nTabCount; ++nSelTab)
1888 {
1889 if (!rDoc.IsVisible(nSelTab) || rMark.GetTableSelect(nSelTab))
1890 {
1891 if (nTab == nSelTab)
1892 // This tab is already in selection. Keep the current
1893 // selection.
1894 bExtendSelection = true;
1895 }
1896 else
1897 {
1898 bAllSelected = false;
1899 if (bExtendSelection)
1900 // We got what we need. No need to stay in the loop.
1901 break;
1902 }
1903 }
1904 if (bAllSelected && !bNew)
1905 // #i6327# if all tables are selected, a selection event (#i6330#) will deselect all
1906 // (not if called with bNew to update settings)
1907 bExtendSelection = false;
1908
1909 if (bExtendSelection)
1910 rMark.SelectTable( nTab, true );
1911 else
1912 {
1913 rMark.SelectOneTable( nTab );
1914 rBindings.Invalidate( FID_FILL_TAB );
1915 rBindings.Invalidate( FID_TAB_DESELECTALL );
1916 }
1917
1918 bool bUnoRefDialog = pScMod->IsRefDialogOpen() && pScMod->GetCurRefDlgId() == WID_SIMPLE_REF;
1919
1920 // recalc zoom-dependent values (before TabChanged, before UpdateEditViewPos)
1921 RefreshZoom();
1922 UpdateVarZoom();
1923
1924 if ( bRefMode ) // hide EditView if necessary (after aViewData.SetTabNo !)
1925 {
1926 for (VclPtr<ScGridWindow> & pWin : pGridWin)
1927 {
1928 if (pWin && pWin->IsVisible())
1929 pWin->UpdateEditViewPos();
1930 }
1931 }
1932
1933 TabChanged(bSameTabButMoved); // DrawView
1934 collectUIInformation({{"TABLE", OUString::number(nTab)}});
1935 UpdateVisibleRange();
1936
1937 aViewData.GetViewShell()->WindowChanged(); // if the active window has changed
1938 aViewData.ResetOldCursor();
1939 SetCursor( aViewData.GetCurX(), aViewData.GetCurY(), true );
1940
1941 if ( !bUnoRefDialog )
1942 aViewData.GetViewShell()->DisconnectAllClients(); // important for floating frames
1943 else
1944 {
1945 // hide / show inplace client
1946 ScClient* pClient = static_cast<ScClient*>(aViewData.GetViewShell()->GetIPClient());
1947 if ( pClient && pClient->IsObjectInPlaceActive() )
1948 {
1949 tools::Rectangle aObjArea = pClient->GetObjArea();
1950 if ( nTab == aViewData.GetRefTabNo() )
1951 {
1952 // move to its original position
1953
1954 SdrOle2Obj* pDrawObj = pClient->GetDrawObj();
1955 if ( pDrawObj )
1956 {
1957 tools::Rectangle aRect = pDrawObj->GetLogicRect();
1958 MapMode aMapMode( MapUnit::Map100thMM );
1959 Size aOleSize = pDrawObj->GetOrigObjSize( &aMapMode );
1960 aRect.SetSize( aOleSize );
1961 aObjArea = aRect;
1962 }
1963 }
1964 else
1965 {
1966 // move to an invisible position
1967
1968 aObjArea.SetPos( Point( 0, -2*aObjArea.GetHeight() ) );
1969 }
1970 pClient->SetObjArea( aObjArea );
1971 }
1972 }
1973
1974 if ( bFocus && aViewData.GetActivePart() != eOldActive && !bRefMode )
1975 ActiveGrabFocus(); // grab focus to the pane that's active now
1976
1977 // freeze
1978
1979 bool bResize = false;
1980 if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
1981 if (aViewData.UpdateFixX())
1982 bResize = true;
1983 if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
1984 if (aViewData.UpdateFixY())
1985 bResize = true;
1986 if (bResize)
1987 RepeatResize();
1988 InvalidateSplit();
1989
1990 if ( aViewData.IsPagebreakMode() )
1991 UpdatePageBreakData(); //! asynchronously ??
1992
1993 // Form Layer must know the visible area of the new sheet
1994 // that is why MapMode must already be correct here
1995 for (VclPtr<ScGridWindow> & pWin : pGridWin)
1996 {
1997 if (pWin)
1998 pWin->SetMapMode(pWin->GetDrawMapMode());
1999 }
2000 SetNewVisArea();
2001
2002 PaintGrid();
2003 PaintTop();
2004 PaintLeft();
2005 PaintExtras();
2006
2007 DoResize( aBorderPos, aFrameSize );
2008 rBindings.Invalidate( SID_DELETE_PRINTAREA ); // Menu
2009 rBindings.Invalidate( FID_DEL_MANUALBREAKS );
2010 rBindings.Invalidate( FID_RESET_PRINTZOOM );
2011 rBindings.Invalidate( SID_STATUS_DOCPOS ); // Status bar
2012 rBindings.Invalidate( SID_ROWCOL_SELCOUNT ); // Status bar
2013 rBindings.Invalidate( SID_STATUS_PAGESTYLE ); // Status bar
2014 rBindings.Invalidate( SID_CURRENTTAB ); // Navigator
2015 rBindings.Invalidate( SID_STYLE_FAMILY2 ); // Designer
2016 rBindings.Invalidate( SID_STYLE_FAMILY4 ); // Designer
2017 rBindings.Invalidate( SID_TABLES_COUNT );
2018
2019 if (pScMod->IsRefDialogOpen())
2020 {
2021 sal_uInt16 nCurRefDlgId=pScMod->GetCurRefDlgId();
2022 SfxViewFrame* pViewFrm = aViewData.GetViewShell()->GetViewFrame();
2023 SfxChildWindow* pChildWnd = pViewFrm->GetChildWindow( nCurRefDlgId );
2024 if (pChildWnd)
2025 {
2026 if (pChildWnd->GetController())
2027 {
2028 IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
2029 if (pRefDlg)
2030 pRefDlg->ViewShellChanged();
2031 }
2032 }
2033 }
2034
2035 OnLibreOfficeKitTabChanged();
2036 }
2037
AddWindowToForeignEditView(SfxViewShell * pViewShell,ScSplitPos eWhich)2038 void ScTabView::AddWindowToForeignEditView(SfxViewShell* pViewShell, ScSplitPos eWhich)
2039 {
2040 aExtraEditViewManager.Add(pViewShell, eWhich);
2041 }
2042
RemoveWindowFromForeignEditView(SfxViewShell * pViewShell,ScSplitPos eWhich)2043 void ScTabView::RemoveWindowFromForeignEditView(SfxViewShell* pViewShell, ScSplitPos eWhich)
2044 {
2045 aExtraEditViewManager.Remove(pViewShell, eWhich);
2046 }
2047
OnLibreOfficeKitTabChanged()2048 void ScTabView::OnLibreOfficeKitTabChanged()
2049 {
2050 if (!comphelper::LibreOfficeKit::isActive())
2051 return;
2052
2053 ScTabViewShell* pThisViewShell = aViewData.GetViewShell();
2054 SCTAB nThisTabNo = pThisViewShell->GetViewData().GetTabNo();
2055 auto lTabSwitch = [pThisViewShell, nThisTabNo] (ScTabViewShell* pOtherViewShell)
2056 {
2057 ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
2058 SCTAB nOtherTabNo = rOtherViewData.GetTabNo();
2059 if (nThisTabNo == nOtherTabNo)
2060 {
2061 for (int i = 0; i < 4; ++i)
2062 {
2063 if (rOtherViewData.HasEditView(ScSplitPos(i)))
2064 {
2065 pThisViewShell->AddWindowToForeignEditView(pOtherViewShell, ScSplitPos(i));
2066 }
2067 }
2068 }
2069 else
2070 {
2071 for (int i = 0; i < 4; ++i)
2072 {
2073 if (rOtherViewData.HasEditView(ScSplitPos(i)))
2074 {
2075 pThisViewShell->RemoveWindowFromForeignEditView(pOtherViewShell, ScSplitPos(i));
2076 }
2077 }
2078 }
2079 };
2080
2081 SfxLokHelper::forEachOtherView(pThisViewShell, lTabSwitch);
2082
2083 pThisViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_HEADER, "all");
2084
2085 if (pThisViewShell->GetInputHandler())
2086 pThisViewShell->GetInputHandler()->UpdateLokReferenceMarks();
2087 }
2088
2089 // paint functions - only for this View
2090
MakeEditView(ScEditEngineDefaulter * pEngine,SCCOL nCol,SCROW nRow)2091 void ScTabView::MakeEditView( ScEditEngineDefaulter* pEngine, SCCOL nCol, SCROW nRow )
2092 {
2093 DrawDeselectAll();
2094
2095 if (pDrawView)
2096 DrawEnableAnim( false );
2097
2098 EditView* pSpellingView = aViewData.GetSpellingView();
2099
2100 for (sal_uInt16 i = 0; i < 4; i++)
2101 {
2102 if (pGridWin[i] && pGridWin[i]->IsVisible() && !aViewData.HasEditView(ScSplitPos(i)))
2103 {
2104 ScHSplitPos eHWhich = WhichH( static_cast<ScSplitPos>(i) );
2105 ScVSplitPos eVWhich = WhichV( static_cast<ScSplitPos>(i) );
2106 SCCOL nScrX = aViewData.GetPosX( eHWhich );
2107 SCROW nScrY = aViewData.GetPosY( eVWhich );
2108
2109 bool bPosVisible =
2110 ( nCol >= nScrX && nCol <= nScrX + aViewData.VisibleCellsX(eHWhich) - 1 &&
2111 nRow >= nScrY && nRow <= nScrY + aViewData.VisibleCellsY(eVWhich) - 1 );
2112
2113 // for the active part, create edit view even if outside the visible area,
2114 // so input isn't lost (and the edit view may be scrolled into the visible area)
2115
2116 // #i26433# during spelling, the spelling view must be active
2117 if ( bPosVisible || aViewData.GetActivePart() == static_cast<ScSplitPos>(i) ||
2118 ( pSpellingView && aViewData.GetEditView(static_cast<ScSplitPos>(i)) == pSpellingView ) )
2119 {
2120 pGridWin[i]->HideCursor();
2121
2122 pGridWin[i]->DeleteCursorOverlay();
2123 pGridWin[i]->DeleteAutoFillOverlay();
2124 pGridWin[i]->DeleteCopySourceOverlay();
2125
2126 // flush OverlayManager before changing MapMode to text edit
2127 pGridWin[i]->flushOverlayManager();
2128
2129 // MapMode must be set after HideCursor
2130 pGridWin[i]->SetMapMode(aViewData.GetLogicMode());
2131
2132 aViewData.SetEditEngine( static_cast<ScSplitPos>(i), pEngine, pGridWin[i], nCol, nRow );
2133
2134 if ( !bPosVisible )
2135 {
2136 // move the edit view area to the real (possibly negative) position,
2137 // or hide if completely above or left of the window
2138 pGridWin[i]->UpdateEditViewPos();
2139 }
2140 }
2141 }
2142 }
2143
2144 if (aViewData.GetViewShell()->HasAccessibilityObjects())
2145 aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccEnterEditMode));
2146 }
2147
UpdateEditView()2148 void ScTabView::UpdateEditView()
2149 {
2150 ScSplitPos eActive = aViewData.GetActivePart();
2151 for (sal_uInt16 i = 0; i < 4; i++)
2152 {
2153 ScSplitPos eCurrent = ScSplitPos(i);
2154 if (aViewData.HasEditView(eCurrent))
2155 {
2156 EditView* pEditView = aViewData.GetEditView(eCurrent);
2157
2158 tools::Long nRefTabNo = GetViewData().GetRefTabNo();
2159 tools::Long nX = GetViewData().GetCurXForTab(nRefTabNo);
2160 tools::Long nY = GetViewData().GetCurYForTab(nRefTabNo);
2161
2162 aViewData.SetEditEngine(eCurrent,
2163 static_cast<ScEditEngineDefaulter*>(pEditView->GetEditEngine()),
2164 pGridWin[i], nX, nY );
2165 if (eCurrent == eActive)
2166 pEditView->ShowCursor( false );
2167 }
2168 }
2169 }
2170
KillEditView(bool bNoPaint)2171 void ScTabView::KillEditView( bool bNoPaint )
2172 {
2173 SCCOL nCol1 = aViewData.GetEditStartCol();
2174 SCROW nRow1 = aViewData.GetEditStartRow();
2175 SCCOL nCol2 = aViewData.GetEditEndCol();
2176 SCROW nRow2 = aViewData.GetEditEndRow();
2177 bool bPaint[4];
2178 bool bNotifyAcc = false;
2179 tools::Rectangle aRectangle[4];
2180
2181 bool bExtended = nRow1 != nRow2; // column is painted to the end anyway
2182
2183 bool bAtCursor = nCol1 <= aViewData.GetCurX() &&
2184 nCol2 >= aViewData.GetCurX() &&
2185 nRow1 == aViewData.GetCurY();
2186 for (sal_uInt16 i = 0; i < 4; i++)
2187 {
2188 bPaint[i] = aViewData.HasEditView( static_cast<ScSplitPos>(i) );
2189 if (bPaint[i])
2190 {
2191 bNotifyAcc = true;
2192
2193 EditView* pView = aViewData.GetEditView( static_cast<ScSplitPos>(i) );
2194 aRectangle[i] = pView->GetInvalidateRect();
2195 }
2196 }
2197
2198 // notify accessibility before all things happen
2199 if (bNotifyAcc && aViewData.GetViewShell()->HasAccessibilityObjects())
2200 aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccLeaveEditMode));
2201
2202 aViewData.ResetEditView();
2203 for (sal_uInt16 i = 0; i < 4; i++)
2204 {
2205 if (pGridWin[i] && bPaint[i] && pGridWin[i]->IsVisible())
2206 {
2207 pGridWin[i]->ShowCursor();
2208
2209 pGridWin[i]->SetMapMode(pGridWin[i]->GetDrawMapMode());
2210
2211 if (comphelper::LibreOfficeKit::isActive())
2212 {
2213 const tools::Rectangle& rInvRect = aRectangle[i];
2214 pGridWin[i]->Invalidate(rInvRect);
2215
2216 // invalidate other views
2217 auto lInvalidateWindows =
2218 [&rInvRect] (ScTabView* pTabView)
2219 {
2220 for (VclPtr<ScGridWindow> const & pWin: pTabView->pGridWin)
2221 {
2222 if (pWin)
2223 pWin->Invalidate(rInvRect);
2224 }
2225 };
2226
2227 SfxLokHelper::forEachOtherView(GetViewData().GetViewShell(), lInvalidateWindows);
2228 }
2229 // #i73567# the cell still has to be repainted
2230 else if (bExtended || ( bAtCursor && !bNoPaint ))
2231 {
2232 pGridWin[i]->Draw( nCol1, nRow1, nCol2, nRow2, ScUpdateMode::All );
2233 pGridWin[i]->UpdateSelectionOverlay();
2234 }
2235 }
2236 }
2237
2238 if (pDrawView)
2239 DrawEnableAnim( true );
2240
2241 // GrabFocus always when this View is active and
2242 // when the input row has the focus
2243
2244 bool bGrabFocus = false;
2245 if (aViewData.IsActive())
2246 {
2247 ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
2248 if ( pInputHdl )
2249 {
2250 ScInputWindow* pInputWin = pInputHdl->GetInputWindow();
2251 if (pInputWin && pInputWin->IsInputActive())
2252 bGrabFocus = true;
2253 }
2254 }
2255
2256 if (bGrabFocus)
2257 {
2258 // should be done like this, so that Sfx notice it, but it does not work:
2259 //! aViewData.GetViewShell()->GetViewFrame()->GetWindow().GrabFocus();
2260 // therefore first like this:
2261 GetActiveWin()->GrabFocus();
2262 }
2263
2264 // cursor query only after GrabFocus
2265
2266 for (sal_uInt16 i = 0; i < 4; i++)
2267 {
2268 if (pGridWin[i] && pGridWin[i]->IsVisible())
2269 {
2270 vcl::Cursor* pCur = pGridWin[i]->GetCursor();
2271 if (pCur && pCur->IsVisible())
2272 pCur->Hide();
2273
2274 if (bPaint[i])
2275 {
2276 pGridWin[i]->UpdateCursorOverlay();
2277 pGridWin[i]->UpdateAutoFillOverlay();
2278 }
2279 }
2280 }
2281 }
2282
UpdateFormulas(SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow)2283 void ScTabView::UpdateFormulas(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow)
2284 {
2285 if ( aViewData.GetDocument().IsAutoCalcShellDisabled() )
2286 return;
2287
2288 for (sal_uInt16 i = 0; i < 4; i++)
2289 {
2290 if (pGridWin[i] && pGridWin[i]->IsVisible())
2291 pGridWin[i]->UpdateFormulas(nStartCol, nStartRow, nEndCol, nEndRow);
2292 }
2293
2294 if ( aViewData.IsPagebreakMode() )
2295 UpdatePageBreakData(); //! asynchronous
2296
2297 UpdateHeaderWidth();
2298
2299 // if in edit mode, adjust edit view area because widths/heights may have changed
2300 if ( aViewData.HasEditView( aViewData.GetActivePart() ) )
2301 UpdateEditView();
2302 }
2303
2304 // PaintArea - repaint block
2305
PaintArea(SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow,ScUpdateMode eMode)2306 void ScTabView::PaintArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
2307 ScUpdateMode eMode )
2308 {
2309 SCCOL nCol1;
2310 SCROW nRow1;
2311 SCCOL nCol2;
2312 SCROW nRow2;
2313 bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
2314 ScDocument& rDoc = aViewData.GetDocument();
2315
2316 PutInOrder( nStartCol, nEndCol );
2317 PutInOrder( nStartRow, nEndRow );
2318
2319 for (size_t i = 0; i < 4; ++i)
2320 {
2321 if (!pGridWin[i] || !pGridWin[i]->IsVisible())
2322 continue;
2323
2324 ScHSplitPos eHWhich = WhichH( static_cast<ScSplitPos>(i) );
2325 ScVSplitPos eVWhich = WhichV( static_cast<ScSplitPos>(i) );
2326 bool bOut = false;
2327
2328 nCol1 = nStartCol;
2329 nRow1 = nStartRow;
2330 nCol2 = nEndCol;
2331 nRow2 = nEndRow;
2332
2333 SCCOL nLastX = 0;
2334 SCROW nLastY = 0;
2335
2336 if (bIsTiledRendering)
2337 {
2338 nLastX = aViewData.GetMaxTiledCol();
2339 nLastY = aViewData.GetMaxTiledRow();
2340 }
2341 else
2342 {
2343
2344 SCCOL nScrX = aViewData.GetPosX( eHWhich );
2345 SCROW nScrY = aViewData.GetPosY( eVWhich );
2346
2347 if (nCol1 < nScrX)
2348 nCol1 = nScrX;
2349 if (nCol2 < nScrX)
2350 {
2351 if ( eMode == ScUpdateMode::All ) // for UPDATE_ALL, paint anyway
2352 nCol2 = nScrX; // (because of extending strings to the right)
2353 else
2354 bOut = true; // completely outside the window
2355 }
2356 if (nRow1 < nScrY)
2357 nRow1 = nScrY;
2358 if (nRow2 < nScrY)
2359 bOut = true;
2360
2361 nLastX = nScrX + aViewData.VisibleCellsX( eHWhich ) + 1;
2362 nLastY = nScrY + aViewData.VisibleCellsY( eVWhich ) + 1;
2363 }
2364
2365 if (nCol1 > nLastX)
2366 bOut = true;
2367 if (nCol2 > nLastX)
2368 nCol2 = nLastX;
2369 if (nRow1 > nLastY)
2370 bOut = true;
2371 if (nRow2 > nLastY)
2372 nRow2 = nLastY;
2373
2374 if (bOut)
2375 continue;
2376
2377 bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.GetTabNo() );
2378 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
2379
2380 Point aStart = aViewData.GetScrPos( nCol1, nRow1, static_cast<ScSplitPos>(i) );
2381 Point aEnd = aViewData.GetScrPos( nCol2+1, nRow2+1, static_cast<ScSplitPos>(i) );
2382 if ( eMode == ScUpdateMode::All )
2383 {
2384 if (bIsTiledRendering)
2385 {
2386 // When a cell content is deleted we have no clue about
2387 // the width of the embedded text.
2388 // Anyway, clients will ask only for tiles that overlaps
2389 // the visible area.
2390 // Remember that wsd expects int and that aEnd.X() is
2391 // in pixels and will be converted in twips, before performing
2392 // the lok callback, so we need to avoid that an overflow occurs.
2393 aEnd.setX( bLayoutRTL ? 0 : std::numeric_limits<int>::max() / 1000 );
2394 }
2395 else
2396 {
2397 aEnd.setX( bLayoutRTL ? 0 : pGridWin[i]->GetOutputSizePixel().Width() );
2398 }
2399 }
2400 aEnd.AdjustX( -nLayoutSign );
2401 aEnd.AdjustY( -1 );
2402
2403 // #i85232# include area below cells (could be done in GetScrPos?)
2404 if ( eMode == ScUpdateMode::All && nRow2 >= rDoc.MaxRow() && !bIsTiledRendering )
2405 aEnd.setY( pGridWin[i]->GetOutputSizePixel().Height() );
2406
2407 aStart.AdjustX( -nLayoutSign ); // include change marks
2408 aStart.AdjustY( -1 );
2409
2410 bool bMarkClipped = aViewData.GetOptions().GetOption( VOPT_CLIPMARKS );
2411 if (bMarkClipped)
2412 {
2413 // ScColumn::IsEmptyBlock has to be optimized for this
2414 // (switch to Search() )
2415 //!if ( nCol1 > 0 && !aViewData.GetDocument()->IsBlockEmpty(
2416 //! aViewData.GetTabNo(),
2417 //! 0, nRow1, nCol1-1, nRow2 ) )
2418 tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * aViewData.GetPPTX() );
2419 aStart.AdjustX( -(nMarkPixel * nLayoutSign) );
2420 }
2421
2422 pGridWin[i]->Invalidate( pGridWin[i]->PixelToLogic( tools::Rectangle( aStart,aEnd ) ) );
2423 }
2424
2425 // #i79909# Calling UpdateAllOverlays here isn't necessary and would lead to overlay calls from a timer,
2426 // with a wrong MapMode if editing in a cell (reference input).
2427 // #i80499# Overlays need updates in a lot of cases, e.g. changing row/column size,
2428 // or showing/hiding outlines. TODO: selections in inactive windows are vanishing.
2429 // #i84689# With relative conditional formats, PaintArea may be called often (for each changed cell),
2430 // so UpdateAllOverlays was moved to ScTabViewShell::Notify and is called only if PaintPartFlags::Left/PaintPartFlags::Top
2431 // is set (width or height changed).
2432 }
2433
PaintRangeFinderEntry(const ScRangeFindData * pData,const SCTAB nTab)2434 void ScTabView::PaintRangeFinderEntry (const ScRangeFindData* pData, const SCTAB nTab)
2435 {
2436 ScRange aRef = pData->aRef;
2437 aRef.PutInOrder(); // PutInOrder for the queries below
2438
2439 if ( aRef.aStart == aRef.aEnd ) //! ignore sheet?
2440 aViewData.GetDocument().ExtendMerge(aRef);
2441
2442 if (aRef.aStart.Tab() < nTab || aRef.aEnd.Tab() > nTab)
2443 return;
2444
2445 SCCOL nCol1 = aRef.aStart.Col();
2446 SCROW nRow1 = aRef.aStart.Row();
2447 SCCOL nCol2 = aRef.aEnd.Col();
2448 SCROW nRow2 = aRef.aEnd.Row();
2449
2450 // remove -> repaint
2451 // ScUpdateMode::Marks: Invalidate, nothing until end of row
2452
2453 bool bHiddenEdge = false;
2454 SCROW nTmp;
2455 ScDocument& rDoc = aViewData.GetDocument();
2456 while ( nCol1 > 0 && rDoc.ColHidden(nCol1, nTab) )
2457 {
2458 --nCol1;
2459 bHiddenEdge = true;
2460 }
2461 while ( nCol2 < rDoc.MaxCol() && rDoc.ColHidden(nCol2, nTab) )
2462 {
2463 ++nCol2;
2464 bHiddenEdge = true;
2465 }
2466 nTmp = rDoc.LastVisibleRow(0, nRow1, nTab);
2467 if (!rDoc.ValidRow(nTmp))
2468 nTmp = 0;
2469 if (nTmp < nRow1)
2470 {
2471 nRow1 = nTmp;
2472 bHiddenEdge = true;
2473 }
2474 nTmp = rDoc.FirstVisibleRow(nRow2, rDoc.MaxRow(), nTab);
2475 if (!rDoc.ValidRow(nTmp))
2476 nTmp = rDoc.MaxRow();
2477 if (nTmp > nRow2)
2478 {
2479 nRow2 = nTmp;
2480 bHiddenEdge = true;
2481 }
2482
2483 if ( nCol2 - nCol1 > 1 && nRow2 - nRow1 > 1 && !bHiddenEdge )
2484 {
2485 // only along the edges
2486 PaintArea( nCol1, nRow1, nCol2, nRow1, ScUpdateMode::Marks );
2487 PaintArea( nCol1, nRow1+1, nCol1, nRow2-1, ScUpdateMode::Marks );
2488 PaintArea( nCol2, nRow1+1, nCol2, nRow2-1, ScUpdateMode::Marks );
2489 PaintArea( nCol1, nRow2, nCol2, nRow2, ScUpdateMode::Marks );
2490 }
2491 else // all in one
2492 PaintArea( nCol1, nRow1, nCol2, nRow2, ScUpdateMode::Marks );
2493 }
2494
PaintRangeFinder(tools::Long nNumber)2495 void ScTabView::PaintRangeFinder( tools::Long nNumber )
2496 {
2497 ScInputHandler* pHdl = SC_MOD()->GetInputHdl( aViewData.GetViewShell() );
2498 if (!pHdl)
2499 return;
2500
2501 ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
2502 if ( !(pRangeFinder && pRangeFinder->GetDocName() == aViewData.GetDocShell()->GetTitle()) )
2503 return;
2504
2505 SCTAB nTab = aViewData.GetTabNo();
2506 sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFinder->Count());
2507
2508 if (nNumber < 0)
2509 {
2510 for (sal_uInt16 i=0; i<nCount; i++)
2511 PaintRangeFinderEntry(&pRangeFinder->GetObject(i),nTab);
2512 }
2513 else
2514 {
2515 sal_uInt16 idx = nNumber;
2516 if (idx < nCount)
2517 PaintRangeFinderEntry(&pRangeFinder->GetObject(idx),nTab);
2518 }
2519 }
2520
2521 // for chart data selection
2522
AddHighlightRange(const ScRange & rRange,const Color & rColor)2523 void ScTabView::AddHighlightRange( const ScRange& rRange, const Color& rColor )
2524 {
2525 maHighlightRanges.emplace_back( rRange, rColor );
2526
2527 SCTAB nTab = aViewData.GetTabNo();
2528 if ( nTab >= rRange.aStart.Tab() && nTab <= rRange.aEnd.Tab() )
2529 PaintArea( rRange.aStart.Col(), rRange.aStart.Row(),
2530 rRange.aEnd.Col(), rRange.aEnd.Row(), ScUpdateMode::Marks );
2531 }
2532
ClearHighlightRanges()2533 void ScTabView::ClearHighlightRanges()
2534 {
2535 SCTAB nTab = aViewData.GetTabNo();
2536 for (ScHighlightEntry const & rEntry : maHighlightRanges)
2537 {
2538 ScRange aRange = rEntry.aRef;
2539 if ( nTab >= aRange.aStart.Tab() && nTab <= aRange.aEnd.Tab() )
2540 PaintArea( aRange.aStart.Col(), aRange.aStart.Row(),
2541 aRange.aEnd.Col(), aRange.aEnd.Row(), ScUpdateMode::Marks );
2542 }
2543
2544 maHighlightRanges.clear();
2545 }
2546
DoChartSelection(const uno::Sequence<chart2::data::HighlightedRange> & rHilightRanges)2547 void ScTabView::DoChartSelection(
2548 const uno::Sequence< chart2::data::HighlightedRange > & rHilightRanges )
2549 {
2550 ClearHighlightRanges();
2551 const sal_Unicode sep = ::formula::FormulaCompiler::GetNativeSymbolChar(ocSep);
2552 size_t nSize = 0;
2553 size_t nIndex = 0;
2554 std::vector<ReferenceMark> aReferenceMarks( nSize );
2555
2556 for (chart2::data::HighlightedRange const & rHighlightedRange : rHilightRanges)
2557 {
2558 Color aSelColor(ColorTransparency, rHighlightedRange.PreferredColor);
2559 ScRangeList aRangeList;
2560 ScDocument& rDoc = aViewData.GetDocShell()->GetDocument();
2561 if( ScRangeStringConverter::GetRangeListFromString(
2562 aRangeList, rHighlightedRange.RangeRepresentation, rDoc, rDoc.GetAddressConvention(), sep ))
2563 {
2564 size_t nListSize = aRangeList.size();
2565 nSize += nListSize;
2566 aReferenceMarks.resize(nSize);
2567
2568 for ( size_t j = 0; j < nListSize; ++j )
2569 {
2570 ScRange& p = aRangeList[j];
2571 ScRange aTargetRange;
2572 if( rHighlightedRange.Index == - 1 )
2573 {
2574 aTargetRange = p;
2575 AddHighlightRange( aTargetRange, aSelColor );
2576 }
2577 else
2578 {
2579 aTargetRange = lcl_getSubRangeByIndex( p, rHighlightedRange.Index );
2580 AddHighlightRange( aTargetRange, aSelColor );
2581 }
2582
2583 if ( comphelper::LibreOfficeKit::isActive() && aViewData.GetViewShell() )
2584 {
2585 aTargetRange.PutInOrder();
2586
2587 tools::Long nX1 = aTargetRange.aStart.Col();
2588 tools::Long nX2 = aTargetRange.aEnd.Col();
2589 tools::Long nY1 = aTargetRange.aStart.Row();
2590 tools::Long nY2 = aTargetRange.aEnd.Row();
2591 tools::Long nTab = aTargetRange.aStart.Tab();
2592
2593 aReferenceMarks[nIndex++] = ScInputHandler::GetReferenceMark( aViewData, aViewData.GetDocShell(),
2594 nX1, nX2, nY1, nY2,
2595 nTab, aSelColor );
2596 }
2597 }
2598 }
2599 }
2600
2601 if ( comphelper::LibreOfficeKit::isActive() && aViewData.GetViewShell() )
2602 ScInputHandler::SendReferenceMarks( aViewData.GetViewShell(), aReferenceMarks );
2603 }
2604
DoDPFieldPopup(std::u16string_view rPivotTableName,sal_Int32 nDimensionIndex,Point aPoint,Size aSize)2605 void ScTabView::DoDPFieldPopup(std::u16string_view rPivotTableName, sal_Int32 nDimensionIndex, Point aPoint, Size aSize)
2606 {
2607 ScDocument& rDocument = aViewData.GetDocShell()->GetDocument();
2608 ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get();
2609
2610 if (!pWin)
2611 return;
2612
2613 ScDPCollection* pDPCollection = rDocument.GetDPCollection();
2614 ScDPObject* pDPObject = pDPCollection->GetByName(rPivotTableName);
2615 if (!pDPObject)
2616 return;
2617
2618 pDPObject->BuildAllDimensionMembers();
2619
2620 Point aScreenPoint = pWin->OutputToScreenPixel(pWin->LogicToPixel(aPoint));
2621 Size aScreenSize = pWin->LogicToPixel(aSize);
2622
2623 pWin->DPLaunchFieldPopupMenu(aScreenPoint, aScreenSize, nDimensionIndex, pDPObject);
2624 }
2625
2626 // PaintGrid - repaint data range
2627
PaintGrid()2628 void ScTabView::PaintGrid()
2629 {
2630 for (sal_uInt16 i = 0; i < 4; i++)
2631 {
2632 if (pGridWin[i] && pGridWin[i]->IsVisible())
2633 pGridWin[i]->Invalidate();
2634 }
2635 }
2636
2637 // PaintTop - repaint top control elements
2638
PaintTop()2639 void ScTabView::PaintTop()
2640 {
2641 for (sal_uInt16 i = 0; i < 2; i++)
2642 {
2643 if (pColBar[i])
2644 pColBar[i]->Invalidate();
2645 if (pColOutline[i])
2646 pColOutline[i]->Invalidate();
2647 }
2648 }
2649
CreateAnchorHandles(SdrHdlList & rHdl,const ScAddress & rAddress)2650 void ScTabView::CreateAnchorHandles(SdrHdlList& rHdl, const ScAddress& rAddress)
2651 {
2652 for (sal_uInt16 i = 0; i < 4; i++)
2653 {
2654 if(pGridWin[i] && pGridWin[i]->IsVisible())
2655 pGridWin[i]->CreateAnchorHandle(rHdl, rAddress);
2656 }
2657 }
2658
PaintTopArea(SCCOL nStartCol,SCCOL nEndCol)2659 void ScTabView::PaintTopArea( SCCOL nStartCol, SCCOL nEndCol )
2660 {
2661 // pixel position of the left edge
2662
2663 if ( nStartCol < aViewData.GetPosX(SC_SPLIT_LEFT) ||
2664 nStartCol < aViewData.GetPosX(SC_SPLIT_RIGHT) )
2665 aViewData.RecalcPixPos();
2666
2667 // adjust freeze (UpdateFixX resets HSplitPos)
2668
2669 if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX && nStartCol < aViewData.GetFixPosX() )
2670 if (aViewData.UpdateFixX())
2671 RepeatResize();
2672
2673 // paint
2674
2675 if (nStartCol>0)
2676 --nStartCol; //! general ?
2677
2678 ScDocument& rDoc = aViewData.GetDocument();
2679 bool bLayoutRTL = rDoc.IsLayoutRTL( aViewData.GetTabNo() );
2680 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
2681
2682 for (sal_uInt16 i = 0; i < 2; i++)
2683 {
2684 ScHSplitPos eWhich = ScHSplitPos(i);
2685 if (pColBar[eWhich])
2686 {
2687 Size aWinSize = pColBar[eWhich]->GetSizePixel();
2688 tools::Long nStartX = aViewData.GetScrPos( nStartCol, 0, eWhich ).X();
2689 tools::Long nEndX;
2690 if (nEndCol >= rDoc.MaxCol())
2691 nEndX = bLayoutRTL ? 0 : ( aWinSize.Width()-1 );
2692 else
2693 nEndX = aViewData.GetScrPos( nEndCol+1, 0, eWhich ).X() - nLayoutSign;
2694 if (nStartX > nEndX)
2695 std::swap(nStartX, nEndX);
2696 pColBar[eWhich]->Invalidate(
2697 tools::Rectangle( nStartX, 0, nEndX, aWinSize.Height()-1 ) );
2698 }
2699 if (pColOutline[eWhich])
2700 pColOutline[eWhich]->Invalidate();
2701 }
2702 }
2703
2704 // PaintLeft - repaint left control elements
2705
PaintLeft()2706 void ScTabView::PaintLeft()
2707 {
2708 for (sal_uInt16 i = 0; i < 2; i++)
2709 {
2710 if (pRowBar[i])
2711 pRowBar[i]->Invalidate();
2712 if (pRowOutline[i])
2713 pRowOutline[i]->Invalidate();
2714 }
2715 }
2716
PaintLeftArea(SCROW nStartRow,SCROW nEndRow)2717 void ScTabView::PaintLeftArea( SCROW nStartRow, SCROW nEndRow )
2718 {
2719 // pixel position of the upper edge
2720
2721 if ( nStartRow < aViewData.GetPosY(SC_SPLIT_TOP) ||
2722 nStartRow < aViewData.GetPosY(SC_SPLIT_BOTTOM) )
2723 aViewData.RecalcPixPos();
2724
2725 // adjust freeze (UpdateFixY reset VSplitPos)
2726
2727 if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX && nStartRow < aViewData.GetFixPosY() )
2728 if (aViewData.UpdateFixY())
2729 RepeatResize();
2730
2731 // paint
2732
2733 if (nStartRow>0)
2734 --nStartRow;
2735
2736 ScDocument& rDoc = aViewData.GetDocument();
2737 for (sal_uInt16 i = 0; i < 2; i++)
2738 {
2739 ScVSplitPos eWhich = ScVSplitPos(i);
2740 if (pRowBar[eWhich])
2741 {
2742 Size aWinSize = pRowBar[eWhich]->GetSizePixel();
2743 tools::Long nStartY = aViewData.GetScrPos( 0, nStartRow, eWhich ).Y();
2744 tools::Long nEndY;
2745 if (nEndRow >= rDoc.MaxRow())
2746 nEndY = aWinSize.Height() - 1;
2747 else
2748 nEndY = aViewData.GetScrPos( 0, nEndRow+1, eWhich ).Y() - 1;
2749 if (nStartY > nEndY)
2750 std::swap(nStartY, nEndY);
2751 pRowBar[eWhich]->Invalidate(
2752 tools::Rectangle( 0, nStartY, aWinSize.Width()-1, nEndY ) );
2753 }
2754 if (pRowOutline[eWhich])
2755 pRowOutline[eWhich]->Invalidate();
2756 }
2757 }
2758
PaintExtras()2759 bool ScTabView::PaintExtras()
2760 {
2761 bool bRet = false;
2762 ScDocument& rDoc = aViewData.GetDocument();
2763 SCTAB nTab = aViewData.GetTabNo();
2764 if (!rDoc.HasTable(nTab)) // sheet is deleted?
2765 {
2766 SCTAB nCount = rDoc.GetTableCount();
2767 aViewData.SetTabNo(nCount-1);
2768 bRet = true;
2769 }
2770 pTabControl->UpdateStatus(); // true = active
2771 return bRet;
2772 }
2773
RecalcPPT()2774 void ScTabView::RecalcPPT()
2775 {
2776 // called after changes that require the PPT values to be recalculated
2777 // (currently from detective operations)
2778
2779 double nOldX = aViewData.GetPPTX();
2780 double nOldY = aViewData.GetPPTY();
2781
2782 aViewData.RefreshZoom(); // pre-calculate new PPT values
2783
2784 bool bChangedX = ( aViewData.GetPPTX() != nOldX );
2785 bool bChangedY = ( aViewData.GetPPTY() != nOldY );
2786 if ( !(bChangedX || bChangedY) )
2787 return;
2788
2789 // call view SetZoom (including draw scale, split update etc)
2790 // and paint only if values changed
2791
2792 Fraction aZoomX = aViewData.GetZoomX();
2793 Fraction aZoomY = aViewData.GetZoomY();
2794 SetZoom( aZoomX, aZoomY, false );
2795
2796 PaintGrid();
2797 if (bChangedX)
2798 PaintTop();
2799 if (bChangedY)
2800 PaintLeft();
2801 }
2802
ActivateView(bool bActivate,bool bFirst)2803 void ScTabView::ActivateView( bool bActivate, bool bFirst )
2804 {
2805 if ( bActivate == aViewData.IsActive() && !bFirst )
2806 {
2807 // no assertion anymore - occurs when previously in Drag&Drop switching over
2808 // to another document
2809 return;
2810 }
2811
2812 // is only called for MDI-(De)Activate
2813 // aViewData.Activate behind due to cursor show for KillEditView
2814 // don't delete selection - if Activate(false) is set in ViewData,
2815 // then the selection is not displayed
2816
2817 if (!bActivate)
2818 {
2819 ScModule* pScMod = SC_MOD();
2820 bool bRefMode = pScMod->IsFormulaMode();
2821
2822 // don't cancel reference input, to allow reference
2823 // to other document
2824
2825 if (!bRefMode)
2826 {
2827 // pass view to GetInputHdl, this view may not be current anymore
2828 ScInputHandler* pHdl = SC_MOD()->GetInputHdl(aViewData.GetViewShell());
2829 if (pHdl)
2830 pHdl->EnterHandler();
2831 }
2832 }
2833
2834 PaintExtras();
2835
2836 aViewData.Activate(bActivate);
2837
2838 PaintBlock(false); // repaint, selection after active status
2839
2840 if (!bActivate)
2841 HideAllCursors(); // Cursor
2842 else if (!bFirst)
2843 ShowAllCursors();
2844
2845 if (bActivate)
2846 {
2847 if ( bFirst )
2848 {
2849 ScSplitPos eWin = aViewData.GetActivePart();
2850 OSL_ENSURE( pGridWin[eWin], "Corrupted document, not all SplitPos in GridWin" );
2851 if ( !pGridWin[eWin] )
2852 {
2853 eWin = SC_SPLIT_BOTTOMLEFT;
2854 if ( !pGridWin[eWin] )
2855 {
2856 short i;
2857 for ( i=0; i<4; i++ )
2858 {
2859 if ( pGridWin[i] )
2860 {
2861 eWin = static_cast<ScSplitPos>(i);
2862 break; // for
2863 }
2864 }
2865 OSL_ENSURE( i<4, "and BOOM" );
2866 }
2867 aViewData.SetActivePart( eWin );
2868 }
2869 }
2870 // do not call GrabFocus from here!
2871 // if the document is processed, then Sfx calls GrabFocus in the window of the shell.
2872 // if it is a mail body for instance, then it can't get the focus
2873 UpdateInputContext();
2874 }
2875 else
2876 pGridWin[aViewData.GetActivePart()]->ClickExtern();
2877 }
2878
ActivatePart(ScSplitPos eWhich)2879 void ScTabView::ActivatePart( ScSplitPos eWhich )
2880 {
2881 ScSplitPos eOld = aViewData.GetActivePart();
2882 if ( eOld == eWhich )
2883 return;
2884
2885 bInActivatePart = true;
2886
2887 bool bRefMode = SC_MOD()->IsFormulaMode();
2888
2889 // the HasEditView call during SetCursor would fail otherwise
2890 if ( aViewData.HasEditView(eOld) && !bRefMode )
2891 UpdateInputLine();
2892
2893 ScHSplitPos eOldH = WhichH(eOld);
2894 ScVSplitPos eOldV = WhichV(eOld);
2895 ScHSplitPos eNewH = WhichH(eWhich);
2896 ScVSplitPos eNewV = WhichV(eWhich);
2897 bool bTopCap = pColBar[eOldH] && pColBar[eOldH]->IsMouseCaptured();
2898 bool bLeftCap = pRowBar[eOldV] && pRowBar[eOldV]->IsMouseCaptured();
2899
2900 bool bFocus = pGridWin[eOld]->HasFocus();
2901 bool bCapture = pGridWin[eOld]->IsMouseCaptured();
2902 if (bCapture)
2903 pGridWin[eOld]->ReleaseMouse();
2904 pGridWin[eOld]->ClickExtern();
2905 pGridWin[eOld]->HideCursor();
2906 pGridWin[eWhich]->HideCursor();
2907 aViewData.SetActivePart( eWhich );
2908
2909 ScTabViewShell* pShell = aViewData.GetViewShell();
2910 pShell->WindowChanged();
2911
2912 pSelEngine->SetWindow(pGridWin[eWhich]);
2913 pSelEngine->SetWhich(eWhich);
2914 pSelEngine->SetVisibleArea( tools::Rectangle(Point(), pGridWin[eWhich]->GetOutputSizePixel()) );
2915
2916 pGridWin[eOld]->MoveMouseStatus(*pGridWin[eWhich]);
2917
2918 if ( bCapture || pGridWin[eWhich]->IsMouseCaptured() )
2919 {
2920 // tracking instead of CaptureMouse, so it can be cancelled cleanly
2921 // (SelectionEngine calls CaptureMouse for SetWindow)
2922 //! someday SelectionEngine itself should call StartTracking!?!
2923 pGridWin[eWhich]->ReleaseMouse();
2924 pGridWin[eWhich]->StartTracking();
2925 }
2926
2927 if ( bTopCap && pColBar[eNewH] )
2928 {
2929 pColBar[eOldH]->SetIgnoreMove(true);
2930 pColBar[eNewH]->SetIgnoreMove(false);
2931 pHdrSelEng->SetWindow( pColBar[eNewH] );
2932 tools::Long nWidth = pColBar[eNewH]->GetOutputSizePixel().Width();
2933 pHdrSelEng->SetVisibleArea( tools::Rectangle( 0, LONG_MIN, nWidth-1, LONG_MAX ) );
2934 pColBar[eNewH]->CaptureMouse();
2935 }
2936 if ( bLeftCap && pRowBar[eNewV] )
2937 {
2938 pRowBar[eOldV]->SetIgnoreMove(true);
2939 pRowBar[eNewV]->SetIgnoreMove(false);
2940 pHdrSelEng->SetWindow( pRowBar[eNewV] );
2941 tools::Long nHeight = pRowBar[eNewV]->GetOutputSizePixel().Height();
2942 pHdrSelEng->SetVisibleArea( tools::Rectangle( LONG_MIN, 0, LONG_MAX, nHeight-1 ) );
2943 pRowBar[eNewV]->CaptureMouse();
2944 }
2945 aHdrFunc.SetWhich(eWhich);
2946
2947 pGridWin[eOld]->ShowCursor();
2948 pGridWin[eWhich]->ShowCursor();
2949
2950 SfxInPlaceClient* pClient = aViewData.GetViewShell()->GetIPClient();
2951 bool bOleActive = ( pClient && pClient->IsObjectInPlaceActive() );
2952
2953 // don't switch ViewShell's active window during RefInput, because the focus
2954 // might change, and subsequent SetReference calls wouldn't find the right EditView
2955 if ( !bRefMode && !bOleActive )
2956 aViewData.GetViewShell()->SetWindow( pGridWin[eWhich] );
2957
2958 if ( bFocus && !aViewData.IsAnyFillMode() && !bRefMode )
2959 {
2960 // GrabFocus only if previously the other GridWindow had the focus
2961 // (for instance due to search and replace)
2962 pGridWin[eWhich]->GrabFocus();
2963 }
2964
2965 bInActivatePart = false;
2966 }
2967
HideListBox()2968 void ScTabView::HideListBox()
2969 {
2970 for (VclPtr<ScGridWindow> & pWin : pGridWin)
2971 {
2972 if (pWin)
2973 pWin->ClickExtern();
2974 }
2975 }
2976
UpdateInputContext()2977 void ScTabView::UpdateInputContext()
2978 {
2979 ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get();
2980 if (pWin)
2981 pWin->UpdateInputContext();
2982
2983 if (pTabControl)
2984 pTabControl->UpdateInputContext();
2985 }
2986
2987 // GetGridWidth - width of an output range (for ViewData)
2988
GetGridWidth(ScHSplitPos eWhich)2989 tools::Long ScTabView::GetGridWidth( ScHSplitPos eWhich )
2990 {
2991 // at present only the size of the current pane is synchronized with
2992 // the size of the visible area in Online;
2993 // as a workaround we use the same width for all panes independently
2994 // from the eWhich value
2995 if (comphelper::LibreOfficeKit::isActive())
2996 {
2997 ScGridWindow* pGridWindow = aViewData.GetActiveWin();
2998 if (pGridWindow)
2999 return pGridWindow->GetSizePixel().Width();
3000 }
3001
3002 ScSplitPos eGridWhich = ( eWhich == SC_SPLIT_LEFT ) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT;
3003 if (pGridWin[eGridWhich])
3004 return pGridWin[eGridWhich]->GetSizePixel().Width();
3005 else
3006 return 0;
3007 }
3008
3009 // GetGridHeight - height of an output range (for ViewData)
3010
GetGridHeight(ScVSplitPos eWhich)3011 tools::Long ScTabView::GetGridHeight( ScVSplitPos eWhich )
3012 {
3013 // at present only the size of the current pane is synchronized with
3014 // the size of the visible area in Online;
3015 // as a workaround we use the same height for all panes independently
3016 // from the eWhich value
3017 if (comphelper::LibreOfficeKit::isActive())
3018 {
3019 ScGridWindow* pGridWindow = aViewData.GetActiveWin();
3020 if (pGridWindow)
3021 return pGridWindow->GetSizePixel().Height();
3022 }
3023
3024 ScSplitPos eGridWhich = ( eWhich == SC_SPLIT_TOP ) ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT;
3025 if (pGridWin[eGridWhich])
3026 return pGridWin[eGridWhich]->GetSizePixel().Height();
3027 else
3028 return 0;
3029 }
3030
UpdateInputLine()3031 void ScTabView::UpdateInputLine()
3032 {
3033 SC_MOD()->InputEnterHandler();
3034 }
3035
ZoomChanged()3036 void ScTabView::ZoomChanged()
3037 {
3038 ScInputHandler* pHdl = SC_MOD()->GetInputHdl(aViewData.GetViewShell());
3039 if (pHdl)
3040 pHdl->SetRefScale( aViewData.GetZoomX(), aViewData.GetZoomY() );
3041
3042 UpdateFixPos();
3043
3044 UpdateScrollBars();
3045
3046 // VisArea...
3047 // AW: Discussed with NN if there is a reason that new map mode was only set for one window,
3048 // but is not. Setting only on one window causes the first repaint to have the old mapMode
3049 // in three of four views, so the overlay will save the wrong content e.g. when zooming out.
3050 // Changing to setting map mode at all windows.
3051
3052 for (sal_uInt32 i = 0; i < 4; i++)
3053 {
3054 if (pGridWin[i])
3055 pGridWin[i]->SetMapMode(pGridWin[i]->GetDrawMapMode());
3056 }
3057
3058 SetNewVisArea();
3059
3060 InterpretVisible(); // have everything calculated before painting
3061
3062 SfxBindings& rBindings = aViewData.GetBindings();
3063 rBindings.Invalidate( SID_ATTR_ZOOM );
3064 rBindings.Invalidate( SID_ATTR_ZOOMSLIDER );
3065 rBindings.Invalidate(SID_ZOOM_IN);
3066 rBindings.Invalidate(SID_ZOOM_OUT);
3067
3068 HideNoteMarker();
3069
3070 // To not change too much, use pWin here
3071 ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get();
3072
3073 if ( pWin && aViewData.HasEditView( aViewData.GetActivePart() ) )
3074 {
3075 // flush OverlayManager before changing the MapMode
3076 pWin->flushOverlayManager();
3077
3078 // make sure the EditView's position and size are updated
3079 // with the right (logic, not drawing) MapMode
3080 pWin->SetMapMode( aViewData.GetLogicMode() );
3081 UpdateEditView();
3082 }
3083 }
3084
CheckNeedsRepaint()3085 void ScTabView::CheckNeedsRepaint()
3086 {
3087 for (sal_uInt16 i = 0; i < 4; i++)
3088 {
3089 if (pGridWin[i] && pGridWin[i]->IsVisible())
3090 pGridWin[i]->CheckNeedsRepaint();
3091 }
3092 }
3093
NeedsRepaint()3094 bool ScTabView::NeedsRepaint()
3095 {
3096 for (VclPtr<ScGridWindow> & pWin : pGridWin)
3097 {
3098 if (pWin && pWin->IsVisible() && pWin->NeedsRepaint())
3099 return true;
3100 }
3101 return false;
3102 }
3103
3104 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3105