Line data Source code
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 <vcl/svapp.hxx>
22 : #include <sfx2/docfile.hxx>
23 :
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>
34 :
35 : #if defined WNT
36 : #define SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN 65
37 : #endif
38 :
39 : extern sal_uInt16 nScFillModeMouseModifier; // global.cxx
40 :
41 : using namespace com::sun::star;
42 :
43 : // STATIC DATA -----------------------------------------------------------
44 :
45 52 : static Point aSwitchPos; //! Member
46 : static bool bDidSwitch = false;
47 :
48 : // View (Gridwin / keyboard)
49 348 : ScViewFunctionSet::ScViewFunctionSet( ScViewData* pNewViewData ) :
50 : pViewData( pNewViewData ),
51 : pEngine( NULL ),
52 : bAnchor( false ),
53 348 : bStarted( false )
54 : {
55 : OSL_ENSURE(pViewData, "ViewData==0 at FunctionSet");
56 348 : }
57 :
58 0 : ScSplitPos ScViewFunctionSet::GetWhich()
59 : {
60 0 : if (pEngine)
61 0 : return pEngine->GetWhich();
62 : else
63 0 : return pViewData->GetActivePart();
64 : }
65 :
66 0 : sal_uLong ScViewFunctionSet::CalcUpdateInterval( const Size& rWinSize, const Point& rEffPos,
67 : bool bLeftScroll, bool bTopScroll, bool bRightScroll, bool bBottomScroll )
68 : {
69 0 : sal_uLong nUpdateInterval = SELENG_AUTOREPEAT_INTERVAL_MAX;
70 0 : vcl::Window* pWin = pEngine->GetWindow();
71 0 : Rectangle aScrRect = pWin->GetDesktopRectPixel();
72 0 : Point aRootPos = pWin->OutputToAbsoluteScreenPixel(Point(0,0));
73 0 : if (bRightScroll)
74 : {
75 0 : double nWinRight = rWinSize.getWidth() + aRootPos.getX();
76 0 : double nMarginRight = aScrRect.GetWidth() - nWinRight;
77 0 : double nHOffset = rEffPos.X() - rWinSize.Width();
78 0 : double nHAccelRate = nHOffset / nMarginRight;
79 :
80 0 : if (nHAccelRate > 1.0)
81 0 : nHAccelRate = 1.0;
82 :
83 0 : nUpdateInterval = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nHAccelRate));
84 : }
85 :
86 0 : if (bLeftScroll)
87 : {
88 0 : double nMarginLeft = aRootPos.getX();
89 0 : double nHOffset = -rEffPos.X();
90 0 : double nHAccelRate = nHOffset / nMarginLeft;
91 :
92 0 : if (nHAccelRate > 1.0)
93 0 : nHAccelRate = 1.0;
94 :
95 0 : sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nHAccelRate));
96 0 : if (nUpdateInterval > nTmp)
97 0 : nUpdateInterval = nTmp;
98 : }
99 :
100 0 : if (bBottomScroll)
101 : {
102 0 : double nWinBottom = rWinSize.getHeight() + aRootPos.getY();
103 0 : double nMarginBottom = aScrRect.GetHeight() - nWinBottom;
104 0 : double nVOffset = rEffPos.Y() - rWinSize.Height();
105 0 : double nVAccelRate = nVOffset / nMarginBottom;
106 :
107 0 : if (nVAccelRate > 1.0)
108 0 : nVAccelRate = 1.0;
109 :
110 0 : sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nVAccelRate));
111 0 : if (nUpdateInterval > nTmp)
112 0 : nUpdateInterval = nTmp;
113 : }
114 :
115 0 : if (bTopScroll)
116 : {
117 0 : double nMarginTop = aRootPos.getY();
118 0 : double nVOffset = -rEffPos.Y();
119 0 : double nVAccelRate = nVOffset / nMarginTop;
120 :
121 0 : if (nVAccelRate > 1.0)
122 0 : nVAccelRate = 1.0;
123 :
124 0 : sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nVAccelRate));
125 0 : if (nUpdateInterval > nTmp)
126 0 : nUpdateInterval = nTmp;
127 : }
128 :
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 0 : return nUpdateInterval;
141 : }
142 :
143 348 : void ScViewFunctionSet::SetSelectionEngine( ScViewSelectionEngine* pSelEngine )
144 : {
145 348 : pEngine = pSelEngine;
146 348 : }
147 :
148 : // Drag & Drop
149 0 : void ScViewFunctionSet::BeginDrag()
150 : {
151 0 : SCTAB nTab = pViewData->GetTabNo();
152 :
153 : SCsCOL nPosX;
154 : SCsROW nPosY;
155 0 : if (pEngine)
156 : {
157 0 : Point aMPos = pEngine->GetMousePosPixel();
158 0 : pViewData->GetPosFromPixel( aMPos.X(), aMPos.Y(), GetWhich(), nPosX, nPosY );
159 : }
160 : else
161 : {
162 0 : nPosX = pViewData->GetCurX();
163 0 : nPosY = pViewData->GetCurY();
164 : }
165 :
166 0 : ScModule* pScMod = SC_MOD();
167 0 : bool bRefMode = pScMod->IsFormulaMode();
168 0 : if (!bRefMode)
169 : {
170 0 : pViewData->GetView()->FakeButtonUp( GetWhich() ); // ButtonUp is swallowed
171 :
172 0 : ScMarkData& rMark = pViewData->GetMarkData();
173 0 : rMark.MarkToSimple();
174 0 : if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
175 : {
176 0 : ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP );
177 : // bApi = TRUE -> no error messages
178 0 : bool bCopied = pViewData->GetView()->CopyToClip( pClipDoc, false, true );
179 0 : if ( bCopied )
180 : {
181 0 : sal_Int8 nDragActions = pViewData->GetView()->SelectionEditable() ?
182 : ( DND_ACTION_COPYMOVE | DND_ACTION_LINK ) :
183 0 : ( DND_ACTION_COPY | DND_ACTION_LINK );
184 :
185 0 : ScDocShell* pDocSh = pViewData->GetDocShell();
186 0 : TransferableObjectDescriptor aObjDesc;
187 0 : pDocSh->FillTransferableObjectDescriptor( aObjDesc );
188 0 : aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
189 : // maSize is set in ScTransferObj ctor
190 :
191 0 : ScTransferObj* pTransferObj = new ScTransferObj( pClipDoc, aObjDesc );
192 0 : uno::Reference<datatransfer::XTransferable> xTransferable( pTransferObj );
193 :
194 : // set position of dragged cell within range
195 0 : ScRange aMarkRange = pTransferObj->GetRange();
196 0 : SCCOL nStartX = aMarkRange.aStart.Col();
197 0 : SCROW nStartY = aMarkRange.aStart.Row();
198 0 : SCCOL nHandleX = (nPosX >= (SCsCOL) nStartX) ? nPosX - nStartX : 0;
199 0 : SCROW nHandleY = (nPosY >= (SCsROW) nStartY) ? nPosY - nStartY : 0;
200 0 : pTransferObj->SetDragHandlePos( nHandleX, nHandleY );
201 0 : pTransferObj->SetVisibleTab( nTab );
202 :
203 0 : pTransferObj->SetDragSource( pDocSh, rMark );
204 :
205 0 : vcl::Window* pWindow = pViewData->GetActiveWin();
206 0 : if ( pWindow->IsTracking() )
207 0 : pWindow->EndTracking( TrackingEventFlags::Cancel ); // abort selecting
208 :
209 0 : SC_MOD()->SetDragObject( pTransferObj, NULL ); // for internal D&D
210 0 : pTransferObj->StartDrag( pWindow, nDragActions );
211 :
212 0 : return; // dragging started
213 : }
214 : else
215 0 : delete pClipDoc;
216 : }
217 : }
218 :
219 : }
220 :
221 : // Selection
222 0 : void ScViewFunctionSet::CreateAnchor()
223 : {
224 0 : if (bAnchor) return;
225 :
226 0 : bool bRefMode = SC_MOD()->IsFormulaMode();
227 0 : if (bRefMode)
228 0 : SetAnchor( pViewData->GetRefStartX(), pViewData->GetRefStartY() );
229 : else
230 0 : SetAnchor( pViewData->GetCurX(), pViewData->GetCurY() );
231 : }
232 :
233 0 : void ScViewFunctionSet::SetAnchor( SCCOL nPosX, SCROW nPosY )
234 : {
235 0 : bool bRefMode = SC_MOD()->IsFormulaMode();
236 0 : ScTabView* pView = pViewData->GetView();
237 0 : SCTAB nTab = pViewData->GetTabNo();
238 :
239 0 : if (bRefMode)
240 : {
241 0 : pView->DoneRefMode( false );
242 0 : aAnchorPos.Set( nPosX, nPosY, nTab );
243 0 : pView->InitRefMode( aAnchorPos.Col(), aAnchorPos.Row(), aAnchorPos.Tab(),
244 0 : SC_REFTYPE_REF );
245 0 : bStarted = true;
246 : }
247 0 : else if (pViewData->IsAnyFillMode())
248 : {
249 0 : aAnchorPos.Set( nPosX, nPosY, nTab );
250 0 : bStarted = true;
251 : }
252 : else
253 : {
254 : // don't go there and back again
255 0 : if ( bStarted && pView->IsMarking( nPosX, nPosY, nTab ) )
256 : {
257 : // don't do anything
258 : }
259 : else
260 : {
261 0 : pView->DoneBlockMode( true );
262 0 : aAnchorPos.Set( nPosX, nPosY, nTab );
263 0 : ScMarkData& rMark = pViewData->GetMarkData();
264 0 : if ( rMark.IsMarked() || rMark.IsMultiMarked() )
265 : {
266 0 : pView->InitBlockMode( aAnchorPos.Col(), aAnchorPos.Row(),
267 0 : aAnchorPos.Tab(), true );
268 0 : bStarted = true;
269 : }
270 : else
271 0 : bStarted = false;
272 : }
273 : }
274 0 : bAnchor = true;
275 0 : }
276 :
277 0 : void ScViewFunctionSet::DestroyAnchor()
278 : {
279 0 : bool bRefMode = SC_MOD()->IsFormulaMode();
280 0 : if (bRefMode)
281 0 : pViewData->GetView()->DoneRefMode( true );
282 : else
283 0 : pViewData->GetView()->DoneBlockMode( true );
284 :
285 0 : bAnchor = false;
286 0 : }
287 :
288 0 : void ScViewFunctionSet::SetAnchorFlag( bool bSet )
289 : {
290 0 : bAnchor = bSet;
291 0 : }
292 :
293 0 : bool ScViewFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool /* bDontSelectAtCursor */ )
294 : {
295 0 : if ( bDidSwitch )
296 : {
297 0 : if ( rPointPixel == aSwitchPos )
298 0 : return false; // don't scroll in wrong window
299 : else
300 0 : bDidSwitch = false;
301 : }
302 0 : aSwitchPos = rPointPixel; // only important, if bDidSwitch
303 :
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)
307 :
308 0 : Point aEffPos = rPointPixel;
309 0 : if ( aEffPos.X() == 0 )
310 0 : aEffPos.X() = -1;
311 0 : if ( aEffPos.Y() == 0 )
312 0 : aEffPos.Y() = -1;
313 :
314 : // Scrolling
315 0 : Size aWinSize = pEngine->GetWindow()->GetOutputSizePixel();
316 0 : bool bRightScroll = ( aEffPos.X() >= aWinSize.Width() );
317 0 : bool bLeftScroll = ( aEffPos.X() < 0 );
318 0 : bool bBottomScroll = ( aEffPos.Y() >= aWinSize.Height() );
319 0 : bool bTopScroll = ( aEffPos.Y() < 0 );
320 0 : bool bScroll = bRightScroll || bBottomScroll || bLeftScroll || bTopScroll;
321 :
322 : SCsCOL nPosX;
323 : SCsROW nPosY;
324 0 : pViewData->GetPosFromPixel( aEffPos.X(), aEffPos.Y(), GetWhich(),
325 0 : nPosX, nPosY, true, true ); // with Repair
326 :
327 : // for Autofill switch in the center of cell
328 : // thereby don't prevent scrolling to bottom/right
329 0 : if ( pViewData->IsFillMode() || pViewData->GetFillMode() == SC_FILL_MATRIX )
330 : {
331 : bool bLeft, bTop;
332 0 : pViewData->GetMouseQuadrant( aEffPos, GetWhich(), nPosX, nPosY, bLeft, bTop );
333 0 : ScDocument* pDoc = pViewData->GetDocument();
334 0 : SCTAB nTab = pViewData->GetTabNo();
335 0 : if ( bLeft && !bRightScroll )
336 0 : do --nPosX; while ( nPosX>=0 && pDoc->ColHidden( nPosX, nTab ) );
337 0 : if ( bTop && !bBottomScroll )
338 : {
339 0 : if (--nPosY >= 0)
340 : {
341 0 : nPosY = pDoc->LastVisibleRow(0, nPosY, nTab);
342 0 : if (!ValidRow(nPosY))
343 0 : nPosY = -1;
344 : }
345 : }
346 : // negative value is allowed
347 : }
348 :
349 : // moved out of fix limit?
350 0 : ScSplitPos eWhich = GetWhich();
351 0 : if ( eWhich == pViewData->GetActivePart() )
352 : {
353 0 : if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
354 0 : if ( aEffPos.X() >= aWinSize.Width() )
355 : {
356 0 : if ( eWhich == SC_SPLIT_TOPLEFT )
357 0 : pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT ), bScroll = false, bDidSwitch = true;
358 0 : else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
359 0 : pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ), bScroll = false, bDidSwitch = true;
360 : }
361 :
362 0 : if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
363 0 : if ( aEffPos.Y() >= aWinSize.Height() )
364 : {
365 0 : if ( eWhich == SC_SPLIT_TOPLEFT )
366 0 : pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT ), bScroll = false, bDidSwitch = true;
367 0 : else if ( eWhich == SC_SPLIT_TOPRIGHT )
368 0 : pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ), bScroll = false, bDidSwitch = true;
369 : }
370 : }
371 :
372 0 : if (bScroll)
373 : {
374 : // Adjust update interval based on how far the mouse pointer is from the edge.
375 : sal_uLong nUpdateInterval = CalcUpdateInterval(
376 0 : aWinSize, aEffPos, bLeftScroll, bTopScroll, bRightScroll, bBottomScroll);
377 0 : pEngine->SetUpdateInterval(nUpdateInterval);
378 : }
379 : else
380 : {
381 : // Don't forget to reset the interval when not scrolling!
382 0 : pEngine->SetUpdateInterval(SELENG_AUTOREPEAT_INTERVAL);
383 : }
384 :
385 0 : pViewData->ResetOldCursor();
386 0 : return SetCursorAtCell( nPosX, nPosY, bScroll );
387 : }
388 :
389 86 : bool ScViewFunctionSet::SetCursorAtCell( SCsCOL nPosX, SCsROW nPosY, bool bScroll )
390 : {
391 86 : ScTabView* pView = pViewData->GetView();
392 86 : SCTAB nTab = pViewData->GetTabNo();
393 86 : ScDocument* pDoc = pViewData->GetDocument();
394 :
395 86 : if ( pDoc->IsTabProtected(nTab) )
396 : {
397 0 : if (nPosX < 0 || nPosY < 0)
398 0 : return false;
399 :
400 0 : ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
401 0 : if (!pProtect)
402 0 : return false;
403 :
404 0 : bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
405 0 : bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
406 :
407 0 : if ( bSkipProtected && bSkipUnprotected )
408 0 : return false;
409 :
410 0 : bool bCellProtected = pDoc->HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HASATTR_PROTECTED);
411 0 : if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) )
412 : // Don't select this cell!
413 0 : return false;
414 : }
415 :
416 86 : ScModule* pScMod = SC_MOD();
417 86 : ScTabViewShell* pViewShell = pViewData->GetViewShell();
418 86 : bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
419 :
420 241 : bool bHide = !bRefMode && !pViewData->IsAnyFillMode() &&
421 223 : ( nPosX != (SCsCOL) pViewData->GetCurX() || nPosY != (SCsROW) pViewData->GetCurY() );
422 :
423 86 : if (bHide)
424 69 : pView->HideAllCursors();
425 :
426 86 : if (bScroll)
427 : {
428 0 : if (bRefMode)
429 : {
430 0 : ScSplitPos eWhich = GetWhich();
431 0 : pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE, &eWhich );
432 : }
433 : else
434 0 : pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE );
435 : }
436 :
437 86 : if (bRefMode)
438 : {
439 : // if no input is possible from this doc, don't move the reference cursor around
440 0 : if ( !pScMod->IsModalMode(pViewData->GetSfxDocShell()) )
441 : {
442 0 : if (!bAnchor)
443 : {
444 0 : pView->DoneRefMode( true );
445 0 : pView->InitRefMode( nPosX, nPosY, pViewData->GetTabNo(), SC_REFTYPE_REF );
446 : }
447 :
448 0 : pView->UpdateRef( nPosX, nPosY, pViewData->GetTabNo() );
449 0 : pView->SelectionChanged();
450 : }
451 : }
452 172 : else if (pViewData->IsFillMode() ||
453 86 : (pViewData->GetFillMode() == SC_FILL_MATRIX && (nScFillModeMouseModifier & KEY_MOD1) ))
454 : {
455 : // If a matrix got touched, switch back to Autofill is possible with Ctrl
456 :
457 : SCCOL nStartX, nEndX;
458 : SCROW nStartY, nEndY; // Block
459 : SCTAB nDummy;
460 0 : pViewData->GetSimpleArea( nStartX, nStartY, nDummy, nEndX, nEndY, nDummy );
461 :
462 0 : if (pViewData->GetRefType() != SC_REFTYPE_FILL)
463 : {
464 0 : pView->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
465 0 : CreateAnchor();
466 : }
467 :
468 0 : ScRange aDelRange;
469 0 : bool bOldDelMark = pViewData->GetDelMark( aDelRange );
470 :
471 0 : if ( nPosX+1 >= (SCsCOL) nStartX && nPosX <= (SCsCOL) nEndX &&
472 0 : nPosY+1 >= (SCsROW) nStartY && nPosY <= (SCsROW) nEndY &&
473 0 : ( nPosX != nEndX || nPosY != nEndY ) ) // minimize?
474 : {
475 : // direction (left or top)
476 :
477 0 : long nSizeX = 0;
478 0 : for (SCCOL i=nPosX+1; i<=nEndX; i++)
479 0 : nSizeX += pDoc->GetColWidth( i, nTab );
480 0 : long nSizeY = (long) pDoc->GetRowHeight( nPosY+1, nEndY, nTab );
481 :
482 0 : SCCOL nDelStartX = nStartX;
483 0 : SCROW nDelStartY = nStartY;
484 0 : if ( nSizeX > nSizeY )
485 0 : nDelStartX = nPosX + 1;
486 : else
487 0 : nDelStartY = nPosY + 1;
488 : // there is no need to check for zero, because nPosX/Y is also negative
489 :
490 0 : if ( nDelStartX < nStartX )
491 0 : nDelStartX = nStartX;
492 0 : if ( nDelStartY < nStartY )
493 0 : nDelStartY = nStartY;
494 :
495 : // set range
496 :
497 : pViewData->SetDelMark( ScRange( nDelStartX,nDelStartY,nTab,
498 0 : nEndX,nEndY,nTab ) );
499 0 : pViewData->GetView()->UpdateShrinkOverlay();
500 :
501 0 : pViewData->GetView()->
502 0 : PaintArea( nStartX,nDelStartY, nEndX,nEndY, SC_UPDATE_MARKS );
503 :
504 0 : nPosX = nEndX; // keep red border around range
505 0 : nPosY = nEndY;
506 :
507 : // reference the right way up, if it's upside down below
508 0 : if ( nStartX != pViewData->GetRefStartX() || nStartY != pViewData->GetRefStartY() )
509 : {
510 0 : pViewData->GetView()->DoneRefMode();
511 0 : pViewData->GetView()->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
512 0 : }
513 : }
514 : else
515 : {
516 0 : if ( bOldDelMark )
517 : {
518 0 : pViewData->ResetDelMark();
519 0 : pViewData->GetView()->UpdateShrinkOverlay();
520 : }
521 :
522 0 : bool bNegX = ( nPosX < (SCsCOL) nStartX );
523 0 : bool bNegY = ( nPosY < (SCsROW) nStartY );
524 :
525 0 : long nSizeX = 0;
526 0 : if ( bNegX )
527 : {
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 0 : do ++nPosX; while ( nPosX<nStartX && pDoc->ColHidden(nPosX, nTab) );
531 0 : for (SCCOL i=nPosX; i<nStartX; i++)
532 0 : nSizeX += pDoc->GetColWidth( i, nTab );
533 : }
534 : else
535 0 : for (SCCOL i=nEndX+1; i<=nPosX; i++)
536 0 : nSizeX += pDoc->GetColWidth( i, nTab );
537 :
538 0 : long nSizeY = 0;
539 0 : if ( bNegY )
540 : {
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 0 : if (++nPosY < nStartY)
544 : {
545 0 : nPosY = pDoc->FirstVisibleRow(nPosY, nStartY-1, nTab);
546 0 : if (!ValidRow(nPosY))
547 0 : nPosY = nStartY;
548 : }
549 0 : nSizeY += pDoc->GetRowHeight( nPosY, nStartY-1, nTab );
550 : }
551 : else
552 0 : nSizeY += pDoc->GetRowHeight( nEndY+1, nPosY, nTab );
553 :
554 0 : if ( nSizeX > nSizeY ) // Fill only ever in one direction
555 : {
556 0 : nPosY = nEndY;
557 0 : bNegY = false;
558 : }
559 : else
560 : {
561 0 : nPosX = nEndX;
562 0 : bNegX = false;
563 : }
564 :
565 0 : SCCOL nRefStX = bNegX ? nEndX : nStartX;
566 0 : SCROW nRefStY = bNegY ? nEndY : nStartY;
567 0 : if ( nRefStX != pViewData->GetRefStartX() || nRefStY != pViewData->GetRefStartY() )
568 : {
569 0 : pViewData->GetView()->DoneRefMode();
570 0 : pViewData->GetView()->InitRefMode( nRefStX, nRefStY, nTab, SC_REFTYPE_FILL );
571 : }
572 : }
573 :
574 0 : pView->UpdateRef( nPosX, nPosY, nTab );
575 : }
576 86 : else if (pViewData->IsAnyFillMode())
577 : {
578 0 : sal_uInt8 nMode = pViewData->GetFillMode();
579 0 : if ( nMode == SC_FILL_EMBED_LT || nMode == SC_FILL_EMBED_RB )
580 : {
581 : OSL_ENSURE( pDoc->IsEmbedded(), "!pDoc->IsEmbedded()" );
582 0 : ScRange aRange;
583 0 : pDoc->GetEmbedded( aRange);
584 0 : ScRefType eRefMode = (nMode == SC_FILL_EMBED_LT) ? SC_REFTYPE_EMBED_LT : SC_REFTYPE_EMBED_RB;
585 0 : if (pViewData->GetRefType() != eRefMode)
586 : {
587 0 : if ( nMode == SC_FILL_EMBED_LT )
588 0 : pView->InitRefMode( aRange.aEnd.Col(), aRange.aEnd.Row(), nTab, eRefMode );
589 : else
590 0 : pView->InitRefMode( aRange.aStart.Col(), aRange.aStart.Row(), nTab, eRefMode );
591 0 : CreateAnchor();
592 : }
593 :
594 0 : pView->UpdateRef( nPosX, nPosY, nTab );
595 : }
596 0 : else if ( nMode == SC_FILL_MATRIX )
597 : {
598 : SCCOL nStartX, nEndX;
599 : SCROW nStartY, nEndY; // Block
600 : SCTAB nDummy;
601 0 : pViewData->GetSimpleArea( nStartX, nStartY, nDummy, nEndX, nEndY, nDummy );
602 :
603 0 : if (pViewData->GetRefType() != SC_REFTYPE_FILL)
604 : {
605 0 : pView->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
606 0 : CreateAnchor();
607 : }
608 :
609 0 : if ( nPosX < nStartX ) nPosX = nStartX;
610 0 : if ( nPosY < nStartY ) nPosY = nStartY;
611 :
612 0 : pView->UpdateRef( nPosX, nPosY, nTab );
613 : }
614 : // else new modes
615 : }
616 : else // regular selection
617 : {
618 86 : bool bHideCur = bAnchor && ( (SCCOL)nPosX != pViewData->GetCurX() ||
619 86 : (SCROW)nPosY != pViewData->GetCurY() );
620 86 : if (bHideCur)
621 0 : pView->HideAllCursors(); // otherwise twice: Block and SetCursor
622 :
623 86 : if (bAnchor)
624 : {
625 0 : if (!bStarted)
626 : {
627 0 : bool bMove = ( nPosX != (SCsCOL) aAnchorPos.Col() ||
628 0 : nPosY != (SCsROW) aAnchorPos.Row() );
629 0 : if ( bMove || ( pEngine && pEngine->GetMouseEvent().IsShift() ) )
630 : {
631 0 : pView->InitBlockMode( aAnchorPos.Col(), aAnchorPos.Row(),
632 0 : aAnchorPos.Tab(), true );
633 0 : bStarted = true;
634 : }
635 : }
636 0 : if (bStarted)
637 : // If the selection is already started, don't set the cursor.
638 0 : pView->MarkCursor( (SCCOL) nPosX, (SCROW) nPosY, nTab, false, false, true );
639 : else
640 0 : pView->SetCursor( (SCCOL) nPosX, (SCROW) nPosY );
641 : }
642 : else
643 : {
644 86 : ScMarkData& rMark = pViewData->GetMarkData();
645 86 : if (rMark.IsMarked() || rMark.IsMultiMarked())
646 : {
647 0 : pView->DoneBlockMode(true);
648 0 : pView->InitBlockMode( nPosX, nPosY, nTab, true );
649 0 : pView->MarkCursor( (SCCOL) nPosX, (SCROW) nPosY, nTab );
650 :
651 0 : aAnchorPos.Set( nPosX, nPosY, nTab );
652 0 : bStarted = true;
653 : }
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 86 : else if ( pViewData->IsSelCtrlMouseClick() )
659 : {
660 0 : SCCOL nOldX = pViewData->GetCurX();
661 0 : SCROW nOldY = pViewData->GetCurY();
662 :
663 0 : pView->InitBlockMode( nOldX, nOldY, nTab, true );
664 0 : pView->MarkCursor( (SCCOL) nOldX, (SCROW) nOldY, nTab );
665 :
666 0 : if ( nOldX != nPosX || nOldY != nPosY )
667 : {
668 0 : pView->DoneBlockMode( true );
669 0 : pView->InitBlockMode( nPosX, nPosY, nTab, true );
670 0 : pView->MarkCursor( (SCCOL) nPosX, (SCROW) nPosY, nTab );
671 0 : aAnchorPos.Set( nPosX, nPosY, nTab );
672 : }
673 :
674 0 : bStarted = true;
675 : }
676 86 : pView->SetCursor( (SCCOL) nPosX, (SCROW) nPosY );
677 : }
678 :
679 86 : pViewData->SetRefStart( nPosX, nPosY, nTab );
680 86 : if (bHideCur)
681 0 : pView->ShowAllCursors();
682 : }
683 :
684 86 : if (bHide)
685 69 : pView->ShowAllCursors();
686 :
687 86 : return true;
688 : }
689 :
690 0 : bool ScViewFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
691 : {
692 0 : bool bRefMode = SC_MOD()->IsFormulaMode();
693 0 : if (bRefMode)
694 0 : return false;
695 :
696 0 : if (pViewData->IsAnyFillMode())
697 0 : return false;
698 :
699 0 : ScMarkData& rMark = pViewData->GetMarkData();
700 0 : if (bAnchor || !rMark.IsMultiMarked())
701 : {
702 : SCsCOL nPosX;
703 : SCsROW nPosY;
704 0 : pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), GetWhich(), nPosX, nPosY );
705 0 : return pViewData->GetMarkData().IsCellMarked( (SCCOL) nPosX, (SCROW) nPosY );
706 : }
707 :
708 0 : return false;
709 : }
710 :
711 0 : void ScViewFunctionSet::DeselectAtPoint( const Point& /* rPointPixel */ )
712 : {
713 : // doesn't exist
714 0 : }
715 :
716 190 : void ScViewFunctionSet::DeselectAll()
717 : {
718 190 : if (pViewData->IsAnyFillMode())
719 190 : return;
720 :
721 190 : bool bRefMode = SC_MOD()->IsFormulaMode();
722 190 : if (bRefMode)
723 : {
724 0 : pViewData->GetView()->DoneRefMode( false );
725 : }
726 : else
727 : {
728 190 : pViewData->GetView()->DoneBlockMode( false );
729 190 : pViewData->GetViewShell()->UpdateInputHandler();
730 : }
731 :
732 190 : bAnchor = false;
733 : }
734 :
735 348 : ScViewSelectionEngine::ScViewSelectionEngine( vcl::Window* pWindow, ScTabView* pView,
736 : ScSplitPos eSplitPos ) :
737 348 : SelectionEngine( pWindow, &pView->GetFunctionSet() ),
738 348 : eWhich( eSplitPos )
739 : {
740 348 : SetSelectionMode( MULTIPLE_SELECTION );
741 348 : EnableDrag( true );
742 348 : }
743 :
744 : // column and row headers
745 348 : ScHeaderFunctionSet::ScHeaderFunctionSet( ScViewData* pNewViewData ) :
746 : pViewData( pNewViewData ),
747 : bColumn( false ),
748 : eWhich( SC_SPLIT_TOPLEFT ),
749 : bAnchor( false ),
750 348 : nCursorPos( 0 )
751 : {
752 : OSL_ENSURE(pViewData, "ViewData==0 at FunctionSet");
753 348 : }
754 :
755 0 : void ScHeaderFunctionSet::SetColumn( bool bSet )
756 : {
757 0 : bColumn = bSet;
758 0 : }
759 :
760 8 : void ScHeaderFunctionSet::SetWhich( ScSplitPos eNew )
761 : {
762 8 : eWhich = eNew;
763 8 : }
764 :
765 0 : void ScHeaderFunctionSet::BeginDrag()
766 : {
767 : // doesn't exist
768 0 : }
769 :
770 0 : void ScHeaderFunctionSet::CreateAnchor()
771 : {
772 0 : if (bAnchor)
773 0 : return;
774 :
775 0 : ScTabView* pView = pViewData->GetView();
776 0 : pView->DoneBlockMode( true );
777 0 : if (bColumn)
778 : {
779 0 : pView->InitBlockMode( static_cast<SCCOL>(nCursorPos), 0, pViewData->GetTabNo(), true, true, false );
780 0 : pView->MarkCursor( static_cast<SCCOL>(nCursorPos), MAXROW, pViewData->GetTabNo() );
781 : }
782 : else
783 : {
784 0 : pView->InitBlockMode( 0, nCursorPos, pViewData->GetTabNo(), true, false, true );
785 0 : pView->MarkCursor( MAXCOL, nCursorPos, pViewData->GetTabNo() );
786 : }
787 0 : bAnchor = true;
788 : }
789 :
790 0 : void ScHeaderFunctionSet::DestroyAnchor()
791 : {
792 0 : pViewData->GetView()->DoneBlockMode( true );
793 0 : bAnchor = false;
794 0 : }
795 :
796 0 : bool ScHeaderFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool /* bDontSelectAtCursor */ )
797 : {
798 0 : if ( bDidSwitch )
799 : {
800 : // next valid position has to be originated from another window
801 0 : if ( rPointPixel == aSwitchPos )
802 0 : return false; // don't scroll in the wrong window
803 : else
804 0 : bDidSwitch = false;
805 : }
806 :
807 : // Scrolling
808 0 : Size aWinSize = pViewData->GetActiveWin()->GetOutputSizePixel();
809 : bool bScroll;
810 0 : if (bColumn)
811 0 : bScroll = ( rPointPixel.X() < 0 || rPointPixel.X() >= aWinSize.Width() );
812 : else
813 0 : bScroll = ( rPointPixel.Y() < 0 || rPointPixel.Y() >= aWinSize.Height() );
814 :
815 : // moved out of fix limit?
816 0 : bool bSwitched = false;
817 0 : if ( bColumn )
818 : {
819 0 : if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
820 : {
821 0 : if ( rPointPixel.X() > aWinSize.Width() )
822 : {
823 0 : if ( eWhich == SC_SPLIT_TOPLEFT )
824 0 : pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT ), bSwitched = true;
825 0 : else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
826 0 : pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ), bSwitched = true;
827 : }
828 : }
829 : }
830 : else // column headers
831 : {
832 0 : if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
833 : {
834 0 : if ( rPointPixel.Y() > aWinSize.Height() )
835 : {
836 0 : if ( eWhich == SC_SPLIT_TOPLEFT )
837 0 : pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT ), bSwitched = true;
838 0 : else if ( eWhich == SC_SPLIT_TOPRIGHT )
839 0 : pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ), bSwitched = true;
840 : }
841 : }
842 : }
843 0 : if (bSwitched)
844 : {
845 0 : aSwitchPos = rPointPixel;
846 0 : bDidSwitch = true;
847 0 : return false; // do not crunch with wrong positions
848 : }
849 :
850 : SCsCOL nPosX;
851 : SCsROW nPosY;
852 : pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), pViewData->GetActivePart(),
853 0 : nPosX, nPosY, false );
854 0 : if (bColumn)
855 : {
856 0 : nCursorPos = static_cast<SCCOLROW>(nPosX);
857 0 : nPosY = pViewData->GetPosY(WhichV(pViewData->GetActivePart()));
858 : }
859 : else
860 : {
861 0 : nCursorPos = static_cast<SCCOLROW>(nPosY);
862 0 : nPosX = pViewData->GetPosX(WhichH(pViewData->GetActivePart()));
863 : }
864 :
865 0 : ScTabView* pView = pViewData->GetView();
866 0 : bool bHide = pViewData->GetCurX() != nPosX ||
867 0 : pViewData->GetCurY() != nPosY;
868 0 : if (bHide)
869 0 : pView->HideAllCursors();
870 :
871 0 : if (bScroll)
872 0 : pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE );
873 0 : pView->SetCursor( nPosX, nPosY );
874 :
875 0 : if ( !bAnchor || !pView->IsBlockMode() )
876 : {
877 0 : pView->DoneBlockMode( true );
878 0 : pViewData->GetMarkData().MarkToMulti(); //! who changes this?
879 0 : pView->InitBlockMode( nPosX, nPosY, pViewData->GetTabNo(), true, bColumn, !bColumn );
880 :
881 0 : bAnchor = true;
882 : }
883 :
884 0 : pView->MarkCursor( nPosX, nPosY, pViewData->GetTabNo(), bColumn, !bColumn );
885 :
886 : // SelectionChanged inside of HideCursor because of UpdateAutoFillMark
887 0 : pView->SelectionChanged();
888 :
889 0 : if (bHide)
890 0 : pView->ShowAllCursors();
891 :
892 0 : return true;
893 : }
894 :
895 0 : bool ScHeaderFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
896 : {
897 : SCsCOL nPosX;
898 : SCsROW nPosY;
899 : pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), pViewData->GetActivePart(),
900 0 : nPosX, nPosY, false );
901 :
902 0 : ScMarkData& rMark = pViewData->GetMarkData();
903 0 : if (bColumn)
904 0 : return rMark.IsColumnMarked( nPosX );
905 : else
906 0 : return rMark.IsRowMarked( nPosY );
907 : }
908 :
909 0 : void ScHeaderFunctionSet::DeselectAtPoint( const Point& /* rPointPixel */ )
910 : {
911 0 : }
912 :
913 0 : void ScHeaderFunctionSet::DeselectAll()
914 : {
915 0 : pViewData->GetView()->DoneBlockMode( false );
916 0 : bAnchor = false;
917 0 : }
918 :
919 348 : ScHeaderSelectionEngine::ScHeaderSelectionEngine( vcl::Window* pWindow, ScHeaderFunctionSet* pFuncSet ) :
920 348 : SelectionEngine( pWindow, pFuncSet )
921 : {
922 348 : SetSelectionMode( MULTIPLE_SELECTION );
923 348 : EnableDrag( false );
924 504 : }
925 :
926 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|