OSDN Git Service

Handling key and mouse events in listctrl is improved
[molby/Molby.git] / wxSources / MyListCtrl_orig.cpp
1 /*
2  *  MyListCtrl.cpp
3  *  Molby
4  *
5  *  Created by Toshi Nagata on 08/12/09.
6  *  Copyright 2008 Toshi Nagata. All rights reserved.
7  *
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation version 2 of the License.
11  
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU General Public License for more details.
16  */
17
18 #include "MyListCtrl.h"
19 #include "MyMBConv.h"
20
21 #include "wx/dcclient.h"
22 #include "wx/scrolwin.h"
23 #include "wx/glcanvas.h"
24 #include "wx/menu.h"
25
26 const wxEventType MyListCtrlEvent = wxNewEventType();
27
28 IMPLEMENT_DYNAMIC_CLASS(MyListCtrl, wxGenericListCtrl)
29
30 BEGIN_EVENT_TABLE(MyListCtrl, wxGenericListCtrl)
31 EVT_LIST_ITEM_SELECTED(-1, MyListCtrl::OnItemSelectionChanged)
32 EVT_LIST_ITEM_DESELECTED(-1, MyListCtrl::OnItemSelectionChanged)
33 EVT_COMMAND(MyListCtrlEvent_tableSelectionChanged, MyListCtrlEvent, MyListCtrl::OnTableSelectionChanged)
34 EVT_COMMAND(MyListCtrlEvent_enableTableSelectionNotification, MyListCtrlEvent, MyListCtrl::OnEnableTableSelectionNotification)
35 EVT_LIST_BEGIN_DRAG(-1, MyListCtrl::OnBeginDrag)
36 EVT_LEFT_DCLICK(MyListCtrl::OnLeftDClick)
37 EVT_CHAR(MyListCtrl::OnChar)
38 EVT_LEFT_DOWN(MyListCtrl::OnMouseDown)
39 END_EVENT_TABLE()
40
41 MyListCtrl::MyListCtrl()
42 {
43         editText = NULL;
44 #if defined(__WXMAC__)
45         //  On OSX, the default font seems to be 14-point, which is too big.
46         wxFont font = this->GetFont();
47         font.SetPointSize(12);
48         this->SetFont(font);
49 #endif
50 }
51
52 MyListCtrl::~MyListCtrl()
53 {
54         if (editText != NULL) {
55         /*      editText->Destroy(); */  /*  May be unnecessary  */
56                 editText = NULL;
57         }
58 }
59
60 bool
61 MyListCtrl::Create(wxWindow* parent, wxWindowID wid, const wxPoint& pos, const wxSize& size)
62 {
63         this->wxGenericListCtrl::Create(parent, wid, pos, size, wxLC_REPORT | wxLC_VIRTUAL | wxBORDER_SIMPLE);
64         dataSource = NULL;
65
66     /*  Create a TextCtrl for editing Text  */
67     /*  m_mainWin is a protected member in wxGenericListCtrl  */
68     editText = new wxTextCtrl((wxWindow *)m_mainWin, -1, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
69     editText->Hide();
70     editText->Connect(wxID_ANY, wxEVT_KEY_DOWN, wxKeyEventHandler(MyListCtrl::OnKeyDownOnEditText), NULL, this);
71     editText->Connect(wxID_ANY, wxEVT_KILL_FOCUS, wxFocusEventHandler(MyListCtrl::OnKillFocusOnEditText), NULL, this);
72
73         selectionChangeNotificationSent = false;
74         selectionChangeNotificationEnabled = true;
75         subTitleRowAttr = new wxListItemAttr;
76         dragTargetRow = -1;
77         return true;
78 }
79
80 void
81 MyListCtrl::SetDataSource(MyListCtrlDataSource *source)
82 {
83         dataSource = source;
84         RefreshTable();
85 }
86
87 void
88 MyListCtrl::RefreshTable()
89 {
90         if (dataSource != NULL) {
91                 int nrows = dataSource->GetItemCount(this);
92                 SetItemCount(nrows);
93                 if (nrows > 0) {
94                         RefreshItems(0, nrows - 1);
95                 }
96         }
97 }
98
99 // Define the repainting behaviour
100 void
101 MyListCtrl::OnPaintCallback(wxDC *dc)
102 {
103         if (dragTargetRow >= 0) {
104                 wxRect r;
105                 wxPen pen = *wxCYAN_PEN;
106                 int dx, dy, y;
107 #if defined(__WXMSW__)
108                 static const int offset_y = -6;
109 #else
110                 static const int offset_y = 0;
111 #endif
112                 CalcScrolledPosition(0, 0, &dx, &dy);   
113                 pen.SetWidth(3);
114                 dc->SetPen(pen);
115                 if (dragTargetRow == GetItemCount()) {
116                         GetItemRect(dragTargetRow - 1, r);
117                         y = r.y - dy;
118                 } else {
119                         GetItemRect(dragTargetRow, r);
120                         y = r.y - dy - r.height;
121                 }
122                 y += offset_y;
123         //      printf("dragTargetRow = %d, r.y = %d, y = %d, r.x-dx = %d, r.width = %d\n", dragTargetRow, r.y, y, r.x - dx, r.width);
124                 dc->DrawLine(r.x - dx, y, r.x - dx + r.width, y);
125         }
126 }
127
128 //  Callback function that is called from wxListMainWindow::OnPaint().
129 //  This is a very ugly hack, but I can think of no alternative...
130 void
131 wxListCtrl_onPaintCallback(wxGenericListCtrl *listctrl, wxDC *dc)
132 {
133         MyListCtrl *ctrl = wxStaticCast(listctrl, MyListCtrl);
134         if (ctrl != NULL && dc != NULL)
135                 ctrl->OnPaintCallback(dc);
136 }
137
138 wxString
139 MyListCtrl::OnGetItemText(long item, long column) const
140 {
141         if (dataSource == NULL)
142                 return wxEmptyString;
143         return dataSource->GetItemText((MyListCtrl *)this, item, column);
144 }
145
146 wxListItemAttr *
147 MyListCtrl::OnGetItemAttr(long item) const
148 {
149         float fg[3], bg[3];
150         long row, col;
151         int ret;
152         row = item % 1000000;
153         col = item / 1000000 - 1;  //  -1 for all rows
154         ret = dataSource->SetItemColor((MyListCtrl *)this, row, col, fg, bg);
155         if (ret == 0)
156                 return NULL;
157         if (ret & 1) {
158                 wxColour fgcol((int)(fg[0] * 255), (int)(fg[1] * 255), (int)(fg[2] * 255));
159                 subTitleRowAttr->SetTextColour(fgcol);
160         } else subTitleRowAttr->SetTextColour(*wxBLACK);
161         if (ret & 2) {
162                 wxColour bgcol((int)(bg[0] * 255), (int)(bg[1] * 255), (int)(bg[2] * 255));
163                 subTitleRowAttr->SetBackgroundColour(bgcol);
164         } else subTitleRowAttr->SetBackgroundColour(*wxWHITE);
165         return subTitleRowAttr;
166 }
167
168 void
169 MyListCtrl::PostSelectionChangeNotification()
170 {
171         if (!selectionChangeNotificationSent && selectionChangeNotificationEnabled) {
172                 selectionChangeNotificationSent = true;
173                 wxCommandEvent myEvent(MyListCtrlEvent, MyListCtrlEvent_tableSelectionChanged);
174                 wxPostEvent(this, myEvent);
175         }
176 }
177
178 void
179 MyListCtrl::OnBeginLabelEdit(wxListEvent &event)
180 {
181 //      printf("OnBeginLabelEdit: item index = %d\n", event.GetIndex());
182 }
183
184 void
185 MyListCtrl::OnEndLabelEdit(wxListEvent &event)
186 {
187 //      printf("OnEndLabelEdit: item index = %d\n", event.GetIndex());
188 }
189
190 void
191 MyListCtrl::OnItemActivated(wxListEvent &event)
192 {
193 //      printf("OnItemActivated: item index = %d, col = %d\n", event.GetIndex(), event.GetItem().m_col);
194 }
195
196 void
197 MyListCtrl::OnBeginDrag(wxListEvent &event)
198 {
199         int count = GetItemCount();
200         
201         if (dataSource == NULL || !dataSource->IsDragAndDropEnabled(this))
202                 return;
203         EndEditText(true);
204         dragTargetRow = -1;
205         while (1) {
206                 wxRect r;
207                 wxMouseState mstate = wxGetMouseState();
208                 wxPoint pt(mstate.GetX(), mstate.GetY());
209                 pt = ScreenToClient(pt);
210                 long newRow = FindItem(-1, pt, 0);
211                 if (newRow != dragTargetRow) {
212                         if (newRow >= 0)
213                                 EnsureVisible(newRow);
214                         else {
215                                 GetItemRect(0, r);
216                                 if (pt.y < r.y)
217                                         EnsureVisible(0);
218                                 else {
219                                         GetItemRect(count - 1, r);
220                                         if (pt.y >= r.y) {
221                                                 EnsureVisible(count - 1);
222                                                 if (pt.y < r.y + r.height)
223                                                         newRow = count;
224                                         } else if (count > 0 && pt.y >= r.y - r.height)
225                                                 newRow = count - 1;
226                                 }
227                         }
228                 }
229                 if (newRow != dragTargetRow) {
230                         if (newRow >= 0) {
231                                 if (newRow == count) {
232                                         GetItemRect(newRow - 1, r);
233                                         r.y += r.height / 2;
234                                 } else {
235                                         GetItemRect(newRow, r);
236                                         r.y -= r.height / 2;
237                                 }
238                                 RefreshRect(r);
239                         }
240                         if (dragTargetRow >= 0) {
241                                 if (dragTargetRow == count) {
242                                         GetItemRect(dragTargetRow - 1, r);
243                                         r.y += r.height / 2;
244                                 } else {
245                                         GetItemRect(dragTargetRow, r);
246                                         r.y -= r.height / 2;
247                                 }
248                                 RefreshRect(r);
249                         }
250                         dragTargetRow = newRow;
251                         Update();
252                 }
253                 if (!mstate.LeftIsDown()) {
254                         //  If the mouse cursor is outside the item rect, then dragging should be discarded
255                         if (dragTargetRow >= 0) {
256                                 r = GetClientRect();
257                                 if (!r.Contains(pt))
258                                         dragTargetRow = -1;
259                         }
260                         break;
261                 }
262         }
263         if (dragTargetRow >= 0)
264                 dataSource->DragSelectionToRow(this, dragTargetRow);
265         dragTargetRow = -1;
266         Update();
267 }
268
269 bool
270 MyListCtrl::GetItemRectForRowAndColumn(wxRect &rect, int row, int column)
271 {
272         int i, xpos, width, xunit, yunit;
273         if (!GetItemRect(row, rect))
274                 return false;
275         GetScrollPixelsPerUnit(&xunit, &yunit);
276         xpos = -GetScrollPos(wxHORIZONTAL) * xunit;
277         for (i = 0; i < column; i++) {
278                 width = GetColumnWidth(i);
279                 xpos += width;
280         }
281         rect.SetX(xpos);
282         rect.SetWidth(GetColumnWidth(column));
283         return true;
284 }
285
286 void
287 MyListCtrl::GetScrollPixelsPerUnit(int *xunit, int *yunit)
288 {
289         wxGenericListCtrl::GetScrollPixelsPerUnit(xunit, yunit);
290 //      int x, y;
291 //      /*  m_mainWin is a protected member in wxGenericListCtrl  */
292 //      /*((wxScrolledWindow *)m_mainWin)->*/GetScrollPixelsPerUnit(&x, &y);    
293 //      if (xunit != NULL)
294 //              *xunit = x;
295 //      if (yunit != NULL)
296 //              *yunit = y;
297 }
298
299 bool
300 MyListCtrl::FindItemAtPosition(const wxPoint &pos, int *row, int *column)
301 {
302         int i, r, ncols, width, xpos, flags, xunit, yunit;
303         r = (int)HitTest(pos, flags, NULL);
304         if (r == wxNOT_FOUND)
305                 return false;
306         ncols = GetColumnCount();
307         GetScrollPixelsPerUnit(&xunit, &yunit);
308         xpos = -GetScrollPos(wxHORIZONTAL) * xunit;
309         for (i = 0; i < ncols; i++) {
310                 width = GetColumnWidth(i);
311                 xpos += width;
312                 if (pos.x < xpos)
313                         break;
314         }
315         if (i >= ncols)
316                 return false;
317         *row = r;
318         *column = i;
319         return true;
320 }
321
322 void
323 MyListCtrl::StartEditText(int row, int column)
324 {
325         wxRect rect;
326         int x0, x1, dx, size, xpos, ypos, xunit, yunit;
327         if (editText != NULL && editText->IsShown())
328                 EndEditText(true);
329         if (dataSource == NULL || !dataSource->IsItemEditable(this, row, column))
330                 return;
331
332         /*  Select only this row  */
333         x1 = GetItemCount();
334         for (x0 = 0; x0 < x1; x0++)
335                 SetItemState(x0, (x0 == row ? wxLIST_STATE_SELECTED : 0), wxLIST_STATE_SELECTED);
336         
337         //  Call the event handler directly
338         //  (Otherwise, the table selection may be updated from the "current" selection in the molecule
339         //  before the selection is updated from the table)
340         wxCommandEvent dummyEvent;
341         OnTableSelectionChanged(dummyEvent);
342
343         /*  Scroll the list so that the editing item is visible  */
344         EnsureVisible(row);
345         GetItemRectForRowAndColumn(rect, row, column);
346         rect.Inflate(1, 2);
347         editRow = row;
348         editColumn = column;
349         GetScrollPixelsPerUnit(&xunit, &yunit);
350         xpos = GetScrollPos(wxHORIZONTAL);
351         ypos = GetScrollPos(wxVERTICAL);
352         x0 = rect.GetX();
353         x1 = x0 + rect.GetWidth();
354         if (x0 < 0) {
355                 /*  Scroll right  */
356                 dx = x0 / xunit - 1;
357                 if (xpos + dx < 0)
358                         dx = -xpos;
359         } else if (x1 > (size = GetSize().GetWidth())) {
360                 /*  Scroll left  */
361                 dx = ((x1 - size) / xunit) + 1;
362         } else dx = 0;
363         if (dx != 0) {
364                 Scroll(xpos + dx, -1);
365         //      Refresh();
366                 rect.x += dx * xunit;
367         }
368
369         /*  Reposition the rect relative to the origin of the scrolling area  */
370         GetItemRectForRowAndColumn(rect, row, column);
371         rect.Inflate(1, 2);
372         ClientToScreen(&rect.x, &rect.y);
373         ((wxWindow *)m_mainWin)->ScreenToClient(&rect.x, &rect.y);
374         
375 #if defined(__WXMSW__)
376         //  wxMSW seems to require that rect.y >= 0
377 //      if (rect.y < 0)
378 //              rect.y = 0;
379 #endif
380         
381         wxString str = dataSource->GetItemText(this, editRow, editColumn);
382         if (editText == NULL) {
383                 /*  m_mainWin is a protected member in wxGenericListCtrl  */
384                 editText = new wxTextCtrl((wxWindow *)m_mainWin, -1, wxT(""), rect.GetPosition(), rect.GetSize(), wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
385                 editText->Connect(wxID_ANY, wxEVT_KEY_DOWN, wxKeyEventHandler(MyListCtrl::OnKeyDownOnEditText), NULL, this);
386                 editText->Connect(wxID_ANY, wxEVT_KILL_FOCUS, wxFocusEventHandler(MyListCtrl::OnKillFocusOnEditText), NULL, this);
387         } else {
388                 editText->SetSize(rect.x, rect.y, rect.width, rect.height, wxSIZE_ALLOW_MINUS_ONE);
389                 editText->Clear();
390                 editText->Show();
391         }
392         editText->AppendText(str);
393         editText->SetFocus();
394 //      editText->Connect(wxID_ANY, wxEVT_IDLE, wxIdleEventHandler(MyListCtrl::OnIdle), NULL, this);
395
396         editText->SetSelection(-1, -1);  //  Select all text
397 }
398
399 void
400 MyListCtrl::EndEditTextAndRestart(bool setValueFlag, int newRow, int newColumn)
401 {
402         wxString sval;
403         if (editText != NULL && editText->IsShown()) {
404                 if (setValueFlag && dataSource) {
405                         sval = editText->GetValue();
406                 }
407         //      if (wxWindow::FindFocus() == editText) {
408         //              SetFocus();
409         //      }
410 #if defined(__WXMAC__)
411                 {
412                         /*  Erase the focus ring  */
413                         wxRect rect = editText->GetRect();
414                         rect = rect.Inflate(5, 5);
415                         //      Refresh(true, &rect);  /*  This somehow leaves lower side of the focus ring to remain  */
416                         Refresh();
417                 }
418 #endif
419         
420         //  Should we destroy editText every time?
421         //  (It would be safer anyway)
422         //editText->Destroy();
423         //editText = NULL;
424     
425         //  Temporarily hide until new editing starts
426                 //  (editText is set to NULL to avoid recursive calling of EndEditText())
427                 wxTextCtrl *saveEditText = editText;
428                 editText = NULL;
429                 saveEditText->Hide();
430                 editText = saveEditText;
431                 
432                 if (setValueFlag && dataSource)
433                         dataSource->SetItemText(this, editRow, editColumn, sval);
434
435         }
436         
437         if (newRow >= 0 && newColumn >= 0) {
438                 StartEditText(newRow, newColumn);
439         } else {
440                 editRow = editColumn = -1;
441 #if 0 && defined(__WXMAC__)
442                 if (editText != NULL) {
443                         editText->Disconnect(wxID_ANY);
444                         editText->Destroy();
445                         editText = NULL;
446                 }
447 #else
448                 if (editText != NULL) {
449                         editText->Move(-1000, -1000);
450                         editText->Hide();
451                 }
452 #endif
453         }
454
455 }
456
457 void
458 MyListCtrl::EndEditText(bool setValueFlag)
459 {
460         EndEditTextAndRestart(setValueFlag, -1, -1);
461 }
462
463 void
464 MyListCtrl::OnKillFocusOnEditText(wxFocusEvent &event)
465 {
466         if (editText != NULL && editText->IsShown()) {
467                 EndEditText(true);
468         }
469 }
470
471 void
472 MyListCtrl::OnIdle(wxIdleEvent &event)
473 {
474         /*
475         wxWindow *wp;
476         if (editText != NULL && (wp = wxWindow::FindFocus()) != editText) {
477                 EndEditText(true);
478         }
479          */
480 }
481
482 void
483 MyListCtrl::OnKeyDownOnEditText(wxKeyEvent &event)
484 {
485         int keyCode, ncols, nrows, ecol, erow;
486         bool shiftDown;
487         if (editText == NULL || !editText->IsShown()) {
488                 event.Skip();
489                 return;
490         }
491         keyCode = event.GetKeyCode();
492         ncols = GetColumnCount();
493         nrows = GetItemCount();
494         shiftDown = (event.GetModifiers() == wxMOD_SHIFT);
495         switch (keyCode) {
496                 case WXK_TAB:
497                         ecol = editColumn;
498                         erow = editRow;
499                         while (1) {
500                                 if (shiftDown) {
501                                         if (ecol == 0) {
502                                                 if (erow == 0)
503                                                         return;
504                                                 ecol = ncols - 1;
505                                                 erow--;
506                                         } else {
507                                                 ecol--;
508                                         }
509                                 } else {
510                                         if (ecol == ncols - 1) {
511                                                 if (erow >= nrows - 1)
512                                                         return;
513                                                 ecol = 0;
514                                                 erow++;
515                                         } else {
516                                                 ecol++;
517                                         }
518                                 }
519                                 if (dataSource == NULL || dataSource->IsItemEditable(this, erow, ecol))
520                                         break;
521                         }
522                         EndEditTextAndRestart(true, erow, ecol);
523                         break;
524                 case WXK_RETURN:
525                         if (event.GetModifiers() == wxMOD_ALT) {
526                                 printf("alt-return pressed\n"); fflush(stdout);
527                                 EndEditText(true);
528                                 printf("EndEditText completed\n"); fflush(stdout);
529                                 return;
530                         }
531                         ecol = editColumn;
532                         erow = editRow;
533                         while (1) {
534                                 if (shiftDown) {
535                                         if (erow == 0)
536                                                 return;
537                                         erow--;
538                                 } else {
539                                         if (erow == nrows - 1)
540                                                 return;
541                                         erow++;
542                                 }
543                                 if (dataSource == NULL || dataSource->IsItemEditable(this, erow, ecol))
544                                         break;
545                         }
546                         EndEditTextAndRestart(true, erow, ecol);
547                         break;
548                 case WXK_ESCAPE:
549                         EndEditText(false);
550                         break;
551                 default:
552                         event.Skip();
553                         break;
554         }
555 }
556
557 bool
558 MyListCtrl::DeleteColumn(int col)
559 {
560         EndEditText(false);
561         return wxGenericListCtrl::DeleteColumn(col);
562 }
563
564 bool
565 MyListCtrl::InsertColumn(long col, const wxString &heading, int format, int width)
566 {
567         EndEditText(false);
568         return wxGenericListCtrl::InsertColumn(col, heading, format, width);
569 }
570
571 void
572 MyListCtrl::OnPopUpMenuSelected(wxCommandEvent &event)
573 {
574         if (dataSource != NULL)
575                 dataSource->OnPopUpMenuSelected(this, lastPopUpRow, lastPopUpColumn, event.GetId() - 1);
576 }
577
578 void
579 MyListCtrl::OnLeftDClick(wxMouseEvent &event)
580 {
581         int row, col;
582         wxPoint pos = event.GetPosition();
583         if (!FindItemAtPosition(pos, &row, &col))
584                 return;
585         if (editText != NULL) {
586                 if (editRow == row && editColumn == col) {
587                         event.Skip();
588                         return;
589                 }
590                 EndEditTextAndRestart(true, row, col);
591         } else {
592                 StartEditText(row, col);
593         }
594 }
595
596 void
597 MyListCtrl::OnMouseDown(wxMouseEvent &event)
598 {
599         int row, col, i, n;
600         char **items;
601
602         if (editText != NULL && editText->IsShown()) {
603                 //  During the text edit, mouse down outside the textctrl will terminate the editing
604                 EndEditText();
605         }
606
607         wxPoint pos = event.GetPosition();
608         if (FindItemAtPosition(pos, &row, &col) && dataSource != NULL && (n = dataSource->HasPopUpMenu(this, row, col, &items)) > 0) {
609                 wxMenu mnu;
610                 for (i = 0; i < n; i++) {
611                         char *p = items[i];
612                         bool enabled = true;
613                         if (*p == '-') {
614                                 if (p[1] == 0) {
615                                         //  Separator
616                                         mnu.AppendSeparator();
617                                         p = NULL;
618                                 } else {
619                                         //  Disabled item
620                                         p++;
621                                         enabled = false;
622                                 }
623                         }
624                         if (p != NULL) {
625                                 wxString itemStr(p, WX_DEFAULT_CONV);
626                                 mnu.Append(i + 1, itemStr);
627                                 if (!enabled)
628                                         mnu.Enable(i + 1, false);
629                         }
630                         free(items[i]);
631                         items[i] = NULL;
632                 }
633                 free(items);
634                 lastPopUpColumn = col;
635                 lastPopUpRow = row;
636                 mnu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MyListCtrl::OnPopUpMenuSelected), NULL, this);
637                 PopupMenu(&mnu);
638                 n = dataSource->GetItemCount(this);
639                 for (i = 0; i < n; i++)
640                         SetItemState(i, (i == row ? wxLIST_STATE_SELECTED : 0), wxLIST_STATE_SELECTED);
641                 PostSelectionChangeNotification();
642                 return;
643         }
644         
645         //  Intercept mouse down event and post selection change notification
646         //  (a workaround of wxMSW problem where EVT_LIST_ITEM_SELECTED is not sent in some occasions)
647         PostSelectionChangeNotification();
648         event.Skip();
649 }
650
651 void
652 MyListCtrl::OnChar(wxKeyEvent &event)
653 {
654         //  See comments on OnMouseUp()
655         PostSelectionChangeNotification();
656         event.Skip();
657 }
658
659 void
660 MyListCtrl::OnItemSelectionChanged(wxListEvent &event)
661 {
662         PostSelectionChangeNotification();
663 }
664
665 void
666 MyListCtrl::OnTableSelectionChanged(wxCommandEvent &event)
667 {
668         selectionChangeNotificationSent = false;
669         if (dataSource == NULL)
670                 return;
671         dataSource->OnSelectionChanged(this);
672 }
673
674 void
675 MyListCtrl::OnEnableTableSelectionNotification(wxCommandEvent &event)
676 {
677         selectionChangeNotificationEnabled = true;
678 }