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