1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/urlobj.hxx>
21 #include <sfx2/docfile.hxx>
22 #include <osl/diagnose.h>
25 #include <tabvwsh.hxx>
27 #include <document.hxx>
28 #include <transobj.hxx>
30 #include <tabprotection.hxx>
31 #include <markdata.hxx>
32 #include <gridwin.hxx>
33 #include <sfx2/lokhelper.hxx>
34 #include <comphelper/lok.hxx>
37 #define SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN 65
40 using namespace com::sun::star
;
42 static Point aSwitchPos
; //! Member
43 static bool bDidSwitch
= false;
45 // View (Gridwin / keyboard)
46 ScViewFunctionSet::ScViewFunctionSet( ScViewData
* pNewViewData
) :
47 m_pViewData( pNewViewData
),
52 OSL_ENSURE(m_pViewData
, "ViewData==0 at FunctionSet");
55 ScSplitPos
ScViewFunctionSet::GetWhich() const
58 return m_pEngine
->GetWhich();
60 return m_pViewData
->GetActivePart();
63 sal_uInt64
ScViewFunctionSet::CalcUpdateInterval( const Size
& rWinSize
, const Point
& rEffPos
,
64 bool bLeftScroll
, bool bTopScroll
, bool bRightScroll
, bool bBottomScroll
)
66 sal_uInt64 nUpdateInterval
= SELENG_AUTOREPEAT_INTERVAL_MAX
;
67 vcl::Window
* pWin
= m_pEngine
->GetWindow();
68 AbsoluteScreenPixelRectangle aScrRect
= pWin
->GetDesktopRectPixel();
69 AbsoluteScreenPixelPoint aRootPos
= pWin
->OutputToAbsoluteScreenPixel(Point(0,0));
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
;
77 if (nHAccelRate
> 1.0)
80 nUpdateInterval
= SELENG_AUTOREPEAT_INTERVAL_MAX
*(1.0 - nHAccelRate
);
85 double nMarginLeft
= aRootPos
.getX();
86 double nHOffset
= -rEffPos
.X();
87 double nHAccelRate
= nHOffset
/ nMarginLeft
;
89 if (nHAccelRate
> 1.0)
92 sal_uLong nTmp
= static_cast<sal_uLong
>(SELENG_AUTOREPEAT_INTERVAL_MAX
*(1.0 - nHAccelRate
));
93 if (nUpdateInterval
> nTmp
)
94 nUpdateInterval
= nTmp
;
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
;
104 if (nVAccelRate
> 1.0)
107 sal_uInt64 nTmp
= SELENG_AUTOREPEAT_INTERVAL_MAX
*(1.0 - nVAccelRate
);
108 if (nUpdateInterval
> nTmp
)
109 nUpdateInterval
= nTmp
;
114 double nMarginTop
= aRootPos
.getY();
115 double nVOffset
= -rEffPos
.Y();
116 double nVAccelRate
= nVOffset
/ nMarginTop
;
118 if (nVAccelRate
> 1.0)
121 sal_uInt64 nTmp
= SELENG_AUTOREPEAT_INTERVAL_MAX
*(1.0 - nVAccelRate
);
122 if (nUpdateInterval
> nTmp
)
123 nUpdateInterval
= nTmp
;
127 ScTabViewShell
* pViewShell
= m_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
;
137 return nUpdateInterval
;
140 void ScViewFunctionSet::SetSelectionEngine( ScViewSelectionEngine
* pSelEngine
)
142 m_pEngine
= pSelEngine
;
146 void ScViewFunctionSet::BeginDrag()
148 if (m_pViewData
->GetViewShell()->IsLokReadOnlyView())
151 SCTAB nTab
= m_pViewData
->GetTabNo();
157 Point aMPos
= m_pEngine
->GetMousePosPixel();
158 m_pViewData
->GetPosFromPixel( aMPos
.X(), aMPos
.Y(), GetWhich(), nPosX
, nPosY
);
162 nPosX
= m_pViewData
->GetCurX();
163 nPosY
= m_pViewData
->GetCurY();
166 ScModule
* pScMod
= ScModule::get();
167 bool bRefMode
= pScMod
->IsFormulaMode();
171 m_pViewData
->GetView()->FakeButtonUp( GetWhich() ); // ButtonUp is swallowed
173 ScMarkData
& rMark
= m_pViewData
->GetMarkData();
174 rMark
.MarkToSimple();
175 if ( !rMark
.IsMarked() || rMark
.IsMultiMarked() )
178 ScDocumentUniquePtr
pClipDoc(new ScDocument( SCDOCMODE_CLIP
));
179 // bApi = TRUE -> no error messages
180 bool bCopied
= m_pViewData
->GetView()->CopyToClip( pClipDoc
.get(), false, true );
184 sal_Int8 nDragActions
= m_pViewData
->GetView()->SelectionEditable() ?
185 ( DND_ACTION_COPYMOVE
| DND_ACTION_LINK
) :
186 ( DND_ACTION_COPY
| DND_ACTION_LINK
);
188 ScDocShell
* pDocSh
= m_pViewData
->GetDocShell();
189 TransferableObjectDescriptor aObjDesc
;
190 pDocSh
->FillTransferableObjectDescriptor( aObjDesc
);
191 aObjDesc
.maDisplayName
= pDocSh
->GetMedium()->GetURLObject().GetURLNoPass();
192 // maSize is set in ScTransferObj ctor
194 rtl::Reference
<ScTransferObj
> pTransferObj
= new ScTransferObj( std::move(pClipDoc
), std::move(aObjDesc
) );
196 // set position of dragged cell within range
197 ScRange aMarkRange
= pTransferObj
->GetRange();
198 SCCOL nStartX
= aMarkRange
.aStart
.Col();
199 SCROW nStartY
= aMarkRange
.aStart
.Row();
200 SCCOL nHandleX
= (nPosX
>= nStartX
) ? nPosX
- nStartX
: 0;
201 SCROW nHandleY
= (nPosY
>= nStartY
) ? nPosY
- nStartY
: 0;
202 pTransferObj
->SetDragHandlePos( nHandleX
, nHandleY
);
203 pTransferObj
->SetSourceCursorPos( m_pViewData
->GetCurX(), m_pViewData
->GetCurY() );
204 pTransferObj
->SetVisibleTab( nTab
);
206 pTransferObj
->SetDragSource( pDocSh
, rMark
);
208 vcl::Window
* pWindow
= m_pViewData
->GetActiveWin();
209 if ( pWindow
->IsTracking() )
210 pWindow
->EndTracking( TrackingEventFlags::Cancel
); // abort selecting
212 if (comphelper::LibreOfficeKit::isActive())
213 pWindow
->LocalStartDrag();
215 pScMod
->SetDragObject( pTransferObj
.get(), nullptr ); // for internal D&D
216 pTransferObj
->StartDrag( pWindow
, nDragActions
);
218 return; // dragging started
223 void ScViewFunctionSet::CreateAnchor()
225 if (m_bAnchor
) return;
227 bool bRefMode
= ScModule::get()->IsFormulaMode();
229 SetAnchor( m_pViewData
->GetRefStartX(), m_pViewData
->GetRefStartY() );
231 SetAnchor( m_pViewData
->GetCurX(), m_pViewData
->GetCurY() );
234 void ScViewFunctionSet::SetAnchor( SCCOL nPosX
, SCROW nPosY
)
236 bool bRefMode
= ScModule::get()->IsFormulaMode();
237 ScTabView
* pView
= m_pViewData
->GetView();
238 SCTAB nTab
= m_pViewData
->GetTabNo();
242 pView
->DoneRefMode();
243 m_aAnchorPos
.Set( nPosX
, nPosY
, nTab
);
244 pView
->InitRefMode( m_aAnchorPos
.Col(), m_aAnchorPos
.Row(), m_aAnchorPos
.Tab(),
248 else if (m_pViewData
->IsAnyFillMode())
250 m_aAnchorPos
.Set( nPosX
, nPosY
, nTab
);
255 // don't go there and back again
256 if ( m_bStarted
&& pView
->IsMarking( nPosX
, nPosY
, nTab
) )
262 pView
->DoneBlockMode( true );
263 m_aAnchorPos
.Set( nPosX
, nPosY
, nTab
);
264 ScMarkData
& rMark
= m_pViewData
->GetMarkData();
265 if ( rMark
.IsMarked() || rMark
.IsMultiMarked() )
267 pView
->InitBlockMode( m_aAnchorPos
.Col(), m_aAnchorPos
.Row(),
268 m_aAnchorPos
.Tab(), true );
278 void ScViewFunctionSet::DestroyAnchor()
280 if (m_pViewData
->IsAnyFillMode())
283 bool bRefMode
= ScModule::get()->IsFormulaMode();
285 m_pViewData
->GetView()->DoneRefMode( true );
287 m_pViewData
->GetView()->DoneBlockMode( true );
292 void ScViewFunctionSet::SetAnchorFlag( bool bSet
)
297 void ScViewFunctionSet::SetCursorAtPoint( const Point
& rPointPixel
, bool /* bDontSelectAtCursor */ )
301 if ( rPointPixel
== aSwitchPos
)
302 return; // don't scroll in wrong window
306 aSwitchPos
= rPointPixel
; // only important, if bDidSwitch
308 // treat position 0 as -1, so scrolling is always possible
309 // (with full screen and hidden headers, the top left border may be at 0)
310 // (moved from ScViewData::GetPosFromPixel)
312 Point aEffPos
= rPointPixel
;
313 if ( aEffPos
.X() == 0 )
315 if ( aEffPos
.Y() == 0 )
319 Size aWinSize
= m_pEngine
->GetWindow()->GetOutputSizePixel();
320 bool bLeftScroll
= ( aEffPos
.X() < 0 );
321 bool bTopScroll
= ( aEffPos
.Y() < 0 );
325 m_pViewData
->GetPosFromPixel( aEffPos
.X(), aEffPos
.Y(), GetWhich(),
326 nPosX
, nPosY
, true, true ); // with Repair
328 tools::Rectangle aEditArea
= m_pViewData
->GetEditArea(GetWhich(), nPosX
, nPosY
,
329 m_pEngine
->GetWindow(),
332 bool bFillingSelection
= m_pViewData
->IsFillMode() || m_pViewData
->GetFillMode() == ScFillMode::MATRIX
;
335 // for Autofill don't yet assume we want to auto-scroll to the cell under the mouse
336 // because the autofill handle extends into a cells neighbours so initial click is usually
337 // above a neighbour cell
338 if (bFillingSelection
)
340 bBottomScroll
= aEffPos
.Y() >= aWinSize
.Height();
341 bRightScroll
= aEffPos
.X() >= aWinSize
.Width();
345 //in the normal case make the full selected cell visible
346 bBottomScroll
= aEditArea
.Bottom() >= aWinSize
.Height();
347 bRightScroll
= aEditArea
.Right() >= aWinSize
.Width();
350 bool bScroll
= bRightScroll
|| bBottomScroll
|| bLeftScroll
|| bTopScroll
;
352 // for Autofill switch in the center of cell thereby don't prevent scrolling to bottom/right
353 if (bFillingSelection
)
356 m_pViewData
->GetMouseQuadrant( aEffPos
, GetWhich(), nPosX
, nPosY
, bLeft
, bTop
);
357 ScDocument
& rDoc
= m_pViewData
->GetDocument();
358 SCTAB nTab
= m_pViewData
->GetTabNo();
359 if ( bLeft
&& !bRightScroll
)
360 do --nPosX
; while ( nPosX
>=0 && rDoc
.ColHidden( nPosX
, nTab
) );
361 if ( bTop
&& !bBottomScroll
)
365 nPosY
= rDoc
.LastVisibleRow(0, nPosY
, nTab
);
366 if (!rDoc
.ValidRow(nPosY
))
370 // negative value is allowed
373 // moved out of fix limit?
374 ScSplitPos eWhich
= GetWhich();
375 if ( eWhich
== m_pViewData
->GetActivePart() )
377 if ( m_pViewData
->GetHSplitMode() == SC_SPLIT_FIX
)
378 if ( aEffPos
.X() >= aWinSize
.Width() )
380 if ( eWhich
== SC_SPLIT_TOPLEFT
)
382 m_pViewData
->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT
);
386 else if ( eWhich
== SC_SPLIT_BOTTOMLEFT
)
388 m_pViewData
->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT
);
394 if ( m_pViewData
->GetVSplitMode() == SC_SPLIT_FIX
)
395 if ( aEffPos
.Y() >= aWinSize
.Height() )
397 if ( eWhich
== SC_SPLIT_TOPLEFT
)
399 m_pViewData
->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT
);
403 else if ( eWhich
== SC_SPLIT_TOPRIGHT
)
405 m_pViewData
->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT
);
414 // Adjust update interval based on how far the mouse pointer is from the edge.
415 sal_uInt64 nUpdateInterval
= CalcUpdateInterval(
416 aWinSize
, aEffPos
, bLeftScroll
, bTopScroll
, bRightScroll
, bBottomScroll
);
417 m_pEngine
->SetUpdateInterval(nUpdateInterval
);
421 // Don't forget to reset the interval when not scrolling!
422 m_pEngine
->SetUpdateInterval(SELENG_AUTOREPEAT_INTERVAL
);
425 m_pViewData
->ResetOldCursor();
426 SetCursorAtCell( nPosX
, nPosY
, bScroll
);
429 bool ScViewFunctionSet::CheckRefBounds(SCCOL nPosX
, SCROW nPosY
)
431 SCCOL startX
= m_pViewData
->GetRefStartX();
432 SCROW startY
= m_pViewData
->GetRefStartY();
434 SCCOL endX
= m_pViewData
->GetRefEndX();
435 SCROW endY
= m_pViewData
->GetRefEndY();
437 return nPosX
>= startX
&& nPosX
<= endX
&& nPosY
>= startY
&& nPosY
<= endY
;
440 bool ScViewFunctionSet::SetCursorAtCell( SCCOL nPosX
, SCROW nPosY
, bool bScroll
)
442 ScTabView
* pView
= m_pViewData
->GetView();
443 SCTAB nTab
= m_pViewData
->GetTabNo();
444 ScDocument
& rDoc
= m_pViewData
->GetDocument();
446 if ( rDoc
.IsTabProtected(nTab
) )
448 if (nPosX
< 0 || nPosY
< 0)
451 const ScTableProtection
* pProtect
= rDoc
.GetTabProtection(nTab
);
455 bool bSkipProtected
= !pProtect
->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS
);
456 bool bSkipUnprotected
= !pProtect
->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS
);
458 if ( bSkipProtected
&& bSkipUnprotected
)
461 bool bCellProtected
= rDoc
.HasAttrib(nPosX
, nPosY
, nTab
, nPosX
, nPosY
, nTab
, HasAttrFlags::Protected
);
462 if ( (bCellProtected
&& bSkipProtected
) || (!bCellProtected
&& bSkipUnprotected
) )
463 // Don't select this cell!
467 ScTabViewShell
* pViewShell
= m_pViewData
->GetViewShell();
468 bool bRefMode
= pViewShell
&& pViewShell
->IsRefInputMode();
470 bool bHide
= !bRefMode
&& !m_pViewData
->IsAnyFillMode() &&
471 ( nPosX
!= m_pViewData
->GetCurX() || nPosY
!= m_pViewData
->GetCurY() );
474 pView
->HideAllCursors();
480 ScSplitPos eWhich
= GetWhich();
481 pView
->AlignToCursor( nPosX
, nPosY
, SC_FOLLOW_LINE
, &eWhich
);
484 pView
->AlignToCursor( nPosX
, nPosY
, SC_FOLLOW_LINE
);
489 // if no input is possible from this doc, don't move the reference cursor around
490 if ( !ScModule::get()->IsModalMode(m_pViewData
->GetSfxDocShell()) && (!CheckRefBounds(nPosX
, nPosY
) || SfxLokHelper::getDeviceFormFactor() != LOKDeviceFormFactor::MOBILE
))
494 pView
->DoneRefMode( true );
495 pView
->InitRefMode( nPosX
, nPosY
, m_pViewData
->GetTabNo(), SC_REFTYPE_REF
);
498 if(SfxLokHelper::getDeviceFormFactor() != LOKDeviceFormFactor::MOBILE
)
499 pView
->UpdateRef( nPosX
, nPosY
, m_pViewData
->GetTabNo() );
501 pView
->SelectionChanged();
504 else if (m_pViewData
->IsFillMode() ||
505 (m_pViewData
->GetFillMode() == ScFillMode::MATRIX
&& (nScFillModeMouseModifier
& KEY_MOD1
) ))
507 // If a matrix got touched, switch back to Autofill is possible with Ctrl
509 SCCOL nStartX
, nEndX
;
510 SCROW nStartY
, nEndY
; // Block
512 m_pViewData
->GetSimpleArea( nStartX
, nStartY
, nDummy
, nEndX
, nEndY
, nDummy
);
514 if (m_pViewData
->GetRefType() != SC_REFTYPE_FILL
)
516 pView
->InitRefMode( nStartX
, nStartY
, nTab
, SC_REFTYPE_FILL
);
521 bool bOldDelMark
= m_pViewData
->GetDelMark( aDelRange
);
523 if ( nPosX
+1 >= nStartX
&& nPosX
<= nEndX
&&
524 nPosY
+1 >= nStartY
&& nPosY
<= nEndY
&&
525 ( nPosX
!= nEndX
|| nPosY
!= nEndY
) ) // minimize?
527 // direction (left or top)
529 tools::Long nSizeX
= 0;
530 for (SCCOL i
=nPosX
+1; i
<=nEndX
; i
++)
531 nSizeX
+= rDoc
.GetColWidth( i
, nTab
);
532 tools::Long nSizeY
= rDoc
.GetRowHeight( nPosY
+1, nEndY
, nTab
);
534 SCCOL nDelStartX
= nStartX
;
535 SCROW nDelStartY
= nStartY
;
536 if ( nSizeX
> nSizeY
)
537 nDelStartX
= nPosX
+ 1;
539 nDelStartY
= nPosY
+ 1;
540 // there is no need to check for zero, because nPosX/Y is also negative
542 if ( nDelStartX
< nStartX
)
543 nDelStartX
= nStartX
;
544 if ( nDelStartY
< nStartY
)
545 nDelStartY
= nStartY
;
549 m_pViewData
->SetDelMark( ScRange( nDelStartX
,nDelStartY
,nTab
,
550 nEndX
,nEndY
,nTab
) );
551 m_pViewData
->GetView()->UpdateShrinkOverlay();
553 m_pViewData
->GetView()->
554 PaintArea( nStartX
,nDelStartY
, nEndX
,nEndY
, ScUpdateMode::Marks
);
556 nPosX
= nEndX
; // keep red border around range
559 // reference the right way up, if it's upside down below
560 if ( nStartX
!= m_pViewData
->GetRefStartX() || nStartY
!= m_pViewData
->GetRefStartY() )
562 m_pViewData
->GetView()->DoneRefMode();
563 m_pViewData
->GetView()->InitRefMode( nStartX
, nStartY
, nTab
, SC_REFTYPE_FILL
);
570 m_pViewData
->ResetDelMark();
571 m_pViewData
->GetView()->UpdateShrinkOverlay();
574 bool bNegX
= ( nPosX
< nStartX
);
575 bool bNegY
= ( nPosY
< nStartY
);
577 tools::Long nSizeX
= 0;
580 // in SetCursorAtPoint hidden columns are skipped.
581 // They must be skipped here too, or the result will always be the first hidden column.
582 do ++nPosX
; while ( nPosX
<nStartX
&& rDoc
.ColHidden(nPosX
, nTab
) );
583 for (SCCOL i
=nPosX
; i
<nStartX
; i
++)
584 nSizeX
+= rDoc
.GetColWidth( i
, nTab
);
587 for (SCCOL i
=nEndX
+1; i
<=nPosX
; i
++)
588 nSizeX
+= rDoc
.GetColWidth( i
, nTab
);
590 tools::Long nSizeY
= 0;
593 // in SetCursorAtPoint hidden rows are skipped.
594 // They must be skipped here too, or the result will always be the first hidden row.
595 if (++nPosY
< nStartY
)
597 nPosY
= rDoc
.FirstVisibleRow(nPosY
, nStartY
-1, nTab
);
598 if (!rDoc
.ValidRow(nPosY
))
601 nSizeY
+= rDoc
.GetRowHeight( nPosY
, nStartY
-1, nTab
);
604 nSizeY
+= rDoc
.GetRowHeight( nEndY
+1, nPosY
, nTab
);
606 if ( nSizeX
> nSizeY
) // Fill only ever in one direction
617 SCCOL nRefStX
= bNegX
? nEndX
: nStartX
;
618 SCROW nRefStY
= bNegY
? nEndY
: nStartY
;
619 if ( nRefStX
!= m_pViewData
->GetRefStartX() || nRefStY
!= m_pViewData
->GetRefStartY() )
621 m_pViewData
->GetView()->DoneRefMode();
622 m_pViewData
->GetView()->InitRefMode( nRefStX
, nRefStY
, nTab
, SC_REFTYPE_FILL
);
626 pView
->UpdateRef( nPosX
, nPosY
, nTab
);
628 else if (m_pViewData
->IsAnyFillMode())
630 ScFillMode nMode
= m_pViewData
->GetFillMode();
631 if ( nMode
== ScFillMode::EMBED_LT
|| nMode
== ScFillMode::EMBED_RB
)
633 OSL_ENSURE( rDoc
.IsEmbedded(), "!rDoc.IsEmbedded()" );
635 rDoc
.GetEmbedded( aRange
);
636 ScRefType eRefMode
= (nMode
== ScFillMode::EMBED_LT
) ? SC_REFTYPE_EMBED_LT
: SC_REFTYPE_EMBED_RB
;
637 if (m_pViewData
->GetRefType() != eRefMode
)
639 if ( nMode
== ScFillMode::EMBED_LT
)
640 pView
->InitRefMode( aRange
.aEnd
.Col(), aRange
.aEnd
.Row(), nTab
, eRefMode
);
642 pView
->InitRefMode( aRange
.aStart
.Col(), aRange
.aStart
.Row(), nTab
, eRefMode
);
646 pView
->UpdateRef( nPosX
, nPosY
, nTab
);
648 else if ( nMode
== ScFillMode::MATRIX
)
650 SCCOL nStartX
, nEndX
;
651 SCROW nStartY
, nEndY
; // Block
653 m_pViewData
->GetSimpleArea( nStartX
, nStartY
, nDummy
, nEndX
, nEndY
, nDummy
);
655 if (m_pViewData
->GetRefType() != SC_REFTYPE_FILL
)
657 pView
->InitRefMode( nStartX
, nStartY
, nTab
, SC_REFTYPE_FILL
);
661 if ( nPosX
< nStartX
) nPosX
= nStartX
;
662 if ( nPosY
< nStartY
) nPosY
= nStartY
;
664 pView
->UpdateRef( nPosX
, nPosY
, nTab
);
668 else // regular selection
670 bool bHideCur
= m_bAnchor
&& ( nPosX
!= m_pViewData
->GetCurX() ||
671 nPosY
!= m_pViewData
->GetCurY() );
673 pView
->HideAllCursors(); // otherwise twice: Block and SetCursor
679 bool bMove
= ( nPosX
!= m_aAnchorPos
.Col() ||
680 nPosY
!= m_aAnchorPos
.Row() );
681 if ( bMove
|| ( m_pEngine
&& m_pEngine
->GetMouseEvent().IsShift() ) )
683 pView
->InitBlockMode( m_aAnchorPos
.Col(), m_aAnchorPos
.Row(),
684 m_aAnchorPos
.Tab(), true );
689 // If the selection is already started, don't set the cursor.
690 pView
->MarkCursor( nPosX
, nPosY
, nTab
, false, false, true );
692 pView
->SetCursor( nPosX
, nPosY
);
696 ScMarkData
& rMark
= m_pViewData
->GetMarkData();
697 if (rMark
.IsMarked() || rMark
.IsMultiMarked())
699 pView
->DoneBlockMode(true);
700 pView
->InitBlockMode( nPosX
, nPosY
, nTab
, true );
701 pView
->MarkCursor( nPosX
, nPosY
, nTab
);
703 m_aAnchorPos
.Set( nPosX
, nPosY
, nTab
);
706 // #i3875# *Hack* When a new cell is Ctrl-clicked with no pre-selected cells,
707 // it highlights that new cell as well as the old cell where the cursor is
708 // positioned prior to the click. A selection mode via Shift-F8 should also
709 // follow the same behavior.
710 else if ( m_pViewData
->IsSelCtrlMouseClick() )
712 SCCOL nOldX
= m_pViewData
->GetCurX();
713 SCROW nOldY
= m_pViewData
->GetCurY();
715 pView
->InitBlockMode( nOldX
, nOldY
, nTab
, true );
716 pView
->MarkCursor( nOldX
, nOldY
, nTab
);
718 if ( nOldX
!= nPosX
|| nOldY
!= nPosY
)
720 pView
->DoneBlockMode( true );
721 pView
->InitBlockMode( nPosX
, nPosY
, nTab
, true );
722 pView
->MarkCursor( nPosX
, nPosY
, nTab
);
723 m_aAnchorPos
.Set( nPosX
, nPosY
, nTab
);
728 pView
->SetCursor( nPosX
, nPosY
);
731 m_pViewData
->SetRefStart( nPosX
, nPosY
, nTab
);
733 pView
->ShowAllCursors();
737 pView
->ShowAllCursors();
742 bool ScViewFunctionSet::IsSelectionAtPoint( const Point
& rPointPixel
)
744 bool bRefMode
= ScModule::get()->IsFormulaMode();
748 if (m_pViewData
->IsAnyFillMode())
751 ScMarkData
& rMark
= m_pViewData
->GetMarkData();
752 if (m_bAnchor
|| !rMark
.IsMultiMarked())
756 m_pViewData
->GetPosFromPixel( rPointPixel
.X(), rPointPixel
.Y(), GetWhich(), nPosX
, nPosY
);
757 return m_pViewData
->GetMarkData().IsCellMarked( nPosX
, nPosY
);
763 void ScViewFunctionSet::DeselectAtPoint( const Point
& /* rPointPixel */ )
768 void ScViewFunctionSet::DeselectAll()
770 if (m_pViewData
->IsAnyFillMode())
773 bool bRefMode
= ScModule::get()->IsFormulaMode();
776 m_pViewData
->GetView()->DoneRefMode();
780 m_pViewData
->GetView()->DoneBlockMode();
781 m_pViewData
->GetViewShell()->UpdateInputHandler();
787 ScViewSelectionEngine::ScViewSelectionEngine( vcl::Window
* pWindow
, ScTabView
* pView
,
788 ScSplitPos eSplitPos
) :
789 SelectionEngine( pWindow
, &pView
->GetFunctionSet() ),
792 SetSelectionMode( SelectionMode::Multiple
);
796 // column and row headers
797 ScHeaderFunctionSet::ScHeaderFunctionSet( ScViewData
* pNewViewData
) :
798 pViewData( pNewViewData
),
800 eWhich( SC_SPLIT_TOPLEFT
),
804 OSL_ENSURE(pViewData
, "ViewData==0 at FunctionSet");
807 void ScHeaderFunctionSet::SetColumn( bool bSet
)
812 void ScHeaderFunctionSet::SetWhich( ScSplitPos eNew
)
817 void ScHeaderFunctionSet::BeginDrag()
822 void ScHeaderFunctionSet::CreateAnchor()
827 ScTabView
* pView
= pViewData
->GetView();
828 pView
->DoneBlockMode( true );
831 pView
->InitBlockMode( static_cast<SCCOL
>(nCursorPos
), 0, pViewData
->GetTabNo(), true, true );
832 pView
->MarkCursor( static_cast<SCCOL
>(nCursorPos
), pViewData
->MaxRow(), pViewData
->GetTabNo() );
836 pView
->InitBlockMode( 0, nCursorPos
, pViewData
->GetTabNo(), true, false, true );
837 pView
->MarkCursor( pViewData
->MaxCol(), nCursorPos
, pViewData
->GetTabNo() );
842 void ScHeaderFunctionSet::DestroyAnchor()
844 pViewData
->GetView()->DoneBlockMode( true );
848 void ScHeaderFunctionSet::SetCursorAtPoint( const Point
& rPointPixel
, bool /* bDontSelectAtCursor */ )
852 // next valid position has to be originated from another window
853 if ( rPointPixel
== aSwitchPos
)
854 return; // don't scroll in the wrong window
860 Size aWinSize
= pViewData
->GetActiveWin()->GetOutputSizePixel();
863 bScroll
= ( rPointPixel
.X() < 0 || rPointPixel
.X() >= aWinSize
.Width() );
865 bScroll
= ( rPointPixel
.Y() < 0 || rPointPixel
.Y() >= aWinSize
.Height() );
867 // moved out of fix limit?
868 bool bSwitched
= false;
871 if ( pViewData
->GetHSplitMode() == SC_SPLIT_FIX
)
873 if ( rPointPixel
.X() > aWinSize
.Width() )
875 if ( eWhich
== SC_SPLIT_TOPLEFT
)
877 pViewData
->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT
);
880 else if ( eWhich
== SC_SPLIT_BOTTOMLEFT
)
882 pViewData
->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT
);
888 else // column headers
890 if ( pViewData
->GetVSplitMode() == SC_SPLIT_FIX
)
892 if ( rPointPixel
.Y() > aWinSize
.Height() )
894 if ( eWhich
== SC_SPLIT_TOPLEFT
)
896 pViewData
->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT
);
899 else if ( eWhich
== SC_SPLIT_TOPRIGHT
)
901 pViewData
->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT
);
909 aSwitchPos
= rPointPixel
;
911 return; // do not crunch with wrong positions
916 pViewData
->GetPosFromPixel( rPointPixel
.X(), rPointPixel
.Y(), pViewData
->GetActivePart(),
917 nPosX
, nPosY
, false );
920 nCursorPos
= static_cast<SCCOLROW
>(nPosX
);
921 nPosY
= pViewData
->GetPosY(WhichV(pViewData
->GetActivePart()));
925 nCursorPos
= static_cast<SCCOLROW
>(nPosY
);
926 nPosX
= pViewData
->GetPosX(WhichH(pViewData
->GetActivePart()));
929 ScTabView
* pView
= pViewData
->GetView();
930 bool bHide
= pViewData
->GetCurX() != nPosX
||
931 pViewData
->GetCurY() != nPosY
;
933 pView
->HideAllCursors();
936 pView
->AlignToCursor( nPosX
, nPosY
, SC_FOLLOW_LINE
);
937 pView
->SetCursor( nPosX
, nPosY
);
939 if ( !bAnchor
|| !pView
->IsBlockMode() )
941 pView
->DoneBlockMode( true );
942 pViewData
->GetMarkData().MarkToMulti(); //! who changes this?
943 pView
->InitBlockMode( nPosX
, nPosY
, pViewData
->GetTabNo(), true, bColumn
, !bColumn
);
948 pView
->MarkCursor( nPosX
, nPosY
, pViewData
->GetTabNo(), bColumn
, !bColumn
);
950 // SelectionChanged inside of HideCursor because of UpdateAutoFillMark
951 pView
->SelectionChanged();
954 pView
->ShowAllCursors();
957 bool ScHeaderFunctionSet::IsSelectionAtPoint( const Point
& rPointPixel
)
961 pViewData
->GetPosFromPixel( rPointPixel
.X(), rPointPixel
.Y(), pViewData
->GetActivePart(),
962 nPosX
, nPosY
, false );
964 ScMarkData
& rMark
= pViewData
->GetMarkData();
966 return rMark
.IsColumnMarked( nPosX
);
968 return rMark
.IsRowMarked( nPosY
);
971 void ScHeaderFunctionSet::DeselectAtPoint( const Point
& /* rPointPixel */ )
975 void ScHeaderFunctionSet::DeselectAll()
977 pViewData
->GetView()->DoneBlockMode();
981 ScHeaderSelectionEngine::ScHeaderSelectionEngine( vcl::Window
* pWindow
, ScHeaderFunctionSet
* pFuncSet
) :
982 SelectionEngine( pWindow
, pFuncSet
)
984 SetSelectionMode( SelectionMode::Multiple
);
988 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */