]> Creatis software - creaImageIO.git/blob - src2/creaImageIOWxTreeView.cpp
export from storage to storage functionality
[creaImageIO.git] / src2 / creaImageIOWxTreeView.cpp
1 #include <creaImageIOWxTreeView.h>
2 #include <creaImageIOGimmickView.h>
3 #include <creaImageIOSystem.h>
4 #include <wx/splitter.h>
5 #include <wx/gdicmn.h>
6 #include <boost/date_time/gregorian/gregorian.hpp>
7 #include <creaImageIOGimmick.h>
8 #ifdef _DEBUG
9 #define new DEBUG_NEW
10 #endif
11 //=====================================================================
12 namespace creaImageIO
13 {
14
15   //=====================================================================
16 }
17 //=====================================================================
18
19 //=====================================================================
20 ///Comparing function for ordering algorithm. Takes parameters as strings.
21 int wxCALLBACK CompareFunctionStrings(long item1, long item2, long sortData)
22 {       
23   creaImageIO::ItemData* data1 = (creaImageIO::ItemData*)item1;
24   creaImageIO::ItemData* data2 = (creaImageIO::ItemData*)item2;
25
26   const std::string& s1(*(data1->attr));
27   const std::string& s2(*(data2->attr));
28   if(sortData==1)
29     {
30       // inverse the order
31       if (s1 < s2)
32         return 1;
33       if (s1 > s2)
34         return -1;
35       
36       return 0;
37     }
38   else
39     {
40       if (s1 < s2)
41         return -1;
42       if (s1 > s2)
43         return 1;
44       
45       return 0;
46       
47     }
48 }
49 //=====================================================================
50
51 //=====================================================================
52 ///Comparing function for ordering algorithm. Takes parameters as ints.
53 int wxCALLBACK CompareFunctionInts(long item1, long item2, long sortData)
54 {       
55   creaImageIO::ItemData* data1 = (creaImageIO::ItemData*)item1;
56   creaImageIO::ItemData* data2 = (creaImageIO::ItemData*)item2;
57
58   const std::string& s1(*(data1->attr));
59   const std::string& s2(*(data2->attr));
60
61   int val1=atoi(s1.c_str());
62   int val2=atoi(s2.c_str());
63
64   if(sortData==1)
65     {
66       // inverse the order
67       if (val1 < val2)
68         return 1;
69       if (val1 > val2)
70         return -1;
71       
72       return 0;
73     }
74   else
75     {
76       if (val1 < val2)
77         return -1;
78       if (val1 > val2)
79         return 1;
80
81       return 0;
82       
83     }
84   
85 }
86
87 //=====================================================================
88
89
90 //=====================================================================
91 namespace creaImageIO
92 {
93   //=====================================================================
94   // CTor
95   WxTreeView::WxTreeView(TreeHandler* handler,
96                          GimmickView* gimmick,
97                          wxWindow* parent,
98                          const wxWindowID id)
99     : wxPanel(parent,id),
100       TreeView(handler, gimmick)
101   {
102     GimmickDebugMessage(1,"WxTreeView::WxTreeView"
103                         <<std::endl);
104
105     
106     // Split part below toolbar into notebook for views and panel
107     // for preview, messages...
108     // TO DO : Splitter
109     //    mSplitter = new wxSplitterWindow( this , -1);
110
111     // Global sizer
112     msizer = new wxBoxSizer(wxHORIZONTAL);
113     
114     int ctrl_style = wxLC_REPORT | wxLC_VRULES;
115     int col_style = wxLIST_FORMAT_LEFT;
116
117     // Creating the ListCtrl for the levels > 0 (not for Root level)
118     for (int i = 0;
119          i < handler->GetTree().GetNumberOfLevels() -1;
120          ++i)
121       {
122         GimmickDebugMessage(5,"Creating view for level "<<i
123                             <<std::endl);
124         LevelType level;
125         level.SelectedUpToDate = true;
126         level.SortColumn = 0;
127
128         // If the first level : parent = this
129         wxWindow* sparent = this;
130         // else parent = last splitter
131         if (i>0) 
132                 sparent = mLevelList[i-1].wxSplitter;
133
134         level.wxSplitter = new wxSplitterWindow( sparent , -1);
135         if(i!=0)
136         {
137         level.wxSplitter->Show(false);
138         }
139         //          level.wxSplitter->SetMinimumPaneSize(100);
140         
141         wxListCtrl* ctrl = new wxListCtrl(level.wxSplitter,
142                                           i,
143                                           wxDefaultPosition, 
144                                           wxDefaultSize,
145                                           ctrl_style);
146         level.wxCtrl = ctrl;
147         level.wxSplitter->Initialize(ctrl);
148    
149         // Create the columns : one for each attribute of the level
150         int col = 0;
151         std::string title;
152
153         tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
154         for (a  = handler->GetTree().GetAttributeDescriptorList(i+1).begin();
155              a != handler->GetTree().GetAttributeDescriptorList(i+1).end();
156              ++a)
157
158 {
159         
160             GimmickDebugMessage(5,"Creating column "<<col<<" : "
161                                 <<a->GetName()
162                                 <<std::endl);
163             
164             if(a->GetFlags()!=creaImageIO::tree::AttributeDescriptor::PRIVATE)
165               {
166                 
167                 if(a->GetName()=="UNKNOWN")
168                   {
169                     title = "#";
170                     title += handler->GetTree().GetLevelDescriptor(i+1).GetName();
171                     if (title[title.size()-1]!='s')
172                       title += "s";
173                     
174                   }
175                 else
176                   {
177                     title=a->GetName();
178                   }
179                   std::string temp = a->GetKey();
180                   if (temp.compare("ID") != 0)
181                   {
182                 
183                 ctrl->InsertColumn(col, 
184                                    crea::std2wx(title),
185                                    col_style);
186                 col++;
187                   }
188                 level.key.push_back(a->GetKey());
189               }
190                 
191           }
192           
193         mLevelList.push_back(level);
194       }
195     
196 #if wxUSE_MENUS
197
198          // Column Menu
199     menu =new wxMenu;
200         wxMenuItem* m1=menu->Append(wxID_ANY, _T("&Sort ascending"));
201         wxMenuItem* m2=menu->Append(wxID_ANY, _T("&Sort descending"));
202         wxMenuItem* m3=menu->Append(wxID_ANY, _T("&Filter"));
203         mAscendingID=m1->GetId();
204         mDescendingID=m2->GetId();
205         mFilterID=m3->GetId();
206         Connect( mAscendingID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnPopupSort) );
207         Connect( mDescendingID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnPopupSort) );
208         Connect( mFilterID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnPopupFilter) );
209
210
211         ////SubMenuItem EXPORT
212         subExportMenu = new wxMenu;
213         wxMenuItem *subExp1 = subExportMenu->Append(wxID_ANY, _T("&Export to Storage"));
214         Connect( subExp1->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnExportToStorage) );
215
216         //ItemMenu
217         menuItem =new wxMenu;
218         wxMenuItem* m1Item=menuItem->Append(wxID_ANY, _T("&Anonymize"));
219         wxMenuItem* m2Item=menuItem->Append(wxID_ANY, _T("&Local Copy"));
220         wxMenuItem* m3Item=menuItem->Append(wxID_ANY, _T("&Edit Fields"));
221         wxMenuItem* m4Item=menuItem->Append(wxID_ANY, _T("&Display Dicom Tags"));
222         menuItem->AppendSubMenu(subExportMenu, wxT("&Export"));
223
224         mAnonymizingID=m1Item->GetId();
225         mLocalCopyID=m2Item->GetId();
226         mEditFieldID=m3Item->GetId();
227         mDumpID=m4Item->GetId();
228         
229         //Connect( mAnonymizingID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnAnonymize) );
230         Connect( mLocalCopyID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnLocalCopy) );
231         Connect( mEditFieldID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnEditField) );
232         Connect( mDumpID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WxTreeView::OnDumpTags) );
233         
234
235         
236 #endif // wxUSE_MENUS
237         /// Initialize the first level splitter
238           
239         msizer->Add( mLevelList[0].wxSplitter ,1, wxGROW  ,0);
240         //      mColumnSelected=1;
241         mLastSelected=0;
242         mLastLevel=0;
243         //      mDirection=true;
244
245         mIgnoreSelectedChanged = false;
246
247         //CreateColorPalette();
248     UpdateLevel(1);
249
250     SetSizer( msizer );     
251     SetAutoLayout(true);
252     Layout();
253
254   }
255   //=====================================================================
256
257   //=====================================================================
258   /// Destructor
259   WxTreeView::~WxTreeView()
260   {
261     GimmickDebugMessage(1,"WxTreeView::~WxTreeView"
262                         <<std::endl);
263         delete menu;
264         delete menuItem;
265
266   }
267   //=====================================================================
268   
269   
270   
271   //=====================================================================
272   const std::vector<tree::Node*>& WxTreeView::GetSelected(int level)
273   {
274           std::vector<tree::Node*>& sel = mLevelList[0].Selected;
275     //  if (GetSelectedUpToDate(level)) 
276     int l = level - 1;
277     // the selection of upper level
278         if(mLevelList.size() == level -1)
279                  sel = mLevelList.back().Selected;
280         else
281                   sel=  mLevelList[l].Selected;
282         if (sel.size() > 0)
283         {
284                 sel.clear();
285         }
286           if (level == 1) 
287       {
288         sel.push_back(GetTreeHandler()->GetTree().GetTree());
289       }
290           else if (level < mLevelList.size()+2 ) 
291     {
292                 long item = -1;
293                 for ( ;; )
294                 {
295                         item = GetCtrl(l-1)->GetNextItem(item,
296                                                                                  wxLIST_NEXT_ALL,
297                                                                                  wxLIST_STATE_SELECTED);
298                         if ( item == -1 )
299                                 break;
300                         long adr = GetCtrl(l-1)->GetItemData(item);
301                         tree::Node* n = ((ItemData*)adr)->node;
302                         if(mLastSelected==item)
303                         {
304                                 std::vector<tree::Node*>::iterator it;
305                                 it = sel.begin();
306                                 it = sel.insert ( it , n );
307                         }
308                         else
309                         {
310                                 
311                                 sel.push_back(n);
312                         }                       
313                         
314                 }
315                 /*int n = GetCtrl(l-1)->GetItemCount();
316                 for (int i = 0; i<n; i++)
317                 {
318                         std::cout<<GetCtrl(l-1)->GetItemState(i,wxLIST_STATE_SELECTED)<<std::endl;
319                         if ( GetCtrl(l-1)->GetItemState(i,wxLIST_STATE_SELECTED))
320                         {
321                                 long adr = GetCtrl(l-1)->GetItemData(i);
322                                 tree::Node* n = ((ItemData*)adr)->node;
323                                 if(mLastSelected==i)
324                                 {
325                                         std::vector<tree::Node*>::iterator it;
326                                         it = sel.begin();
327                                         it = sel.insert ( it , n );
328                                 }
329                                 else
330                                 {
331                                         
332                                         sel.push_back(n);
333                                 }
334                         }
335               }*/
336           }
337         else
338         {
339                 // NOTHING
340         }   
341          
342     //    return mLevelList[level-1].Selected;
343     return sel;
344   }
345
346   //=====================================================================
347   
348   //=====================================================================
349   ///Removes selected nodes on last selected level
350    // NOT SPECIFIC 
351   void WxTreeView::RemoveSelected(std::string &i_save)
352   {
353          bool erase=false;
354          
355          unsigned int tempLevel = mLastLevel;
356     mLastLevel+=1;
357     const std::vector<tree::Node*>& sel=GetSelected(mLastLevel+1);
358         // if no selection, no remove action.
359     if(sel.size() != 0)
360         {
361         
362             std::stringstream out;
363             std::string levelName=GetTreeHandler()->GetTree().GetLevelDescriptor(mLastLevel).GetName();
364             out<<"Delete ";
365             out<<sel.size();
366             if(sel.size()>1&&levelName.at(levelName.size()-1)!='s')
367               {
368                 out<<" "<<levelName;
369                 out<<"s?";
370               }
371             else
372               {
373                 out<<" "<<GetTreeHandler()->GetTree().GetLevelDescriptor(mLastLevel).GetName()<<"?";
374               }
375             if (wxMessageBox(crea::std2wx(out.str()),
376                              _T("Remove Files"),
377                              wxYES_NO,this ) == wxYES)
378               {
379                 erase = true;
380               }
381             if(erase)
382                   {
383             GetGimmickView()->modifyValidationSignal(false);
384                     bool needRefresh=false;
385                     std::vector<tree::Node*>::const_iterator i;
386                     for (i=sel.begin(); i!=sel.end(); ++i)
387                       {
388                         GimmickMessage(1,
389                                        "deleting '"
390                                        <<(*i)->GetLabel()
391                                        <<"'"<<mLastLevel
392                                        <<std::endl);
393                         if((*i)->GetParent()->GetNumberOfChildren()<2)
394                           {
395                             needRefresh=true;
396                           }
397                           //tree::Node* n = new (tree::Node*)(*i);
398                           GetTreeHandler()->LoadChildren((*i),4);
399                           GetGimmickView()->AddIgnoreFile(*i);
400                           GetTreeHandler()->Remove(*i);
401                       }
402                     
403                     if(needRefresh && mLastLevel>1)
404                       {
405                         UpdateLevel(mLastLevel-2);
406                       }
407                     else if(mLastLevel>1)
408                       {
409                         UpdateLevel(mLastLevel-1);
410                       }
411                     else
412                       {
413                         UpdateLevel(mLastLevel);
414                       }
415                   }
416         }
417         else
418         {
419                 // no need to incremente level
420                 mLastLevel = tempLevel;
421         }
422     
423         if (erase && mLastLevel == 1 && i_save == "0")
424         {
425         
426                 RemoveAlertDlg *dial = new RemoveAlertDlg(this,  crea::std2wx("Remove files"), wxSize(370,100));
427                 //dial->ShowModal();
428                 if (dial->ShowModal() == wxID_OK)
429                 {
430                         i_save = dial->isChecked() == false? "0" : "1";
431                 }
432                 
433         }
434   }
435   
436   
437   //=====================================================================
438   /// Updates a level of the view (adds or removes children, etc.)
439   void WxTreeView::UpdateLevel( int level )
440   {
441     GimmickDebugMessage(1,
442                         GetTreeHandler()->GetTree().GetLabel()
443                         <<"WxTreeView::UpdateLevel(level "
444                         <<level
445                         <<")"
446                         <<std::endl);
447     
448     wxBusyCursor busy;
449     RecursiveUpdateLevel(level);
450     int i;
451     for (i=0; i<level-1; i++)
452       {
453         if (!GetSplitter(i)->IsSplit()) 
454           GetSplitter(i)->SplitVertically(  GetCtrl(i), GetSplitter(i+1),
455                                             100 );
456       }
457     if (GetSplitter(i)->IsSplit()) GetSplitter(i)->Unsplit();    
458     
459   }
460   //=====================================================================
461   
462   //=====================================================================
463   /// Recursive method called upon by UpdateLevel to refresh all windows
464   void WxTreeView::RecursiveUpdateLevel( int level )
465   {
466     GimmickDebugMessage(1,
467                         GetTreeHandler()->GetTree().GetLabel()
468                         <<"WxTreeView::RecursiveUpdateLevel(level "
469                         <<level
470                         <<")"<<std::endl);
471     
472     
473     const std::vector<tree::Node*>& sel(GetSelected(level));
474     
475     int l = level - 1;
476     
477     // to speed up inserting we hide the control temporarily
478     GetCtrl(l)->Hide();
479     GetCtrl(l)->DeleteAllItems();
480     
481     std::vector<tree::Node*>::const_iterator i;
482     
483     for (i=sel.begin(); i!=sel.end(); ++i)
484       {
485         GimmickDebugMessage(1,
486                             "adding children of '"
487                             <<(*i)->GetLabel()
488                             <<"'"
489                             <<std::endl);
490         int _id=0;
491         
492         //Adds items and sets their attributes 
493         
494         GetTreeHandler()->LoadChildren(*i,1);
495         tree::Node::ChildrenListType::reverse_iterator j;
496         for (j = (*i)->GetChildrenList().rbegin(); 
497              j!= (*i)->GetChildrenList().rend(); 
498              ++j)
499           {
500             GimmickDebugMessage(1,
501                                 "adding children "
502                                 <<(*j)->GetLabel()
503                                 <<"'"
504                                 <<std::endl);
505             
506             wxListItem item;
507             item.SetMask(wxLIST_MASK_STATE | 
508                          wxLIST_MASK_TEXT |
509                          //                      wxLIST_MASK_IMAGE |
510                          wxLIST_MASK_DATA |
511                          //                      wxLIST_MASK_WIDTH |
512                          wxLIST_MASK_FORMAT
513                          );
514             
515                 ItemData* data = new ItemData();
516             data->node = *j;
517             data->id = _id;
518                 
519             item.SetId(_id);
520             item.SetData(data);
521
522             _id++;
523             GetCtrl(l)->InsertItem(item);
524             
525             //Setting attributes
526             for (int k=0; k<GetCtrl(l)->GetColumnCount(); ++k)                          
527               {
528                 std::string val;
529                 //  Temporary correction : it works but no explanation about the problem FCY
530                 
531                 if(k==0 && level <3)
532                 {
533                   val = (*j)->GetAttribute("NumberOfChildren");
534                 }
535                 else
536                   val = (*j)->GetAttribute(mLevelList[l].key[k]);
537                 if(((*j)->GetAttributeDescriptor(mLevelList[l].key[k])).isDateEntry()) // Date
538                   {
539                     //                                    std::cout << "["<<val<< "]" << std::endl;
540                     std::string valtmp(val);
541                     try
542                       {
543                         boost::gregorian::date d1(boost::gregorian::from_undelimited_string(val));                                 
544                         val = to_iso_extended_string(d1);
545                       }
546                     catch (...)
547                       {
548                         val =  valtmp;
549                       }
550                     //                                    std::cout << "["<<val<< "]" << std::endl;     
551                   }
552                 else if(((*j)->GetAttributeDescriptor(mLevelList[l].key[k])).isTimeEntry()) // Time
553                   {
554                     if ((val.size()>6) && 
555                         (val != "" || val != " "))
556                       val = val.substr(0,2) + " : " 
557                         + val.substr(2,2) + " : " 
558                         + val.substr(4,2);
559                   }
560                 else
561                   {
562                     if (val.size()==0) val = "?";
563                   }
564                 if (val.size()==0) val = "X";
565                 item.SetText( crea::std2wx(val));
566                 item.SetColumn(k);
567                   
568                   GetCtrl(l)->SetItem(item);
569                   }
570                 item.Clear();
571             
572           }
573       }
574     
575     SortLevel(l);
576     GetCtrl(l)->Show();
577   }
578   //=====================================================================
579   
580   
581   //================================================================
582   void WxTreeView::OnItemDeSelected(wxListEvent& event)
583   { 
584     GimmickDebugMessage(1,
585                         GetTreeHandler()->GetTree().GetLabel()
586                         <<" WxTreeView::OnItemDeselected"<<std::endl);
587     // retrieve the level
588     wxObject* obj = event.GetEventObject();   
589     unsigned int level = 0;
590     for (level = 0; level<mLevelList.size(); ++level)
591       {
592         if ( GetCtrl(level) == obj ) break;
593       } 
594     SetSelectedUpToDate(level,false);
595     // to allow a first selection in images TreeView
596     if (level==mLevelList.size()-1) 
597       OnItemSelected(event);
598   }
599   //================================================================
600   
601   //================================================================
602   void WxTreeView::OnItemSelected(wxListEvent& event)
603   { 
604           
605     GimmickDebugMessage(1,
606                         GetTreeHandler()->GetTree().GetLabel()
607                         <<" WxTreeView::OnItemSelected"<<std::endl);
608
609     if (mIgnoreSelectedChanged) 
610       {
611         GimmickDebugMessage(1,
612                             " mIgnoreSelectedChanged true: returning"
613                             <<std::endl);
614         return;
615       }
616     
617
618     
619     wxListItem info;
620     info.m_itemId = event.m_itemIndex;
621     mLastSelected = event.m_itemIndex;
622     // retrieve the level
623     wxObject* obj = event.GetEventObject();   
624     unsigned int level = 0;
625     for (level = 0; level<mLevelList.size(); ++level)
626       {
627         if ( GetCtrl(level) == obj ) break;
628       }
629         mLastLevel=level;
630     GimmickDebugMessage(1,
631                         " Level "<<level+1
632                         <<std::endl);
633     
634     // Update the children level (if selection not at last level)
635     if (level<mLevelList.size()-1) 
636       {
637                 
638         UpdateLevel( level + 2 ); 
639         // Reset the viewer setting the default image
640         GetGimmickView()->ClearSelection();
641       }
642     // Select all images if the selection is at series level
643     if (level==mLevelList.size()-2) 
644                 SelectAll(level+1);
645     // Validate selected images if the selection is at image level
646     if (level==(mLevelList.size()-1)) //&&mProcess) 
647       {
648         if(event.GetEventType()==wxEVT_COMMAND_LIST_ITEM_SELECTED)
649           {
650                   ValidateSelectedImages (true);
651           }
652         else
653           {
654                   ValidateSelectedImages (false);
655           }
656       }
657     
658   }
659   //================================================================
660
661   //================================================================
662   void WxTreeView::SelectAll(int level)
663   {
664     long item = -1;
665     //    int level=mLevelList.size()-1;
666     for ( ;; )
667       {
668         item = GetCtrl(level)->GetNextItem(item,
669                                            wxLIST_NEXT_ALL);
670         if ( item == -1 )
671           break;
672         
673         if(item==(GetCtrl(level)->GetItemCount()-1))
674           {
675             mIgnoreSelectedChanged = false;//mProcess=true;
676           }
677         else
678           {
679             mIgnoreSelectedChanged = true;//    mProcess=false;
680           }
681         GetCtrl(level)->SetItemState(item,wxLIST_STATE_SELECTED, wxLIST_MASK_STATE 
682                                      | wxLIST_MASK_TEXT |wxLIST_MASK_IMAGE | wxLIST_MASK_DATA | wxLIST_MASK_WIDTH | wxLIST_MASK_FORMAT);
683       }
684   }
685
686   //================================================================
687   //================================================================
688
689   void WxTreeView::OnColClick(wxListEvent& event)
690   { 
691     mColumnSelected = event.m_col;
692     wxPoint clientpt;
693     clientpt.x = wxGetMousePosition().x - this->GetScreenPosition().x;
694     clientpt.y = wxGetMousePosition().y - this->GetScreenPosition().y;
695     senderCtrl = event.GetEventObject(); 
696     unsigned int level = 0;
697     for (level = 0; level<mLevelList.size(); ++level)
698       {
699         if ( GetCtrl(level) == senderCtrl ) break;
700       }
701     PopupMenu(menu, clientpt);
702     
703   }
704
705    //================================================================
706   //================================================================
707
708   void WxTreeView::OnItemMenu(wxListEvent &event)
709   {
710          wxPoint clientpt;
711     clientpt.x = wxGetMousePosition().x - this->GetScreenPosition().x;
712     clientpt.y = wxGetMousePosition().y - this->GetScreenPosition().y;
713     senderCtrl = event.GetEventObject();
714     unsigned int level = 0;
715     for (level = 0; level<mLevelList.size(); ++level)
716       {
717                 if ( GetCtrl(level) == senderCtrl ) break;
718       }
719           long* ptr=0;
720           int flag;
721           mLastRightLevel=level;
722           mLastRightSelected=GetCtrl(level)->HitTest(wxPoint(0,clientpt.y-8),flag,ptr);
723     PopupMenu(menuItem, clientpt);
724     
725   }
726   
727   //================================================================
728   //================================================================
729
730   void WxTreeView::OnPopupFilter(wxCommandEvent& event)
731   {
732     wxBusyCursor busy;
733     GimmickDebugMessage(7,
734                         "WxTreeView::OnEndLabelEdit" 
735                         <<std::endl);
736     unsigned int level = 0;
737     for (level = 0; level<mLevelList.size(); ++level)
738       {
739         if ( GetCtrl(level) == senderCtrl ) break;
740       }
741     std::string filter = crea::wx2std(wxGetTextFromUser(_T("Enter the filter to apply"), _T("Filter On Column")));
742     
743     std::string att;
744     
745     long it = -1;
746     UpdateLevel(level+1);
747     
748     std::vector<long> items;
749     bool in=false;
750     int del=0;
751     for ( ;; )
752       {
753         it = GetCtrl(level)->GetNextItem(it,
754                                          wxLIST_NEXT_ALL);
755         if ( it == -1 )
756           break;
757         
758         long adr = GetCtrl(level)->GetItemData(it);
759         tree::Node* nod = ((ItemData*)adr)->node;
760         att=(*nod).GetAttribute(mLevelList[level].key[mColumnSelected]);
761         
762         
763         if(att.find(filter)>900)
764           {
765             
766             if(!in)
767               {
768                 in=true;
769               }
770             else
771               {
772                 del+=1;
773               }
774             
775             items.push_back(it-del);
776           }
777         
778       }
779     std::vector<long>::iterator iter;
780     for(iter=items.begin();iter!=items.end();++iter)
781       {
782         GetCtrl(level)->DeleteItem(*iter);
783       }
784     GetGimmickView()->ClearSelection();
785   }
786   //================================================================
787   
788   //================================================================
789   void WxTreeView::OnPopupSort(wxCommandEvent& event)
790   {
791     wxBusyCursor busy;
792     unsigned int level = 0;
793     for (level = 0; level<mLevelList.size(); ++level)
794       {
795         if ( GetCtrl(level) == senderCtrl ) break;
796       }
797     mLevelList[level].SortColumn = mColumnSelected;
798
799     if(event.GetId()==mAscendingID)
800       {
801         mLevelList[level].SortAscending = true;
802       }
803     else if(event.GetId()==mDescendingID)
804       {
805         mLevelList[level].SortAscending = false;
806       }
807           
808     SortLevel(level);
809   }
810   //================================================================
811
812   //================================================================
813   void WxTreeView::OnLocalCopy(wxCommandEvent& event)
814   {
815     wxBusyCursor busy;
816     
817         unsigned int tempLevel = mLastLevel;
818     mLastLevel+=1;
819     const std::vector<tree::Node*>& sel=GetSelected(mLastLevel+1);
820         
821     if(sel.size() != 0)
822         {
823             bool copy=false;
824             std::stringstream out;
825             std::string levelName=GetTreeHandler()->GetTree().GetLevelDescriptor(mLastLevel).GetName();
826             out<<"Copy ";
827             out<<sel.size();
828             if(sel.size()>1&&levelName.at(levelName.size()-1)!='s')
829               {
830                 out<<" "<<levelName;
831                 out<<"s to .gimmick?";
832               }
833             else
834               {
835                 out<<" "<<GetTreeHandler()->GetTree().GetLevelDescriptor(mLastLevel).GetName()<<" to .gimmick?";
836               }
837             if (wxMessageBox(crea::std2wx(out.str()),
838                              _T("Remove Files"),
839                              wxYES_NO,this ) == wxYES)
840               {
841                 copy = true;
842               }
843             if(copy)
844                   {
845                         std::vector<std::string> s;
846                         GetFilenamesAsString(sel,s);
847             GetGimmickView()->CopyFiles(s);
848                   }
849         }
850         else
851         {
852                 mLastLevel = tempLevel;
853         }
854     
855     
856   }
857   //================================================================
858
859    //================================================================
860   void WxTreeView::OnEditField(wxCommandEvent& event)
861   {
862         if(mLastRightSelected!=-1)
863         {
864     tree::Node* node=((ItemData*)GetCtrl(mLastRightLevel)->GetItemData(mLastRightSelected))->node;
865         tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
866         std::vector<std::string> names;
867         std::vector<std::string> keys;
868         for (a  = GetTreeHandler()->GetTree().GetAttributeDescriptorList(mLastRightLevel+1).begin();
869              a != GetTreeHandler()->GetTree().GetAttributeDescriptorList(mLastRightLevel+1).end();
870              ++a)
871         {
872                 if(a->GetFlags()==creaImageIO::tree::AttributeDescriptor::EDITABLE)
873             {
874                         names.push_back(a->GetName());
875                         keys.push_back(a->GetKey());
876                 }
877         }
878         GetGimmickView()->CreateEditFieldsDialog(node,names,keys);
879         }
880   }
881
882   //================================================================
883
884   //================================================================
885
886   void WxTreeView::OnExportToStorage(wxCommandEvent &event)
887   {
888         std::vector<std::string> filesname;
889         std::vector<tree::Node*> nodes;
890         nodes.push_back(((ItemData*)GetCtrl(mLastRightLevel)->GetItemData(mLastRightSelected))->node);
891         GetFilenamesAsString(nodes,filesname);
892         GetGimmickView()->ExportToStorage(filesname);
893   }
894
895   //================================================================
896
897   //================================================================
898
899   void WxTreeView::OnDumpTags(wxCommandEvent &event)
900   {
901           if(mLastRightSelected!=-1)
902         {
903                 tree::Node* node=((ItemData*)GetCtrl(mLastRightLevel)->GetItemData(mLastRightSelected))->node;
904                 tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
905                 std::vector<std::string> names;
906                 std::vector<std::string> keys;
907                 for (a  = GetTreeHandler()->GetTree().GetAttributeDescriptorList(mLastRightLevel+1).begin();
908                          a != GetTreeHandler()->GetTree().GetAttributeDescriptorList(mLastRightLevel+1).end();
909                          ++a)
910                         {
911                                 if(a->GetKey()=="FullFileName")
912                                 {
913                                         GetGimmickView()->DumpTags(node->GetAttribute("FullFileName"));
914                                         return;
915                                 }
916                         }
917           }
918   }
919   
920
921   //================================================================
922
923   //================================================================
924   void WxTreeView::SortLevel(int level)
925   {       
926     GimmickDebugMessage(1,
927                         "WxTreeView::SortLevel(" 
928                         <<level<<")"
929                         <<std::endl);  
930     //Obtain the column name and the level that needs to be organized
931     
932     //    int l = level - 1;
933     //Sets the data for the items to be sorted
934     //    std::string att;
935     unsigned int ty=0;
936     int nbselected = 0;
937     int n = GetCtrl(level)->GetItemCount();
938     for (int i = 0; i < n; i++)
939       {
940         
941         //Gets current item data
942         ItemData* data = (ItemData*)GetCtrl(level)->GetItemData(i);
943         
944         //Extracts the node and the type of attribute   
945         tree::Node* nod = data->node;
946         if(i==0)
947           {
948             (*nod).GetAttributeDescriptor
949               (mLevelList[level].key[mLevelList[level].SortColumn])
950               .DecodeType( ty );
951           }
952         //Obtains the organizing attribute
953         data->attr = & (*nod).GetAttribute
954           (mLevelList[level].key[mLevelList[level].SortColumn]);
955         //Selected ?
956         data->selected = false;
957         if (GetCtrl(level)->GetItemState(i,wxLIST_STATE_SELECTED)>0)
958           {
959             data->selected = true;
960             nbselected++;
961           }
962
963       } 
964     GimmickDebugMessage(1,
965                         "WxTreeView::OnSort : " 
966                         <<nbselected<<" selected before sorting"
967                         <<std::endl);  
968
969     mIgnoreSelectedChanged = true; 
970     // 
971     if (mLevelList[level].SortAscending)
972       {
973         
974         if(ty==1)
975           {
976             GetCtrl(level)->SortItems(CompareFunctionInts, 0);
977           }
978         else
979           {
980             GetCtrl(level)->SortItems(CompareFunctionStrings, 0);
981           }
982         
983       }
984     else
985       {
986         if(ty==1)
987           {
988             GetCtrl(level)->SortItems(CompareFunctionInts, 1);
989           }
990         else
991           {
992             GetCtrl(level)->SortItems(CompareFunctionStrings, 1);
993           }
994       }
995  
996
997     // Reselects the unselected 
998     n = GetCtrl(level)->GetItemCount();
999     int after = 0;
1000     for (int i = 0; i < n; i++)
1001       {
1002         
1003         //Gets current item data
1004         ItemData* data = (ItemData*)GetCtrl(level)->GetItemData(i);
1005   
1006         //  long item = -1;
1007         //    for ( ;; )
1008         //      {
1009         //      item = GetCtrl(level)->GetNextItem(item,wxLIST_NEXT_ALL);
1010         //      if ( item == -1 ) break;
1011         //Gets current item data
1012         //      ItemData* data = (ItemData*)GetCtrl(level)->GetItemData(item);
1013         // was selected ?
1014         
1015         if (data->selected)
1016           {
1017             nbselected--;
1018             if (nbselected==0)
1019               {
1020                 // if it is the last one we must process the selection
1021                 mIgnoreSelectedChanged = false;
1022               }
1023             GetCtrl(level)->SetItemState(i,
1024                                          wxLIST_STATE_SELECTED, 
1025                                          wxLIST_MASK_STATE 
1026                                          | wxLIST_MASK_TEXT 
1027                                          | wxLIST_MASK_IMAGE 
1028                                          | wxLIST_MASK_DATA 
1029                                          | wxLIST_MASK_WIDTH 
1030                                          | wxLIST_MASK_FORMAT);   
1031           }
1032         if (GetCtrl(level)->GetItemState(i,wxLIST_STATE_SELECTED)>0)
1033           {
1034             after++;
1035           }
1036
1037         
1038       }
1039     mIgnoreSelectedChanged = false; 
1040      GimmickDebugMessage(1,
1041                         "WxTreeView::SortLevel : " 
1042                         <<after<<" selected after sorting"
1043                         <<std::endl);  
1044   
1045   }
1046   //================================================================
1047
1048   
1049   //================================================================
1050   void WxTreeView::ValidateSelectedImages(bool isSelection)
1051   {
1052     GimmickDebugMessage(7,
1053                         "WxTreeView::ValidateSelectedImages" 
1054                         <<std::endl);
1055     const std::vector<tree::Node*>& sel(GetSelected(mLevelList.size()+1));
1056     GetGimmickView()->OnSelectionChange(sel,
1057                                         isSelection,(mLastSelected-1),
1058                                         !mIgnoreSelectedChanged);
1059  
1060   }
1061   //================================================================
1062
1063
1064   //================================================================
1065   void WxTreeView::GetNodes(std::vector<tree::Node*>& nodes, bool direction)
1066   {
1067         long item = mLastSelected;
1068         int level=mLevelList.size()-1;
1069         //Gets current item data
1070         long adr = GetCtrl(level)->GetItemData(item);
1071         //Extracts the node
1072         tree::Node* nod = ((ItemData*)adr)->node;
1073     for ( ;; )
1074     {
1075                 if(direction)
1076                 {
1077                         item = GetCtrl(level)->GetNextItem(item,
1078                                      wxLIST_NEXT_ABOVE);
1079                 }
1080                 else
1081                 {
1082                         item = GetCtrl(level)->GetNextItem(item,
1083                                      wxLIST_NEXT_BELOW);
1084                 }
1085         if ( item == -1 || item==0  )
1086                 {
1087             break;
1088                 }
1089                 if(GetCtrl(level)->GetItemState(item, wxLIST_STATE_SELECTED)==0 )
1090                 {
1091
1092                         adr = GetCtrl(level)->GetItemData(item);
1093                         nod = ((ItemData*)adr)->node;
1094                         nodes.push_back(nod);
1095                 }
1096     }
1097
1098   }
1099   //================================================================
1100    //=================================================
1101   void WxTreeView::OnKeyDown(wxListEvent &event)
1102   {
1103           if(event.GetKeyCode() == WXK_DELETE)
1104           {
1105                    wxBusyCursor busy;
1106                    std::string temp = "0";
1107                    RemoveSelected(temp);
1108                    GetGimmickView()->ClearSelection();
1109           }
1110                   
1111   }
1112   //================================================================
1113
1114   //================================================================
1115   // Should be in another place : not specific !
1116   void WxTreeView::GetSelectedAsString(std::vector<std::string>&s)
1117   {
1118     int level=mLevelList.size();
1119     const std::vector<tree::Node*>& sel=GetSelected(level+1);
1120     std::vector<tree::Node*>::const_iterator i;
1121     
1122     for (i=sel.begin(); i!=sel.end(); ++i)
1123       {
1124         std::string filename=(*i)->GetAttribute("FullFileName");
1125         s.push_back(filename);
1126       }
1127   }
1128
1129   //================================================================
1130   void WxTreeView::GetFilenamesAsString(const std::vector<tree::Node*>& nodes, std::vector<std::string>&s)
1131   {
1132     std::vector<tree::Node*>::const_iterator i;
1133     
1134     for (i=nodes.begin(); i!=nodes.end(); ++i)
1135       {
1136                   if((*i)->GetLevel()<mLevelList.size())
1137                   {
1138                          GetTreeHandler()->LoadChildren(*i,0);
1139                          GetFilenamesAsString((*i)->GetChildrenList(),s);
1140                   }
1141                   else
1142                   {
1143                         std::string filename=(*i)->GetAttribute("FullFileName");
1144                         s.push_back(filename);
1145                   }
1146       }
1147   }
1148
1149    //================================================================
1150
1151    //================================================================
1152   void WxTreeView::GetAttributes(std::vector<std::string>& areShown, std::vector<std::string>& notShown, int level)
1153   {
1154           areShown.clear();
1155           notShown.clear();
1156         tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
1157         for (a  = GetTreeHandler()->GetTree().GetAttributeDescriptorList(level).begin();
1158              a != GetTreeHandler()->GetTree().GetAttributeDescriptorList(level).end();
1159              ++a)
1160         {
1161                 if(a->GetFlags()==creaImageIO::tree::AttributeDescriptor::EDITABLE && IsAttributeVisible(a->GetName(),level))
1162             {
1163                         areShown.push_back(a->GetName());
1164                 }
1165         }
1166         notShown=mLevelList[level-1].notShownAtts;
1167   }
1168
1169   //================================================================
1170   void WxTreeView::SetNonVisibleAttributes(const std::vector<std::string>& notShown, int nlevel)
1171   {
1172         mLevelList[nlevel].notShownAtts=notShown;
1173   }
1174
1175   //================================================================
1176    void WxTreeView::CreateCtrl(std::vector<std::string>& notShown, int nlevel)
1177   {
1178         int ctrl_style = wxLC_REPORT | wxLC_VRULES;
1179     int col_style = wxLIST_FORMAT_LEFT;
1180         LevelType level;
1181         mLevelList[nlevel].SelectedUpToDate = true;
1182         mLevelList[nlevel].SortColumn = 0;
1183         mLevelList[nlevel].key.clear();
1184         
1185         mLevelList[nlevel].wxCtrl = new wxListCtrl(mLevelList[nlevel].wxSplitter,
1186                                           nlevel,
1187                                           wxDefaultPosition, 
1188                                           wxDefaultSize,
1189                                           ctrl_style);
1190         wxWindow* oldWin=mLevelList[nlevel].wxSplitter->GetWindow1();
1191         mLevelList[nlevel].wxSplitter->ReplaceWindow(oldWin,mLevelList[nlevel].wxCtrl);
1192         mLevelList[nlevel].wxSplitter->Initialize(mLevelList[nlevel].wxCtrl);
1193    
1194         // Create the columns : one for each attribute of the level
1195         int col = 0;
1196         std::string title;
1197
1198         tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
1199         for (a  = GetTreeHandler()->GetTree().GetAttributeDescriptorList(nlevel+1).begin();
1200              a != GetTreeHandler()->GetTree().GetAttributeDescriptorList(nlevel+1).end();
1201              ++a)
1202
1203         {   
1204             if(a->GetFlags()!=creaImageIO::tree::AttributeDescriptor::PRIVATE && IsAttributeVisible(a->GetName(),nlevel+1))
1205               {
1206                   title=a->GetName();
1207                   std::string temp = a->GetKey();
1208                   if (temp.compare("ID") != 0)
1209                   {
1210                         mLevelList[nlevel].wxCtrl->InsertColumn(col, 
1211                                         crea::std2wx(title),
1212                                         col_style);
1213                         col++;
1214                   }
1215                 mLevelList[nlevel].key.push_back(a->GetKey());
1216               }
1217                 
1218           }
1219         oldWin->Destroy();
1220         UpdateLevel(1);
1221         }
1222
1223    //================================================================
1224   bool WxTreeView::IsAttributeVisible(const std::string& val, int level)
1225   {
1226           std::vector<std::string> ns=mLevelList[level-1].notShownAtts;
1227           std::vector<std::string>::iterator it;
1228           bool found=false;
1229           for(it=ns.begin();it!=ns.end()&&!found;++it)
1230           {
1231                   if(val.compare(*it)==0)
1232                   {
1233                           found=true;
1234                   }
1235           }
1236
1237           return !found;
1238   }
1239  //================================================================
1240   //================================================================
1241
1242         RemoveAlertDlg::RemoveAlertDlg(wxWindow *parent, 
1243                                                wxString title,    
1244                                                    const wxSize& size)
1245  :   wxDialog( parent, 
1246                   wxID_ANY, 
1247                   title,
1248                   wxDefaultPosition,
1249                   size,
1250                   wxDEFAULT_DIALOG_STYLE)
1251         {
1252             wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
1253
1254                 //std::string out("To reload deleted patient, you should synchronize your database before.");  // JPR
1255                 //wxTextCtrl *text = new wxTextCtrl(this, wxID_ANY,crea::std2wx(out),wxDefaultPosition, wxSize(500,20));
1256                 wxTextCtrl *text = new wxTextCtrl(this, wxID_ANY,
1257                                         _T("To reload deleted patient, you should synchronize your database before."),
1258                                         wxDefaultPosition, wxSize(500,20));
1259                 mcheck = new wxCheckBox(this, 5478, _T("Do not display this warning again!"));
1260                 Connect( mcheck->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED , (wxObjectEventFunction) &RemoveAlertDlg::onCheck ); 
1261                 wxSizer* buttonsSizer = this->CreateSeparatedButtonSizer(wxOK|wxCANCEL);
1262                 
1263                 topsizer->Add(text);
1264                 topsizer->Add(mcheck,0,wxGROW);
1265                 topsizer->Add(buttonsSizer,0,wxGROW);
1266                 SetSizer(topsizer, true);
1267                 mSave = false;
1268                 Layout();
1269         }
1270         RemoveAlertDlg::~RemoveAlertDlg(){};
1271         bool RemoveAlertDlg::isChecked()
1272         {
1273                 return mSave;
1274         }
1275         void RemoveAlertDlg::onCheck(wxCommandEvent &Event)
1276         {
1277                 mSave = mcheck->IsChecked();
1278         }
1279         
1280
1281   //================================================================
1282   //================================================================
1283   BEGIN_EVENT_TABLE(WxTreeView, wxPanel)   
1284   /*
1285     EVT_SIZE(MyFrame::OnSize)
1286
1287     EVT_MENU(LIST_QUIT, MyFrame::OnQuit)
1288     EVT_MENU(LIST_ABOUT, MyFrame::OnAbout)
1289     EVT_MENU(LIST_LIST_VIEW, MyFrame::OnListView)
1290     EVT_MENU(LIST_REPORT_VIEW, MyFrame::OnReportView)
1291     EVT_MENU(LIST_ICON_VIEW, MyFrame::OnIconView)
1292     EVT_MENU(LIST_ICON_TEXT_VIEW, MyFrame::OnIconTextView)
1293     EVT_MENU(LIST_SMALL_ICON_VIEW, MyFrame::OnSmallIconView)
1294     EVT_MENU(LIST_SMALL_ICON_TEXT_VIEW, MyFrame::OnSmallIconTextView)
1295     EVT_MENU(LIST_VIRTUAL_VIEW, MyFrame::OnVirtualView)
1296     EVT_MENU(LIST_SMALL_VIRTUAL_VIEW, MyFrame::OnSmallVirtualView)
1297
1298     EVT_MENU(LIST_FOCUS_LAST, MyFrame::OnFocusLast)
1299     EVT_MENU(LIST_TOGGLE_FIRST, MyFrame::OnToggleFirstSel)
1300     EVT_MENU(LIST_DESELECT_ALL, MyFrame::OnDeselectAll)
1301     EVT_MENU(LIST_SELECT_ALL, MyFrame::OnSelectAll)
1302     EVT_MENU(LIST_DELETE, MyFrame::OnDelete)
1303     EVT_MENU(LIST_ADD, MyFrame::OnAdd)
1304     EVT_MENU(LIST_EDIT, MyFrame::OnEdit)
1305     EVT_MENU(LIST_DELETE_ALL, MyFrame::OnDeleteAll)
1306     EVT_MENU(LIST_SORT, MyFrame::OnSort)
1307     EVT_MENU(LIST_SET_FG_COL, MyFrame::OnSetFgColour)
1308     EVT_MENU(LIST_SET_BG_COL, MyFrame::OnSetBgColour)
1309     EVT_MENU(LIST_TOGGLE_MULTI_SEL, MyFrame::OnToggleMultiSel)
1310     EVT_MENU(LIST_SHOW_COL_INFO, MyFrame::OnShowColInfo)
1311     EVT_MENU(LIST_SHOW_SEL_INFO, MyFrame::OnShowSelInfo)
1312     EVT_MENU(LIST_FREEZE, MyFrame::OnFreeze)
1313     EVT_MENU(LIST_THAW, MyFrame::OnThaw)
1314     EVT_MENU(LIST_TOGGLE_LINES, MyFrame::OnToggleLines)
1315     EVT_MENU(LIST_MAC_USE_GENERIC, MyFrame::OnToggleMacUseGeneric)
1316
1317     EVT_UPDATE_UI(LIST_SHOW_COL_INFO, MyFrame::OnUpdateShowColInfo)
1318     EVT_UPDATE_UI(LIST_TOGGLE_MULTI_SEL, MyFrame::OnUpdateToggleMultiSel)
1319 END_EVENT_TABLE()
1320
1321 BEGIN_EVENT_TABLE(MyListCtrl, wxListCtrl)
1322     EVT_LIST_BEGIN_DRAG(LIST_CTRL, MyListCtrl::OnBeginDrag)
1323     EVT_LIST_BEGIN_RDRAG(LIST_CTRL, MyListCtrl::OnBeginRDrag)
1324         
1325     EVT_LIST_BEGIN_LABEL_EDIT(-1, WxTreeView::OnBeginLabelEdit)
1326     EVT_LIST_END_LABEL_EDIT(-1, WxTreeView::OnEndLabelEdit)
1327         
1328     EVT_LIST_DELETE_ITEM(LIST_CTRL, MyListCtrl::OnDeleteItem)
1329     EVT_LIST_DELETE_ALL_ITEMS(LIST_CTRL, MyListCtrl::OnDeleteAllItems)
1330 #if WXWIN_COMPATIBILITY_2_4
1331     EVT_LIST_GET_INFO(LIST_CTRL, MyListCtrl::OnGetInfo)
1332     EVT_LIST_SET_INFO(LIST_CTRL, MyListCtrl::OnSetInfo)
1333 #endif
1334   */
1335     EVT_LIST_KEY_DOWN(-1, WxTreeView::OnKeyDown)
1336     EVT_LIST_ITEM_SELECTED(-1, WxTreeView::OnItemSelected)
1337         EVT_LIST_ITEM_RIGHT_CLICK(-1, WxTreeView::OnItemMenu)
1338     EVT_LIST_ITEM_DESELECTED(-1, WxTreeView::OnItemDeSelected)
1339         /*
1340     EVT_LIST_KEY_DOWN(LIST_CTRL, MyListCtrl::OnListKeyDown)
1341     EVT_LIST_ITEM_ACTIVATED(LIST_CTRL, MyListCtrl::OnActivated)
1342     EVT_LIST_ITEM_FOCUSED(LIST_CTRL, MyListCtrl::OnFocused)
1343 */
1344     EVT_LIST_COL_RIGHT_CLICK(-1, WxTreeView::OnColClick)
1345         
1346     EVT_LIST_COL_CLICK(-1, WxTreeView::OnColClick)
1347
1348         //EVT_LEFT_DOWN(WxTreeView::OnMouseClick)
1349         /*
1350     EVT_LIST_COL_BEGIN_DRAG(LIST_CTRL, MyListCtrl::OnColBeginDrag)
1351     EVT_LIST_COL_DRAGGING(LIST_CTRL, MyListCtrl::OnColDragging)
1352     EVT_LIST_COL_END_DRAG(LIST_CTRL, MyListCtrl::OnColEndDrag)
1353
1354     EVT_LIST_CACHE_HINT(LIST_CTRL, MyListCtrl::OnCacheHint)
1355
1356 #if USE_CONTEXT_MENU
1357     EVT_CONTEXT_MENU(MyListCtrl::OnContextMenu)
1358 #endif
1359     EVT_CHAR(MyListCtrl::OnChar)
1360
1361     EVT_RIGHT_DOWN(MyListCtrl::OnRightClick)
1362   */
1363 END_EVENT_TABLE()
1364   
1365 } // EO namespace creaImageIO
1366