LibreOffice Module sc (master)  1
select.cxx
Go to the documentation of this file.
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 <tools/urlobj.hxx>
21 #include <sfx2/docfile.hxx>
22 #include <osl/diagnose.h>
23 
24 #include <select.hxx>
25 #include <tabvwsh.hxx>
26 #include <scmod.hxx>
27 #include <document.hxx>
28 #include <transobj.hxx>
29 #include <docsh.hxx>
30 #include <tabprotection.hxx>
31 #include <markdata.hxx>
32 #include <gridwin.hxx>
33 #include <sfx2/lokhelper.hxx>
34 #include <comphelper/lok.hxx>
35 
36 #if defined(_WIN32)
37 #define SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN 65
38 #endif
39 
40 using namespace com::sun::star;
41 
42 static Point aSwitchPos;
43 static bool bDidSwitch = false;
44 
45 // View (Gridwin / keyboard)
47  pViewData( pNewViewData ),
48  pEngine( nullptr ),
49  bAnchor( false ),
50  bStarted( false )
51 {
52  OSL_ENSURE(pViewData, "ViewData==0 at FunctionSet");
53 }
54 
56 {
57  if (pEngine)
58  return pEngine->GetWhich();
59  else
60  return pViewData->GetActivePart();
61 }
62 
63 sal_uLong ScViewFunctionSet::CalcUpdateInterval( const Size& rWinSize, const Point& rEffPos,
64  bool bLeftScroll, bool bTopScroll, bool bRightScroll, bool bBottomScroll )
65 {
66  sal_uLong nUpdateInterval = SELENG_AUTOREPEAT_INTERVAL_MAX;
67  vcl::Window* pWin = pEngine->GetWindow();
68  tools::Rectangle aScrRect = pWin->GetDesktopRectPixel();
69  Point aRootPos = pWin->OutputToAbsoluteScreenPixel(Point(0,0));
70  if (bRightScroll)
71  {
72  double nWinRight = rWinSize.getWidth() + aRootPos.getX();
73  double nMarginRight = aScrRect.GetWidth() - nWinRight;
74  double nHOffset = rEffPos.X() - rWinSize.Width();
75  double nHAccelRate = nHOffset / nMarginRight;
76 
77  if (nHAccelRate > 1.0)
78  nHAccelRate = 1.0;
79 
80  nUpdateInterval = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nHAccelRate));
81  }
82 
83  if (bLeftScroll)
84  {
85  double nMarginLeft = aRootPos.getX();
86  double nHOffset = -rEffPos.X();
87  double nHAccelRate = nHOffset / nMarginLeft;
88 
89  if (nHAccelRate > 1.0)
90  nHAccelRate = 1.0;
91 
92  sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nHAccelRate));
93  if (nUpdateInterval > nTmp)
94  nUpdateInterval = nTmp;
95  }
96 
97  if (bBottomScroll)
98  {
99  double nWinBottom = rWinSize.getHeight() + aRootPos.getY();
100  double nMarginBottom = aScrRect.GetHeight() - nWinBottom;
101  double nVOffset = rEffPos.Y() - rWinSize.Height();
102  double nVAccelRate = nVOffset / nMarginBottom;
103 
104  if (nVAccelRate > 1.0)
105  nVAccelRate = 1.0;
106 
107  sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nVAccelRate));
108  if (nUpdateInterval > nTmp)
109  nUpdateInterval = nTmp;
110  }
111 
112  if (bTopScroll)
113  {
114  double nMarginTop = aRootPos.getY();
115  double nVOffset = -rEffPos.Y();
116  double nVAccelRate = nVOffset / nMarginTop;
117 
118  if (nVAccelRate > 1.0)
119  nVAccelRate = 1.0;
120 
121  sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nVAccelRate));
122  if (nUpdateInterval > nTmp)
123  nUpdateInterval = nTmp;
124  }
125 
126 #ifdef _WIN32
127  ScTabViewShell* pViewShell = pViewData->GetViewShell();
128  bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
129  if (bRefMode && nUpdateInterval < SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN)
130  // Lower the update interval during ref mode, because re-draw can be
131  // expensive on Windows. Making this interval too small would queue up
132  // the scroll/paint requests which would cause semi-infinite
133  // scrolls even after the mouse cursor is released. We don't have
134  // this problem on Linux.
135  nUpdateInterval = SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN;
136 #endif
137  return nUpdateInterval;
138 }
139 
141 {
142  pEngine = pSelEngine;
143 }
144 
145 // Drag & Drop
147 {
148  SCTAB nTab = pViewData->GetTabNo();
149 
150  SCCOL nPosX;
151  SCROW nPosY;
152  if (pEngine)
153  {
154  Point aMPos = pEngine->GetMousePosPixel();
155  pViewData->GetPosFromPixel( aMPos.X(), aMPos.Y(), GetWhich(), nPosX, nPosY );
156  }
157  else
158  {
159  nPosX = pViewData->GetCurX();
160  nPosY = pViewData->GetCurY();
161  }
162 
163  ScModule* pScMod = SC_MOD();
164  bool bRefMode = pScMod->IsFormulaMode();
165  if (bRefMode)
166  return;
167 
168  pViewData->GetView()->FakeButtonUp( GetWhich() ); // ButtonUp is swallowed
169 
170  ScMarkData& rMark = pViewData->GetMarkData();
171  rMark.MarkToSimple();
172  if ( !rMark.IsMarked() || rMark.IsMultiMarked() )
173  return;
174 
176  // bApi = TRUE -> no error messages
177  bool bCopied = pViewData->GetView()->CopyToClip( pClipDoc.get(), false, true );
178  if ( !bCopied )
179  return;
180 
181  sal_Int8 nDragActions = pViewData->GetView()->SelectionEditable() ?
184 
185  ScDocShell* pDocSh = pViewData->GetDocShell();
187  pDocSh->FillTransferableObjectDescriptor( aObjDesc );
188  aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
189  // maSize is set in ScTransferObj ctor
190 
191  rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), aObjDesc );
192 
193  // set position of dragged cell within range
194  ScRange aMarkRange = pTransferObj->GetRange();
195  SCCOL nStartX = aMarkRange.aStart.Col();
196  SCROW nStartY = aMarkRange.aStart.Row();
197  SCCOL nHandleX = (nPosX >= nStartX) ? nPosX - nStartX : 0;
198  SCROW nHandleY = (nPosY >= nStartY) ? nPosY - nStartY : 0;
199  pTransferObj->SetDragHandlePos( nHandleX, nHandleY );
200  pTransferObj->SetSourceCursorPos( pViewData->GetCurX(), pViewData->GetCurY() );
201  pTransferObj->SetVisibleTab( nTab );
202 
203  pTransferObj->SetDragSource( pDocSh, rMark );
204 
205  vcl::Window* pWindow = pViewData->GetActiveWin();
206  if ( pWindow->IsTracking() )
207  pWindow->EndTracking( TrackingEventFlags::Cancel ); // abort selecting
208 
210  pWindow->LocalStartDrag();
211 
212  SC_MOD()->SetDragObject( pTransferObj.get(), nullptr ); // for internal D&D
213  pTransferObj->StartDrag( pWindow, nDragActions );
214 
215  return; // dragging started
216 
217 }
218 
219 // Selection
221 {
222  if (bAnchor) return;
223 
224  bool bRefMode = SC_MOD()->IsFormulaMode();
225  if (bRefMode)
227  else
229 }
230 
232 {
233  bool bRefMode = SC_MOD()->IsFormulaMode();
234  ScTabView* pView = pViewData->GetView();
235  SCTAB nTab = pViewData->GetTabNo();
236 
237  if (bRefMode)
238  {
239  pView->DoneRefMode();
240  aAnchorPos.Set( nPosX, nPosY, nTab );
242  SC_REFTYPE_REF );
243  bStarted = true;
244  }
245  else if (pViewData->IsAnyFillMode())
246  {
247  aAnchorPos.Set( nPosX, nPosY, nTab );
248  bStarted = true;
249  }
250  else
251  {
252  // don't go there and back again
253  if ( bStarted && pView->IsMarking( nPosX, nPosY, nTab ) )
254  {
255  // don't do anything
256  }
257  else
258  {
259  pView->DoneBlockMode( true );
260  aAnchorPos.Set( nPosX, nPosY, nTab );
261  ScMarkData& rMark = pViewData->GetMarkData();
262  if ( rMark.IsMarked() || rMark.IsMultiMarked() )
263  {
265  aAnchorPos.Tab(), true );
266  bStarted = true;
267  }
268  else
269  bStarted = false;
270  }
271  }
272  bAnchor = true;
273 }
274 
276 {
277  bool bRefMode = SC_MOD()->IsFormulaMode();
278  if (bRefMode)
279  pViewData->GetView()->DoneRefMode( true );
280  else
281  pViewData->GetView()->DoneBlockMode( true );
282 
283  bAnchor = false;
284 }
285 
287 {
288  bAnchor = bSet;
289 }
290 
291 void ScViewFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool /* bDontSelectAtCursor */ )
292 {
293  if ( bDidSwitch )
294  {
295  if ( rPointPixel == aSwitchPos )
296  return; // don't scroll in wrong window
297  else
298  bDidSwitch = false;
299  }
300  aSwitchPos = rPointPixel; // only important, if bDidSwitch
301 
302  // treat position 0 as -1, so scrolling is always possible
303  // (with full screen and hidden headers, the top left border may be at 0)
304  // (moved from ScViewData::GetPosFromPixel)
305 
306  Point aEffPos = rPointPixel;
307  if ( aEffPos.X() == 0 )
308  aEffPos.setX( -1 );
309  if ( aEffPos.Y() == 0 )
310  aEffPos.setY( -1 );
311 
312  // Scrolling
313  Size aWinSize = pEngine->GetWindow()->GetOutputSizePixel();
314  bool bLeftScroll = ( aEffPos.X() < 0 );
315  bool bTopScroll = ( aEffPos.Y() < 0 );
316 
317  SCCOL nPosX;
318  SCROW nPosY;
319  pViewData->GetPosFromPixel( aEffPos.X(), aEffPos.Y(), GetWhich(),
320  nPosX, nPosY, true, true ); // with Repair
321 
322  tools::Rectangle aEditArea = pViewData->GetEditArea(GetWhich(), nPosX, nPosY,
323  pEngine->GetWindow(),
324  nullptr, false);
325 
326  bool bFillingSelection = pViewData->IsFillMode() || pViewData->GetFillMode() == ScFillMode::MATRIX;
327  bool bBottomScroll;
328  bool bRightScroll;
329  // for Autofill don't yet assume we want to auto-scroll to the cell under the mouse
330  // because the autofill handle extends into a cells neighbours so initial click is usually
331  // above a neighbour cell
332  if (bFillingSelection)
333  {
334  bBottomScroll = aEffPos.Y() >= aWinSize.Height();
335  bRightScroll = aEffPos.X() >= aWinSize.Width();
336  }
337  else
338  {
339  //in the normal case make the full selected cell visible
340  bBottomScroll = aEditArea.Bottom() >= aWinSize.Height();
341  bRightScroll = aEditArea.Right() >= aWinSize.Width();
342  }
343 
344  bool bScroll = bRightScroll || bBottomScroll || bLeftScroll || bTopScroll;
345 
346  // for Autofill switch in the center of cell thereby don't prevent scrolling to bottom/right
347  if (bFillingSelection)
348  {
349  bool bLeft, bTop;
350  pViewData->GetMouseQuadrant( aEffPos, GetWhich(), nPosX, nPosY, bLeft, bTop );
351  ScDocument& rDoc = pViewData->GetDocument();
352  SCTAB nTab = pViewData->GetTabNo();
353  if ( bLeft && !bRightScroll )
354  do --nPosX; while ( nPosX>=0 && rDoc.ColHidden( nPosX, nTab ) );
355  if ( bTop && !bBottomScroll )
356  {
357  if (--nPosY >= 0)
358  {
359  nPosY = rDoc.LastVisibleRow(0, nPosY, nTab);
360  if (!rDoc.ValidRow(nPosY))
361  nPosY = -1;
362  }
363  }
364  // negative value is allowed
365  }
366 
367  // moved out of fix limit?
368  ScSplitPos eWhich = GetWhich();
369  if ( eWhich == pViewData->GetActivePart() )
370  {
372  if ( aEffPos.X() >= aWinSize.Width() )
373  {
374  if ( eWhich == SC_SPLIT_TOPLEFT )
375  {
377  bScroll = false;
378  bDidSwitch = true;
379  }
380  else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
381  {
383  bScroll = false;
384  bDidSwitch = true;
385  }
386  }
387 
389  if ( aEffPos.Y() >= aWinSize.Height() )
390  {
391  if ( eWhich == SC_SPLIT_TOPLEFT )
392  {
394  bScroll = false;
395  bDidSwitch = true;
396  }
397  else if ( eWhich == SC_SPLIT_TOPRIGHT )
398  {
400  bScroll = false;
401  bDidSwitch = true;
402  }
403  }
404  }
405 
406  if (bScroll)
407  {
408  // Adjust update interval based on how far the mouse pointer is from the edge.
409  sal_uLong nUpdateInterval = CalcUpdateInterval(
410  aWinSize, aEffPos, bLeftScroll, bTopScroll, bRightScroll, bBottomScroll);
411  pEngine->SetUpdateInterval(nUpdateInterval);
412  }
413  else
414  {
415  // Don't forget to reset the interval when not scrolling!
417  }
418 
420  SetCursorAtCell( nPosX, nPosY, bScroll );
421 }
422 
424 {
425  SCCOL startX = pViewData->GetRefStartX();
426  SCROW startY = pViewData->GetRefStartY();
427 
428  SCCOL endX = pViewData->GetRefEndX();
429  SCROW endY = pViewData->GetRefEndY();
430 
431  return nPosX >= startX && nPosX <= endX && nPosY >= startY && nPosY <= endY;
432 }
433 
434 bool ScViewFunctionSet::SetCursorAtCell( SCCOL nPosX, SCROW nPosY, bool bScroll )
435 {
436  ScTabView* pView = pViewData->GetView();
437  SCTAB nTab = pViewData->GetTabNo();
438  ScDocument& rDoc = pViewData->GetDocument();
439 
440  if ( rDoc.IsTabProtected(nTab) )
441  {
442  if (nPosX < 0 || nPosY < 0)
443  return false;
444 
445  const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
446  if (!pProtect)
447  return false;
448 
449  bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
450  bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
451 
452  if ( bSkipProtected && bSkipUnprotected )
453  return false;
454 
455  bool bCellProtected = rDoc.HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HasAttrFlags::Protected);
456  if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) )
457  // Don't select this cell!
458  return false;
459  }
460 
461  ScModule* pScMod = SC_MOD();
462  ScTabViewShell* pViewShell = pViewData->GetViewShell();
463  bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
464 
465  bool bHide = !bRefMode && !pViewData->IsAnyFillMode() &&
466  ( nPosX != pViewData->GetCurX() || nPosY != pViewData->GetCurY() );
467 
468  if (bHide)
469  pView->HideAllCursors();
470 
471  if (bScroll)
472  {
473  if (bRefMode)
474  {
475  ScSplitPos eWhich = GetWhich();
476  pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE, &eWhich );
477  }
478  else
479  pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE );
480  }
481 
482  if (bRefMode)
483  {
484  // if no input is possible from this doc, don't move the reference cursor around
485  if ( !pScMod->IsModalMode(pViewData->GetSfxDocShell()) && (!CheckRefBounds(nPosX, nPosY) || SfxLokHelper::getDeviceFormFactor() != LOKDeviceFormFactor::MOBILE))
486  {
487  if (!bAnchor)
488  {
489  pView->DoneRefMode( true );
490  pView->InitRefMode( nPosX, nPosY, pViewData->GetTabNo(), SC_REFTYPE_REF );
491  }
492 
493  if(SfxLokHelper::getDeviceFormFactor() != LOKDeviceFormFactor::MOBILE)
494  pView->UpdateRef( nPosX, nPosY, pViewData->GetTabNo() );
495 
496  pView->SelectionChanged();
497  }
498  }
499  else if (pViewData->IsFillMode() ||
501  {
502  // If a matrix got touched, switch back to Autofill is possible with Ctrl
503 
504  SCCOL nStartX, nEndX;
505  SCROW nStartY, nEndY; // Block
506  SCTAB nDummy;
507  pViewData->GetSimpleArea( nStartX, nStartY, nDummy, nEndX, nEndY, nDummy );
508 
510  {
511  pView->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
512  CreateAnchor();
513  }
514 
515  ScRange aDelRange;
516  bool bOldDelMark = pViewData->GetDelMark( aDelRange );
517 
518  if ( nPosX+1 >= nStartX && nPosX <= nEndX &&
519  nPosY+1 >= nStartY && nPosY <= nEndY &&
520  ( nPosX != nEndX || nPosY != nEndY ) ) // minimize?
521  {
522  // direction (left or top)
523 
524  tools::Long nSizeX = 0;
525  for (SCCOL i=nPosX+1; i<=nEndX; i++)
526  nSizeX += rDoc.GetColWidth( i, nTab );
527  tools::Long nSizeY = rDoc.GetRowHeight( nPosY+1, nEndY, nTab );
528 
529  SCCOL nDelStartX = nStartX;
530  SCROW nDelStartY = nStartY;
531  if ( nSizeX > nSizeY )
532  nDelStartX = nPosX + 1;
533  else
534  nDelStartY = nPosY + 1;
535  // there is no need to check for zero, because nPosX/Y is also negative
536 
537  if ( nDelStartX < nStartX )
538  nDelStartX = nStartX;
539  if ( nDelStartY < nStartY )
540  nDelStartY = nStartY;
541 
542  // set range
543 
544  pViewData->SetDelMark( ScRange( nDelStartX,nDelStartY,nTab,
545  nEndX,nEndY,nTab ) );
547 
548  pViewData->GetView()->
549  PaintArea( nStartX,nDelStartY, nEndX,nEndY, ScUpdateMode::Marks );
550 
551  nPosX = nEndX; // keep red border around range
552  nPosY = nEndY;
553 
554  // reference the right way up, if it's upside down below
555  if ( nStartX != pViewData->GetRefStartX() || nStartY != pViewData->GetRefStartY() )
556  {
558  pViewData->GetView()->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
559  }
560  }
561  else
562  {
563  if ( bOldDelMark )
564  {
567  }
568 
569  bool bNegX = ( nPosX < nStartX );
570  bool bNegY = ( nPosY < nStartY );
571 
572  tools::Long nSizeX = 0;
573  if ( bNegX )
574  {
575  // in SetCursorAtPoint hidden columns are skipped.
576  // They must be skipped here too, or the result will always be the first hidden column.
577  do ++nPosX; while ( nPosX<nStartX && rDoc.ColHidden(nPosX, nTab) );
578  for (SCCOL i=nPosX; i<nStartX; i++)
579  nSizeX += rDoc.GetColWidth( i, nTab );
580  }
581  else
582  for (SCCOL i=nEndX+1; i<=nPosX; i++)
583  nSizeX += rDoc.GetColWidth( i, nTab );
584 
585  tools::Long nSizeY = 0;
586  if ( bNegY )
587  {
588  // in SetCursorAtPoint hidden rows are skipped.
589  // They must be skipped here too, or the result will always be the first hidden row.
590  if (++nPosY < nStartY)
591  {
592  nPosY = rDoc.FirstVisibleRow(nPosY, nStartY-1, nTab);
593  if (!rDoc.ValidRow(nPosY))
594  nPosY = nStartY;
595  }
596  nSizeY += rDoc.GetRowHeight( nPosY, nStartY-1, nTab );
597  }
598  else
599  nSizeY += rDoc.GetRowHeight( nEndY+1, nPosY, nTab );
600 
601  if ( nSizeX > nSizeY ) // Fill only ever in one direction
602  {
603  nPosY = nEndY;
604  bNegY = false;
605  }
606  else
607  {
608  nPosX = nEndX;
609  bNegX = false;
610  }
611 
612  SCCOL nRefStX = bNegX ? nEndX : nStartX;
613  SCROW nRefStY = bNegY ? nEndY : nStartY;
614  if ( nRefStX != pViewData->GetRefStartX() || nRefStY != pViewData->GetRefStartY() )
615  {
617  pViewData->GetView()->InitRefMode( nRefStX, nRefStY, nTab, SC_REFTYPE_FILL );
618  }
619  }
620 
621  pView->UpdateRef( nPosX, nPosY, nTab );
622  }
623  else if (pViewData->IsAnyFillMode())
624  {
625  ScFillMode nMode = pViewData->GetFillMode();
626  if ( nMode == ScFillMode::EMBED_LT || nMode == ScFillMode::EMBED_RB )
627  {
628  OSL_ENSURE( rDoc.IsEmbedded(), "!rDoc.IsEmbedded()" );
629  ScRange aRange;
630  rDoc.GetEmbedded( aRange);
632  if (pViewData->GetRefType() != eRefMode)
633  {
634  if ( nMode == ScFillMode::EMBED_LT )
635  pView->InitRefMode( aRange.aEnd.Col(), aRange.aEnd.Row(), nTab, eRefMode );
636  else
637  pView->InitRefMode( aRange.aStart.Col(), aRange.aStart.Row(), nTab, eRefMode );
638  CreateAnchor();
639  }
640 
641  pView->UpdateRef( nPosX, nPosY, nTab );
642  }
643  else if ( nMode == ScFillMode::MATRIX )
644  {
645  SCCOL nStartX, nEndX;
646  SCROW nStartY, nEndY; // Block
647  SCTAB nDummy;
648  pViewData->GetSimpleArea( nStartX, nStartY, nDummy, nEndX, nEndY, nDummy );
649 
651  {
652  pView->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
653  CreateAnchor();
654  }
655 
656  if ( nPosX < nStartX ) nPosX = nStartX;
657  if ( nPosY < nStartY ) nPosY = nStartY;
658 
659  pView->UpdateRef( nPosX, nPosY, nTab );
660  }
661  // else new modes
662  }
663  else // regular selection
664  {
665  bool bHideCur = bAnchor && ( nPosX != pViewData->GetCurX() ||
666  nPosY != pViewData->GetCurY() );
667  if (bHideCur)
668  pView->HideAllCursors(); // otherwise twice: Block and SetCursor
669 
670  if (bAnchor)
671  {
672  if (!bStarted)
673  {
674  bool bMove = ( nPosX != aAnchorPos.Col() ||
675  nPosY != aAnchorPos.Row() );
676  if ( bMove || ( pEngine && pEngine->GetMouseEvent().IsShift() ) )
677  {
679  aAnchorPos.Tab(), true );
680  bStarted = true;
681  }
682  }
683  if (bStarted)
684  // If the selection is already started, don't set the cursor.
685  pView->MarkCursor( nPosX, nPosY, nTab, false, false, true );
686  else
687  pView->SetCursor( nPosX, nPosY );
688  }
689  else
690  {
691  ScMarkData& rMark = pViewData->GetMarkData();
692  if (rMark.IsMarked() || rMark.IsMultiMarked())
693  {
694  pView->DoneBlockMode(true);
695  pView->InitBlockMode( nPosX, nPosY, nTab, true );
696  pView->MarkCursor( nPosX, nPosY, nTab );
697 
698  aAnchorPos.Set( nPosX, nPosY, nTab );
699  bStarted = true;
700  }
701  // #i3875# *Hack* When a new cell is Ctrl-clicked with no pre-selected cells,
702  // it highlights that new cell as well as the old cell where the cursor is
703  // positioned prior to the click. A selection mode via Shift-F8 should also
704  // follow the same behavior.
705  else if ( pViewData->IsSelCtrlMouseClick() )
706  {
707  SCCOL nOldX = pViewData->GetCurX();
708  SCROW nOldY = pViewData->GetCurY();
709 
710  pView->InitBlockMode( nOldX, nOldY, nTab, true );
711  pView->MarkCursor( nOldX, nOldY, nTab );
712 
713  if ( nOldX != nPosX || nOldY != nPosY )
714  {
715  pView->DoneBlockMode( true );
716  pView->InitBlockMode( nPosX, nPosY, nTab, true );
717  pView->MarkCursor( nPosX, nPosY, nTab );
718  aAnchorPos.Set( nPosX, nPosY, nTab );
719  }
720 
721  bStarted = true;
722  }
723  pView->SetCursor( nPosX, nPosY );
724  }
725 
726  pViewData->SetRefStart( nPosX, nPosY, nTab );
727  if (bHideCur)
728  pView->ShowAllCursors();
729  }
730 
731  if (bHide)
732  pView->ShowAllCursors();
733 
734  return true;
735 }
736 
737 bool ScViewFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
738 {
739  bool bRefMode = SC_MOD()->IsFormulaMode();
740  if (bRefMode)
741  return false;
742 
743  if (pViewData->IsAnyFillMode())
744  return false;
745 
746  ScMarkData& rMark = pViewData->GetMarkData();
747  if (bAnchor || !rMark.IsMultiMarked())
748  {
749  SCCOL nPosX;
750  SCROW nPosY;
751  pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), GetWhich(), nPosX, nPosY );
752  return pViewData->GetMarkData().IsCellMarked( nPosX, nPosY );
753  }
754 
755  return false;
756 }
757 
758 void ScViewFunctionSet::DeselectAtPoint( const Point& /* rPointPixel */ )
759 {
760  // doesn't exist
761 }
762 
764 {
765  if (pViewData->IsAnyFillMode())
766  return;
767 
768  bool bRefMode = SC_MOD()->IsFormulaMode();
769  if (bRefMode)
770  {
772  }
773  else
774  {
777  }
778 
779  bAnchor = false;
780 }
781 
783  ScSplitPos eSplitPos ) :
784  SelectionEngine( pWindow, &pView->GetFunctionSet() ),
785  eWhich( eSplitPos )
786 {
787  SetSelectionMode( SelectionMode::Multiple );
788  EnableDrag( true );
789 }
790 
791 // column and row headers
793  pViewData( pNewViewData ),
794  bColumn( false ),
795  eWhich( SC_SPLIT_TOPLEFT ),
796  bAnchor( false ),
797  nCursorPos( 0 )
798 {
799  OSL_ENSURE(pViewData, "ViewData==0 at FunctionSet");
800 }
801 
803 {
804  bColumn = bSet;
805 }
806 
808 {
809  eWhich = eNew;
810 }
811 
813 {
814  // doesn't exist
815 }
816 
818 {
819  if (bAnchor)
820  return;
821 
822  ScTabView* pView = pViewData->GetView();
823  pView->DoneBlockMode( true );
824  if (bColumn)
825  {
826  pView->InitBlockMode( static_cast<SCCOL>(nCursorPos), 0, pViewData->GetTabNo(), true, true );
827  pView->MarkCursor( static_cast<SCCOL>(nCursorPos), pViewData->MaxRow(), pViewData->GetTabNo() );
828  }
829  else
830  {
831  pView->InitBlockMode( 0, nCursorPos, pViewData->GetTabNo(), true, false, true );
833  }
834  bAnchor = true;
835 }
836 
838 {
839  pViewData->GetView()->DoneBlockMode( true );
840  bAnchor = false;
841 }
842 
843 void ScHeaderFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool /* bDontSelectAtCursor */ )
844 {
845  if ( bDidSwitch )
846  {
847  // next valid position has to be originated from another window
848  if ( rPointPixel == aSwitchPos )
849  return; // don't scroll in the wrong window
850  else
851  bDidSwitch = false;
852  }
853 
854  // Scrolling
856  bool bScroll;
857  if (bColumn)
858  bScroll = ( rPointPixel.X() < 0 || rPointPixel.X() >= aWinSize.Width() );
859  else
860  bScroll = ( rPointPixel.Y() < 0 || rPointPixel.Y() >= aWinSize.Height() );
861 
862  // moved out of fix limit?
863  bool bSwitched = false;
864  if ( bColumn )
865  {
867  {
868  if ( rPointPixel.X() > aWinSize.Width() )
869  {
870  if ( eWhich == SC_SPLIT_TOPLEFT )
871  {
873  bSwitched = true;
874  }
875  else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
876  {
878  bSwitched = true;
879  }
880  }
881  }
882  }
883  else // column headers
884  {
886  {
887  if ( rPointPixel.Y() > aWinSize.Height() )
888  {
889  if ( eWhich == SC_SPLIT_TOPLEFT )
890  {
892  bSwitched = true;
893  }
894  else if ( eWhich == SC_SPLIT_TOPRIGHT )
895  {
897  bSwitched = true;
898  }
899  }
900  }
901  }
902  if (bSwitched)
903  {
904  aSwitchPos = rPointPixel;
905  bDidSwitch = true;
906  return; // do not crunch with wrong positions
907  }
908 
909  SCCOL nPosX;
910  SCROW nPosY;
911  pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), pViewData->GetActivePart(),
912  nPosX, nPosY, false );
913  if (bColumn)
914  {
915  nCursorPos = static_cast<SCCOLROW>(nPosX);
917  }
918  else
919  {
920  nCursorPos = static_cast<SCCOLROW>(nPosY);
922  }
923 
924  ScTabView* pView = pViewData->GetView();
925  bool bHide = pViewData->GetCurX() != nPosX ||
926  pViewData->GetCurY() != nPosY;
927  if (bHide)
928  pView->HideAllCursors();
929 
930  if (bScroll)
931  pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE );
932  pView->SetCursor( nPosX, nPosY );
933 
934  if ( !bAnchor || !pView->IsBlockMode() )
935  {
936  pView->DoneBlockMode( true );
938  pView->InitBlockMode( nPosX, nPosY, pViewData->GetTabNo(), true, bColumn, !bColumn );
939 
940  bAnchor = true;
941  }
942 
943  pView->MarkCursor( nPosX, nPosY, pViewData->GetTabNo(), bColumn, !bColumn );
944 
945  // SelectionChanged inside of HideCursor because of UpdateAutoFillMark
946  pView->SelectionChanged();
947 
948  if (bHide)
949  pView->ShowAllCursors();
950 }
951 
952 bool ScHeaderFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
953 {
954  SCCOL nPosX;
955  SCROW nPosY;
956  pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), pViewData->GetActivePart(),
957  nPosX, nPosY, false );
958 
959  ScMarkData& rMark = pViewData->GetMarkData();
960  if (bColumn)
961  return rMark.IsColumnMarked( nPosX );
962  else
963  return rMark.IsRowMarked( nPosY );
964 }
965 
966 void ScHeaderFunctionSet::DeselectAtPoint( const Point& /* rPointPixel */ )
967 {
968 }
969 
971 {
973  bAnchor = false;
974 }
975 
977  SelectionEngine( pWindow, pFuncSet )
978 {
979  SetSelectionMode( SelectionMode::Multiple );
980  EnableDrag( false );
981 }
982 
983 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsAnyFillMode() const
Definition: viewdata.hxx:514
ScMarkData & GetMarkData()
Definition: viewdata.cxx:3135
virtual void BeginDrag() override
Definition: select.cxx:146
void InitRefMode(SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, ScRefType eType)
Definition: tabview4.cxx:309
void MarkToSimple()
Definition: markdata.cxx:222
virtual void SetCursorAtPoint(const Point &rPointPixel, bool bDontSelectAtCursor=false) override
Definition: select.cxx:291
void SetDelMark(const ScRange &rRange)
Definition: viewdata.hxx:546
ScAddress aStart
Definition: address.hxx:497
ScDocShell * GetDocShell() const
Definition: viewdata.hxx:354
SC_DLLPUBLIC bool IsTabProtected(SCTAB nTab) const
Definition: documen3.cxx:1913
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:42
ScRefType GetRefType() const
Definition: viewdata.hxx:531
SCROW GetRefEndY() const
Definition: viewdata.hxx:536
virtual void DeselectAll() override
Definition: select.cxx:763
ScVSplitPos WhichV(ScSplitPos ePos)
Definition: viewdata.hxx:728
constexpr sal_uInt16 KEY_MOD1
SC_DLLPUBLIC bool CopyToClip(ScDocument *pClipDoc, bool bCut, bool bApi=false, bool bIncludeObjects=false, bool bStopEdit=true)
Definition: viewfun3.cxx:168
void SetSelectionMode(SelectionMode eMode)
ScViewSelectionEngine(vcl::Window *pWindow, ScTabView *pView, ScSplitPos eSplitPos)
Definition: select.cxx:782
SCROW Row() const
Definition: address.hxx:274
#define DND_ACTION_COPY
void MarkToMulti()
Definition: markdata.cxx:209
SCCOL MaxCol() const
Definition: viewdata.hxx:396
signed char sal_Int8
bool GetDelMark(ScRange &rRange) const
Definition: viewdata.hxx:549
sheet protection state container
void DoneRefMode(bool bContinue=false)
Definition: tabview4.cxx:159
SCROW GetRefStartY() const
Definition: viewdata.hxx:533
sal_uIntPtr sal_uLong
long Long
ScHeaderFunctionSet(ScViewData *pNewViewData)
Definition: select.cxx:792
SCROW GetCurY() const
Definition: viewdata.hxx:402
ScHSplitPos WhichH(ScSplitPos ePos)
Definition: viewdata.hxx:722
static LOKDeviceFormFactor getDeviceFormFactor()
ScViewSelectionEngine * pEngine
Definition: select.hxx:44
virtual bool IsSelectionAtPoint(const Point &rPointPixel) override
Definition: select.cxx:737
sal_uLong CalcUpdateInterval(const Size &rWinSize, const Point &rEffPos, bool bLeftScroll, bool bTopScroll, bool bRightScroll, bool bBottomScroll)
Definition: select.cxx:63
bool IsShift() const
#define DND_ACTION_COPYMOVE
SCTAB GetTabNo() const
Definition: viewdata.hxx:395
SC_DLLPUBLIC SCROW FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
Definition: document.cxx:4526
ScSplitPos GetActivePart() const
Definition: viewdata.hxx:398
SC_DLLPUBLIC SCROW LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
Definition: document.cxx:4534
ScDocument & GetDocument() const
Definition: viewdata.hxx:380
tools::Rectangle GetDesktopRectPixel() const
void SetSelectionEngine(ScViewSelectionEngine *pSelEngine)
Definition: select.cxx:140
void GetEmbedded(ScRange &rRange) const
Definition: documen3.cxx:1711
void FillTransferableObjectDescriptor(TransferableObjectDescriptor &rDesc) const
void EnableDrag(bool bOn)
SC_DLLPUBLIC void SetCursor(SCCOL nPosX, SCROW nPosY, bool bNew=false)
Definition: tabview3.cxx:363
SCCOL GetPosX(ScHSplitPos eWhich, SCTAB nForTab=-1) const
Definition: viewdata.cxx:1402
SC_DLLPUBLIC bool HasAttrib(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, HasAttrFlags nMask) const
Definition: document.cxx:5265
bool IsTracking() const
SC_DLLPUBLIC sal_uInt16 GetRowHeight(SCROW nRow, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4212
ScSplitPos
Definition: viewdata.hxx:44
void SetColumn(bool bSet)
Definition: select.cxx:802
bool IsCellMarked(SCCOL nCol, SCROW nRow, bool bNoSimple=false) const
Definition: markdata.cxx:270
constexpr tools::Long Width() const
ScHeaderSelectionEngine(vcl::Window *pWindow, ScHeaderFunctionSet *pFuncSet)
Definition: select.cxx:976
bool isOptionEnabled(Option eOption) const
void SetUpdateInterval(sal_uLong nInterval)
bool SelectionEditable(bool *pOnlyNotBecauseOfMatrix=nullptr)
Definition: viewfunc.cxx:260
bool IsFormulaMode()
Definition: scmod.cxx:1678
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:23
#define SELENG_AUTOREPEAT_INTERVAL
bool IsMultiMarked() const
Definition: markdata.hxx:81
void EndTracking(TrackingEventFlags nFlags=TrackingEventFlags::NONE)
const Point & GetMousePosPixel() const
void UpdateShrinkOverlay()
Definition: tabview2.cxx:1028
constexpr tools::Long GetWidth() const
void UpdateInputHandler(bool bForce=false, bool bStopEditing=true)
Definition: tabvwsha.cxx:656
SCTAB Tab() const
Definition: address.hxx:283
void ActivatePart(ScSplitPos eWhich)
Definition: tabview3.cxx:2884
void DoneBlockMode(bool bContinue=false)
Definition: tabview2.cxx:409
constexpr tools::Long getHeight() const
SCROW GetPosY(ScVSplitPos eWhich, SCTAB nForTab=-1) const
Definition: viewdata.cxx:1416
ScSplitMode GetHSplitMode() const
Definition: viewdata.hxx:416
bool IsBlockMode() const
Definition: tabview2.cxx:444
bool IsFillMode() const
Definition: viewdata.hxx:515
void SelectionChanged(bool bFromPaste=false)
Definition: tabview3.cxx:532
void SetRefStart(SCCOL nNewX, SCROW nNewY, SCTAB nNewZ)
Definition: viewdata.cxx:4126
bool IsRowMarked(SCROW nRow) const
Definition: markdata.cxx:303
ScTabViewShell * GetViewShell() const
Definition: viewdata.hxx:357
void ResetDelMark()
Definition: viewdata.hxx:545
SCROW MaxRow() const
Definition: viewdata.hxx:397
SC_DLLPUBLIC bool ColHidden(SCCOL nCol, SCTAB nTab, SCCOL *pFirstCol=nullptr, SCCOL *pLastCol=nullptr) const
Definition: document.cxx:4496
void SetWhich(ScSplitPos eNew)
Definition: select.cxx:807
bool IsModalMode(SfxObjectShell *pDocSh=nullptr)
Definition: scmod.cxx:1594
bool IsMarked() const
Definition: markdata.hxx:80
virtual bool IsSelectionAtPoint(const Point &rPointPixel) override
Definition: select.cxx:952
int i
bool IsColumnMarked(SCCOL nCol) const
Definition: markdata.cxx:287
virtual void DeselectAll() override
Definition: select.cxx:970
tools::Rectangle GetEditArea(ScSplitPos eWhich, SCCOL nPosX, SCROW nPosY, vcl::Window *pWin, const ScPatternAttr *pPattern, bool bForceToTop, bool bInPrintTwips=false)
Definition: viewdata.cxx:1509
void Set(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: address.hxx:403
std::unique_ptr< ScDocument, o3tl::default_delete< ScDocument > > ScDocumentUniquePtr
Definition: document.hxx:2711
void GetPosFromPixel(tools::Long nClickX, tools::Long nClickY, ScSplitPos eWhich, SCCOL &rPosX, SCROW &rPosY, bool bTestMerge=true, bool bRepair=false, SCTAB nForTab=-1)
Definition: viewdata.cxx:2774
ScViewData * pViewData
Definition: select.hxx:43
sal_Int16 SCCOL
Definition: types.hxx:21
virtual void CreateAnchor() override
Definition: select.cxx:817
#define SC_MOD()
Definition: scmod.hxx:249
void FakeButtonUp(ScSplitPos eWhich)
Definition: tabview3.cxx:214
static bool bDidSwitch
Member.
Definition: select.cxx:43
constexpr tools::Long Right() const
SCCOLROW nCursorPos
Definition: select.hxx:83
ScMarkType GetSimpleArea(SCCOL &rStartCol, SCROW &rStartRow, SCTAB &rStartTab, SCCOL &rEndCol, SCROW &rEndRow, SCTAB &rEndTab) const
Definition: viewdata.cxx:1181
ScSplitPos eWhich
Definition: select.hxx:80
virtual void BeginDrag() override
Definition: select.cxx:812
bool CheckRefBounds(SCCOL nPosX, SCROW nPosY)
Definition: select.cxx:423
ScGridWindow * GetActiveWin()
Definition: viewdata.cxx:3151
virtual void SetCursorAtPoint(const Point &rPointPixel, bool bDontSelectAtCursor=false) override
Definition: select.cxx:843
vcl::Window * GetWindow() const
PaintArea
ScSplitPos GetWhich() const
Definition: select.hxx:36
#define DND_ACTION_LINK
SCCOL GetRefEndX() const
Definition: viewdata.hxx:535
Point OutputToAbsoluteScreenPixel(const Point &rPos) const
SCCOL Col() const
Definition: address.hxx:279
ScSplitPos GetWhich() const
Definition: select.cxx:55
ScDBFunc * GetView() const
Definition: viewdata.cxx:863
SCCOL GetRefStartX() const
Definition: viewdata.hxx:532
static Point aSwitchPos
Definition: select.cxx:42
constexpr tools::Long Bottom() const
void LocalStartDrag()
const MouseEvent & GetMouseEvent() const
void GetMouseQuadrant(const Point &rClickPos, ScSplitPos eWhich, SCCOL nPosX, SCROW nPosY, bool &rLeft, bool &rTop)
Definition: viewdata.cxx:2889
sal_Int32 SCROW
Definition: types.hxx:17
ScAddress aAnchorPos
Definition: select.hxx:48
bool ValidRow(SCROW nRow) const
Definition: document.hxx:901
void HideAllCursors()
Definition: tabview3.cxx:220
ScFillMode GetFillMode() const
Definition: viewdata.hxx:516
#define SELENG_AUTOREPEAT_INTERVAL_MAX
constexpr tools::Long Height() const
sal_uInt16 nScFillModeMouseModifier
Definition: global.cxx:117
void SetAnchor(SCCOL nPosX, SCROW nPosY)
Definition: select.cxx:231
virtual void DestroyAnchor() override
Definition: select.cxx:275
bool IsEmbedded() const
Definition: document.hxx:953
bool IsSelCtrlMouseClick() const
Definition: viewdata.hxx:668
ScRefType
Mouse mode to select areas.
Definition: viewdata.hxx:55
const INetURLObject & GetURLObject() const
virtual void DestroyAnchor() override
Definition: select.cxx:837
ScViewData * pViewData
Definition: select.hxx:78
void AlignToCursor(SCCOL nCurX, SCROW nCurY, ScFollowMode eMode, const ScSplitPos *pWhich=nullptr)
Definition: tabview3.cxx:920
Size GetOutputSizePixel() const
virtual void DeselectAtPoint(const Point &rPointPixel) override
Definition: select.cxx:966
OUString GetURLNoPass(DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
SfxObjectShell * GetSfxDocShell() const
Definition: viewdata.hxx:358
bool IsRefInputMode() const
Definition: tabvwsha.cxx:606
constexpr tools::Long getWidth() const
virtual void DeselectAtPoint(const Point &rPointPixel) override
Definition: select.cxx:758
void UpdateRef(SCCOL nCurX, SCROW nCurY, SCTAB nCurZ)
Definition: tabview4.cxx:186
virtual void CreateAnchor() override
Definition: select.cxx:220
SC_DLLPUBLIC sal_uInt16 GetColWidth(SCCOL nCol, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4171
void MarkCursor(SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, bool bCols=false, bool bRows=false, bool bCellSelection=false)
Definition: tabview2.cxx:449
void SetAnchorFlag(bool bSet)
Definition: select.cxx:286
ScFillMode
Definition: viewdata.hxx:33
bool SetCursorAtCell(SCCOL nPosX, SCROW nPosY, bool bScroll)
Definition: select.cxx:434
ScSplitMode GetVSplitMode() const
Definition: viewdata.hxx:417
void InitBlockMode(SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, bool bTestNeg=false, bool bCols=false, bool bRows=false, bool bForceNeg=false)
Definition: tabview2.cxx:353
bool IsMarking(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: tabview2.cxx:324
sal_Int16 SCTAB
Definition: types.hxx:22
ScViewFunctionSet(ScViewData *pNewViewData)
Definition: select.cxx:46
void ResetOldCursor()
Definition: viewdata.cxx:1397
void ShowAllCursors()
Definition: tabview3.cxx:234
SCCOL GetCurX() const
Definition: viewdata.hxx:401
bool m_bDetectedRangeSegmentation false
constexpr tools::Long GetHeight() const
SC_DLLPUBLIC const ScTableProtection * GetTabProtection(SCTAB nTab) const
Definition: documen3.cxx:1922
SfxMedium * GetMedium() const