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