tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / view / select.cxx
blob28ee0bc4cc77b0300301fc7efa67ce7ec748801c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
24 #include <select.hxx>
25 #include <tabvwsh.hxx>
26 #include <scmod.hxx>
27 #include <document.hxx>
28 #include <transobj.hxx>
29 #include <docsh.hxx>
30 #include <tabprotection.hxx>
31 #include <markdata.hxx>
32 #include <gridwin.hxx>
33 #include <sfx2/lokhelper.hxx>
34 #include <comphelper/lok.hxx>
36 #if defined(_WIN32)
37 #define SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN 65
38 #endif
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 ),
48 m_pEngine( nullptr ),
49 m_bAnchor( false ),
50 m_bStarted( false )
52 OSL_ENSURE(m_pViewData, "ViewData==0 at FunctionSet");
55 ScSplitPos ScViewFunctionSet::GetWhich() const
57 if (m_pEngine)
58 return m_pEngine->GetWhich();
59 else
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));
70 if (bRightScroll)
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)
78 nHAccelRate = 1.0;
80 nUpdateInterval = SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nHAccelRate);
83 if (bLeftScroll)
85 double nMarginLeft = aRootPos.getX();
86 double nHOffset = -rEffPos.X();
87 double nHAccelRate = nHOffset / nMarginLeft;
89 if (nHAccelRate > 1.0)
90 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;
97 if (bBottomScroll)
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)
105 nVAccelRate = 1.0;
107 sal_uInt64 nTmp = SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nVAccelRate);
108 if (nUpdateInterval > nTmp)
109 nUpdateInterval = nTmp;
112 if (bTopScroll)
114 double nMarginTop = aRootPos.getY();
115 double nVOffset = -rEffPos.Y();
116 double nVAccelRate = nVOffset / nMarginTop;
118 if (nVAccelRate > 1.0)
119 nVAccelRate = 1.0;
121 sal_uInt64 nTmp = SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nVAccelRate);
122 if (nUpdateInterval > nTmp)
123 nUpdateInterval = nTmp;
126 #ifdef _WIN32
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;
136 #endif
137 return nUpdateInterval;
140 void ScViewFunctionSet::SetSelectionEngine( ScViewSelectionEngine* pSelEngine )
142 m_pEngine = pSelEngine;
145 // Drag & Drop
146 void ScViewFunctionSet::BeginDrag()
148 if (m_pViewData->GetViewShell()->IsLokReadOnlyView())
149 return;
151 SCTAB nTab = m_pViewData->GetTabNo();
153 SCCOL nPosX;
154 SCROW nPosY;
155 if (m_pEngine)
157 Point aMPos = m_pEngine->GetMousePosPixel();
158 m_pViewData->GetPosFromPixel( aMPos.X(), aMPos.Y(), GetWhich(), nPosX, nPosY );
160 else
162 nPosX = m_pViewData->GetCurX();
163 nPosY = m_pViewData->GetCurY();
166 ScModule* pScMod = ScModule::get();
167 bool bRefMode = pScMod->IsFormulaMode();
168 if (bRefMode)
169 return;
171 m_pViewData->GetView()->FakeButtonUp( GetWhich() ); // ButtonUp is swallowed
173 ScMarkData& rMark = m_pViewData->GetMarkData();
174 rMark.MarkToSimple();
175 if ( !rMark.IsMarked() || rMark.IsMultiMarked() )
176 return;
178 ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
179 // bApi = TRUE -> no error messages
180 bool bCopied = m_pViewData->GetView()->CopyToClip( pClipDoc.get(), false, true );
181 if ( !bCopied )
182 return;
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
222 // Selection
223 void ScViewFunctionSet::CreateAnchor()
225 if (m_bAnchor) return;
227 bool bRefMode = ScModule::get()->IsFormulaMode();
228 if (bRefMode)
229 SetAnchor( m_pViewData->GetRefStartX(), m_pViewData->GetRefStartY() );
230 else
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();
240 if (bRefMode)
242 pView->DoneRefMode();
243 m_aAnchorPos.Set( nPosX, nPosY, nTab );
244 pView->InitRefMode( m_aAnchorPos.Col(), m_aAnchorPos.Row(), m_aAnchorPos.Tab(),
245 SC_REFTYPE_REF );
246 m_bStarted = true;
248 else if (m_pViewData->IsAnyFillMode())
250 m_aAnchorPos.Set( nPosX, nPosY, nTab );
251 m_bStarted = true;
253 else
255 // don't go there and back again
256 if ( m_bStarted && pView->IsMarking( nPosX, nPosY, nTab ) )
258 // don't do anything
260 else
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 );
269 m_bStarted = true;
271 else
272 m_bStarted = false;
275 m_bAnchor = true;
278 void ScViewFunctionSet::DestroyAnchor()
280 if (m_pViewData->IsAnyFillMode())
281 return;
283 bool bRefMode = ScModule::get()->IsFormulaMode();
284 if (bRefMode)
285 m_pViewData->GetView()->DoneRefMode( true );
286 else
287 m_pViewData->GetView()->DoneBlockMode( true );
289 m_bAnchor = false;
292 void ScViewFunctionSet::SetAnchorFlag( bool bSet )
294 m_bAnchor = bSet;
297 void ScViewFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool /* bDontSelectAtCursor */ )
299 if ( bDidSwitch )
301 if ( rPointPixel == aSwitchPos )
302 return; // don't scroll in wrong window
303 else
304 bDidSwitch = false;
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 )
314 aEffPos.setX( -1 );
315 if ( aEffPos.Y() == 0 )
316 aEffPos.setY( -1 );
318 // Scrolling
319 Size aWinSize = m_pEngine->GetWindow()->GetOutputSizePixel();
320 bool bLeftScroll = ( aEffPos.X() < 0 );
321 bool bTopScroll = ( aEffPos.Y() < 0 );
323 SCCOL nPosX;
324 SCROW nPosY;
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(),
330 nullptr, false);
332 bool bFillingSelection = m_pViewData->IsFillMode() || m_pViewData->GetFillMode() == ScFillMode::MATRIX;
333 bool bBottomScroll;
334 bool bRightScroll;
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();
343 else
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)
355 bool bLeft, bTop;
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 )
363 if (--nPosY >= 0)
365 nPosY = rDoc.LastVisibleRow(0, nPosY, nTab);
366 if (!rDoc.ValidRow(nPosY))
367 nPosY = -1;
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 );
383 bScroll = false;
384 bDidSwitch = true;
386 else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
388 m_pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
389 bScroll = false;
390 bDidSwitch = true;
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 );
400 bScroll = false;
401 bDidSwitch = true;
403 else if ( eWhich == SC_SPLIT_TOPRIGHT )
405 m_pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
406 bScroll = false;
407 bDidSwitch = true;
412 if (bScroll)
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);
419 else
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)
449 return false;
451 const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
452 if (!pProtect)
453 return false;
455 bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
456 bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
458 if ( bSkipProtected && bSkipUnprotected )
459 return false;
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!
464 return false;
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() );
473 if (bHide)
474 pView->HideAllCursors();
476 if (bScroll)
478 if (bRefMode)
480 ScSplitPos eWhich = GetWhich();
481 pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE, &eWhich );
483 else
484 pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE );
487 if (bRefMode)
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))
492 if (!m_bAnchor)
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
511 SCTAB nDummy;
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 );
517 CreateAnchor();
520 ScRange aDelRange;
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;
538 else
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;
547 // set range
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
557 nPosY = nEndY;
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 );
566 else
568 if ( bOldDelMark )
570 m_pViewData->ResetDelMark();
571 m_pViewData->GetView()->UpdateShrinkOverlay();
574 bool bNegX = ( nPosX < nStartX );
575 bool bNegY = ( nPosY < nStartY );
577 tools::Long nSizeX = 0;
578 if ( bNegX )
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 );
586 else
587 for (SCCOL i=nEndX+1; i<=nPosX; i++)
588 nSizeX += rDoc.GetColWidth( i, nTab );
590 tools::Long nSizeY = 0;
591 if ( bNegY )
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))
599 nPosY = nStartY;
601 nSizeY += rDoc.GetRowHeight( nPosY, nStartY-1, nTab );
603 else
604 nSizeY += rDoc.GetRowHeight( nEndY+1, nPosY, nTab );
606 if ( nSizeX > nSizeY ) // Fill only ever in one direction
608 nPosY = nEndY;
609 bNegY = false;
611 else
613 nPosX = nEndX;
614 bNegX = false;
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()" );
634 ScRange aRange;
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 );
641 else
642 pView->InitRefMode( aRange.aStart.Col(), aRange.aStart.Row(), nTab, eRefMode );
643 CreateAnchor();
646 pView->UpdateRef( nPosX, nPosY, nTab );
648 else if ( nMode == ScFillMode::MATRIX )
650 SCCOL nStartX, nEndX;
651 SCROW nStartY, nEndY; // Block
652 SCTAB nDummy;
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 );
658 CreateAnchor();
661 if ( nPosX < nStartX ) nPosX = nStartX;
662 if ( nPosY < nStartY ) nPosY = nStartY;
664 pView->UpdateRef( nPosX, nPosY, nTab );
666 // else new modes
668 else // regular selection
670 bool bHideCur = m_bAnchor && ( nPosX != m_pViewData->GetCurX() ||
671 nPosY != m_pViewData->GetCurY() );
672 if (bHideCur)
673 pView->HideAllCursors(); // otherwise twice: Block and SetCursor
675 if (m_bAnchor)
677 if (!m_bStarted)
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 );
685 m_bStarted = true;
688 if (m_bStarted)
689 // If the selection is already started, don't set the cursor.
690 pView->MarkCursor( nPosX, nPosY, nTab, false, false, true );
691 else
692 pView->SetCursor( nPosX, nPosY );
694 else
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 );
704 m_bStarted = true;
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 );
726 m_bStarted = true;
728 pView->SetCursor( nPosX, nPosY );
731 m_pViewData->SetRefStart( nPosX, nPosY, nTab );
732 if (bHideCur)
733 pView->ShowAllCursors();
736 if (bHide)
737 pView->ShowAllCursors();
739 return true;
742 bool ScViewFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
744 bool bRefMode = ScModule::get()->IsFormulaMode();
745 if (bRefMode)
746 return false;
748 if (m_pViewData->IsAnyFillMode())
749 return false;
751 ScMarkData& rMark = m_pViewData->GetMarkData();
752 if (m_bAnchor || !rMark.IsMultiMarked())
754 SCCOL nPosX;
755 SCROW nPosY;
756 m_pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), GetWhich(), nPosX, nPosY );
757 return m_pViewData->GetMarkData().IsCellMarked( nPosX, nPosY );
760 return false;
763 void ScViewFunctionSet::DeselectAtPoint( const Point& /* rPointPixel */ )
765 // doesn't exist
768 void ScViewFunctionSet::DeselectAll()
770 if (m_pViewData->IsAnyFillMode())
771 return;
773 bool bRefMode = ScModule::get()->IsFormulaMode();
774 if (bRefMode)
776 m_pViewData->GetView()->DoneRefMode();
778 else
780 m_pViewData->GetView()->DoneBlockMode();
781 m_pViewData->GetViewShell()->UpdateInputHandler();
784 m_bAnchor = false;
787 ScViewSelectionEngine::ScViewSelectionEngine( vcl::Window* pWindow, ScTabView* pView,
788 ScSplitPos eSplitPos ) :
789 SelectionEngine( pWindow, &pView->GetFunctionSet() ),
790 eWhich( eSplitPos )
792 SetSelectionMode( SelectionMode::Multiple );
793 EnableDrag( true );
796 // column and row headers
797 ScHeaderFunctionSet::ScHeaderFunctionSet( ScViewData* pNewViewData ) :
798 pViewData( pNewViewData ),
799 bColumn( false ),
800 eWhich( SC_SPLIT_TOPLEFT ),
801 bAnchor( false ),
802 nCursorPos( 0 )
804 OSL_ENSURE(pViewData, "ViewData==0 at FunctionSet");
807 void ScHeaderFunctionSet::SetColumn( bool bSet )
809 bColumn = bSet;
812 void ScHeaderFunctionSet::SetWhich( ScSplitPos eNew )
814 eWhich = eNew;
817 void ScHeaderFunctionSet::BeginDrag()
819 // doesn't exist
822 void ScHeaderFunctionSet::CreateAnchor()
824 if (bAnchor)
825 return;
827 ScTabView* pView = pViewData->GetView();
828 pView->DoneBlockMode( true );
829 if (bColumn)
831 pView->InitBlockMode( static_cast<SCCOL>(nCursorPos), 0, pViewData->GetTabNo(), true, true );
832 pView->MarkCursor( static_cast<SCCOL>(nCursorPos), pViewData->MaxRow(), pViewData->GetTabNo() );
834 else
836 pView->InitBlockMode( 0, nCursorPos, pViewData->GetTabNo(), true, false, true );
837 pView->MarkCursor( pViewData->MaxCol(), nCursorPos, pViewData->GetTabNo() );
839 bAnchor = true;
842 void ScHeaderFunctionSet::DestroyAnchor()
844 pViewData->GetView()->DoneBlockMode( true );
845 bAnchor = false;
848 void ScHeaderFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool /* bDontSelectAtCursor */ )
850 if ( bDidSwitch )
852 // next valid position has to be originated from another window
853 if ( rPointPixel == aSwitchPos )
854 return; // don't scroll in the wrong window
855 else
856 bDidSwitch = false;
859 // Scrolling
860 Size aWinSize = pViewData->GetActiveWin()->GetOutputSizePixel();
861 bool bScroll;
862 if (bColumn)
863 bScroll = ( rPointPixel.X() < 0 || rPointPixel.X() >= aWinSize.Width() );
864 else
865 bScroll = ( rPointPixel.Y() < 0 || rPointPixel.Y() >= aWinSize.Height() );
867 // moved out of fix limit?
868 bool bSwitched = false;
869 if ( bColumn )
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 );
878 bSwitched = true;
880 else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
882 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
883 bSwitched = true;
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 );
897 bSwitched = true;
899 else if ( eWhich == SC_SPLIT_TOPRIGHT )
901 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
902 bSwitched = true;
907 if (bSwitched)
909 aSwitchPos = rPointPixel;
910 bDidSwitch = true;
911 return; // do not crunch with wrong positions
914 SCCOL nPosX;
915 SCROW nPosY;
916 pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), pViewData->GetActivePart(),
917 nPosX, nPosY, false );
918 if (bColumn)
920 nCursorPos = static_cast<SCCOLROW>(nPosX);
921 nPosY = pViewData->GetPosY(WhichV(pViewData->GetActivePart()));
923 else
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;
932 if (bHide)
933 pView->HideAllCursors();
935 if (bScroll)
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 );
945 bAnchor = true;
948 pView->MarkCursor( nPosX, nPosY, pViewData->GetTabNo(), bColumn, !bColumn );
950 // SelectionChanged inside of HideCursor because of UpdateAutoFillMark
951 pView->SelectionChanged();
953 if (bHide)
954 pView->ShowAllCursors();
957 bool ScHeaderFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
959 SCCOL nPosX;
960 SCROW nPosY;
961 pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), pViewData->GetActivePart(),
962 nPosX, nPosY, false );
964 ScMarkData& rMark = pViewData->GetMarkData();
965 if (bColumn)
966 return rMark.IsColumnMarked( nPosX );
967 else
968 return rMark.IsRowMarked( nPosY );
971 void ScHeaderFunctionSet::DeselectAtPoint( const Point& /* rPointPixel */ )
975 void ScHeaderFunctionSet::DeselectAll()
977 pViewData->GetView()->DoneBlockMode();
978 bAnchor = false;
981 ScHeaderSelectionEngine::ScHeaderSelectionEngine( vcl::Window* pWindow, ScHeaderFunctionSet* pFuncSet ) :
982 SelectionEngine( pWindow, pFuncSet )
984 SetSelectionMode( SelectionMode::Multiple );
985 EnableDrag( false );
988 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */