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 :
21 : #include <vcl/window.hxx>
22 : #include <vcl/seleng.hxx>
23 : #include <tools/debug.hxx>
24 :
25 3917 : FunctionSet::~FunctionSet()
26 : {
27 3917 : }
28 :
29 :
30 0 : inline sal_Bool SelectionEngine::ShouldDeselect( sal_Bool bModifierKey1 ) const
31 : {
32 : // return !( eSelMode == MULTIPLE_SELECTION && bModifierKey1 );
33 0 : return eSelMode != MULTIPLE_SELECTION || !bModifierKey1;
34 : }
35 :
36 :
37 : // TODO: FunctionSet::SelectAtPoint raus
38 :
39 : /*************************************************************************
40 : |*
41 : |* SelectionEngine::SelectionEngine()
42 : |*
43 : *************************************************************************/
44 :
45 4318 : SelectionEngine::SelectionEngine( Window* pWindow, FunctionSet* pFuncSet,
46 : sal_uLong nAutoRepeatInterval ) :
47 : pWin( pWindow ),
48 4318 : nUpdateInterval( nAutoRepeatInterval )
49 : {
50 4318 : eSelMode = SINGLE_SELECTION;
51 4318 : pFunctionSet = pFuncSet;
52 4318 : nFlags = SELENG_EXPANDONMOVE;
53 4318 : nLockedMods = 0;
54 :
55 4318 : aWTimer.SetTimeoutHdl( LINK( this, SelectionEngine, ImpWatchDog ) );
56 4318 : aWTimer.SetTimeout( nUpdateInterval );
57 4318 : }
58 :
59 : /*************************************************************************
60 : |*
61 : |* SelectionEngine::~SelectionEngine()
62 : |*
63 : *************************************************************************/
64 :
65 7834 : SelectionEngine::~SelectionEngine()
66 : {
67 3917 : aWTimer.Stop();
68 3917 : }
69 :
70 : /*************************************************************************
71 : |*
72 : |* SelectionEngine::ImpWatchDog()
73 : |*
74 : *************************************************************************/
75 :
76 0 : IMPL_LINK_NOARG(SelectionEngine, ImpWatchDog)
77 : {
78 0 : if ( !aArea.IsInside( aLastMove.GetPosPixel() ) )
79 0 : SelMouseMove( aLastMove );
80 0 : return 0;
81 : }
82 :
83 : /*************************************************************************
84 : |*
85 : |* SelectionEngine::SetSelectionMode()
86 : |*
87 : *************************************************************************/
88 :
89 4318 : void SelectionEngine::SetSelectionMode( SelectionMode eMode )
90 : {
91 4318 : eSelMode = eMode;
92 4318 : }
93 :
94 : /*************************************************************************
95 : |*
96 : |* SelectionEngine::CursorPosChanging()
97 : |*
98 : *************************************************************************/
99 :
100 0 : void SelectionEngine::CursorPosChanging( sal_Bool bShift, sal_Bool bMod1 )
101 : {
102 0 : if ( !pFunctionSet )
103 0 : return;
104 :
105 0 : if ( bShift && eSelMode != SINGLE_SELECTION )
106 : {
107 0 : if ( IsAddMode() )
108 : {
109 0 : if ( !(nFlags & SELENG_HAS_ANCH) )
110 : {
111 0 : pFunctionSet->CreateAnchor();
112 0 : nFlags |= SELENG_HAS_ANCH;
113 : }
114 : }
115 : else
116 : {
117 0 : if ( !(nFlags & SELENG_HAS_ANCH) )
118 : {
119 0 : if( ShouldDeselect( bMod1 ) )
120 0 : pFunctionSet->DeselectAll();
121 0 : pFunctionSet->CreateAnchor();
122 0 : nFlags |= SELENG_HAS_ANCH;
123 : }
124 : }
125 : }
126 : else
127 : {
128 0 : if ( IsAddMode() )
129 : {
130 0 : if ( nFlags & SELENG_HAS_ANCH )
131 : {
132 : // pFunctionSet->CreateCursor();
133 0 : pFunctionSet->DestroyAnchor();
134 0 : nFlags &= (~SELENG_HAS_ANCH);
135 : }
136 : }
137 : else
138 : {
139 0 : if( ShouldDeselect( bMod1 ) )
140 0 : pFunctionSet->DeselectAll();
141 : else
142 0 : pFunctionSet->DestroyAnchor();
143 0 : nFlags &= (~SELENG_HAS_ANCH);
144 : }
145 : }
146 : }
147 :
148 : /*************************************************************************
149 : |*
150 : |* SelectionEngine::SelMouseButtonDown()
151 : |*
152 : *************************************************************************/
153 :
154 0 : sal_Bool SelectionEngine::SelMouseButtonDown( const MouseEvent& rMEvt )
155 : {
156 0 : nFlags &= (~SELENG_CMDEVT);
157 0 : if ( !pFunctionSet || !pWin || rMEvt.GetClicks() > 1 || rMEvt.IsRight() )
158 0 : return sal_False;
159 :
160 0 : sal_uInt16 nModifier = rMEvt.GetModifier() | nLockedMods;
161 0 : if ( nModifier & KEY_MOD2 )
162 0 : return sal_False;
163 : // in SingleSelection: Control-Taste filtern (damit auch
164 : // mit Ctrl-Click ein D&D gestartet werden kann)
165 0 : if ( nModifier == KEY_MOD1 && eSelMode == SINGLE_SELECTION )
166 0 : nModifier = 0;
167 :
168 0 : Point aPos = rMEvt.GetPosPixel();
169 0 : aLastMove = rMEvt;
170 :
171 0 : if( !rMEvt.IsRight() )
172 : {
173 0 : pWin->CaptureMouse();
174 0 : nFlags |= SELENG_IN_SEL;
175 : }
176 : else
177 : {
178 0 : nModifier = 0;
179 : }
180 :
181 0 : switch ( nModifier )
182 : {
183 : case 0: // KEY_NO_KEY
184 : {
185 0 : sal_Bool bSelAtPoint = pFunctionSet->IsSelectionAtPoint( aPos );
186 0 : nFlags &= (~SELENG_IN_ADD);
187 0 : if ( (nFlags & SELENG_DRG_ENAB) && bSelAtPoint )
188 : {
189 0 : nFlags |= SELENG_WAIT_UPEVT;
190 0 : nFlags &= ~(SELENG_IN_SEL);
191 0 : pWin->ReleaseMouse();
192 0 : return sal_True; //auf STARTDRAG-Command-Event warten
193 : }
194 0 : if ( eSelMode != SINGLE_SELECTION )
195 : {
196 0 : if( !IsAddMode() )
197 0 : pFunctionSet->DeselectAll();
198 : else
199 0 : pFunctionSet->DestroyAnchor();
200 0 : nFlags &= (~SELENG_HAS_ANCH); // bHasAnchor = sal_False;
201 : }
202 0 : pFunctionSet->SetCursorAtPoint( aPos );
203 : // Sonderbehandlung Single-Selection, damit Select+Drag
204 : // in einem Zug moeglich ist
205 0 : if (eSelMode == SINGLE_SELECTION && (nFlags & SELENG_DRG_ENAB))
206 0 : nFlags |= SELENG_WAIT_UPEVT;
207 0 : return sal_True;
208 : }
209 :
210 : case KEY_SHIFT:
211 0 : if ( eSelMode == SINGLE_SELECTION )
212 : {
213 0 : pWin->ReleaseMouse();
214 0 : nFlags &= (~SELENG_IN_SEL);
215 0 : return sal_False;
216 : }
217 0 : if ( nFlags & SELENG_ADD_ALW )
218 0 : nFlags |= SELENG_IN_ADD;
219 : else
220 0 : nFlags &= (~SELENG_IN_ADD);
221 :
222 0 : if( !(nFlags & SELENG_HAS_ANCH) )
223 : {
224 0 : if ( !(nFlags & SELENG_IN_ADD) )
225 0 : pFunctionSet->DeselectAll();
226 0 : pFunctionSet->CreateAnchor();
227 0 : nFlags |= SELENG_HAS_ANCH;
228 : }
229 0 : pFunctionSet->SetCursorAtPoint( aPos );
230 0 : return sal_True;
231 :
232 : case KEY_MOD1:
233 : // Control nur bei Mehrfachselektion erlaubt
234 0 : if ( eSelMode != MULTIPLE_SELECTION )
235 : {
236 0 : nFlags &= (~SELENG_IN_SEL);
237 0 : pWin->ReleaseMouse();
238 0 : return sal_True; // Mausclick verschlucken
239 : }
240 0 : if ( nFlags & SELENG_HAS_ANCH )
241 : {
242 : // pFunctionSet->CreateCursor();
243 0 : pFunctionSet->DestroyAnchor();
244 0 : nFlags &= (~SELENG_HAS_ANCH);
245 : }
246 0 : if ( pFunctionSet->IsSelectionAtPoint( aPos ) )
247 : {
248 0 : pFunctionSet->DeselectAtPoint( aPos );
249 0 : pFunctionSet->SetCursorAtPoint( aPos, sal_True );
250 : }
251 : else
252 : {
253 0 : pFunctionSet->SetCursorAtPoint( aPos );
254 : }
255 0 : return sal_True;
256 :
257 : case KEY_SHIFT + KEY_MOD1:
258 0 : if ( eSelMode != MULTIPLE_SELECTION )
259 : {
260 0 : pWin->ReleaseMouse();
261 0 : nFlags &= (~SELENG_IN_SEL);
262 0 : return sal_False;
263 : }
264 0 : nFlags |= SELENG_IN_ADD; //bIsInAddMode = sal_True;
265 0 : if ( !(nFlags & SELENG_HAS_ANCH) )
266 : {
267 0 : pFunctionSet->CreateAnchor();
268 0 : nFlags |= SELENG_HAS_ANCH;
269 : }
270 0 : pFunctionSet->SetCursorAtPoint( aPos );
271 0 : return sal_True;
272 : }
273 :
274 0 : return sal_False;
275 : }
276 :
277 : /*************************************************************************
278 : |*
279 : |* SelectionEngine::SelMouseButtonUp()
280 : |*
281 : *************************************************************************/
282 :
283 0 : sal_Bool SelectionEngine::SelMouseButtonUp( const MouseEvent& rMEvt )
284 : {
285 0 : aWTimer.Stop();
286 : //DbgOut("Up");
287 0 : if( !pFunctionSet || !pWin )
288 : {
289 0 : nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL);
290 0 : return sal_False;
291 : }
292 :
293 0 : if( !rMEvt.IsRight() )
294 : {
295 0 : pWin->ReleaseMouse();
296 : }
297 :
298 0 : if( (nFlags & SELENG_WAIT_UPEVT) && !(nFlags & SELENG_CMDEVT) &&
299 : eSelMode != SINGLE_SELECTION)
300 : {
301 : // MouseButtonDown in Sel aber kein CommandEvent eingetrudelt
302 : // ==> deselektieren
303 0 : sal_uInt16 nModifier = aLastMove.GetModifier() | nLockedMods;
304 0 : if( nModifier == KEY_MOD1 || IsAlwaysAdding() )
305 : {
306 0 : if( !(nModifier & KEY_SHIFT) )
307 : {
308 0 : pFunctionSet->DestroyAnchor();
309 0 : nFlags &= (~SELENG_HAS_ANCH); // nix Anker
310 : }
311 0 : pFunctionSet->DeselectAtPoint( aLastMove.GetPosPixel() );
312 0 : nFlags &= (~SELENG_HAS_ANCH); // nix Anker
313 0 : pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel(), sal_True );
314 : }
315 : else
316 : {
317 0 : pFunctionSet->DeselectAll();
318 0 : nFlags &= (~SELENG_HAS_ANCH); // nix Anker
319 0 : pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel() );
320 : }
321 : }
322 :
323 0 : nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL);
324 0 : return sal_True;
325 : }
326 :
327 : /*************************************************************************
328 : |*
329 : |* SelectionEngine::SelMouseMove()
330 : |*
331 : *************************************************************************/
332 :
333 0 : sal_Bool SelectionEngine::SelMouseMove( const MouseEvent& rMEvt )
334 : {
335 :
336 0 : if ( !pFunctionSet || !(nFlags & SELENG_IN_SEL) ||
337 : (nFlags & (SELENG_CMDEVT | SELENG_WAIT_UPEVT)) )
338 0 : return sal_False;
339 :
340 0 : if( !(nFlags & SELENG_EXPANDONMOVE) )
341 0 : return sal_False; // auf DragEvent warten!
342 :
343 0 : aLastMove = rMEvt;
344 : // wenn die Maus ausserhalb der Area steht, dann wird die
345 : // Frequenz des SetCursorAtPoint() nur durch den Timer bestimmt
346 0 : if( aWTimer.IsActive() && !aArea.IsInside( rMEvt.GetPosPixel() ))
347 0 : return sal_True;
348 :
349 0 : aWTimer.SetTimeout( nUpdateInterval );
350 0 : aWTimer.Start();
351 0 : if ( eSelMode != SINGLE_SELECTION )
352 : {
353 0 : if ( !(nFlags & SELENG_HAS_ANCH) )
354 : {
355 0 : pFunctionSet->CreateAnchor();
356 : //DbgOut("Move:Creating anchor");
357 0 : nFlags |= SELENG_HAS_ANCH;
358 : }
359 : }
360 :
361 : //DbgOut("Move:SetCursor");
362 0 : pFunctionSet->SetCursorAtPoint( rMEvt.GetPosPixel() );
363 :
364 0 : return sal_True;
365 : }
366 :
367 : /*************************************************************************
368 : |*
369 : |* SelectionEngine::SetWindow()
370 : |*
371 : *************************************************************************/
372 :
373 4 : void SelectionEngine::SetWindow( Window* pNewWin )
374 : {
375 4 : if( pNewWin != pWin )
376 : {
377 0 : if ( pWin && (nFlags & SELENG_IN_SEL) )
378 0 : pWin->ReleaseMouse();
379 0 : pWin = pNewWin;
380 0 : if ( pWin && ( nFlags & SELENG_IN_SEL ) )
381 0 : pWin->CaptureMouse();
382 : }
383 4 : }
384 :
385 : /*************************************************************************
386 : |*
387 : |* SelectionEngine::Reset()
388 : |*
389 : *************************************************************************/
390 :
391 3 : void SelectionEngine::Reset()
392 : {
393 3 : aWTimer.Stop();
394 3 : if ( nFlags & SELENG_IN_SEL )
395 0 : pWin->ReleaseMouse();
396 3 : nFlags &= ~(SELENG_HAS_ANCH | SELENG_IN_SEL);
397 3 : nLockedMods = 0;
398 3 : }
399 :
400 : /*************************************************************************
401 : |*
402 : |* SelectionEngine::Command()
403 : |*
404 : *************************************************************************/
405 :
406 0 : void SelectionEngine::Command( const CommandEvent& rCEvt )
407 : {
408 : // Timer aWTimer ist beim Aufspannen einer Selektion aktiv
409 0 : if ( !pFunctionSet || !pWin || aWTimer.IsActive() )
410 0 : return;
411 0 : aWTimer.Stop();
412 0 : nFlags |= SELENG_CMDEVT;
413 0 : if ( rCEvt.GetCommand() == COMMAND_STARTDRAG )
414 : {
415 0 : if ( nFlags & SELENG_DRG_ENAB )
416 : {
417 : DBG_ASSERT( rCEvt.IsMouseEvent(), "STARTDRAG: Not a MouseEvent" );
418 0 : if ( pFunctionSet->IsSelectionAtPoint( rCEvt.GetMousePosPixel() ) )
419 : {
420 0 : aLastMove = MouseEvent( rCEvt.GetMousePosPixel(),
421 0 : aLastMove.GetClicks(), aLastMove.GetMode(),
422 0 : aLastMove.GetButtons(), aLastMove.GetModifier() );
423 0 : pFunctionSet->BeginDrag();
424 0 : nFlags &= ~(SELENG_CMDEVT|SELENG_WAIT_UPEVT|SELENG_IN_SEL);
425 : }
426 : else
427 0 : nFlags &= ~SELENG_CMDEVT;
428 : }
429 : else
430 0 : nFlags &= ~SELENG_CMDEVT;
431 : }
432 : }
433 :
434 0 : void SelectionEngine::SetUpdateInterval( sal_uLong nInterval )
435 : {
436 0 : if (nInterval < SELENG_AUTOREPEAT_INTERVAL_MIN)
437 : // Set a lower threshold. On Windows, setting this value too low
438 : // would cause selection to get updated indefinitely.
439 0 : nInterval = SELENG_AUTOREPEAT_INTERVAL_MIN;
440 :
441 0 : if (nUpdateInterval == nInterval)
442 : // no update needed.
443 0 : return;
444 :
445 0 : if (aWTimer.IsActive())
446 : {
447 : // reset the timer right away on interval change.
448 0 : aWTimer.Stop();
449 0 : aWTimer.SetTimeout(nInterval);
450 0 : aWTimer.Start();
451 : }
452 : else
453 0 : aWTimer.SetTimeout(nInterval);
454 :
455 0 : nUpdateInterval = nInterval;
456 : }
457 :
458 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|