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