fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / view / select.cxx
blob09169f11c695b5cc99d31bb152da67753b6e38e5
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 <vcl/svapp.hxx>
22 #include <sfx2/docfile.hxx>
24 #include "select.hxx"
25 #include "sc.hrc"
26 #include "tabvwsh.hxx"
27 #include "scmod.hxx"
28 #include "document.hxx"
29 #include "transobj.hxx"
30 #include "docsh.hxx"
31 #include "tabprotection.hxx"
32 #include "markdata.hxx"
33 #include <gridwin.hxx>
35 #if defined WNT
36 #define SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN 65
37 #endif
39 extern sal_uInt16 nScFillModeMouseModifier; // global.cxx
41 using namespace com::sun::star;
43 // STATIC DATA -----------------------------------------------------------
45 static Point aSwitchPos; //! Member
46 static bool bDidSwitch = false;
48 // View (Gridwin / keyboard)
49 ScViewFunctionSet::ScViewFunctionSet( ScViewData* pNewViewData ) :
50 pViewData( pNewViewData ),
51 pEngine( NULL ),
52 bAnchor( false ),
53 bStarted( false )
55 OSL_ENSURE(pViewData, "ViewData==0 at FunctionSet");
58 ScSplitPos ScViewFunctionSet::GetWhich()
60 if (pEngine)
61 return pEngine->GetWhich();
62 else
63 return pViewData->GetActivePart();
66 sal_uLong ScViewFunctionSet::CalcUpdateInterval( const Size& rWinSize, const Point& rEffPos,
67 bool bLeftScroll, bool bTopScroll, bool bRightScroll, bool bBottomScroll )
69 sal_uLong nUpdateInterval = SELENG_AUTOREPEAT_INTERVAL_MAX;
70 vcl::Window* pWin = pEngine->GetWindow();
71 Rectangle aScrRect = pWin->GetDesktopRectPixel();
72 Point aRootPos = pWin->OutputToAbsoluteScreenPixel(Point(0,0));
73 if (bRightScroll)
75 double nWinRight = rWinSize.getWidth() + aRootPos.getX();
76 double nMarginRight = aScrRect.GetWidth() - nWinRight;
77 double nHOffset = rEffPos.X() - rWinSize.Width();
78 double nHAccelRate = nHOffset / nMarginRight;
80 if (nHAccelRate > 1.0)
81 nHAccelRate = 1.0;
83 nUpdateInterval = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nHAccelRate));
86 if (bLeftScroll)
88 double nMarginLeft = aRootPos.getX();
89 double nHOffset = -rEffPos.X();
90 double nHAccelRate = nHOffset / nMarginLeft;
92 if (nHAccelRate > 1.0)
93 nHAccelRate = 1.0;
95 sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nHAccelRate));
96 if (nUpdateInterval > nTmp)
97 nUpdateInterval = nTmp;
100 if (bBottomScroll)
102 double nWinBottom = rWinSize.getHeight() + aRootPos.getY();
103 double nMarginBottom = aScrRect.GetHeight() - nWinBottom;
104 double nVOffset = rEffPos.Y() - rWinSize.Height();
105 double nVAccelRate = nVOffset / nMarginBottom;
107 if (nVAccelRate > 1.0)
108 nVAccelRate = 1.0;
110 sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nVAccelRate));
111 if (nUpdateInterval > nTmp)
112 nUpdateInterval = nTmp;
115 if (bTopScroll)
117 double nMarginTop = aRootPos.getY();
118 double nVOffset = -rEffPos.Y();
119 double nVAccelRate = nVOffset / nMarginTop;
121 if (nVAccelRate > 1.0)
122 nVAccelRate = 1.0;
124 sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nVAccelRate));
125 if (nUpdateInterval > nTmp)
126 nUpdateInterval = nTmp;
129 #ifdef WNT
130 ScTabViewShell* pViewShell = pViewData->GetViewShell();
131 bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
132 if (bRefMode && nUpdateInterval < SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN)
133 // Lower the update interval during ref mode, because re-draw can be
134 // expensive on Windows. Making this interval too small would queue up
135 // the scroll/paint requests which would cause semi-infinite
136 // scrolls even after the mouse cursor is released. We don't have
137 // this problem on Linux.
138 nUpdateInterval = SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN;
139 #endif
140 return nUpdateInterval;
143 void ScViewFunctionSet::SetSelectionEngine( ScViewSelectionEngine* pSelEngine )
145 pEngine = pSelEngine;
148 // Drag & Drop
149 void ScViewFunctionSet::BeginDrag()
151 SCTAB nTab = pViewData->GetTabNo();
153 SCsCOL nPosX;
154 SCsROW nPosY;
155 if (pEngine)
157 Point aMPos = pEngine->GetMousePosPixel();
158 pViewData->GetPosFromPixel( aMPos.X(), aMPos.Y(), GetWhich(), nPosX, nPosY );
160 else
162 nPosX = pViewData->GetCurX();
163 nPosY = pViewData->GetCurY();
166 ScModule* pScMod = SC_MOD();
167 bool bRefMode = pScMod->IsFormulaMode();
168 if (!bRefMode)
170 pViewData->GetView()->FakeButtonUp( GetWhich() ); // ButtonUp is swallowed
172 ScMarkData& rMark = pViewData->GetMarkData();
173 rMark.MarkToSimple();
174 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
176 ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP );
177 // bApi = TRUE -> no error messages
178 bool bCopied = pViewData->GetView()->CopyToClip( pClipDoc, false, true );
179 if ( bCopied )
181 sal_Int8 nDragActions = pViewData->GetView()->SelectionEditable() ?
182 ( DND_ACTION_COPYMOVE | DND_ACTION_LINK ) :
183 ( DND_ACTION_COPY | DND_ACTION_LINK );
185 ScDocShell* pDocSh = pViewData->GetDocShell();
186 TransferableObjectDescriptor aObjDesc;
187 pDocSh->FillTransferableObjectDescriptor( aObjDesc );
188 aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
189 // maSize is set in ScTransferObj ctor
191 ScTransferObj* pTransferObj = new ScTransferObj( pClipDoc, aObjDesc );
192 uno::Reference<datatransfer::XTransferable> xTransferable( pTransferObj );
194 // set position of dragged cell within range
195 ScRange aMarkRange = pTransferObj->GetRange();
196 SCCOL nStartX = aMarkRange.aStart.Col();
197 SCROW nStartY = aMarkRange.aStart.Row();
198 SCCOL nHandleX = (nPosX >= (SCsCOL) nStartX) ? nPosX - nStartX : 0;
199 SCROW nHandleY = (nPosY >= (SCsROW) nStartY) ? nPosY - nStartY : 0;
200 pTransferObj->SetDragHandlePos( nHandleX, nHandleY );
201 pTransferObj->SetVisibleTab( nTab );
203 pTransferObj->SetDragSource( pDocSh, rMark );
205 vcl::Window* pWindow = pViewData->GetActiveWin();
206 if ( pWindow->IsTracking() )
207 pWindow->EndTracking( TrackingEventFlags::Cancel ); // abort selecting
209 SC_MOD()->SetDragObject( pTransferObj, NULL ); // for internal D&D
210 pTransferObj->StartDrag( pWindow, nDragActions );
212 return; // dragging started
214 else
215 delete pClipDoc;
221 // Selection
222 void ScViewFunctionSet::CreateAnchor()
224 if (bAnchor) return;
226 bool bRefMode = SC_MOD()->IsFormulaMode();
227 if (bRefMode)
228 SetAnchor( pViewData->GetRefStartX(), pViewData->GetRefStartY() );
229 else
230 SetAnchor( pViewData->GetCurX(), pViewData->GetCurY() );
233 void ScViewFunctionSet::SetAnchor( SCCOL nPosX, SCROW nPosY )
235 bool bRefMode = SC_MOD()->IsFormulaMode();
236 ScTabView* pView = pViewData->GetView();
237 SCTAB nTab = pViewData->GetTabNo();
239 if (bRefMode)
241 pView->DoneRefMode( false );
242 aAnchorPos.Set( nPosX, nPosY, nTab );
243 pView->InitRefMode( aAnchorPos.Col(), aAnchorPos.Row(), aAnchorPos.Tab(),
244 SC_REFTYPE_REF );
245 bStarted = true;
247 else if (pViewData->IsAnyFillMode())
249 aAnchorPos.Set( nPosX, nPosY, nTab );
250 bStarted = true;
252 else
254 // don't go there and back again
255 if ( bStarted && pView->IsMarking( nPosX, nPosY, nTab ) )
257 // don't do anything
259 else
261 pView->DoneBlockMode( true );
262 aAnchorPos.Set( nPosX, nPosY, nTab );
263 ScMarkData& rMark = pViewData->GetMarkData();
264 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
266 pView->InitBlockMode( aAnchorPos.Col(), aAnchorPos.Row(),
267 aAnchorPos.Tab(), true );
268 bStarted = true;
270 else
271 bStarted = false;
274 bAnchor = true;
277 void ScViewFunctionSet::DestroyAnchor()
279 bool bRefMode = SC_MOD()->IsFormulaMode();
280 if (bRefMode)
281 pViewData->GetView()->DoneRefMode( true );
282 else
283 pViewData->GetView()->DoneBlockMode( true );
285 bAnchor = false;
288 void ScViewFunctionSet::SetAnchorFlag( bool bSet )
290 bAnchor = bSet;
293 bool ScViewFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool /* bDontSelectAtCursor */ )
295 if ( bDidSwitch )
297 if ( rPointPixel == aSwitchPos )
298 return false; // don't scroll in wrong window
299 else
300 bDidSwitch = false;
302 aSwitchPos = rPointPixel; // only important, if bDidSwitch
304 // treat position 0 as -1, so scrolling is always possible
305 // (with full screen and hidden headers, the top left border may be at 0)
306 // (moved from ScViewData::GetPosFromPixel)
308 Point aEffPos = rPointPixel;
309 if ( aEffPos.X() == 0 )
310 aEffPos.X() = -1;
311 if ( aEffPos.Y() == 0 )
312 aEffPos.Y() = -1;
314 // Scrolling
315 Size aWinSize = pEngine->GetWindow()->GetOutputSizePixel();
316 bool bRightScroll = ( aEffPos.X() >= aWinSize.Width() );
317 bool bLeftScroll = ( aEffPos.X() < 0 );
318 bool bBottomScroll = ( aEffPos.Y() >= aWinSize.Height() );
319 bool bTopScroll = ( aEffPos.Y() < 0 );
320 bool bScroll = bRightScroll || bBottomScroll || bLeftScroll || bTopScroll;
322 SCsCOL nPosX;
323 SCsROW nPosY;
324 pViewData->GetPosFromPixel( aEffPos.X(), aEffPos.Y(), GetWhich(),
325 nPosX, nPosY, true, true ); // with Repair
327 // for Autofill switch in the center of cell
328 // thereby don't prevent scrolling to bottom/right
329 if ( pViewData->IsFillMode() || pViewData->GetFillMode() == SC_FILL_MATRIX )
331 bool bLeft, bTop;
332 pViewData->GetMouseQuadrant( aEffPos, GetWhich(), nPosX, nPosY, bLeft, bTop );
333 ScDocument* pDoc = pViewData->GetDocument();
334 SCTAB nTab = pViewData->GetTabNo();
335 if ( bLeft && !bRightScroll )
336 do --nPosX; while ( nPosX>=0 && pDoc->ColHidden( nPosX, nTab ) );
337 if ( bTop && !bBottomScroll )
339 if (--nPosY >= 0)
341 nPosY = pDoc->LastVisibleRow(0, nPosY, nTab);
342 if (!ValidRow(nPosY))
343 nPosY = -1;
346 // negative value is allowed
349 // moved out of fix limit?
350 ScSplitPos eWhich = GetWhich();
351 if ( eWhich == pViewData->GetActivePart() )
353 if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
354 if ( aEffPos.X() >= aWinSize.Width() )
356 if ( eWhich == SC_SPLIT_TOPLEFT )
357 pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT ), bScroll = false, bDidSwitch = true;
358 else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
359 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ), bScroll = false, bDidSwitch = true;
362 if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
363 if ( aEffPos.Y() >= aWinSize.Height() )
365 if ( eWhich == SC_SPLIT_TOPLEFT )
366 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT ), bScroll = false, bDidSwitch = true;
367 else if ( eWhich == SC_SPLIT_TOPRIGHT )
368 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ), bScroll = false, bDidSwitch = true;
372 if (bScroll)
374 // Adjust update interval based on how far the mouse pointer is from the edge.
375 sal_uLong nUpdateInterval = CalcUpdateInterval(
376 aWinSize, aEffPos, bLeftScroll, bTopScroll, bRightScroll, bBottomScroll);
377 pEngine->SetUpdateInterval(nUpdateInterval);
379 else
381 // Don't forget to reset the interval when not scrolling!
382 pEngine->SetUpdateInterval(SELENG_AUTOREPEAT_INTERVAL);
385 pViewData->ResetOldCursor();
386 return SetCursorAtCell( nPosX, nPosY, bScroll );
389 bool ScViewFunctionSet::SetCursorAtCell( SCsCOL nPosX, SCsROW nPosY, bool bScroll )
391 ScTabView* pView = pViewData->GetView();
392 SCTAB nTab = pViewData->GetTabNo();
393 ScDocument* pDoc = pViewData->GetDocument();
395 if ( pDoc->IsTabProtected(nTab) )
397 if (nPosX < 0 || nPosY < 0)
398 return false;
400 ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
401 if (!pProtect)
402 return false;
404 bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
405 bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
407 if ( bSkipProtected && bSkipUnprotected )
408 return false;
410 bool bCellProtected = pDoc->HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HASATTR_PROTECTED);
411 if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) )
412 // Don't select this cell!
413 return false;
416 ScModule* pScMod = SC_MOD();
417 ScTabViewShell* pViewShell = pViewData->GetViewShell();
418 bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
420 bool bHide = !bRefMode && !pViewData->IsAnyFillMode() &&
421 ( nPosX != (SCsCOL) pViewData->GetCurX() || nPosY != (SCsROW) pViewData->GetCurY() );
423 if (bHide)
424 pView->HideAllCursors();
426 if (bScroll)
428 if (bRefMode)
430 ScSplitPos eWhich = GetWhich();
431 pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE, &eWhich );
433 else
434 pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE );
437 if (bRefMode)
439 // if no input is possible from this doc, don't move the reference cursor around
440 if ( !pScMod->IsModalMode(pViewData->GetSfxDocShell()) )
442 if (!bAnchor)
444 pView->DoneRefMode( true );
445 pView->InitRefMode( nPosX, nPosY, pViewData->GetTabNo(), SC_REFTYPE_REF );
448 pView->UpdateRef( nPosX, nPosY, pViewData->GetTabNo() );
449 pView->SelectionChanged();
452 else if (pViewData->IsFillMode() ||
453 (pViewData->GetFillMode() == SC_FILL_MATRIX && (nScFillModeMouseModifier & KEY_MOD1) ))
455 // If a matrix got touched, switch back to Autofill is possible with Ctrl
457 SCCOL nStartX, nEndX;
458 SCROW nStartY, nEndY; // Block
459 SCTAB nDummy;
460 pViewData->GetSimpleArea( nStartX, nStartY, nDummy, nEndX, nEndY, nDummy );
462 if (pViewData->GetRefType() != SC_REFTYPE_FILL)
464 pView->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
465 CreateAnchor();
468 ScRange aDelRange;
469 bool bOldDelMark = pViewData->GetDelMark( aDelRange );
471 if ( nPosX+1 >= (SCsCOL) nStartX && nPosX <= (SCsCOL) nEndX &&
472 nPosY+1 >= (SCsROW) nStartY && nPosY <= (SCsROW) nEndY &&
473 ( nPosX != nEndX || nPosY != nEndY ) ) // minimize?
475 // direction (left or top)
477 long nSizeX = 0;
478 for (SCCOL i=nPosX+1; i<=nEndX; i++)
479 nSizeX += pDoc->GetColWidth( i, nTab );
480 long nSizeY = (long) pDoc->GetRowHeight( nPosY+1, nEndY, nTab );
482 SCCOL nDelStartX = nStartX;
483 SCROW nDelStartY = nStartY;
484 if ( nSizeX > nSizeY )
485 nDelStartX = nPosX + 1;
486 else
487 nDelStartY = nPosY + 1;
488 // there is no need to check for zero, because nPosX/Y is also negative
490 if ( nDelStartX < nStartX )
491 nDelStartX = nStartX;
492 if ( nDelStartY < nStartY )
493 nDelStartY = nStartY;
495 // set range
497 pViewData->SetDelMark( ScRange( nDelStartX,nDelStartY,nTab,
498 nEndX,nEndY,nTab ) );
499 pViewData->GetView()->UpdateShrinkOverlay();
501 pViewData->GetView()->
502 PaintArea( nStartX,nDelStartY, nEndX,nEndY, SC_UPDATE_MARKS );
504 nPosX = nEndX; // keep red border around range
505 nPosY = nEndY;
507 // reference the right way up, if it's upside down below
508 if ( nStartX != pViewData->GetRefStartX() || nStartY != pViewData->GetRefStartY() )
510 pViewData->GetView()->DoneRefMode();
511 pViewData->GetView()->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
514 else
516 if ( bOldDelMark )
518 pViewData->ResetDelMark();
519 pViewData->GetView()->UpdateShrinkOverlay();
522 bool bNegX = ( nPosX < (SCsCOL) nStartX );
523 bool bNegY = ( nPosY < (SCsROW) nStartY );
525 long nSizeX = 0;
526 if ( bNegX )
528 // in SetCursorAtPoint hidden columns are skipped.
529 // They must be skipped here too, or the result will always be the first hidden column.
530 do ++nPosX; while ( nPosX<nStartX && pDoc->ColHidden(nPosX, nTab) );
531 for (SCCOL i=nPosX; i<nStartX; i++)
532 nSizeX += pDoc->GetColWidth( i, nTab );
534 else
535 for (SCCOL i=nEndX+1; i<=nPosX; i++)
536 nSizeX += pDoc->GetColWidth( i, nTab );
538 long nSizeY = 0;
539 if ( bNegY )
541 // in SetCursorAtPoint hidden rows are skipped.
542 // They must be skipped here too, or the result will always be the first hidden row.
543 if (++nPosY < nStartY)
545 nPosY = pDoc->FirstVisibleRow(nPosY, nStartY-1, nTab);
546 if (!ValidRow(nPosY))
547 nPosY = nStartY;
549 nSizeY += pDoc->GetRowHeight( nPosY, nStartY-1, nTab );
551 else
552 nSizeY += pDoc->GetRowHeight( nEndY+1, nPosY, nTab );
554 if ( nSizeX > nSizeY ) // Fill only ever in one direction
556 nPosY = nEndY;
557 bNegY = false;
559 else
561 nPosX = nEndX;
562 bNegX = false;
565 SCCOL nRefStX = bNegX ? nEndX : nStartX;
566 SCROW nRefStY = bNegY ? nEndY : nStartY;
567 if ( nRefStX != pViewData->GetRefStartX() || nRefStY != pViewData->GetRefStartY() )
569 pViewData->GetView()->DoneRefMode();
570 pViewData->GetView()->InitRefMode( nRefStX, nRefStY, nTab, SC_REFTYPE_FILL );
574 pView->UpdateRef( nPosX, nPosY, nTab );
576 else if (pViewData->IsAnyFillMode())
578 sal_uInt8 nMode = pViewData->GetFillMode();
579 if ( nMode == SC_FILL_EMBED_LT || nMode == SC_FILL_EMBED_RB )
581 OSL_ENSURE( pDoc->IsEmbedded(), "!pDoc->IsEmbedded()" );
582 ScRange aRange;
583 pDoc->GetEmbedded( aRange);
584 ScRefType eRefMode = (nMode == SC_FILL_EMBED_LT) ? SC_REFTYPE_EMBED_LT : SC_REFTYPE_EMBED_RB;
585 if (pViewData->GetRefType() != eRefMode)
587 if ( nMode == SC_FILL_EMBED_LT )
588 pView->InitRefMode( aRange.aEnd.Col(), aRange.aEnd.Row(), nTab, eRefMode );
589 else
590 pView->InitRefMode( aRange.aStart.Col(), aRange.aStart.Row(), nTab, eRefMode );
591 CreateAnchor();
594 pView->UpdateRef( nPosX, nPosY, nTab );
596 else if ( nMode == SC_FILL_MATRIX )
598 SCCOL nStartX, nEndX;
599 SCROW nStartY, nEndY; // Block
600 SCTAB nDummy;
601 pViewData->GetSimpleArea( nStartX, nStartY, nDummy, nEndX, nEndY, nDummy );
603 if (pViewData->GetRefType() != SC_REFTYPE_FILL)
605 pView->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
606 CreateAnchor();
609 if ( nPosX < nStartX ) nPosX = nStartX;
610 if ( nPosY < nStartY ) nPosY = nStartY;
612 pView->UpdateRef( nPosX, nPosY, nTab );
614 // else new modes
616 else // regular selection
618 bool bHideCur = bAnchor && ( (SCCOL)nPosX != pViewData->GetCurX() ||
619 (SCROW)nPosY != pViewData->GetCurY() );
620 if (bHideCur)
621 pView->HideAllCursors(); // otherwise twice: Block and SetCursor
623 if (bAnchor)
625 if (!bStarted)
627 bool bMove = ( nPosX != (SCsCOL) aAnchorPos.Col() ||
628 nPosY != (SCsROW) aAnchorPos.Row() );
629 if ( bMove || ( pEngine && pEngine->GetMouseEvent().IsShift() ) )
631 pView->InitBlockMode( aAnchorPos.Col(), aAnchorPos.Row(),
632 aAnchorPos.Tab(), true );
633 bStarted = true;
636 if (bStarted)
637 // If the selection is already started, don't set the cursor.
638 pView->MarkCursor( (SCCOL) nPosX, (SCROW) nPosY, nTab, false, false, true );
639 else
640 pView->SetCursor( (SCCOL) nPosX, (SCROW) nPosY );
642 else
644 ScMarkData& rMark = pViewData->GetMarkData();
645 if (rMark.IsMarked() || rMark.IsMultiMarked())
647 pView->DoneBlockMode(true);
648 pView->InitBlockMode( nPosX, nPosY, nTab, true );
649 pView->MarkCursor( (SCCOL) nPosX, (SCROW) nPosY, nTab );
651 aAnchorPos.Set( nPosX, nPosY, nTab );
652 bStarted = true;
654 // #i3875# *Hack* When a new cell is Ctrl-clicked with no pre-selected cells,
655 // it highlights that new cell as well as the old cell where the cursor is
656 // positioned prior to the click. A selection mode via Shift-F8 should also
657 // follow the same behavior.
658 else if ( pViewData->IsSelCtrlMouseClick() )
660 SCCOL nOldX = pViewData->GetCurX();
661 SCROW nOldY = pViewData->GetCurY();
663 pView->InitBlockMode( nOldX, nOldY, nTab, true );
664 pView->MarkCursor( (SCCOL) nOldX, (SCROW) nOldY, nTab );
666 if ( nOldX != nPosX || nOldY != nPosY )
668 pView->DoneBlockMode( true );
669 pView->InitBlockMode( nPosX, nPosY, nTab, true );
670 pView->MarkCursor( (SCCOL) nPosX, (SCROW) nPosY, nTab );
671 aAnchorPos.Set( nPosX, nPosY, nTab );
674 bStarted = true;
676 pView->SetCursor( (SCCOL) nPosX, (SCROW) nPosY );
679 pViewData->SetRefStart( nPosX, nPosY, nTab );
680 if (bHideCur)
681 pView->ShowAllCursors();
684 if (bHide)
685 pView->ShowAllCursors();
687 return true;
690 bool ScViewFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
692 bool bRefMode = SC_MOD()->IsFormulaMode();
693 if (bRefMode)
694 return false;
696 if (pViewData->IsAnyFillMode())
697 return false;
699 ScMarkData& rMark = pViewData->GetMarkData();
700 if (bAnchor || !rMark.IsMultiMarked())
702 SCsCOL nPosX;
703 SCsROW nPosY;
704 pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), GetWhich(), nPosX, nPosY );
705 return pViewData->GetMarkData().IsCellMarked( (SCCOL) nPosX, (SCROW) nPosY );
708 return false;
711 void ScViewFunctionSet::DeselectAtPoint( const Point& /* rPointPixel */ )
713 // doesn't exist
716 void ScViewFunctionSet::DeselectAll()
718 if (pViewData->IsAnyFillMode())
719 return;
721 bool bRefMode = SC_MOD()->IsFormulaMode();
722 if (bRefMode)
724 pViewData->GetView()->DoneRefMode( false );
726 else
728 pViewData->GetView()->DoneBlockMode( false );
729 pViewData->GetViewShell()->UpdateInputHandler();
732 bAnchor = false;
735 ScViewSelectionEngine::ScViewSelectionEngine( vcl::Window* pWindow, ScTabView* pView,
736 ScSplitPos eSplitPos ) :
737 SelectionEngine( pWindow, &pView->GetFunctionSet() ),
738 eWhich( eSplitPos )
740 SetSelectionMode( MULTIPLE_SELECTION );
741 EnableDrag( true );
744 // column and row headers
745 ScHeaderFunctionSet::ScHeaderFunctionSet( ScViewData* pNewViewData ) :
746 pViewData( pNewViewData ),
747 bColumn( false ),
748 eWhich( SC_SPLIT_TOPLEFT ),
749 bAnchor( false ),
750 nCursorPos( 0 )
752 OSL_ENSURE(pViewData, "ViewData==0 at FunctionSet");
755 void ScHeaderFunctionSet::SetColumn( bool bSet )
757 bColumn = bSet;
760 void ScHeaderFunctionSet::SetWhich( ScSplitPos eNew )
762 eWhich = eNew;
765 void ScHeaderFunctionSet::BeginDrag()
767 // doesn't exist
770 void ScHeaderFunctionSet::CreateAnchor()
772 if (bAnchor)
773 return;
775 ScTabView* pView = pViewData->GetView();
776 pView->DoneBlockMode( true );
777 if (bColumn)
779 pView->InitBlockMode( static_cast<SCCOL>(nCursorPos), 0, pViewData->GetTabNo(), true, true, false );
780 pView->MarkCursor( static_cast<SCCOL>(nCursorPos), MAXROW, pViewData->GetTabNo() );
782 else
784 pView->InitBlockMode( 0, nCursorPos, pViewData->GetTabNo(), true, false, true );
785 pView->MarkCursor( MAXCOL, nCursorPos, pViewData->GetTabNo() );
787 bAnchor = true;
790 void ScHeaderFunctionSet::DestroyAnchor()
792 pViewData->GetView()->DoneBlockMode( true );
793 bAnchor = false;
796 bool ScHeaderFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool /* bDontSelectAtCursor */ )
798 if ( bDidSwitch )
800 // next valid position has to be originated from another window
801 if ( rPointPixel == aSwitchPos )
802 return false; // don't scroll in the wrong window
803 else
804 bDidSwitch = false;
807 // Scrolling
808 Size aWinSize = pViewData->GetActiveWin()->GetOutputSizePixel();
809 bool bScroll;
810 if (bColumn)
811 bScroll = ( rPointPixel.X() < 0 || rPointPixel.X() >= aWinSize.Width() );
812 else
813 bScroll = ( rPointPixel.Y() < 0 || rPointPixel.Y() >= aWinSize.Height() );
815 // moved out of fix limit?
816 bool bSwitched = false;
817 if ( bColumn )
819 if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
821 if ( rPointPixel.X() > aWinSize.Width() )
823 if ( eWhich == SC_SPLIT_TOPLEFT )
824 pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT ), bSwitched = true;
825 else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
826 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ), bSwitched = true;
830 else // column headers
832 if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
834 if ( rPointPixel.Y() > aWinSize.Height() )
836 if ( eWhich == SC_SPLIT_TOPLEFT )
837 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT ), bSwitched = true;
838 else if ( eWhich == SC_SPLIT_TOPRIGHT )
839 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ), bSwitched = true;
843 if (bSwitched)
845 aSwitchPos = rPointPixel;
846 bDidSwitch = true;
847 return false; // do not crunch with wrong positions
850 SCsCOL nPosX;
851 SCsROW nPosY;
852 pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), pViewData->GetActivePart(),
853 nPosX, nPosY, false );
854 if (bColumn)
856 nCursorPos = static_cast<SCCOLROW>(nPosX);
857 nPosY = pViewData->GetPosY(WhichV(pViewData->GetActivePart()));
859 else
861 nCursorPos = static_cast<SCCOLROW>(nPosY);
862 nPosX = pViewData->GetPosX(WhichH(pViewData->GetActivePart()));
865 ScTabView* pView = pViewData->GetView();
866 bool bHide = pViewData->GetCurX() != nPosX ||
867 pViewData->GetCurY() != nPosY;
868 if (bHide)
869 pView->HideAllCursors();
871 if (bScroll)
872 pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE );
873 pView->SetCursor( nPosX, nPosY );
875 if ( !bAnchor || !pView->IsBlockMode() )
877 pView->DoneBlockMode( true );
878 pViewData->GetMarkData().MarkToMulti(); //! who changes this?
879 pView->InitBlockMode( nPosX, nPosY, pViewData->GetTabNo(), true, bColumn, !bColumn );
881 bAnchor = true;
884 pView->MarkCursor( nPosX, nPosY, pViewData->GetTabNo(), bColumn, !bColumn );
886 // SelectionChanged inside of HideCursor because of UpdateAutoFillMark
887 pView->SelectionChanged();
889 if (bHide)
890 pView->ShowAllCursors();
892 return true;
895 bool ScHeaderFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
897 SCsCOL nPosX;
898 SCsROW nPosY;
899 pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), pViewData->GetActivePart(),
900 nPosX, nPosY, false );
902 ScMarkData& rMark = pViewData->GetMarkData();
903 if (bColumn)
904 return rMark.IsColumnMarked( nPosX );
905 else
906 return rMark.IsRowMarked( nPosY );
909 void ScHeaderFunctionSet::DeselectAtPoint( const Point& /* rPointPixel */ )
913 void ScHeaderFunctionSet::DeselectAll()
915 pViewData->GetView()->DoneBlockMode( false );
916 bAnchor = false;
919 ScHeaderSelectionEngine::ScHeaderSelectionEngine( vcl::Window* pWindow, ScHeaderFunctionSet* pFuncSet ) :
920 SelectionEngine( pWindow, pFuncSet )
922 SetSelectionMode( MULTIPLE_SELECTION );
923 EnableDrag( false );
926 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */