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