]> git.saurik.com Git - wxWidgets.git/blob - src/common/event.cpp
tree ctrl sorting shouldn't crash when items don't have data
[wxWidgets.git] / src / common / event.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: event.cpp
3 // Purpose: Event classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "event.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/defs.h"
25 #include "wx/control.h"
26 #include "wx/utils.h"
27 #include "wx/app.h"
28 #include "wx/dc.h"
29 #endif
30
31 #include "wx/event.h"
32 #include "wx/validate.h"
33
34 #if !USE_SHARED_LIBRARY
35 IMPLEMENT_DYNAMIC_CLASS(wxEvtHandler, wxObject)
36 IMPLEMENT_ABSTRACT_CLASS(wxEvent, wxObject)
37 IMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent)
38 IMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent)
39 IMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent)
40 IMPLEMENT_DYNAMIC_CLASS(wxMouseEvent, wxEvent)
41 IMPLEMENT_DYNAMIC_CLASS(wxKeyEvent, wxEvent)
42 IMPLEMENT_DYNAMIC_CLASS(wxSizeEvent, wxEvent)
43 IMPLEMENT_DYNAMIC_CLASS(wxPaintEvent, wxEvent)
44 IMPLEMENT_DYNAMIC_CLASS(wxEraseEvent, wxEvent)
45 IMPLEMENT_DYNAMIC_CLASS(wxMoveEvent, wxEvent)
46 IMPLEMENT_DYNAMIC_CLASS(wxFocusEvent, wxEvent)
47 IMPLEMENT_DYNAMIC_CLASS(wxCloseEvent, wxEvent)
48 IMPLEMENT_DYNAMIC_CLASS(wxShowEvent, wxEvent)
49 IMPLEMENT_DYNAMIC_CLASS(wxMaximizeEvent, wxEvent)
50 IMPLEMENT_DYNAMIC_CLASS(wxIconizeEvent, wxEvent)
51 IMPLEMENT_DYNAMIC_CLASS(wxMenuEvent, wxEvent)
52 IMPLEMENT_DYNAMIC_CLASS(wxJoystickEvent, wxEvent)
53 IMPLEMENT_DYNAMIC_CLASS(wxDropFilesEvent, wxEvent)
54 IMPLEMENT_DYNAMIC_CLASS(wxActivateEvent, wxEvent)
55 IMPLEMENT_DYNAMIC_CLASS(wxInitDialogEvent, wxEvent)
56 IMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent)
57 IMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent)
58 IMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxCommandEvent)
59 IMPLEMENT_DYNAMIC_CLASS(wxNavigationKeyEvent, wxCommandEvent)
60 IMPLEMENT_DYNAMIC_CLASS(wxPaletteChangedEvent, wxEvent)
61 IMPLEMENT_DYNAMIC_CLASS(wxQueryNewPaletteEvent, wxEvent)
62
63 const wxEventTable *wxEvtHandler::GetEventTable() const
64 { return &wxEvtHandler::sm_eventTable; }
65
66 const wxEventTable wxEvtHandler::sm_eventTable =
67 { (const wxEventTable *)NULL, &wxEvtHandler::sm_eventTableEntries[0] };
68
69 const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] =
70 { { 0, 0, 0, (wxObjectEventFunction) NULL, (wxObject*) NULL } };
71
72 #endif // !USE_SHARED_LIBRARY
73
74 #if wxUSE_THREADS
75 /* To put pending event handlers */
76 extern wxList *wxPendingEvents;
77 extern wxCriticalSection *wxPendingEventsLocker;
78 #endif
79
80 /*
81 * General wxWindows events, covering
82 * all interesting things that might happen (button clicking, resizing,
83 * setting text in widgets, etc.).
84 *
85 * For each completely new event type, derive a new event class.
86 *
87 */
88
89 wxEvent::wxEvent(int theId)
90 {
91 m_eventType = wxEVT_NULL;
92 m_eventObject = (wxObject *) NULL;
93 m_eventHandle = (char *) NULL;
94 m_timeStamp = 0;
95 m_id = theId;
96 m_skipped = FALSE;
97 m_callbackUserData = (wxObject *) NULL;
98 m_isCommandEvent = FALSE;
99 }
100
101 wxObject *wxEvent::Clone() const
102 {
103 wxEvent *event = (wxEvent *)wxObject::Clone();
104
105 event->m_eventType = m_eventType;
106 event->m_eventObject = m_eventObject;
107 event->m_eventHandle = m_eventHandle;
108 event->m_timeStamp = m_timeStamp;
109 event->m_id = m_id;
110 event->m_skipped = m_skipped;
111 event->m_callbackUserData = m_callbackUserData;
112 event->m_isCommandEvent = m_isCommandEvent;
113
114 return event;
115 }
116
117 /*
118 * Command events
119 *
120 */
121
122 wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId)
123 {
124 m_eventType = commandType;
125 m_clientData = (char *) NULL;
126 m_clientObject = (wxClientData *) NULL;
127 m_extraLong = 0;
128 m_commandInt = 0;
129 m_id = theId;
130 m_commandString = (wxChar *) NULL;
131 m_isCommandEvent = TRUE;
132 }
133
134 /*
135 * Scroll events
136 */
137
138 wxScrollEvent::wxScrollEvent(wxEventType commandType,
139 int id,
140 int pos,
141 int orient)
142 : wxCommandEvent(commandType, id)
143 {
144 m_extraLong = orient;
145 m_commandInt = pos;
146 }
147
148
149 /*
150 * Mouse events
151 *
152 */
153
154 wxMouseEvent::wxMouseEvent(wxEventType commandType)
155 {
156 m_eventType = commandType;
157 m_metaDown = FALSE;
158 m_altDown = FALSE;
159 m_controlDown = FALSE;
160 m_shiftDown = FALSE;
161 m_leftDown = FALSE;
162 m_rightDown = FALSE;
163 m_middleDown = FALSE;
164 m_x = 0;
165 m_y = 0;
166 }
167
168 // True if was a button dclick event (1 = left, 2 = middle, 3 = right)
169 // or any button dclick event (but = -1)
170 bool wxMouseEvent::ButtonDClick(int but) const
171 {
172 switch (but)
173 {
174 case -1:
175 return (LeftDClick() || MiddleDClick() || RightDClick());
176 case 1:
177 return LeftDClick();
178 case 2:
179 return MiddleDClick();
180 case 3:
181 return RightDClick();
182 default:
183 wxFAIL_MSG(_T("invalid parameter in wxMouseEvent::ButtonDClick"));
184 }
185
186 return FALSE;
187 }
188
189 // True if was a button down event (1 = left, 2 = middle, 3 = right)
190 // or any button down event (but = -1)
191 bool wxMouseEvent::ButtonDown(int but) const
192 {
193 switch (but)
194 {
195 case -1:
196 return (LeftDown() || MiddleDown() || RightDown());
197 case 1:
198 return LeftDown();
199 case 2:
200 return MiddleDown();
201 case 3:
202 return RightDown();
203 default:
204 wxFAIL_MSG(_T("invalid parameter in wxMouseEvent::ButtonDown"));
205 }
206
207 return FALSE;
208 }
209
210 // True if was a button up event (1 = left, 2 = middle, 3 = right)
211 // or any button up event (but = -1)
212 bool wxMouseEvent::ButtonUp(int but) const
213 {
214 switch (but) {
215 case -1:
216 return (LeftUp() || MiddleUp() || RightUp());
217 case 1:
218 return LeftUp();
219 case 2:
220 return MiddleUp();
221 case 3:
222 return RightUp();
223 default:
224 wxFAIL_MSG(_T("invalid parameter in wxMouseEvent::ButtonUp"));
225 }
226
227 return FALSE;
228 }
229
230 // True if the given button is currently changing state
231 bool wxMouseEvent::Button(int but) const
232 {
233 switch (but) {
234 case -1:
235 return (ButtonUp(-1) || ButtonDown(-1) || ButtonDClick(-1)) ;
236 case 1:
237 return (LeftDown() || LeftUp() || LeftDClick());
238 case 2:
239 return (MiddleDown() || MiddleUp() || MiddleDClick());
240 case 3:
241 return (RightDown() || RightUp() || RightDClick());
242 default:
243 wxFAIL_MSG(_T("invalid parameter in wxMouseEvent::Button"));
244 }
245
246 return FALSE;
247 }
248
249 bool wxMouseEvent::ButtonIsDown(int but) const
250 {
251 switch (but) {
252 case -1:
253 return (LeftIsDown() || MiddleIsDown() || RightIsDown());
254 case 1:
255 return LeftIsDown();
256 case 2:
257 return MiddleIsDown();
258 case 3:
259 return RightIsDown();
260 default:
261 wxFAIL_MSG(_T("invalid parameter in wxMouseEvent::ButtonIsDown"));
262 }
263
264 return FALSE;
265 }
266
267 // Find the logical position of the event given the DC
268 wxPoint wxMouseEvent::GetLogicalPosition(const wxDC& dc) const
269 {
270 wxPoint pt(dc.DeviceToLogicalX(m_x), dc.DeviceToLogicalY(m_y));
271 return pt;
272 }
273
274
275 /*
276 * Keyboard events
277 *
278 */
279
280 wxKeyEvent::wxKeyEvent(wxEventType type)
281 {
282 m_eventType = type;
283 m_shiftDown = FALSE;
284 m_controlDown = FALSE;
285 m_metaDown = FALSE;
286 m_altDown = FALSE;
287 m_keyCode = 0;
288 }
289
290 /*
291 * Event handler
292 */
293
294 wxEvtHandler::wxEvtHandler()
295 {
296 m_nextHandler = (wxEvtHandler *) NULL;
297 m_previousHandler = (wxEvtHandler *) NULL;
298 m_enabled = TRUE;
299 m_dynamicEvents = (wxList *) NULL;
300 m_isWindow = FALSE;
301 #if wxUSE_THREADS
302 m_eventsLocker = new wxCriticalSection();
303 #endif
304 m_pendingEvents = (wxList *) NULL;
305 }
306
307 wxEvtHandler::~wxEvtHandler()
308 {
309 // Takes itself out of the list of handlers
310 if (m_previousHandler)
311 m_previousHandler->m_nextHandler = m_nextHandler;
312
313 if (m_nextHandler)
314 m_nextHandler->m_previousHandler = m_previousHandler;
315
316 if (m_dynamicEvents)
317 {
318 wxNode *node = m_dynamicEvents->First();
319 while (node)
320 {
321 wxEventTableEntry *entry = (wxEventTableEntry*)node->Data();
322 if (entry->m_callbackUserData) delete entry->m_callbackUserData;
323 delete entry;
324 node = node->Next();
325 }
326 delete m_dynamicEvents;
327 };
328
329 #if wxUSE_THREADS
330 if (m_pendingEvents)
331 delete m_pendingEvents;
332
333 delete m_eventsLocker;
334 #endif
335 }
336
337 #if wxUSE_THREADS
338 bool wxEvtHandler::ProcessThreadEvent(wxEvent& event)
339 {
340 wxEvent *event_main;
341 wxCriticalSectionLocker locker(*m_eventsLocker);
342
343 // check that we are really in a child thread
344 wxASSERT( !wxThread::IsMain() );
345
346 if (m_pendingEvents == NULL)
347 m_pendingEvents = new wxList();
348
349 event_main = (wxEvent *)event.Clone();
350
351 m_pendingEvents->Append(event_main);
352
353 wxPendingEventsLocker->Enter();
354 wxPendingEvents->Append(this);
355 wxPendingEventsLocker->Leave();
356
357 return TRUE;
358 }
359
360 void wxEvtHandler::ProcessPendingEvents()
361 {
362 wxCriticalSectionLocker locker(*m_eventsLocker);
363 wxNode *node = m_pendingEvents->First();
364 wxEvent *event;
365
366 while (node != NULL) {
367 event = (wxEvent *)node->Data();
368 ProcessEvent(*event);
369 delete node;
370 node = m_pendingEvents->First();
371 }
372 }
373 #endif
374
375 /*
376 * Event table stuff
377 */
378
379 bool wxEvtHandler::ProcessEvent(wxEvent& event)
380 {
381 // check that our flag corresponds to reality
382 wxASSERT( m_isWindow == IsKindOf(CLASSINFO(wxWindow)) );
383
384 // An event handler can be enabled or disabled
385 if ( GetEvtHandlerEnabled() )
386 {
387 #if wxUSE_THREADS
388 // Check whether we are in a child thread.
389 if (!wxThread::IsMain())
390 return ProcessThreadEvent(event);
391 #endif
392 // Handle per-instance dynamic event tables first
393
394 if ( m_dynamicEvents && SearchDynamicEventTable(event) )
395 return TRUE;
396
397 // Then static per-class event tables
398
399 const wxEventTable *table = GetEventTable();
400
401 // Try the associated validator first, if this is a window.
402 // Problem: if the event handler of the window has been replaced,
403 // this wxEvtHandler may no longer be a window.
404 // Therefore validators won't be processed if the handler
405 // has been replaced with SetEventHandler.
406 // THIS CAN BE CURED if PushEventHandler is used instead of
407 // SetEventHandler, and then processing will be passed down the
408 // chain of event handlers.
409 if ( m_isWindow )
410 {
411 wxWindow *win = (wxWindow *)this;
412
413 // Can only use the validator of the window which
414 // is receiving the event
415 if ( win == event.GetEventObject() )
416 {
417 wxValidator *validator = win->GetValidator();
418 if ( validator && validator->ProcessEvent(event) )
419 {
420 return TRUE;
421 }
422 }
423 }
424
425 // Search upwards through the inheritance hierarchy
426 while ( table )
427 {
428 if ( SearchEventTable((wxEventTable&)*table, event) )
429 return TRUE;
430 table = table->baseTable;
431 }
432 }
433
434 // Try going down the event handler chain
435 if ( GetNextHandler() )
436 {
437 if ( GetNextHandler()->ProcessEvent(event) )
438 return TRUE;
439 }
440
441 // Carry on up the parent-child hierarchy,
442 // but only if event is a command event: it wouldn't
443 // make sense for a parent to receive a child's size event, for example
444 if ( m_isWindow && event.IsCommandEvent() )
445 {
446 wxWindow *win = (wxWindow *)this;
447 wxWindow *parent = win->GetParent();
448 if (parent && !parent->IsBeingDeleted())
449 return parent->GetEventHandler()->ProcessEvent(event);
450 }
451
452 // Last try - application object.
453 if ( wxTheApp && (this != wxTheApp) )
454 {
455 // Special case: don't pass wxEVT_IDLE to wxApp, since it'll always
456 // swallow it. wxEVT_IDLE is sent explicitly to wxApp so it will be
457 // processed appropriately via SearchEventTable.
458 if ( event.GetEventType() != wxEVT_IDLE )
459 {
460 if ( wxTheApp->ProcessEvent(event) )
461 return TRUE;
462 }
463 }
464
465 return FALSE;
466 }
467
468 bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
469 {
470 int i = 0;
471 int commandId = event.GetId();
472
473 // BC++ doesn't like while (table.entries[i].m_fn)
474
475 #ifdef __SC__
476 while (table.entries[i].m_fn != 0)
477 #else
478 while (table.entries[i].m_fn != 0L)
479 #endif
480 {
481 if ((event.GetEventType() == table.entries[i].m_eventType) &&
482 (table.entries[i].m_id == -1 || // Match, if event spec says any id will do (id == -1)
483 (table.entries[i].m_lastId == -1 && commandId == table.entries[i].m_id) ||
484 (table.entries[i].m_lastId != -1 &&
485 (commandId >= table.entries[i].m_id && commandId <= table.entries[i].m_lastId))))
486 {
487 event.Skip(FALSE);
488 event.m_callbackUserData = table.entries[i].m_callbackUserData;
489
490 (this->*((wxEventFunction) (table.entries[i].m_fn)))(event);
491
492 if ( event.GetSkipped() )
493 return FALSE;
494 else
495 return TRUE;
496 }
497 i++;
498 }
499 return FALSE;
500 }
501 void wxEvtHandler::Connect( int id, int lastId,
502 wxEventType eventType,
503 wxObjectEventFunction func,
504 wxObject *userData )
505 {
506 wxEventTableEntry *entry = new wxEventTableEntry;
507 entry->m_id = id;
508 entry->m_lastId = lastId;
509 entry->m_eventType = eventType;
510 entry->m_fn = func;
511 entry->m_callbackUserData = userData;
512
513 if (!m_dynamicEvents)
514 m_dynamicEvents = new wxList;
515
516 m_dynamicEvents->Append( (wxObject*) entry );
517 }
518
519 bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event )
520 {
521 wxCHECK_MSG( m_dynamicEvents, FALSE,
522 _T("caller should check that we have dynamic events") );
523
524 int commandId = event.GetId();
525
526 wxNode *node = m_dynamicEvents->First();
527 while (node)
528 {
529 wxEventTableEntry *entry = (wxEventTableEntry*)node->Data();
530
531 if (entry->m_fn)
532 {
533 // Match, if event spec says any id will do (id == -1)
534 if ( (event.GetEventType() == entry->m_eventType) &&
535 (entry->m_id == -1 ||
536 (entry->m_lastId == -1 && commandId == entry->m_id) ||
537 (entry->m_lastId != -1 &&
538 (commandId >= entry->m_id && commandId <= entry->m_lastId))) )
539 {
540 event.Skip(FALSE);
541 event.m_callbackUserData = entry->m_callbackUserData;
542
543 (this->*((wxEventFunction) (entry->m_fn)))(event);
544
545 if (event.GetSkipped())
546 return FALSE;
547 else
548 return TRUE;
549 }
550 }
551 node = node->Next();
552 }
553 return FALSE;
554 };
555
556 #if WXWIN_COMPATIBILITY
557 bool wxEvtHandler::OnClose()
558 {
559 if (GetNextHandler())
560 return GetNextHandler()->OnClose();
561 else
562 return FALSE;
563 }
564 #endif // WXWIN_COMPATIBILITY
565
566 // Find a window with the focus, that is also a descendant of the given window.
567 // This is used to determine the window to initially send commands to.
568 wxWindow* wxFindFocusDescendant(wxWindow* ancestor)
569 {
570 // Process events starting with the window with the focus, if any.
571 wxWindow* focusWin = wxWindow::FindFocus();
572 wxWindow* win = focusWin;
573
574 // Check if this is a descendant of this frame.
575 // If not, win will be set to NULL.
576 while (win)
577 {
578 if (win == ancestor)
579 break;
580 else
581 win = win->GetParent();
582 }
583 if (win == (wxWindow*) NULL)
584 focusWin = (wxWindow*) NULL;
585
586 return focusWin;
587 }
588