1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26
27 #include <tools/ref.hxx>
28 #include <vcl/window.hxx>
29 #include <vcl/seleng.hxx>
30 #include <tools/debug.hxx>
31
32
33
34
ShouldDeselect(sal_Bool bModifierKey1) const35 inline sal_Bool SelectionEngine::ShouldDeselect( sal_Bool bModifierKey1 ) const
36 {
37 // return !( eSelMode == MULTIPLE_SELECTION && bModifierKey1 );
38 return eSelMode != MULTIPLE_SELECTION || !bModifierKey1;
39 }
40
41
42 // TODO: FunctionSet::SelectAtPoint raus
43
44 /*************************************************************************
45 |*
46 |* SelectionEngine::SelectionEngine()
47 |*
48 |* Beschreibung SELENG.SDW
49 |* Ersterstellung OV 10.10.94
50 |* Letzte Aenderung OV 10.10.94
51 |*
52 *************************************************************************/
53
SelectionEngine(Window * pWindow,FunctionSet * pFuncSet)54 SelectionEngine::SelectionEngine( Window* pWindow, FunctionSet* pFuncSet ) :
55 pWin( pWindow )
56 {
57 eSelMode = SINGLE_SELECTION;
58 pFunctionSet = pFuncSet;
59 nFlags = SELENG_EXPANDONMOVE;
60 nLockedMods = 0;
61
62 aWTimer.SetTimeoutHdl( LINK( this, SelectionEngine, ImpWatchDog ) );
63 aWTimer.SetTimeout( SELENG_AUTOREPEAT_INTERVAL );
64 }
65
66 /*************************************************************************
67 |*
68 |* SelectionEngine::~SelectionEngine()
69 |*
70 |* Beschreibung SELENG.SDW
71 |* Ersterstellung OV 10.10.94
72 |* Letzte Aenderung OV 10.10.94
73 |*
74 *************************************************************************/
75
~SelectionEngine()76 SelectionEngine::~SelectionEngine()
77 {
78 aWTimer.Stop();
79 }
80
81 /*************************************************************************
82 |*
83 |* SelectionEngine::ImpWatchDog()
84 |*
85 |* Beschreibung SELENG.SDW
86 |* Ersterstellung OV 10.10.94
87 |* Letzte Aenderung OV 10.10.94
88 |*
89 *************************************************************************/
90
IMPL_LINK(SelectionEngine,ImpWatchDog,Timer *,EMPTYARG)91 IMPL_LINK( SelectionEngine, ImpWatchDog, Timer*, EMPTYARG )
92 {
93 if ( !aArea.IsInside( aLastMove.GetPosPixel() ) )
94 SelMouseMove( aLastMove );
95 return 0;
96 }
97
98 /*************************************************************************
99 |*
100 |* SelectionEngine::SetSelectionMode()
101 |*
102 |* Beschreibung SELENG.SDW
103 |* Ersterstellung OV 10.10.94
104 |* Letzte Aenderung OV 10.10.94
105 |*
106 *************************************************************************/
107
SetSelectionMode(SelectionMode eMode)108 void SelectionEngine::SetSelectionMode( SelectionMode eMode )
109 {
110 eSelMode = eMode;
111 }
112
113 /*************************************************************************
114 |*
115 |* SelectionEngine::ActivateDragMode()
116 |*
117 |* Beschreibung SELENG.SDW
118 |* Ersterstellung OV 10.10.94
119 |* Letzte Aenderung OV 10.10.94
120 |*
121 *************************************************************************/
122
ActivateDragMode()123 void SelectionEngine::ActivateDragMode()
124 {
125 DBG_ERRORFILE( "SelectionEngine::ActivateDragMode not implemented" );
126 }
127
128 /*************************************************************************
129 |*
130 |* SelectionEngine::CursorPosChanging()
131 |*
132 |* Beschreibung SELENG.SDW
133 |* Ersterstellung OV 10.10.94
134 |* Letzte Aenderung GT 2002-04-04
135 |*
136 *************************************************************************/
137
CursorPosChanging(sal_Bool bShift,sal_Bool bMod1)138 void SelectionEngine::CursorPosChanging( sal_Bool bShift, sal_Bool bMod1 )
139 {
140 if ( !pFunctionSet )
141 return;
142
143 if ( bShift && eSelMode != SINGLE_SELECTION )
144 {
145 if ( IsAddMode() )
146 {
147 if ( !(nFlags & SELENG_HAS_ANCH) )
148 {
149 pFunctionSet->CreateAnchor();
150 nFlags |= SELENG_HAS_ANCH;
151 }
152 }
153 else
154 {
155 if ( !(nFlags & SELENG_HAS_ANCH) )
156 {
157 if( ShouldDeselect( bMod1 ) )
158 pFunctionSet->DeselectAll();
159 pFunctionSet->CreateAnchor();
160 nFlags |= SELENG_HAS_ANCH;
161 }
162 }
163 }
164 else
165 {
166 if ( IsAddMode() )
167 {
168 if ( nFlags & SELENG_HAS_ANCH )
169 {
170 // pFunctionSet->CreateCursor();
171 pFunctionSet->DestroyAnchor();
172 nFlags &= (~SELENG_HAS_ANCH);
173 }
174 }
175 else
176 {
177 if( ShouldDeselect( bMod1 ) )
178 pFunctionSet->DeselectAll();
179 else
180 pFunctionSet->DestroyAnchor();
181 nFlags &= (~SELENG_HAS_ANCH);
182 }
183 }
184 }
185
186 /*************************************************************************
187 |*
188 |* SelectionEngine::SelMouseButtonDown()
189 |*
190 |* Beschreibung SELENG.SDW
191 |* Ersterstellung OV 10.10.94
192 |* Letzte Aenderung OV 07.06.95
193 |*
194 *************************************************************************/
195
SelMouseButtonDown(const MouseEvent & rMEvt)196 sal_Bool SelectionEngine::SelMouseButtonDown( const MouseEvent& rMEvt )
197 {
198 nFlags &= (~SELENG_CMDEVT);
199 if ( !pFunctionSet || !pWin || rMEvt.GetClicks() > 1 || rMEvt.IsRight() )
200 return sal_False;
201
202 sal_uInt16 nModifier = rMEvt.GetModifier() | nLockedMods;
203 if ( nModifier & KEY_MOD2 )
204 return sal_False;
205 // in SingleSelection: Control-Taste filtern (damit auch
206 // mit Ctrl-Click ein D&D gestartet werden kann)
207 if ( nModifier == KEY_MOD1 && eSelMode == SINGLE_SELECTION )
208 nModifier = 0;
209
210 Point aPos = rMEvt.GetPosPixel();
211 aLastMove = rMEvt;
212
213 if( !rMEvt.IsRight() )
214 {
215 pWin->CaptureMouse();
216 nFlags |= SELENG_IN_SEL;
217 }
218 else
219 {
220 nModifier = 0;
221 }
222
223 switch ( nModifier )
224 {
225 case 0: // KEY_NO_KEY
226 {
227 sal_Bool bSelAtPoint = pFunctionSet->IsSelectionAtPoint( aPos );
228 nFlags &= (~SELENG_IN_ADD);
229 if ( (nFlags & SELENG_DRG_ENAB) && bSelAtPoint )
230 {
231 nFlags |= SELENG_WAIT_UPEVT;
232 nFlags &= ~(SELENG_IN_SEL);
233 pWin->ReleaseMouse();
234 return sal_True; //auf STARTDRAG-Command-Event warten
235 }
236 if ( eSelMode != SINGLE_SELECTION )
237 {
238 if( !IsAddMode() )
239 pFunctionSet->DeselectAll();
240 else
241 pFunctionSet->DestroyAnchor();
242 nFlags &= (~SELENG_HAS_ANCH); // bHasAnchor = sal_False;
243 }
244 pFunctionSet->SetCursorAtPoint( aPos );
245 // Sonderbehandlung Single-Selection, damit Select+Drag
246 // in einem Zug moeglich ist
247 if (eSelMode == SINGLE_SELECTION && (nFlags & SELENG_DRG_ENAB))
248 nFlags |= SELENG_WAIT_UPEVT;
249 return sal_True;
250 }
251
252 case KEY_SHIFT:
253 if ( eSelMode == SINGLE_SELECTION )
254 {
255 pWin->ReleaseMouse();
256 nFlags &= (~SELENG_IN_SEL);
257 return sal_False;
258 }
259 if ( nFlags & SELENG_ADD_ALW )
260 nFlags |= SELENG_IN_ADD;
261 else
262 nFlags &= (~SELENG_IN_ADD);
263
264 if( !(nFlags & SELENG_HAS_ANCH) )
265 {
266 if ( !(nFlags & SELENG_IN_ADD) )
267 pFunctionSet->DeselectAll();
268 pFunctionSet->CreateAnchor();
269 nFlags |= SELENG_HAS_ANCH;
270 }
271 pFunctionSet->SetCursorAtPoint( aPos );
272 return sal_True;
273
274 case KEY_MOD1:
275 // Control nur bei Mehrfachselektion erlaubt
276 if ( eSelMode != MULTIPLE_SELECTION )
277 {
278 nFlags &= (~SELENG_IN_SEL);
279 pWin->ReleaseMouse();
280 return sal_True; // Mausclick verschlucken
281 }
282 if ( nFlags & SELENG_HAS_ANCH )
283 {
284 // pFunctionSet->CreateCursor();
285 pFunctionSet->DestroyAnchor();
286 nFlags &= (~SELENG_HAS_ANCH);
287 }
288 if ( pFunctionSet->IsSelectionAtPoint( aPos ) )
289 {
290 pFunctionSet->DeselectAtPoint( aPos );
291 pFunctionSet->SetCursorAtPoint( aPos, sal_True );
292 }
293 else
294 {
295 pFunctionSet->SetCursorAtPoint( aPos );
296 }
297 return sal_True;
298
299 case KEY_SHIFT + KEY_MOD1:
300 if ( eSelMode != MULTIPLE_SELECTION )
301 {
302 pWin->ReleaseMouse();
303 nFlags &= (~SELENG_IN_SEL);
304 return sal_False;
305 }
306 nFlags |= SELENG_IN_ADD; //bIsInAddMode = sal_True;
307 if ( !(nFlags & SELENG_HAS_ANCH) )
308 {
309 pFunctionSet->CreateAnchor();
310 nFlags |= SELENG_HAS_ANCH;
311 }
312 pFunctionSet->SetCursorAtPoint( aPos );
313 return sal_True;
314 }
315
316 return sal_False;
317 }
318
319 /*************************************************************************
320 |*
321 |* SelectionEngine::SelMouseButtonUp()
322 |*
323 |* Beschreibung SELENG.SDW
324 |* Ersterstellung OV 10.10.94
325 |* Letzte Aenderung OV 10.10.94
326 |*
327 *************************************************************************/
328
SelMouseButtonUp(const MouseEvent & rMEvt)329 sal_Bool SelectionEngine::SelMouseButtonUp( const MouseEvent& rMEvt )
330 {
331 aWTimer.Stop();
332 //DbgOut("Up");
333 if( !pFunctionSet || !pWin )
334 {
335 nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL);
336 return sal_False;
337 }
338
339 if( !rMEvt.IsRight() )
340 {
341 pWin->ReleaseMouse();
342 }
343
344 if( (nFlags & SELENG_WAIT_UPEVT) && !(nFlags & SELENG_CMDEVT) &&
345 eSelMode != SINGLE_SELECTION)
346 {
347 // MouseButtonDown in Sel aber kein CommandEvent eingetrudelt
348 // ==> deselektieren
349 sal_uInt16 nModifier = aLastMove.GetModifier() | nLockedMods;
350 if( nModifier == KEY_MOD1 || IsAlwaysAdding() )
351 {
352 if( !(nModifier & KEY_SHIFT) )
353 {
354 pFunctionSet->DestroyAnchor();
355 nFlags &= (~SELENG_HAS_ANCH); // nix Anker
356 }
357 pFunctionSet->DeselectAtPoint( aLastMove.GetPosPixel() );
358 nFlags &= (~SELENG_HAS_ANCH); // nix Anker
359 pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel(), sal_True );
360 }
361 else
362 {
363 pFunctionSet->DeselectAll();
364 nFlags &= (~SELENG_HAS_ANCH); // nix Anker
365 pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel() );
366 }
367 }
368
369 nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL);
370 return sal_True;
371 }
372
373 /*************************************************************************
374 |*
375 |* SelectionEngine::SelMouseMove()
376 |*
377 |* Beschreibung SELENG.SDW
378 |* Ersterstellung OV 10.10.94
379 |* Letzte Aenderung OV 10.10.94
380 |*
381 *************************************************************************/
382
SelMouseMove(const MouseEvent & rMEvt)383 sal_Bool SelectionEngine::SelMouseMove( const MouseEvent& rMEvt )
384 {
385
386 if ( !pFunctionSet || !(nFlags & SELENG_IN_SEL) ||
387 (nFlags & (SELENG_CMDEVT | SELENG_WAIT_UPEVT)) )
388 return sal_False;
389
390 if( !(nFlags & SELENG_EXPANDONMOVE) )
391 return sal_False; // auf DragEvent warten!
392
393 aLastMove = rMEvt;
394 // wenn die Maus ausserhalb der Area steht, dann wird die
395 // Frequenz des SetCursorAtPoint() nur durch den Timer bestimmt
396 if( aWTimer.IsActive() && !aArea.IsInside( rMEvt.GetPosPixel() ))
397 return sal_True;
398
399
400 aWTimer.Start();
401 if ( eSelMode != SINGLE_SELECTION )
402 {
403 if ( !(nFlags & SELENG_HAS_ANCH) )
404 {
405 pFunctionSet->CreateAnchor();
406 //DbgOut("Move:Creating anchor");
407 nFlags |= SELENG_HAS_ANCH;
408 }
409 }
410
411 //DbgOut("Move:SetCursor");
412 pFunctionSet->SetCursorAtPoint( rMEvt.GetPosPixel() );
413
414 return sal_True;
415 }
416
417 /*************************************************************************
418 |*
419 |* SelectionEngine::SetWindow()
420 |*
421 |* Beschreibung SELENG.SDW
422 |* Ersterstellung OV 10.10.94
423 |* Letzte Aenderung OV 10.10.94
424 |*
425 *************************************************************************/
426
SetWindow(Window * pNewWin)427 void SelectionEngine::SetWindow( Window* pNewWin )
428 {
429 if( pNewWin != pWin )
430 {
431 if ( pWin && (nFlags & SELENG_IN_SEL) )
432 pWin->ReleaseMouse();
433 pWin = pNewWin;
434 if ( pWin && ( nFlags & SELENG_IN_SEL ) )
435 pWin->CaptureMouse();
436 }
437 }
438
439 /*************************************************************************
440 |*
441 |* SelectionEngine::Reset()
442 |*
443 |* Beschreibung SELENG.SDW
444 |* Ersterstellung OV 07.07.95
445 |* Letzte Aenderung OV 07.07.95
446 |*
447 *************************************************************************/
448
Reset()449 void SelectionEngine::Reset()
450 {
451 aWTimer.Stop();
452 if ( nFlags & SELENG_IN_SEL )
453 pWin->ReleaseMouse();
454 nFlags &= ~(SELENG_HAS_ANCH | SELENG_IN_SEL);
455 nLockedMods = 0;
456 }
457
458 /*************************************************************************
459 |*
460 |* SelectionEngine::Command()
461 |*
462 |* Beschreibung SELENG.SDW
463 |* Ersterstellung OV 07.07.95
464 |* Letzte Aenderung OV 07.07.95
465 |*
466 *************************************************************************/
467
Command(const CommandEvent & rCEvt)468 void SelectionEngine::Command( const CommandEvent& rCEvt )
469 {
470 // Timer aWTimer ist beim Aufspannen einer Selektion aktiv
471 if ( !pFunctionSet || !pWin || aWTimer.IsActive() )
472 return;
473 aWTimer.Stop();
474 nFlags |= SELENG_CMDEVT;
475 if ( rCEvt.GetCommand() == COMMAND_STARTDRAG )
476 {
477 if ( nFlags & SELENG_DRG_ENAB )
478 {
479 DBG_ASSERT( rCEvt.IsMouseEvent(), "STARTDRAG: Not a MouseEvent" );
480 if ( pFunctionSet->IsSelectionAtPoint( rCEvt.GetMousePosPixel() ) )
481 {
482 aLastMove = MouseEvent( rCEvt.GetMousePosPixel(),
483 aLastMove.GetClicks(), aLastMove.GetMode(),
484 aLastMove.GetButtons(), aLastMove.GetModifier() );
485 pFunctionSet->BeginDrag();
486 nFlags &= ~(SELENG_CMDEVT|SELENG_WAIT_UPEVT|SELENG_IN_SEL);
487 }
488 else
489 nFlags &= ~SELENG_CMDEVT;
490 }
491 else
492 nFlags &= ~SELENG_CMDEVT;
493 }
494 }
495