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