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