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