]> Creatis software - creaImageIO.git/blob - src/creaImageIOWxGimmick.cpp
4aba5f617256721424967c22c7f085cecaf66960
[creaImageIO.git] / src / creaImageIOWxGimmick.cpp
1
2 #include <creaImageIOWxGimmick.h>
3 #include <creaImageIODicomNodeComparators.h>
4
5 #include <creaMessageManager.h>
6
7 #include "icons/database.xpm"
8 #include "icons/folder.xpm"
9 #include "icons/dicomdir.xpm"
10 #include "icons/patient.xpm"
11 #include "icons/study.xpm"
12 #include "icons/series.xpm"
13 #include "icons/image.xpm"
14 #include "icons/root.xpm"
15 #include <wx/filedlg.h>
16 #include <wx/dirdlg.h>
17
18 #include <fstream>
19 #include <vtkCamera.h>
20 #include <vtkRenderer.h>
21
22 #include <wx/filefn.h>
23 //#include <wx/tipwin.h>
24
25 using namespace crea;
26
27 #include <boost/filesystem.hpp>
28 #include <boost/algorithm/string.hpp>
29
30 namespace creaImageIO
31 {
32   //================================================================
33   const int WxGimmick::UserMenuFirstId = 1000;
34   //================================================================
35
36   //================================================================
37   typedef enum
38     {
39       Icon_Root,
40       Icon_Database,
41       Icon_Folder,
42       Icon_DicomDir,
43       Icon_Patient,
44       Icon_Study,
45       Icon_Series,
46       Icon_Image
47     }
48     icon_id;
49   //================================================================
50
51   //================================================================
52   enum 
53     {
54       PopUp_NewCollection = 100,
55       PopUp_OpenCollection = 101,
56       PopUp_CloseCollection = 102,
57       PopUp_DeleteCollection = 103,
58       PopUp_AddDirectory = 110,
59       PopUp_AddFile = 111,
60       PopUp_AddRawFile = 112,
61       PopUp_Remove = 120,
62       PopUp_Sort = 200,
63       PopUp_Settings = 501,
64       PopUp_About    = 502,
65       PopUp_User = WxGimmick::UserMenuFirstId,
66     };
67   //================================================================
68
69   //================================================================
70 #define TreeListCtrlId 10000
71   //================================================================
72
73   //================================================================
74   const icon_id Icon[5] = { Icon_Database,  
75                             Icon_Patient,
76                             Icon_Study,
77                             Icon_Series,
78                             Icon_Image };
79   //================================================================
80  
81
82   //================================================================
83   class WxGimmickDicomNodeData : public DicomNodeData
84   {
85   public:
86     WxGimmickDicomNodeData
87     (WxGimmickTreeItemData* d = 0) :
88       mTreeItemData(d),
89       mLoaded(false)
90     {}
91     ~WxGimmickDicomNodeData();
92
93     WxGimmickTreeItemData* GetTreeItemData()
94     { return mTreeItemData; }
95     void SetTreeItemData(   WxGimmickTreeItemData* d)
96     { mTreeItemData = d; }
97     inline bool IsLoaded() { return mLoaded; }
98     inline void SetLoaded(bool v) { mLoaded = v; }
99
100   private:    
101     WxGimmickTreeItemData* mTreeItemData;
102     bool mLoaded;
103   };
104   //================================================================
105
106
107   //================================================================
108   class WxGimmickTreeItemData : public wxTreeItemData
109   {
110   public:
111     WxGimmickTreeItemData(DicomNode* node) 
112       : 
113       mType(0),
114       mDicomNode(node), 
115       //        mLoaded(false),
116       mUpdateTime(0),
117       mUserFlags(0)
118     { 
119       if (node) 
120         {
121           WxGimmickDicomNodeData* data =
122             node->GetData<WxGimmickDicomNodeData*>();
123           if (data!=0)
124             {
125               if (data->GetTreeItemData()!=0) 
126                 {
127                   std::cout << "WxGimmickTreeItemData ERROR ****"
128                             << std::endl;
129                   return;
130                 }
131               data->SetTreeItemData(this);
132               return;
133             }
134           node->SetData( new WxGimmickDicomNodeData(this) );
135           if (node->GetType()==DicomNode::Database)
136             {
137               mType = 2;
138             }
139           else 
140             {
141               mType = 1;
142             }
143         }
144     }
145     ~WxGimmickTreeItemData()
146     {
147       if (mDicomNode) 
148         {
149           WxGimmickDicomNodeData* data =
150             mDicomNode->GetData<WxGimmickDicomNodeData*>();
151           if (data) data->SetTreeItemData(0);
152
153         }
154     }
155     inline void ResetDicomNode() 
156     {
157       mDicomNode = 0;
158     }
159
160     inline void SetItemId ( const wxTreeItemId& item ) { mItemId = item; }
161     inline const wxTreeItemId& GetItemId() const { return mItemId; }
162
163     inline bool IsDefault() const { return (mType == 0); }
164     inline bool IsDatabase() const { return (mType == 2); }
165     inline bool IsDicomNode() const { return (mType == 1); }
166     
167     inline DicomNode* GetDicomNode() { return mDicomNode; }
168     inline long& UpdateTime() { return mUpdateTime; }
169     inline bool IsLoaded() 
170     { 
171       mDicomNode->GetData<WxGimmickDicomNodeData*>()->IsLoaded();
172     }
173     inline void SetLoaded(bool v) 
174     { 
175       mDicomNode->GetData<WxGimmickDicomNodeData*>()->SetLoaded(v);
176     }
177
178     inline int GetUserFlags() const { return mUserFlags; }
179     inline void SetUserFlags(int f) { mUserFlags = f; }
180
181   private:
182     // The type of item : 
183     // 0 = Default
184     // 1 = DicomNode
185     // 2 = DicomNode of type Database
186     int mType;
187     wxTreeItemId mItemId;
188     DicomNode* mDicomNode;
189     //    bool mLoaded;
190     long mUpdateTime;
191     int mUserFlags;
192   };
193   //================================================================
194  
195
196   //================================================================
197   WxGimmickDicomNodeData::~WxGimmickDicomNodeData()
198   {
199     if (mTreeItemData) 
200       {
201         mTreeItemData->ResetDicomNode();
202       }
203   }
204   //================================================================
205
206
207  
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239   //================================================================
240   //================================================================
241   //================================================================
242   //================================================================
243   //================================================================
244   //================================================================
245   //================================================================
246   WxGimmick::WxGimmick(wxWindow *parent, 
247                        wxWindowID id,
248                        const wxPoint& pos,
249                        const wxSize& size,
250                        int image_type,
251                        int threads)
252     : wxPanel(parent,id,pos,size),
253       mSelectionType(image_type),
254       mSaveConfigurationOnClose(true),
255       mReader(threads)
256   {
257     // Initialize image size corresponding to current selection
258     switch (mSelectionType) 
259       {
260       case GIMMICK_2D_IMAGE_SELECTION : mSelectionMaxImageDimension = 2; break;
261       case GIMMICK_3D_IMAGE_SELECTION : mSelectionMaxImageDimension = 3; break;
262       case GIMMICK_4D_IMAGE_SELECTION : mSelectionMaxImageDimension = 4; break;
263       default : mSelectionMaxImageDimension = 0;
264       }
265
266
267     // Start the threads ...
268     mReader.Start();
269
270     //
271     SetDatabaseExtension("sqlite3");
272     // Create the UserSettings dir if does not exist
273     CreateUserSettingsDirectory();
274     // Sets the current directory to the Setting dir
275     mCurrentDirectory =  std2wx(GetUserSettingsDirectory());
276
277     // Window layout creation
278     wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
279
280     // Left/Right split
281     mSplitter1 = new wxSplitterWindow( this, -1);
282
283     // TreeCtrl on the left
284     long style = 
285       wxTR_HIDE_ROOT 
286       | wxTR_HAS_BUTTONS 
287       | wxTR_NO_LINES
288       //| wxTR_LINES_AT_ROOT 
289       | wxTR_FULL_ROW_HIGHLIGHT
290       //      | wxTR_SINGLE 
291       | wxTR_MULTIPLE
292       | wxTR_EDIT_LABELS ;
293  
294     /*
295       style = style 
296       | wxTR_EDIT_LABELS        //Use this style if you wish the user to be able to edit labels in the tree list control.
297       //wxTR_NO_BUTTONS         For convenience to document that no buttons are to be drawn.
298       | wxTR_HAS_BUTTONS        //Use this style to show + and - buttons to the left of parent items.
299       | wxTR_TWIST_BUTTONS      //Use this style to show Mac-style twister buttons to the left of parent items. If both wxTR_HAS_BUTTONS and wxTR_TWIST_BUTTONS are given, twister buttons are generated.
300       //wxTR_NO_LINES   Use this style to hide vertical level connectors.
301       | wxTR_FULL_ROW_HIGHLIGHT         //Use this style to have the background colour and the selection highlight extend over the entire horizontal row of the tree list control window. (This flag is ignored under Windows unless you specify wxTR_NO_LINES as well.)
302       | wxTR_LINES_AT_ROOT      //Use this style to show lines between root nodes. Only applicable if wxTR_HIDE_ROOT is set and wxTR_NO_LINES is not set.
303       | wxTR_HIDE_ROOT  //Use this style to suppress the display of the root node, effectively causing the first-level nodes to appear as a series of root nodes.
304       //   wxTR_ROW_LINES //    Use this style to draw a contrasting border between displayed rows.
305       //      wxTR_HAS_VARIABLE_ROW_HEIGHT//    Use this style to cause row heights to be just big enough to fit the content. If not set, all rows use the largest row height. The default is that this flag is unset.
306       // wxTR_SINGLE    For convenience to document that only one item may be selected at a time. Selecting another item causes the current selection, if any, to be deselected. This is the default.
307       | wxTR_MULTIPLE //        Use this style to allow a range of items to be selected. If a second range is selected, the current range, if any, is deselected.
308       | wxTR_EXTENDED //        Use this style to allow disjoint items to be selected. (Only partially implemented; may not work in all cases.)
309       //wxTR_DEFAULT_STYLE      The set of flags that are closest to the defaults for the native control for a particular toolkit.
310       //| wxTR_VIRTUAL //The application provides items text on demand.
311       */
312   
313     mTreeListCtrl = new wxTreeListCtrl(mSplitter1,
314                                        TreeListCtrlId,
315                                        wxDefaultPosition,
316                                        wxDefaultSize,
317                                        style);
318
319     mTreeListCtrl->SetIndent(0);
320     mTreeListCtrl->SetLineSpacing(5); 
321
322     CreateImageList();
323
324     // Right panel
325     wxPanel *rpanel = new wxPanel( mSplitter1, -1 ); 
326     // Right sizer
327     wxBoxSizer  *rsizer = new wxBoxSizer(wxHORIZONTAL);
328     // Right panel top/bottom split
329     mSplitter2 = new wxSplitterWindow( rpanel , -1);
330
331     // Image panel (top)
332     mPanelImage = new wxPanel(mSplitter2,-1);
333     mPanelImage->SetBackgroundColour( wxColour(0,0,0) );
334     // Image sizer
335     wxBoxSizer *isizer = new wxBoxSizer(wxHORIZONTAL  );
336     mPanelImage->SetSizer( isizer ); 
337  
338     // Notebook
339     mwxNotebook = new wxNotebook(mSplitter2,
340                                  -1,wxDefaultPosition, wxDefaultSize, 0);
341
342
343     
344     // Fields view (bottom)
345     mFieldsView = new WxGimmickFieldsView(mwxNotebook,-1,
346                                             wxDefaultPosition,
347                                             wxDefaultSize,0);
348
349     mFieldsView->SetColors
350       ( GetSettings().Colour(DicomNode::Database),
351         GetSettings().BgColour(DicomNode::Database),
352         GetSettings().Colour(DicomNode::Patient),
353         GetSettings().BgColour(DicomNode::Patient),
354         GetSettings().Colour(DicomNode::Study),
355         GetSettings().BgColour(DicomNode::Study),
356         GetSettings().Colour(DicomNode::Series),
357         GetSettings().BgColour(DicomNode::Series),
358         GetSettings().Colour(DicomNode::Image),
359         GetSettings().BgColour(DicomNode::Image));
360     mwxNotebook->AddPage( mFieldsView, _T("Dicom fields"));
361     
362     // Help 
363     mHelp = new WxGimmickHelp(mwxNotebook);
364     mwxNotebook->AddPage( mHelp, _T("Help"));    
365  
366     // Splitting
367     int wsize = size.GetWidth();
368     int hsize = size.GetHeight();
369     int previewhsize = 150;
370     int previewwsize = 400;
371
372     mSplitter2->SetMinimumPaneSize( previewhsize );
373     mSplitter2->SplitHorizontally( mPanelImage, mwxNotebook, //mFieldsView, 
374                                    hsize - previewhsize);
375   
376     rsizer->Add( mSplitter2,1,wxGROW  ,0);
377   
378     rpanel->SetAutoLayout(true);
379     rpanel->SetSizer( rsizer );     
380     rpanel->Layout(); 
381   
382     // previewer
383         mInteractor = new crea::creawxVTKRenderWindowInteractor(mPanelImage,-1);
384     mInteractor->UseCaptureMouseOn();   
385   
386     mViewer     = vtkImageViewer2::New();
387     mViewer->SetupInteractor ( mInteractor );
388     mViewer->SetInput(mReader.GetImage(""));
389
390     isizer-> Add( mInteractor ,1,wxGROW  ,0);
391
392     topsizer->Add( mSplitter1,1,wxGROW  ,0);
393
394     // Left/right split 
395     mSplitter1->SetMinimumPaneSize( 200 );
396     mSplitter1->SplitVertically(mTreeListCtrl, 
397                                 rpanel, 
398                                 wsize - previewwsize );
399
400   
401     //    ProcessImageEvents();
402     SetSizer( topsizer );     
403     SetAutoLayout(true);
404  
405     mDatabaseListFile = GetUserSettingsDirectory();
406     mDatabaseListFile += "collections.txt";
407
408     LoadConfiguration();
409     Layout();
410
411     ShowImage(mReader.GetImage(""));
412
413     // Show help if no collection
414     if (GetDicomDatabaseList().size()==0)
415       {
416         mwxNotebook->SetSelection(1);
417       } 
418     else
419       {
420         mwxNotebook->SetSelection(0);
421       }
422     //    mJustStarted = true;
423   }
424   //================================================================
425     
426 // file separator
427 #if defined(_WIN32)
428 #define VALID_FILE_SEPARATOR "\\"
429 #define INVALID_FILE_SEPARATOR "/"
430 #else
431 #define INVALID_FILE_SEPARATOR "\\"
432 #define VALID_FILE_SEPARATOR "/"
433 #endif
434
435   //================================================================
436   const std::string& WxGimmick::GetUserSettingsDirectory()
437   {
438     if (mUserSettingsDirectory.size()==0) 
439       {
440 #if defined(__GNUC__)
441         mUserSettingsDirectory = getenv("HOME");
442 #elif defined(_WIN32)
443         mUserSettingsDirectory = getenv("USERPROFILE");
444 #endif
445         mUserSettingsDirectory += "/.gimmick/";
446         boost::algorithm::replace_all( mUserSettingsDirectory, 
447                                        INVALID_FILE_SEPARATOR , 
448                                        VALID_FILE_SEPARATOR);
449       }
450     return mUserSettingsDirectory;
451   }
452   //================================================================
453
454   //========================================================================
455   void WxGimmick::CreateUserSettingsDirectory()
456   {
457     if (! boost::filesystem::is_directory( GetUserSettingsDirectory() ) )
458       {
459         creaMessage("Gimmick!",1,"==> Directory '"<<GetUserSettingsDirectory()<<"' "
460                     << "does not exist : creating it"<<std::endl);
461
462         if ( ! boost::filesystem::create_directory( GetUserSettingsDirectory() ) )
463           {
464             creaMessage("Gimmick!",1,"!! ERROR CREATING '"<<GetUserSettingsDirectory()<<"'");
465           }
466       }
467   }
468   //========================================================================
469
470   //================================================================
471   WxGimmick::~WxGimmick()
472   {
473 //    std::cout << "WxGimmick::~WxGimmick()" <<std::endl;
474     if (mSaveConfigurationOnClose) SaveConfiguration();
475     
476         mReader.Stop();
477 //      std::cout << "Reader stopped"<<std::endl;
478     
479         DicomDatabaseListType::iterator i;
480     for (i =GetDicomDatabaseList().begin(); 
481          i!=GetDicomDatabaseList().end(); 
482          ++i)
483       {
484         delete *i;
485       }
486     mViewer->Delete();
487     delete mInteractor;  
488   }
489   //================================================================
490
491
492   //================================================================
493   void WxGimmick::RebuildView()
494   {
495     wxBusyCursor busy;
496
497     mTreeListCtrl->DeleteRoot(); //DeleteAllItems();
498     //    mTreeDefaultItemId = wxTreeItemId();
499
500   
501     int nbattr = mSettings.GetMaxNumberOfColumns();
502
503     for (int j=0;j<nbattr; j++)
504       {
505         mTreeListCtrl->AddColumn (_T(""),
506                                   200, //DEFAULT_COL_WIDTH,
507                                   wxALIGN_LEFT,
508                                   -1,
509                                   true,
510                                   false);
511       }
512     mTreeListCtrl->SetMainColumn (0);
513     mTreeListCtrl->SetColumnEditable (0, true);
514
515     mTreeRootId = mTreeListCtrl->AddRoot( _T(""),Icon_Root,Icon_Root);
516
517     // The collections columns legends
518     mCollectionsTitlesItemId = 
519       CreateChildrenColumnsTitles(mTreeRootId,DicomNode::Database);
520
521     DicomDatabaseListType::iterator i;
522     for (i =GetDicomDatabaseList().begin(); 
523          i!=GetDicomDatabaseList().end(); 
524          ++i)
525       {  
526         UpdateDicomDatabaseView(*i);
527       }
528
529     mTreeListCtrl->Expand(mTreeRootId);
530     // LG : test
531     //    mTreeListCtrl->ExpandAll(mTreeRootId);
532     //    std::cout << "EO RebuildAll"<<std::endl;
533   }
534   //================================================================
535
536   
537
538   //================================================================
539   void WxGimmick::UpdateDicomDatabaseView(DicomDatabase* db)
540   {
541     wxBusyCursor busy;
542     wxTreeItemId dbid;
543     TreeItemData *data;
544
545     // Does the db exist ?
546     wxTreeItemIdValue cookie;
547     for (dbid = mTreeListCtrl->GetFirstChild(mTreeRootId,cookie);
548          dbid.IsOk();
549          dbid = mTreeListCtrl->GetNextChild(mTreeRootId,cookie))
550       {    
551         data = (TreeItemData *)mTreeListCtrl->GetItemData(dbid);
552         if ((data->IsDatabase())&&(data->GetDicomNode()==db)) break;
553       }
554
555     // Not found : create
556     if (!dbid.IsOk())
557       {
558         // Icon
559         int iconid = Icon[DicomNode::Database];
560
561         // Creation
562         //      std::cout << " -> Creating item for '"<<db->GetLabel()<<"'"<<std::endl;
563         data = new TreeItemData(db);
564         dbid = mTreeListCtrl->AppendItem( mTreeRootId,
565                                           std2wx(db->GetLabel()),
566                                           iconid, 
567                                           iconid, 
568                                           data );
569         data->SetItemId(dbid);
570         mTreeListCtrl->SetItemTextColour
571           (dbid,mSettings.Colour(DicomNode::Database));
572         mTreeListCtrl->SetItemBackgroundColour
573           (dbid,mSettings.BgColour(DicomNode::Database));
574         UpdateColumns(dbid);
575         // The patients columns legends
576         CreateChildrenColumnsTitles(dbid,DicomNode::Patient);
577
578       }
579     // Increase UpdateTime to detect obsolete items after 
580     // tree traversal
581     data->UpdateTime()++;
582     // Recurse
583     DicomNode::ChildrenListType::iterator j;
584     for (j= db->GetChildrenList().begin();
585          j!=db->GetChildrenList().end();
586          j++)
587       {
588         UpdateDicomNodeView(*j,dbid);
589       }
590     
591     DeleteObsoleteChildren(dbid);
592
593     mTreeListCtrl->EnsureVisible(dbid);
594
595   }
596   //================================================================
597
598   //================================================================
599   void WxGimmick::UpdateDicomNodeView(DicomNode* n, 
600                                                     const wxTreeItemId& parent)
601   {
602   
603     wxBusyCursor busy;
604     //     std::cout << "* UpdateDicomNodeView("<<n->GetLabel()<<")"<<std::endl;
605
606     wxTreeItemId newparent = parent; 
607     TreeItemData *data;
608     // Skip study level
609     if ((!mSettings.MergeStudySeries()) ||
610         (n->GetType() != DicomNode::Study))
611       {
612         // Does the item exist ?
613         wxTreeItemIdValue cookie;
614         for (newparent = mTreeListCtrl->GetFirstChild(parent,cookie);
615              newparent.IsOk();
616              newparent = mTreeListCtrl->GetNextChild(parent,cookie))
617           {    
618             data = (TreeItemData *)mTreeListCtrl->GetItemData(newparent);
619             if (data->GetDicomNode() == n) break;
620           }
621         // Not found : create
622         if (!newparent.IsOk())
623           {
624             int image(Icon[n->GetType()]);
625             wxColour *colour(&mSettings.Colour(n->GetType()));
626             wxColour *bgcolour(&mSettings.BgColour(n->GetType()));
627
628             if (n->GetType()==DicomNode::Image)
629               {
630                 //              std::cout << "!!!Image"<<std::endl;
631                 if (n->GetData<NodeData*>()!=0)
632                   {
633                     //              std::cout << ">> n->GetData<NodeData*>()!=0" << std::endl;
634                     if (n->GetData<NodeData*>()->IsLoaded())
635                       {
636                         colour = &mSettings.LoadedImageColour();
637                       }
638                     //              std::cout << "<< n->GetData<NodeData*>()!=0" << std::endl;
639                   }
640               }
641
642             data = new TreeItemData(n);
643             newparent = mTreeListCtrl->AppendItem(parent, 
644                                                   _T(""),
645                                                   image, image,
646                                                   data);
647             data->SetItemId(newparent);
648             mTreeListCtrl->SetItemTextColour(newparent,*colour);
649             mTreeListCtrl->SetItemBackgroundColour(newparent,*bgcolour);
650  
651             UpdateColumns(newparent);
652
653             
654             if (n->GetType()!=DicomNode::Image)
655               {
656                 CreateChildrenColumnsTitles(newparent,n->GetType()+1);
657               }
658             
659           }
660         else 
661           {
662             UpdateColumns(newparent,true);
663
664           }
665         // synchonise update time with parent
666         TreeItemData * parent_data = 
667           (TreeItemData *)mTreeListCtrl->GetItemData(parent);
668         data->UpdateTime() = parent_data->UpdateTime();
669       }
670   
671     DicomNode::ChildrenListType::iterator i;
672     for (i=n->GetChildrenList().begin();
673          i!=n->GetChildrenList().end();
674          i++)
675       {
676         UpdateDicomNodeView(*i,newparent);
677       }
678
679     if (n->GetType() != DicomNode::Image) 
680       DeleteObsoleteChildren(newparent);
681
682   }
683   //================================================================
684
685   //================================================================
686   void WxGimmick::UpdateColumns(wxTreeItemId& item,
687                                               bool only_first)
688   {
689     TreeItemData *data = 
690       (TreeItemData *)mTreeListCtrl->GetItemData(item);
691     DicomNode* node = data->GetDicomNode();
692     
693     if (only_first) 
694       {
695         // Update only the first field (for #children update)
696         DicomNode* node2 = node;
697         // If Study and Series level are merged and node type is Series
698         // then have to get back to the Study level
699         if ((mSettings.MergeStudySeries())&& 
700             (node->GetType() == DicomNode::Series))
701           node2 = node->GetParent();
702     
703         std::string lab;
704         lab += node2->GetFieldValueMap()
705           [ mSettings.GetColumnList(node2->GetType())[0].Key ];
706
707         if (node->GetType() != DicomNode::Image) 
708           {
709             if (node->GetChildrenList().size()>0)
710               {
711                 char sz[100];
712                 sprintf(sz,"  [%d]",node->GetNumberOfChildren());
713                 lab += sz;
714               }
715           }
716         mTreeListCtrl->SetItemText(item,std2wx(lab));
717       }
718     else 
719       {
720         
721         int c = 0;
722         Settings::ColumnListType::iterator col;
723         // If Study and Series level are merged and node type is Series
724         // then have to fill the Study level cols first
725         if ((mSettings.MergeStudySeries())&& 
726             (node->GetType() == DicomNode::Series))
727           {
728             DicomNode* node2 = node->GetParent();
729             for (col  = mSettings.GetColumnList(node2->GetType()).begin();
730                  col != mSettings.GetColumnList(node2->GetType()).end();
731                  ++col)
732               {
733                 std::string s = node2->GetFieldValueMap()[col->Key];
734                 
735                 if (c==0) 
736                   {
737                     char sz[100];
738                     sprintf(sz,"  [%d]",node->GetNumberOfChildren());
739                     s += sz;
740                   }
741                 mTreeListCtrl->SetItemText (item, c,  std2wx(s));
742                 c++;
743               }   
744           }
745         
746         for (col  = mSettings.GetColumnList(node->GetType()).begin();
747              col != mSettings.GetColumnList(node->GetType()).end();
748              ++col)
749           {
750             std::string s = node->GetFieldValueMap()[col->Key];
751             if ((c==0)&&(node->GetType() != DicomNode::Image))
752               {
753                 char sz[100];
754                 sprintf(sz,"  [%d]",node->GetNumberOfChildren());
755                 s += sz;
756               }
757             mTreeListCtrl->SetItemText (item, c,  std2wx(s));
758             c++;
759           }
760       }
761
762   }
763   //================================================================
764
765   //================================================================
766   wxTreeItemId WxGimmick::CreateChildrenColumnsTitles
767   (wxTreeItemId& item,
768    DicomNode::Type t)
769   {
770     // Creates the sub-level columns titles
771     TreeItemData* data 
772       = new TreeItemData(0);
773     wxTreeItemId id = mTreeListCtrl->AppendItem( item,
774                                                  _T(""),
775                                                  -1,
776                                                  -1,
777                                                  data );
778     data->SetItemId(id);
779     mTreeListCtrl->SetItemFont(id, *wxITALIC_FONT);
780     mTreeListCtrl->SetItemTextColour(id, mSettings.Colour(t));
781     mTreeListCtrl->SetItemBackgroundColour(id, mSettings.BgColour(t));
782     UpdateColumnsTitles(id,t);  
783     return id;
784   }
785   //================================================================
786
787   //================================================================
788   void WxGimmick::UpdateColumnsTitles(wxTreeItemId& item,
789                                                     DicomNode::Type t)
790   {
791     //    std::cout << "Update columns titles "<<t<<std::endl;
792     int c = 0;
793     Settings::ColumnListType::iterator col;
794     for (col  = mSettings.GetColumnList(t).begin();
795          col != mSettings.GetColumnList(t).end();
796          ++col)
797       {
798         //      std::cout << col->Name << std::endl;
799         mTreeListCtrl->SetItemText (item, c,  std2wx(col->Name));
800         c++;
801       }
802   }
803   //================================================================
804
805
806   //================================================================
807   void WxGimmick::DeleteObsoleteChildren(wxTreeItemId& id)
808     
809   {
810     TreeItemData * parent_data = 
811       (TreeItemData *)mTreeListCtrl->GetItemData(id);
812     
813     wxTreeItemId child;
814     wxTreeItemIdValue cookie;
815     std::vector<wxTreeItemId> children;
816     for (child = mTreeListCtrl->GetFirstChild(id,cookie);
817          child.IsOk();
818          child = mTreeListCtrl->GetNextChild(id,cookie))
819       {    
820         children.push_back(child);
821       }
822     std::vector<wxTreeItemId>::iterator i;
823     for (i=children.begin();i!=children.end();++i)
824       {
825         TreeItemData *data = 
826           (TreeItemData *)mTreeListCtrl->GetItemData(*i);
827         if (
828             ((data->GetDicomNode()>0) && 
829              ((data->UpdateTime() != parent_data->UpdateTime()))) || 
830             ((data->IsDicomNode()) &&
831              (data->GetDicomNode()==0))
832             ) 
833           {
834             //      std::cout << "DOBSC="<<mTreeListCtrl->GetItemText(*i)<<std::endl;
835             mTreeListCtrl->Delete(*i);
836           }
837       }
838   }
839   //================================================================
840
841   //================================================================
842   void WxGimmick::OpenOrNewDatabase(bool open)
843   {
844     wxBusyCursor busy;
845
846     long style = wxFD_SAVE | wxFD_OVERWRITE_PROMPT;
847     if (open) style = wxOPEN | wxFILE_MUST_EXIST;
848     std::string wc("*.");
849     wc += GetDatabaseExtension();
850
851     // TO DO : Handler give their wildcards
852     wxFileDialog* FD = new wxFileDialog( 0, 
853                                          _T("Select file"),
854                                          mCurrentDirectory,
855                                          _T(""),
856                                          std2wx(wc),
857                                          style,
858                                          wxDefaultPosition);
859
860         if (FD->ShowModal()!=wxID_OK) return;
861
862     std::string filename = wx2std (FD->GetPath());
863         mCurrentDirectory = FD->GetDirectory();
864
865     if (!open)
866       {
867         boost::filesystem::path filepath(filename);
868         boost::filesystem::change_extension(filepath,GetDatabaseExtension());
869         if ( boost::filesystem::exists(filepath) )
870           {
871                   boost::filesystem::remove(filepath);  
872                           /* 
873                           LG : works on Linux but not Windows :
874             if ( ! boost::filesystem::remove(filepath) )
875               {
876                 wxMessageBox(_T("Could not overwrite ")
877                              +std2wx(filepath.string()),
878                              _T("Error"),
879                              wxOK,this);
880                 return;
881                 
882         
883               }
884                   */
885           }
886       }
887     
888     DicomDatabase* db = new DicomDatabase(filename);
889     bool r;
890     if (open) 
891       {
892         r = db->Open();
893         if (!r) 
894           {
895             wxMessageBox(_T("An error occured while opening ")
896                          +std2wx(filename),
897                          _T("Error"),
898                          wxOK,this);
899             return;
900           }
901       }
902     else 
903       {
904         wxString collname = 
905           wxGetTextFromUser(_T("Enter collection name"),_T("New collection"),
906                             _T(""),this);
907         db->SetName(wx2std(collname));
908
909         r = db->New();
910         if (!r) 
911           {
912             wxMessageBox(_T("An error occured while creating ")
913                          +std2wx(filename),
914                          _T("Error"),
915                          wxOK,this);
916             return;
917           }
918       }
919
920     if (GetDicomDatabaseList().size()==0) mFieldsView->UpdateFields(db);
921     GetDicomDatabaseList().push_back(db);
922     UpdateDicomDatabaseView(db);
923
924
925   }
926   //================================================================
927
928
929   //================================================================
930   void WxGimmick::LoadConfiguration()
931   {
932     wxBusyCursor busy;
933     //    std::cout << "WxGimmick : Reading config"<<std::endl;
934
935     //    std::cout <<     
936     creaMessage("Gimmick!",1,"Gimmick! : ==> Loading collections from '"<<mDatabaseListFile<<"'"<<std::endl);
937     //        <<"'"<<std::endl;
938
939     std::ifstream s;
940     s.open(mDatabaseListFile.c_str());
941     if (s.good())
942         {
943         while (!s.eof()) 
944           {
945             std::string str;
946             std::getline(s,str);
947             if (str.size()==0) continue;
948
949             std::vector<std::string> tokens;        
950             boost::split( tokens, str, boost::is_any_of("\t") );
951
952             DicomDatabase* db = new DicomDatabase(tokens[0]);
953             
954             //  std::cout << "  -> Loading collection '"<<tokens[0]<<"'"<<std::endl;
955             
956             if (tokens.size()==2) 
957               {
958                 db->SetName(tokens[1]);
959               }
960             
961             if (db->Open()) 
962               {
963                 GetDicomDatabaseList().push_back(db);
964                 db->DBLoadChildren(db,DicomNode::Patient);
965                 if (mSettings.HasActiveComparator(DicomNode::Patient))
966                   {
967                     db->SortChildren
968                       ( mSettings.GetActiveComparator(DicomNode::Patient)  );
969                   }
970               }
971             else 
972               {
973                 creaMessage("Gimmick!",1,"           ==> ERROR opening collection '"<<tokens[0]<<"'"<<std::endl);
974                 delete db;
975               }
976           }
977         s.close();
978         }
979         else 
980         {
981           creaMessage("Gimmick!",1,"           ==> File does not exist. It will be created on exit (if you already ran Gimmick! and exited normally, this is not normal. Send a bug report).");
982         }
983
984         
985     mTreeListCtrl->SetBackgroundColour(mSettings.BgColour(DicomNode::Database));
986     if (GetDicomDatabaseList().begin() != 
987         GetDicomDatabaseList().end() )
988       {
989         mFieldsView->UpdateFields(*GetDicomDatabaseList().begin());
990       }
991
992     RebuildView();
993       
994   }
995   //================================================================
996   
997   //================================================================
998   void WxGimmick::SaveConfiguration()
999   {
1000     wxBusyCursor busy;
1001     creaMessage("Gimmick!",1,"Gimmick! : Saving configuration..."<<std::endl);
1002     
1003     creaMessage("Gimmick!",1,"Gimmick! : ==> Saving collections in '"
1004                 <<mDatabaseListFile<<"'"<<std::endl);
1005     
1006     std::ofstream s;
1007     s.open(mDatabaseListFile.c_str());
1008     if (!s.good())
1009       {
1010         creaError("Gimmick! : error opening '"<<mDatabaseListFile<<"'"); 
1011       }
1012     
1013     DicomDatabaseListType::iterator i;
1014     for (i =GetDicomDatabaseList().begin();
1015          i!=GetDicomDatabaseList().end();
1016          ++i)
1017       {  
1018         s << (*i)->GetFileName() << "\t";
1019         s << (*i)->GetName() << std::endl;
1020       }
1021     
1022     s.close();
1023
1024   }
1025   //================================================================
1026
1027   /*
1028   //================================================================
1029   void  WxGimmick::OnClose(wxCloseEvent& event)
1030   {
1031   if (mSaveConfigurationOnClose) SaveConfiguration();
1032   }
1033   //================================================================
1034   */
1035   //================================================================
1036   void WxGimmick::OnItemActivated(wxTreeEvent& event)
1037   {  
1038     event.Skip();
1039     return;
1040
1041     wxBusyCursor busy;
1042     //    std::cout << "OnItemActivated" <<std::endl;
1043     wxTreeItemId itemId = event.GetItem();
1044     if (mTreeListCtrl->IsExpanded(itemId))
1045       {
1046         mTreeListCtrl->Collapse(itemId);
1047       }
1048     else 
1049       {
1050         mTreeListCtrl->Expand(itemId);
1051       }
1052   }
1053   //================================================================
1054
1055   //================================================================
1056   void WxGimmick::LoadChildren(wxTreeItemId& id)
1057   {
1058     TreeItemData *item = (TreeItemData *)mTreeListCtrl->GetItemData(id);
1059     if (item)
1060       {
1061         if ( ( item->IsDicomNode() || item->IsDatabase() ) &&
1062              ( ! item->GetDicomNode()->ChildrenLoaded() ) )
1063           {
1064             
1065             // If children not already loaded : do it 
1066             if (
1067                 item->GetDicomNode()->GetDicomDatabase()->DBLoadChildren
1068                 (item->GetDicomNode(),item->GetDicomNode()->GetType()+1)
1069                 > 0 )
1070               {
1071                 // Some new children loaded
1072                 // Sort them
1073                 if (mSettings.HasActiveComparator
1074                     (item->GetDicomNode()->GetType()+1))
1075                   {
1076                     /*                  std::cout << "Sorting using '"
1077                       << mSettings.GetActiveComparator
1078                       (item->GetDicomNode()->GetType()+1).GetName() 
1079                       << "' ... ";
1080                     */
1081                     item->GetDicomNode()->SortChildren
1082                       ( mSettings.GetActiveComparator
1083                         (item->GetDicomNode()->GetType()+1)
1084                         );
1085                     //                  std::cout << "ok"<<std::endl;
1086                   }
1087                 // Update tree
1088                 DicomNode::ChildrenListType::iterator i;
1089                 for (i=item->GetDicomNode()->GetChildrenList().begin();
1090                      i!=item->GetDicomNode()->GetChildrenList().end();
1091                      i++)
1092                   {
1093                     UpdateDicomNodeView(*i,id);
1094                   }
1095               }
1096             // EO If children not already loaded 
1097           }
1098       } 
1099   }
1100   //================================================================
1101
1102
1103   //================================================================
1104   void WxGimmick::OnItemExpanded(wxTreeEvent& event)                   
1105   {
1106
1107     //    std::cout << "* Expanded *"<<std::endl;
1108     //  }
1109
1110     wxBusyCursor busy;
1111     
1112     wxTreeItemId itemId = event.GetItem();
1113     LoadChildren(itemId);
1114     
1115     return;
1116
1117     // expand if collapsed and collapse if expanded ...
1118     TreeItemData *item = 
1119       (TreeItemData *)mTreeListCtrl->GetItemData(itemId);
1120     if (item)
1121       {
1122         if ( ( item->IsDicomNode() || item->IsDatabase() ) &&
1123              ( ! item->GetDicomNode()->ChildrenLoaded() ) )
1124           {
1125                 
1126             // If children not already loaded : do it 
1127             if (
1128                 item->GetDicomNode()->GetDicomDatabase()->DBLoadChildren
1129                 (item->GetDicomNode(),item->GetDicomNode()->GetType()+1)
1130                 > 0 )
1131               {
1132                     
1133                 // Some new children loaded
1134                 // Sort them
1135                 if (mSettings.HasActiveComparator
1136                     (item->GetDicomNode()->GetType()+1))
1137                   {
1138                     /*                  std::cout << "Sorting using '"
1139                       << mSettings.GetActiveComparator
1140                       (item->GetDicomNode()->GetType()+1).GetName() 
1141                       << "' ... ";
1142                     */
1143                     item->GetDicomNode()->SortChildren
1144                       ( mSettings.GetActiveComparator
1145                         (item->GetDicomNode()->GetType()+1)
1146                         );
1147                     //                  std::cout << "ok"<<std::endl;
1148                   }
1149                 /*              
1150                 // If images : sort them 
1151                 if (item->IsDicomNode())
1152                 {
1153                 if (item->GetDicomNode()->GetType()==DicomNode::Series)
1154                 {  
1155                 // SORT
1156                    
1157                 LexicographicalDicomNodeComparator compare;
1158                 // DicomNodeImageImageNumberComparator c1;
1159                     
1160                 DicomNodeImageSliceLocationComparator c1;
1161                 DicomNodeImageImageNumberComparator c2;
1162                 DicomNodeImageFileNameComparator cn;
1163                 compare.Add(c1);
1164                 compare.Add(c2);
1165                 compare.Add(cn);
1166                 //              std::cout << "SORT"<<std::endl;
1167                 item->GetDicomNode()->SortChildren(compare);
1168                 //              std::cout << "EO SORT"<<std::endl;
1169                 //
1170                     
1171                 }
1172                 }
1173                 */
1174                     
1175                 // Update tree
1176                 DicomNode::ChildrenListType::iterator i;
1177                 for (i=item->GetDicomNode()->GetChildrenList().begin();
1178                      i!=item->GetDicomNode()->GetChildrenList().end();
1179                      i++)
1180                   {
1181                     UpdateDicomNodeView(*i,itemId);
1182                   }
1183               }
1184             // EO If children not already loaded 
1185           }
1186       }
1187     //  mTreeListCtrl->Expand(itemId);
1188      
1189   }
1190   //================================================================
1191
1192
1193   /*
1194   //=====================================================================
1195   void WxGimmick::InsertRoot(wxTreeItemId& id, Root* r)
1196   {
1197   wxBusyCursor busy;
1198   TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
1199   if (data)
1200   { 
1201         
1202   wxStopWatch sw;
1203   data->GetDicomNode()->GetDicomDatabase()->LoadAll();
1204   printf(">>>>>> Time to load all = %ldms \n",sw.Time());
1205
1206   UpdateRootView(data->GetDicomNode()->GetDicomDatabase());
1207     
1208
1209   if (data->IsDicomNode())
1210   {
1211   wxStopWatch sw1;
1212   r->Insert(data->GetDicomNode());
1213   printf(">>>>>> Time to insert = %ldms \n",sw1.Time());
1214   UpdateRootView(r);
1215   }
1216   else if (data->IsDatabase())
1217   {     
1218   wxStopWatch sw1;
1219   DicomNode::ChildrenListType::iterator j;
1220   for (j= data->GetDicomNode()->GetChildrenList().begin();
1221   j!=data->GetDicomNode()->GetChildrenList().end();
1222   j++)
1223   {
1224   r->Insert(*j);
1225   }
1226   printf(">>>>>> Time to insert = %ldms \n",sw1.Time());
1227   UpdateRootView(r);    
1228   }
1229
1230   }
1231   }
1232   //=====================================================================
1233   */
1234
1235   
1236   //=================================================
1237   void WxGimmick::DeleteDicomDatabase(wxTreeItemId& id, 
1238                                                     DicomDatabase* db)
1239   {
1240     wxBusyCursor busy;
1241     DicomDatabaseListType::iterator i = find(GetDicomDatabaseList().begin(),
1242                                              GetDicomDatabaseList().end(),
1243                                              db);
1244     delete (*i);
1245     GetDicomDatabaseList().erase(i);
1246     mTreeListCtrl->Delete(id);
1247   }
1248   //=================================================
1249
1250
1251
1252   //=====================================================================
1253   
1254   void WxGimmick::OnItemRightClick(wxTreeEvent& event)
1255   {
1256
1257     wxTreeItemId itemId = event.GetItem();
1258     if (itemId.IsOk())
1259       {
1260         wxPoint clientpt = event.GetPoint();
1261         wxPoint screenpt = ClientToScreen(clientpt);
1262         ShowMenu(itemId, clientpt);
1263       }
1264     event.Skip();
1265   }
1266   //=====================================================================
1267   
1268
1269
1270   //=====================================================================
1271   void WxGimmick::ShowMenu(wxTreeItemId id, const wxPoint& pt)
1272   { 
1273
1274     //  std::cout << "ShowMenu" <<std::endl;
1275     mItemOfMenu = id;
1276     TreeItemData *data = 
1277       (TreeItemData *)mTreeListCtrl->GetItemData(id);
1278   
1279     /*
1280       wxString title;
1281       if ( id.IsOk() )
1282       {
1283       title << wxT("Menu for ") << mTreeListCtrl->GetItemText(id);
1284       }
1285       else
1286       {
1287       title = wxT("Menu for no particular item");
1288       }
1289     */
1290
1291 #if wxUSE_MENUS
1292     wxMenu menu;
1293
1294     if (id==mCollectionsTitlesItemId)
1295       {
1296         menu.Append(PopUp_NewCollection, _T("&New collection"));
1297         menu.Append(PopUp_OpenCollection, _T("&Open collection"));
1298       }
1299     if (data)
1300       {
1301         if (data->IsDatabase())
1302           {
1303             wxMenu* addmenu = new wxMenu;
1304             addmenu->Append(PopUp_AddDirectory, _T("Scan &Directory"));
1305             addmenu->Append(PopUp_AddFile, _T("Select &File(s)"));
1306             //      addmenu->Append(PopUp_AddRawFile, _T("Add &Raw image"));
1307             menu.AppendSubMenu(addmenu, _T("&Add image(s) to collection..."));
1308             menu.Append(PopUp_CloseCollection, _T("&Close collection"));
1309             menu.Append(PopUp_DeleteCollection, _T("&Delete collection"));
1310           }
1311         if (data->IsDicomNode())
1312           {
1313             
1314             //      LG : BUGGY
1315             /*
1316             std::string str("&Remove ");
1317             str += data->GetDicomNode()->GetTypeName();
1318             menu.Append(PopUp_Remove, std2wx(str));
1319             */
1320           }
1321       
1322         if ((data->GetDicomNode()>0)&&
1323             ( data->GetDicomNode()->GetType()<DicomNode::Image))
1324           {
1325             int ctype = data->GetDicomNode()->GetType()+1;
1326             if (mSettings.HasActiveComparator(ctype))
1327               {
1328                 wxMenu* sortmenu = new wxMenu;
1329                 int n = 0;
1330                 Settings::ComparatorsList::iterator i;
1331                 for (i =mSettings.GetComparatorsList(ctype).begin();
1332                      i !=mSettings.GetComparatorsList(ctype).end();
1333                      ++i)
1334                   {
1335                     sortmenu->AppendRadioItem(PopUp_Sort+n, std2wx(i->GetName()));
1336                     n++;
1337                   }    
1338               
1339                 sortmenu->Check(PopUp_Sort+
1340                                 mSettings.GetActiveComparatorIndex(ctype)
1341                                 ,true);
1342               
1343                 std::string sortmenustr("&Sort ");
1344                 sortmenustr += DicomNode::GetPluralTypeName(ctype);
1345                 sortmenustr += " by...";
1346                 if (menu.GetMenuItemCount()>0) menu.AppendSeparator();
1347                 menu.AppendSubMenu(sortmenu,std2wx(sortmenustr));
1348               
1349                 /*
1350                   item->GetDicomNode()->SortChildren
1351                   ( mSettings.GetActiveComparator
1352                   (item->GetDicomNode()->GetType()+1)
1353                   );
1354                   std::cout << "ok"<<std::endl;
1355                 */
1356               }
1357           }
1358       }
1359     // Event : user can customize the menu 
1360     WxGimmickEvent 
1361       ev(wxEVT_COMMAND_TREEVIEWLIST_CONTEXTUAL_MENU,this,id);
1362     ev.SetMenu(&menu);
1363     if (data)
1364       {
1365         ev.SetDicomNode(data->GetDicomNode());
1366       }
1367     GetEventHandler()->ProcessEvent(ev);
1368     //
1369   
1370     if (menu.GetMenuItemCount()>0) menu.AppendSeparator();
1371     menu.Append(PopUp_Settings, wxT("&Settings..."));
1372     menu.Append(PopUp_About, wxT("&About..."));
1373   
1374
1375   
1376     /*
1377       wxMenu* newmenu = new wxMenu;
1378       wxMenu* openmenu = new wxMenu;
1379       Tree::RootHandlerListType::iterator h;
1380       int i=0;
1381       for (h= Tree::GetRootHandlerList().begin();
1382       h!=Tree::GetRootHandlerList().end();
1383       h++)
1384       {
1385       if ((*h)->SupportsNew()) 
1386       {
1387       newmenu->Append(PopUp_New+i, std2wx((*h)->GetName()));
1388       }
1389       if ((*h)->SupportsOpen()) 
1390       openmenu->Append(PopUp_Open+i, std2wx((*h)->GetName()));
1391       i++;
1392       }
1393     
1394       menu.AppendSubMenu(openmenu, _T("&Open"));
1395       menu.AppendSubMenu(newmenu, _T("&New"));
1396
1397       if (data)
1398       { 
1399       if ((data->IsDatabase())||(data->IsDicomNode()))
1400       {
1401       Root* itroot = data->GetDicomNode()->GetDicomDatabase();
1402       //        if (!itroot) itroot = data->GetDicomNode()->GetRoot();
1403       wxMenu* insertmenu = new wxMenu;
1404       bool hasone = false;
1405       i = 0;
1406       Tree::RootListType::iterator j;
1407       for (j  = mTree->GetDatabaseList().begin();
1408       j != mTree->GetDatabaseList().end();
1409       j++)
1410       {
1411       //            std::cout << (*j)->GetName() << " " 
1412       //                      <<  (*j)->GetTypeName()
1413       //                      << " i="<<(*j)->SupportsInsert()<<std::endl;
1414       if ( ((*j)!=itroot) && ((*j)->SupportsInsert()) ) 
1415       {
1416       insertmenu->Append(PopUp_Insert+i, 
1417       std2wx((*j)->GetName()));
1418       hasone = true;
1419       }
1420       i++;
1421       }
1422             
1423       if (hasone) menu.AppendSubMenu(insertmenu, _T("&Insert into"));
1424       }
1425       if (data->IsDatabase())
1426       {
1427       menu.Append(PopUp_Close, wxT("&Close"));
1428       }
1429       if (data->IsDicomNode() && data->GetDicomNode()->GetDicomDatabase()->SupportsRemove())
1430       {
1431       menu.Append(PopUp_Remove, wxT("&Remove"));
1432       }
1433       }
1434     */
1435
1436  
1437
1438  
1439     PopupMenu(&menu, pt);
1440 #endif // wxUSE_MENUS
1441
1442     //    std::cout << "EO ShowMenu" <<std::endl;
1443   }
1444   //=====================================================================
1445
1446   //=====================================================================
1447   // Pop up menu callbacks
1448   void  WxGimmick::OnPopUpAbout(wxCommandEvent& event)
1449   {
1450     wxMessageBox( _T("Give me my medical images quick ! \n\n  (c) CREATIS-LRMN 2008\n      laurent.guigues@creatis.insa-lyon.fr"),
1451                   _T("Gimmick!"),
1452                   wxOK | wxICON_INFORMATION, this);
1453   }
1454   //=====================================================================
1455
1456   //=====================================================================
1457   void  WxGimmick::OnPopUpSettings(wxCommandEvent& event)
1458   {
1459     WxGimmickSettingsDialog* s = 
1460       new WxGimmickSettingsDialog(this,&mSettings);
1461     s->ShowModal();
1462     delete s;
1463   }
1464   //=====================================================================
1465
1466   //=====================================================================
1467   void  WxGimmick::OnPopUpNewCollection(wxCommandEvent& event)
1468   {
1469     wxBusyCursor busy;
1470     OpenOrNewDatabase(false);
1471   }
1472   //=====================================================================
1473   
1474
1475  
1476   //=====================================================================
1477   void  WxGimmick::OnPopUpOpenCollection(wxCommandEvent& event)
1478   {
1479     wxBusyCursor busy;
1480     OpenOrNewDatabase(true);
1481   }
1482   //=====================================================================
1483
1484
1485   //=====================================================================
1486   void  WxGimmick::OnPopUpCloseCollection(wxCommandEvent& event)
1487   {
1488     if (wxMessageBox(_T("This will remove this collection from your list of collections but will not delete the collection's file on disk. Proceed ?"),_T("Confirm"),wxYES_NO,this)==wxNO) return;
1489    
1490     wxBusyCursor busy;
1491     //   std::cout << "OnPopUpClose"<<std::endl;
1492     //  wxTreeItemId id = event.GetId();
1493     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1494     DicomDatabase* r = data->GetDicomNode()->GetDicomDatabase();
1495     //   std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1496     DeleteDicomDatabase(mItemOfMenu,r);
1497   }
1498   //=====================================================================
1499
1500   //=====================================================================
1501   void  WxGimmick::OnPopUpDeleteCollection(wxCommandEvent& event)
1502   {
1503     if (wxMessageBox(_T("This will physically delete the collection's file on disk and cannot be reverted. Proceed ?"),_T("Confirm"),wxYES_NO,this)==wxNO) return;
1504     
1505     wxBusyCursor busy;
1506
1507    
1508     //   std::cout << "OnPopUpClose"<<std::endl;
1509     //  wxTreeItemId id = event.GetId();
1510     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1511     DicomDatabase* r = data->GetDicomNode()->GetDicomDatabase();
1512
1513     wxRemoveFile(std2wx(r->GetFileName()));
1514     //   std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1515     DeleteDicomDatabase(mItemOfMenu,r);
1516     
1517   }
1518   //=====================================================================
1519   
1520   void DisplayUpdateSummary( DicomDatabase::UpdateSummary& summary,
1521                              wxWindow* parent )
1522   {
1523     std::stringstream mess;
1524     mess << "Dirs\tscanned\t\t\t: " << summary.scanned_dirs << "\n";
1525     mess << "Files\tscanned\t\t\t: " << summary.scanned_files << "\n";
1526     mess << "Files\thandled\t\t\t: " << summary.handled_images << "\n\n";
1527     mess << "Patients\tadded\t\t: " << summary.added_patients<< "\n";
1528     mess << "Studies\tadded\t\t: " << summary.added_studies<< "\n";
1529     mess << "Series\tadded\t\t: " << summary.added_series<< "\n";
1530     mess << "Images\tadded\t\t: " << summary.added_images<< "\n\n";
1531     char times[500];
1532     sprintf(times,"Time to parse dir \t\t: %ld ms \t%d°/o\nTime to read files info \t: %ld ms \t%d°/o\nTime to update structs \t: %ld ms \t%d°/o\nTime to update database \t: %ld ms \t%d°/o\nTotal time \t\t\t: %ld ms",
1533             summary.parse_time,
1534             (int)( summary.parse_time*100./summary.total_time),
1535             summary.file_scan_time,
1536             (int)(summary.file_scan_time*100./summary.total_time),
1537             summary.update_structs_time,
1538             (int)(summary.update_structs_time*100./summary.total_time),
1539             summary.update_database_time,
1540             (int)(summary.update_database_time*100./summary.total_time),
1541             summary.total_time );
1542     
1543     mess << times;
1544     
1545     wxMessageBox(std2wx(mess.str()),_T("Update summary"),wxOK,parent);
1546   }
1547   
1548   
1549   //=====================================================================
1550   void  WxGimmick::OnPopUpAddFile(wxCommandEvent& event)
1551   {
1552     long style = wxOPEN | wxFILE_MUST_EXIST | wxFD_MULTIPLE;
1553     std::string wc("*.*");
1554     wxFileDialog* FD = new wxFileDialog( 0, 
1555                                          _T("Select file"),
1556                                          mCurrentDirectory,
1557                                          _T(""),
1558                                          std2wx(wc),
1559                                          style,
1560                                          wxDefaultPosition);
1561     
1562     if (FD->ShowModal()==wxID_OK)
1563       {
1564         wxBusyCursor busy;
1565
1566         mCurrentDirectory = FD->GetDirectory();
1567         wxArrayString files;
1568         FD->GetPaths(files);
1569         unsigned int i;
1570         std::vector<std::string> filenames;
1571         for (i=0;i<files.GetCount();++i)
1572           filenames.push_back(wx2std(files[i]));
1573
1574        
1575         TreeItemData *data = 
1576           (TreeItemData *)
1577           mTreeListCtrl->GetItemData(mItemOfMenu);
1578         DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1579         DicomDatabase::UpdateSummary summary;
1580         wxProgressDialog* progress = 
1581           new wxProgressDialog(_T("Adding file(s)"),
1582                                _T(""),
1583                                1000,
1584                                this,
1585                                wxPD_ELAPSED_TIME |
1586                                wxPD_ESTIMATED_TIME | 
1587                                wxPD_REMAINING_TIME |
1588                                wxPD_CAN_ABORT );
1589        
1590         db->AddFiles(filenames,progress,summary);
1591         
1592         progress->Pulse(_T("Updating view..."));
1593         UpdateDicomDatabaseView(db);
1594         delete progress;
1595         DisplayUpdateSummary(summary,this);
1596       }
1597   
1598   }
1599   //=====================================================================
1600
1601   //=====================================================================
1602   void  WxGimmick::OnPopUpAddRawFile(wxCommandEvent& event)
1603   {
1604     wxMessageBox(_T("Not yet implemented !"),_T("Sorry"),wxOK,this);
1605   }
1606   //=====================================================================
1607
1608   //=====================================================================
1609   void  WxGimmick::OnPopUpAddDirectory(wxCommandEvent& event)
1610   {
1611     long style = wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST;
1612     wxDirDialog* FD = 
1613       new wxDirDialog( 0, 
1614                        _T("Select directory"),
1615                        mCurrentDirectory,
1616                        style);
1617    
1618     if (FD->ShowModal()==wxID_OK)
1619       {
1620
1621         bool recurse = false;
1622         if (wxMessageBox(_T("Recurse into sub-directories ?"),
1623                          _T("Scan directory"),
1624                          wxYES_NO,this ) == wxYES)
1625           {
1626             recurse = true;
1627           }
1628        
1629         wxBusyCursor busy;
1630         wxProgressDialog* progress = 
1631           new wxProgressDialog(_T("Scanning directory"),
1632                                _T("Parsing directory"),
1633                                1000,
1634                                this,
1635                                wxPD_ELAPSED_TIME |
1636                                wxPD_ESTIMATED_TIME | 
1637                                wxPD_REMAINING_TIME |
1638                                wxPD_CAN_ABORT );
1639         DicomDatabase::UpdateSummary summary;
1640
1641         std::string dirname = wx2std (FD->GetPath()) ;
1642         mCurrentDirectory = FD->GetPath();
1643         TreeItemData *data = 
1644           (TreeItemData *)
1645           mTreeListCtrl->GetItemData(mItemOfMenu);
1646         DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1647         db->AddDirectory(dirname,recurse,progress,summary);
1648
1649         progress->Pulse(_T("Updating view..."));
1650         UpdateDicomDatabaseView(db);
1651
1652         delete progress;    
1653         DisplayUpdateSummary(summary,this);
1654         /*    
1655               if (summary.cancelled_by_user)
1656               {
1657               std::cout << "!! Cancelled by user !!"<<std::endl;
1658               }
1659         */
1660
1661       }
1662   }
1663   //=====================================================================
1664
1665   //=====================================================================
1666   void  WxGimmick::OnPopUpRemove(wxCommandEvent& event)
1667   {
1668
1669     /*
1670       wxMessageBox(_T("Not yet implemented"),_T("Sorry !"),wxOK);
1671       return;
1672     */
1673
1674     //  wxTreeItemId id = event.GetId();
1675     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1676
1677     std::string mess("Remove ");
1678     mess += data->GetDicomNode()->GetTypeName();
1679     mess += " from collection ?";
1680     int answer = wxMessageBox(std2wx(mess), _T("Confirm"), wxYES_NO);
1681     if (answer == wxNO) return;
1682    
1683     if ( mTreeListCtrl->IsSelected(mItemOfMenu) )
1684       {
1685         wxTreeItemId next = mTreeListCtrl->GetNextSibling(mItemOfMenu);
1686         if (next.IsOk()) 
1687           {
1688             mTreeListCtrl->SelectItem(next);
1689           }
1690         else 
1691           {
1692             return;
1693           }
1694       }
1695
1696     DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1697     db->Remove(data->GetDicomNode());
1698     //   std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1699     // TODO : Optimize update only parent's branch
1700     UpdateDicomDatabaseView(db);
1701     //   DeleteDicomDatabase(mItemOfMenu,r);
1702   }
1703   //=====================================================================
1704
1705   //=====================================================================
1706   void  WxGimmick::OnPopUpSort(wxCommandEvent& event)
1707   {
1708     wxBusyCursor busy;
1709     //    std::cout << "OnPopUpSort"<<std::endl;
1710     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1711     int index = event.GetId() - PopUp_Sort;
1712     DicomNode* node = data->GetDicomNode();
1713     DicomNode::Type ctype = node->GetType()+1;
1714     mSettings.SetActiveComparatorIndex(ctype,index);
1715
1716     if (node->ChildrenLoaded())
1717       {
1718         // Remove children
1719         mTreeListCtrl->DeleteChildren(mItemOfMenu);
1720
1721         /*      std::cout << "Sorting using '"
1722           << mSettings.GetActiveComparator(ctype).GetName() 
1723           << "' ... ";
1724         */
1725         node->SortChildren ( mSettings.GetActiveComparator(ctype) );
1726         //      std::cout << "ok"<<std::endl;
1727
1728         
1729         // Update tree
1730         CreateChildrenColumnsTitles(mItemOfMenu,ctype);
1731         DicomNode::ChildrenListType::iterator i;
1732         for (i=node->GetChildrenList().begin();
1733              i!=node->GetChildrenList().end();
1734              i++)
1735           {
1736             UpdateDicomNodeView(*i,mItemOfMenu);
1737           }
1738       }
1739   }
1740   //=====================================================================
1741
1742
1743   //=====================================================================
1744   void  WxGimmick::OnPopUpUser(wxCommandEvent& event)
1745   {
1746     //    std::cout << "OnPopUpUser"<<std::endl;
1747     event.Skip();
1748   }
1749   //=====================================================================
1750
1751   //=================================================
1752   void WxGimmick::CreateImageList(int size)
1753   {
1754     if ( size == -1 )
1755       {
1756         mTreeListCtrl->SetImageList(NULL);
1757         return;
1758       }
1759     if ( size == 0 )
1760       size = m_imageSize;
1761     else
1762       m_imageSize = size;
1763     
1764     wxIcon icons[20];
1765     // should correspond to Icon_xxx enum
1766     icons[Icon_Patient] = wxIcon(patient_xpm);
1767     icons[Icon_Study] = wxIcon(study_xpm);
1768     icons[Icon_Series] = wxIcon(series_xpm);
1769     icons[Icon_Image] = wxIcon(image_xpm);
1770     icons[Icon_Database] = wxIcon(database_xpm);
1771     icons[Icon_Folder] = wxIcon(folder_xpm);
1772     icons[Icon_DicomDir] = wxIcon(dicomdir_xpm);
1773     icons[Icon_Root] = wxIcon(root_xpm);
1774
1775
1776     //    mFirstRootIconIndex = 8;
1777     //    int i=0;
1778     /*
1779       Tree::RootHandlerListType::iterator h;
1780
1781       for (h= Tree::GetDatabaseHandlerList().begin();
1782       h!=Tree::GetDatabaseHandlerList().end();
1783       h++)
1784       {
1785       icons[mFirstRootIconIndex+i] = (*h)->GetIcon();
1786       i++;
1787       }
1788     */
1789     unsigned int NbIcons = 8;//mFirstRootIconIndex + i;
1790     // Make an image list containing small icons
1791     wxImageList *images = new wxImageList(size, size, true);
1792     
1793     int sizeOrig = icons[0].GetWidth();
1794     for ( size_t i = 0; i < NbIcons; i++ )
1795       {
1796         if ( size == sizeOrig )
1797           {
1798             images->Add(icons[i]);
1799           }
1800         else
1801           {
1802             images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
1803           }
1804       }
1805     mTreeListCtrl->AssignImageList(images);
1806   }
1807   //=================================================
1808
1809
1810
1811
1812
1813
1814
1815
1816   //================================================================
1817   bool WxGimmick::IsImageSelectable(DicomNode* node)                   
1818   {
1819     int rows = node->ImageGetRows();
1820     int cols = node->ImageGetColumns();
1821     int frms = node->ImageGetFrames();
1822     
1823     //    std::cout << "R/C/F = " << rows << "/"<< cols <<"/"<<frms<<std::endl;
1824
1825     int dim = 0;
1826     if (frms>0) dim=3;
1827     else if (cols>0) dim=2;
1828     else if (rows>0) dim=1;
1829     
1830     if (dim == 0) 
1831       {
1832         std::cout << "Unknown image dimension : cannot select !" 
1833                   << std::endl;
1834         return false;
1835       }
1836     else if (dim>mSelectionMaxImageDimension)
1837       {
1838         std::cout << "Selecting "<<dim<<"D images is not allowed !" 
1839                   << std::endl;
1840         return false;
1841       }
1842     
1843     if ( mTreeListCtrl->GetSelectionSize() == 0 ) 
1844       {
1845         mCurrentSelectionImageSize[0] = cols;
1846         mCurrentSelectionImageSize[1] = rows;
1847         mCurrentSelectionImageSize[2] = frms;
1848         return true;
1849       }
1850     else 
1851       {
1852         if ( dim == mSelectionMaxImageDimension )
1853           {
1854             std::cout << "Cannot add this image to selection : would result in a "<<dim+1<<"D image !" << std::endl;
1855             return false;
1856           }
1857         if ( ( cols != mCurrentSelectionImageSize[0] ) ||
1858              ( rows != mCurrentSelectionImageSize[1] ) ||
1859              ( frms != mCurrentSelectionImageSize[2] ) )
1860           {
1861             std::cout << "Cannot add this image to selection : image size is incomptatible with currently selected images" << std::endl; 
1862             return false;
1863           }
1864       }
1865     //    std::cout << "Selecting : "<<node->ImageGetFullFileName() << std::endl;
1866     return true;
1867   }
1868   //================================================================
1869
1870   //================================================================
1871   void WxGimmick::OnSelChanging(wxTreeEvent& event)                   
1872   {
1873     event.Veto();
1874     wxTreeItemId id = event.GetItem();
1875     if (!id.IsOk()) 
1876       {
1877         std::cout << "INTERNAL ERROR : ID NOT OK"<<std::endl;
1878         return;
1879       }
1880
1881
1882     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
1883     if (data->IsDicomNode())
1884       {
1885         if (data->GetDicomNode()>0)
1886           {
1887             // An image was selected 
1888             if (data->GetDicomNode()->GetType()==DicomNode::Image)
1889               {
1890                 if (IsImageSelectable(data->GetDicomNode())) event.Allow();
1891               }
1892             // A series was selected 
1893             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
1894               {
1895                 // If images not loaded do it 
1896                 LoadChildren(id);
1897                 // can be selected if all its images can
1898                 wxTreeItemId child;
1899                 wxTreeItemIdValue cookie;
1900                 for (child = mTreeListCtrl->GetFirstChild(id,cookie);
1901                      child.IsOk();
1902                      child = mTreeListCtrl->GetNextChild(id,cookie))
1903                   {    
1904                     TreeItemData *cdata = 
1905                       (TreeItemData *)mTreeListCtrl->GetItemData(child);
1906                     if ((cdata->IsDicomNode())&&
1907                         (cdata->GetDicomNode()>0)&&
1908                         (cdata->GetDicomNode()->GetType()==DicomNode::Image)&&
1909                         (!IsImageSelectable(cdata->GetDicomNode())))
1910                       return;
1911                   }
1912                 event.Allow();
1913               }
1914           }
1915       }
1916   }
1917   //================================================================
1918
1919   //================================================================
1920   void WxGimmick::OnSelChanged(wxTreeEvent& event)                   
1921   {
1922     //    wxBusyCursor busy;
1923     //    std::vector<wxTreeItemId> items;
1924     //    GetSelectedItems(items);
1925     /*
1926       std::vector<DicomNode*>::iterator i;
1927       for (i=nodes.begin();i!=nodes.end();++i)
1928       {
1929       std::cout << "'" << (*i)->GetFieldValue("FullFileName") 
1930       << "'" << std::endl;
1931       }
1932       std::cout << "++++++++++++++++++++" << std::endl;
1933     */
1934     //    ShowImage(mReader.GetImage(""));
1935
1936      bool no_image = true;
1937
1938     static int max = 1000;
1939
1940     
1941     //    if (items.size()>0) 
1942     //      {
1943
1944         // Update image preview : send requests to the MTImageReader
1945     //  bool first = true;
1946     //  std::vector<wxTreeItemId>::iterator i;
1947     //  for (i=items.begin();i!=items.end();++i)
1948     //    {
1949
1950             /*
1951             if (first)
1952               {
1953                 DicomNode* node = GetDicomNodeOfItem(items[0]);
1954                 if (!node) return;
1955                 // Update dicom fields panel
1956                 mFieldsView->UpdateValues(node);
1957               }
1958             */
1959
1960     wxTreeItemId item =  mTreeListCtrl->GetCurrent();
1961     
1962     DicomNode* n = GetDicomNodeOfItem(item);
1963
1964     if (n) mFieldsView->UpdateValues(n);    
1965
1966     if ( (n!=0) &&
1967          (n->GetType()==DicomNode::Image) )
1968       {
1969
1970         //                
1971         no_image = false;
1972         //if (i==items.begin()) 
1973         mCurImageItemToShow = item;
1974         
1975         int maxprio = mReader.GetMaximalPriority();
1976         int prio = maxprio + 1000;
1977         wxTreeItemId sib = item; //GetTreeListCtrl()->GetNextSibling(*i);
1978         while (sib.IsOk())
1979           {
1980             DicomNode* nsib = GetDicomNodeOfItem(sib);
1981             if (nsib>0) 
1982               {
1983                 //                      std::cout << "-- Request '"
1984                 //                                << nsib->GetFieldValue("FullFileName")
1985                 //                                << "' prio="<<prio<<std::endl;
1986                 mReader.Request(this,
1987                                 nsib->ImageGetFullFileName(), 
1988                                 prio);
1989                 mImageFileNameToNode[nsib->ImageGetFullFileName()] =
1990                   nsib;
1991                 prio--;
1992               }
1993             sib = GetTreeListCtrl()->GetNextSibling(sib);
1994           }
1995         prio = maxprio + 1000;
1996         sib = GetTreeListCtrl()->GetPrevSibling(item);
1997         while (sib.IsOk())
1998           {
1999             DicomNode* nsib = GetDicomNodeOfItem(sib);
2000             if (nsib>0) 
2001               {
2002                 //                      std::cout << "-- Request '"
2003                 //                                << nsib->GetFieldValue("FullFileName")
2004                 //                                << "' prio="<<prio<<std::endl;
2005                 mReader.Request(this,
2006                                 nsib->ImageGetFullFileName(), 
2007                                 prio);
2008                 mImageFileNameToNode[nsib->ImageGetFullFileName()] =
2009                   nsib;
2010                 prio--;
2011               }
2012             sib = GetTreeListCtrl()->GetPrevSibling(sib);
2013           }
2014         //              mImageFileNameToNode[n->GetFieldValue("FullFileName")] = n;
2015         max += 1000;
2016         
2017         ProcessImageEvents();
2018       }
2019     //  std::cout << "* Selection changed * (im)"<<std::endl;
2020
2021     //---------------------------------------------------------------------
2022     // Send event
2023     WxGimmickEvent ev(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGED,
2024                                     this,
2025                                     event.GetItem());
2026     
2027     GetEventHandler()->ProcessEvent(ev);
2028
2029     if (no_image) ShowImage(mReader.GetImage(""));
2030     
2031   }
2032   //================================================================
2033
2034   //================================================================
2035   void WxGimmick::ShowImage(vtkImageData* im)
2036   {
2037     //  wxBusyCursor busy;
2038     
2039     int x1,x2,y1,y2,z1,z2;
2040     double spx,spy,spz;
2041     im->GetSpacing(spx,spy,spz);
2042     im->GetExtent (x1,x2,y1,y2,z1,z2);
2043     
2044     /*
2045       std::cout << x1 << "-"<<x2<<std::endl; 
2046       std::cout << y1 << "-"<<y2<<std::endl; 
2047       std::cout << z1 << "-"<<z2<<std::endl; 
2048       std::cout << spx << "-"<<spy<<"-"<<spz<<std::endl; 
2049     */
2050     
2051     if ((x1!=mx1) ||
2052         (x2!=mx2) ||
2053         (y1!=my1) ||
2054         (y2!=my2) ||
2055         (z1!=mz1) ||
2056         (z2!=mz2) ||
2057         (spx!=mspx) ||
2058         (spy!=mspy) ||
2059         (spz!=mspz) 
2060         )
2061       {
2062         mx1 = x1;
2063         mx2 = x2;
2064         my1 = y1;
2065         my2 = y2;
2066         mz1 = z1;
2067         mz2 = z2;
2068         mspx = spx;
2069         mspy = spy;
2070         mspz = spz;
2071         
2072         vtkCamera *camera = mViewer->GetRenderer()->GetActiveCamera();
2073         
2074         camera->SetViewUp ( spx*0, -spy*1, spz*0);
2075         camera->SetPosition( spx*(x1+x2)/2, spy*(y1+y2)/2, spz*10000000); 
2076         camera->SetFocalPoint   ( spx*(x1+x2)/2 , spy*(y1+y2)/2 , spz*0); 
2077         
2078         camera->ComputeViewPlaneNormal();
2079         camera->SetParallelScale(  spx*(x2-x1)/2.0 );
2080         
2081         camera->Roll ( 180 );
2082       }
2083     
2084     mViewer->SetInput( im );
2085     mViewer->SetSlice( 0 );
2086     mInteractor->Render();
2087   } 
2088   //================================================================
2089   
2090
2091
2092
2093
2094
2095   //================================================================
2096   void WxGimmick::
2097   OnMultiThreadImageReaderEvent(const std::string& filename,
2098                                 MultiThreadImageReaderUser::EventType e,
2099                                 vtkImageData* image)
2100   {
2101     if (filename.size()==0)
2102       {
2103         mImageEventQueue.push_back(ImageEventType(image));
2104         return;
2105       }
2106     std::map<std::string,DicomNode*>::iterator i;
2107     i = mImageFileNameToNode.find(filename);
2108     if (i!=mImageFileNameToNode.end())
2109       {
2110         wxTreeItemId id = i->second->GetData<NodeData*>()->GetTreeItemData()->GetItemId();
2111         mImageEventQueue.push_back(ImageEventType(id,image));
2112       }
2113   }
2114   //================================================================
2115
2116   //================================================================
2117   // Processes the queue of image events 
2118   void WxGimmick::ProcessImageEvents()
2119   {
2120     //    std::cout << "++++++++++ ProcessImageEvents " << std::endl;
2121     MultiThreadImageReaderEventLock();
2122
2123
2124     while (!mImageEventQueue.empty())
2125       {
2126         ImageEventType e = mImageEventQueue.front();
2127         mImageEventQueue.pop_front();
2128         if( e.image!=0 ) 
2129           {
2130             if (e.item.IsOk()) 
2131               {
2132                 mTreeListCtrl->SetItemTextColour(e.item,
2133                                                  mSettings.LoadedImageColour());//wxImageLoadedColour);
2134                 TreeItemData *data = 
2135                   (TreeItemData *)mTreeListCtrl->GetItemData(e.item);
2136                 data->SetLoaded(true);
2137
2138                 if (mCurImageItemToShow == e.item)
2139                   {
2140                     ShowImage(e.image);
2141                   }
2142               }
2143             else if (!mCurImageItemToShow.IsOk())
2144               {
2145                 ShowImage(e.image);
2146               }
2147           }
2148         else if (e.item.IsOk())
2149           {
2150             mTreeListCtrl->SetItemTextColour(e.item,mSettings.Colour(DicomNode::Image)); //.wxImageUnloadedColour);
2151             TreeItemData *data = 
2152               (TreeItemData *)mTreeListCtrl->GetItemData(e.item);
2153             data->SetLoaded(false);
2154           }
2155       }
2156     mImageEventQueue.clear();
2157     MultiThreadImageReaderEventUnlock();
2158     //    std::cout << "++++++++++ END ProcessImageEvents " << std::endl;
2159   }
2160   //================================================================
2161
2162   //================================================================
2163   void  WxGimmick::OnInternalIdle()
2164   {
2165     ProcessImageEvents();
2166     /*
2167     if (mJustStarted)
2168       {
2169
2170         mJustStarted = false;
2171         }
2172     */
2173     //
2174   }
2175   //================================================================
2176  
2177
2178   //================================================================
2179   // LG : For the moment any selection is valid but in the future 
2180   // incomplete selections can be invalid...
2181   bool WxGimmick::IsSelectionValid() 
2182   { 
2183     return (mTreeListCtrl->GetSelectionSize()>0); 
2184   } 
2185   //================================================================
2186
2187   //================================================================
2188   void WxGimmick::GetSelectedFiles(std::vector<std::string>& f)
2189   {
2190     wxArrayTreeItemIds id;
2191     // TO DO : TEST THAT STYLE IS MULTIPLE 
2192     unsigned int nb = mTreeListCtrl->GetSelections(id);
2193     f.clear();
2194     for (unsigned int i=0; i<nb; ++i)
2195       {
2196         TreeItemData *data = 
2197           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2198         if ((data) && (data->IsDicomNode()))
2199           {
2200             if (data->GetDicomNode()->GetType()==DicomNode::Image)
2201               {
2202                 f.push_back ( data->GetDicomNode()->ImageGetFullFileName() );
2203               }
2204             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2205               {
2206                 DicomNode::ChildrenListType::iterator j;
2207                 for (j =data->GetDicomNode()->GetChildrenList().begin();
2208                      j!=data->GetDicomNode()->GetChildrenList().end();
2209                      j++) 
2210                   {
2211                     f.push_back((*j)->ImageGetFullFileName());
2212                   }
2213               }
2214           }
2215       }
2216   }
2217   //================================================================
2218
2219   //================================================================
2220   void WxGimmick::GetSelectedImages(std::vector<vtkImageData*>& f)
2221   {
2222     wxArrayTreeItemIds id;
2223     // TO DO : TEST THAT STYLE IS MULTIPLE 
2224     unsigned int nb = mTreeListCtrl->GetSelections(id);
2225     f.clear();
2226
2227     // Collect the brute vector of Image nodes
2228     std::vector<DicomNode*> im;
2229     for (unsigned int i=0; i<nb; ++i)
2230       {
2231         TreeItemData *data = 
2232           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2233         if ((data) && (data->IsDicomNode()))
2234           {
2235             if (data->GetDicomNode()->GetType()==DicomNode::Image)
2236               {
2237                 im.push_back ( data->GetDicomNode() );
2238
2239               }
2240             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2241               {
2242                 DicomNode::ChildrenListType::iterator j;
2243                 for (j =data->GetDicomNode()->GetChildrenList().begin();
2244                      j!=data->GetDicomNode()->GetChildrenList().end();
2245                      j++) 
2246                   {
2247                     im.push_back ( *j );
2248                   }
2249               }
2250           }
2251       }
2252     // Create the output data
2253     if (im.size()==1) 
2254       {
2255         // Only one image : give it
2256         vtkImageData* out = vtkImageData::New();
2257         out->ShallowCopy(mReader.GetImage(im.front()->ImageGetFullFileName()));
2258         f.push_back( out );
2259       }
2260     else if (im.size()>1)
2261       {
2262         vtkImageData* first = mReader.GetImage( im.front()->ImageGetFullFileName() );
2263         if (first->GetDataDimension()==2) 
2264           {     
2265             // n2D to 3D
2266             vtkImageData* out = vtkImageData::New();
2267             out->CopyStructure(first);  
2268             out->SetScalarType(first->GetScalarType());
2269             int ext[6];
2270             first->GetExtent(ext);
2271             ext[5] = im.size();
2272             out->SetExtent(ext);
2273             // LG : TODO : Z Spacing  ?
2274             
2275             out->AllocateScalars();
2276             
2277             //first->Print(std::cout);
2278             //      out->Print(std::cout);
2279             
2280             int dim[3];
2281             first->GetDimensions(dim);
2282             unsigned long imsize = 
2283               ( (unsigned long)first->GetScalarPointer(0,1,0)
2284                 - (unsigned long)first->GetScalarPointer(0,0,0))
2285               *dim[1];
2286
2287             int slice = 0;
2288             std::vector<DicomNode*>::iterator it;
2289             for (it=im.begin(); it!=im.end(); ++it) 
2290               {
2291                 //std::cout << "copying slice "<<slice <<std::endl;
2292                 vtkImageData* cur = mReader.GetImage( (*it)->ImageGetFullFileName() );
2293                 
2294                 void* src = cur->GetScalarPointer(0,0,0);
2295                 void* dst = out->GetScalarPointer(0,0,slice);
2296                 //              std::cout << "src="<<src<<std::endl;
2297                 //              std::cout << "dst="<<dst<<std::endl;
2298                 //              std::cout << "siz="<<imsize<<std::endl;
2299                 memcpy(dst,src,imsize);
2300
2301                 /*
2302                 // verif
2303                 int ii,jj;
2304                 for (ii=1;ii<4;ii++) {
2305                   for (jj=1;jj<4;jj++) {
2306                     int x = (int)(ii*dim[0] / 4);
2307                     int y = (int)(jj*dim[1] / 4);
2308                     std::cout << cur->GetScalarComponentAsFloat(x,y,0,0)
2309                               << " vs "
2310                               << out->GetScalarComponentAsFloat(x,y,slice,0)
2311                               << std::endl;
2312                   }
2313                 }
2314                 */
2315
2316                 slice++;
2317               }
2318             f.push_back(out);
2319           }
2320         else 
2321           {
2322             // n3D
2323             std::vector<DicomNode*>::iterator it;
2324             for (it=im.begin(); it!=im.end(); ++it) 
2325               {
2326                 vtkImageData* out = vtkImageData::New();
2327                 out->ShallowCopy(mReader.GetImage((*it)->ImageGetFullFileName()));
2328                 f.push_back(out);
2329               }
2330           }
2331       }
2332   }
2333   //================================================================
2334
2335
2336   //================================================================
2337   void WxGimmick::GetSelectedDicomNodes(std::vector<DicomNode*>& f)
2338   {
2339     wxArrayTreeItemIds id;
2340     // TO DO : TEST THAT STYLE IS MULTIPLE 
2341     unsigned int nb = mTreeListCtrl->GetSelections(id);
2342     f.clear();
2343     for (unsigned int i=0; i<nb; ++i)
2344       {
2345         TreeItemData *data = 
2346           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2347         if ((data) && (data->IsDicomNode()))
2348           {
2349             f.push_back ( data->GetDicomNode() );
2350           }
2351         /*
2352
2353         if (data->GetDicomNode()->GetType()==DicomNode::Image)
2354         {
2355         f.push_back ( data->GetDicomNode() ); //->ImageGetFullFileName() );
2356         }  
2357         else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2358         {
2359         DicomNode::ChildrenListType::iterator j;
2360         for (j =data->GetDicomNode()->GetChildrenList().begin();
2361         j!=data->GetDicomNode()->GetChildrenList().end();
2362         j++) 
2363         {
2364         f.push_back((*j)); //->ImageGetFullFileName() );        }
2365         }
2366         }
2367         */
2368       }
2369   }
2370   //================================================================
2371
2372   //================================================================
2373   void WxGimmick::GetSelectedItems(std::vector<wxTreeItemId>& f)
2374   {
2375     wxArrayTreeItemIds id;
2376     // TO DO : TEST THAT STYLE IS MULTIPLE 
2377     unsigned int nb = mTreeListCtrl->GetSelections(id);
2378     f.clear();
2379     for (unsigned int i=0; i<nb; ++i)
2380       {
2381         f.push_back(id[i]);
2382       }
2383   }
2384   //================================================================
2385
2386   //================================================================
2387   DicomNode* WxGimmick::GetDicomNodeOfItem(const wxTreeItemId& i)
2388   {
2389     TreeItemData *data = 
2390       (TreeItemData *)mTreeListCtrl->GetItemData(i);
2391     if (data) return ( data->GetDicomNode() );
2392     return 0;
2393   }
2394   //================================================================
2395
2396   //================================================================
2397   //================================================================
2398   //================================================================
2399   //================================================================
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415   //================================================================
2416   //================================================================
2417   //================================================================
2418   //================================================================
2419   
2420   BEGIN_EVENT_TABLE(WxGimmick, wxPanel)
2421   // POP UP MENU
2422     EVT_MENU(PopUp_NewCollection,WxGimmick::OnPopUpNewCollection)
2423     EVT_MENU(PopUp_OpenCollection,WxGimmick::OnPopUpOpenCollection)
2424     EVT_MENU(PopUp_CloseCollection,WxGimmick::OnPopUpCloseCollection)
2425     EVT_MENU(PopUp_DeleteCollection,WxGimmick::OnPopUpDeleteCollection)
2426     EVT_MENU(PopUp_AddFile, WxGimmick::OnPopUpAddFile)
2427     EVT_MENU(PopUp_AddRawFile, WxGimmick::OnPopUpAddRawFile)
2428     EVT_MENU(PopUp_AddDirectory, WxGimmick::OnPopUpAddDirectory)
2429     EVT_MENU(PopUp_Remove, WxGimmick::OnPopUpRemove)
2430     EVT_MENU(PopUp_About, WxGimmick::OnPopUpAbout)
2431     EVT_MENU(PopUp_Settings, WxGimmick::OnPopUpSettings)
2432     
2433     EVT_MENU_RANGE(PopUp_Sort, PopUp_Sort+99,  WxGimmick::OnPopUpSort)
2434     EVT_MENU_RANGE(PopUp_User, PopUp_User+99,  WxGimmick::OnPopUpUser)
2435     
2436     
2437     
2438   // DRAG
2439     EVT_TREE_BEGIN_DRAG(TreeListCtrlId, WxGimmick::OnBeginDrag)
2440     EVT_TREE_BEGIN_RDRAG(TreeListCtrlId, WxGimmick::OnBeginRDrag)
2441     EVT_TREE_END_DRAG(TreeListCtrlId, WxGimmick::OnEndDrag)
2442
2443   // LABEL
2444     EVT_TREE_BEGIN_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnBeginLabelEdit)
2445     EVT_TREE_END_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnEndLabelEdit)
2446
2447   //DELETE : UNUSED
2448     EVT_TREE_DELETE_ITEM(TreeListCtrlId, WxGimmick::OnDeleteItem)
2449 #if 0       // there are so many of those that logging them causes flicker
2450     EVT_TREE_GET_INFO(TreeListCtrlId, WxGimmick::OnGetInfo)
2451 #endif
2452   // UNUSED
2453     EVT_TREE_SET_INFO(TreeListCtrlId, WxGimmick::OnSetInfo)
2454
2455   // EXPAND/COLLAPSE
2456     EVT_TREE_ITEM_EXPANDED(TreeListCtrlId, WxGimmick::OnItemExpanded)
2457     EVT_TREE_ITEM_EXPANDING(TreeListCtrlId, WxGimmick::OnItemExpanding)
2458     EVT_TREE_ITEM_COLLAPSED(TreeListCtrlId, WxGimmick::OnItemCollapsed)
2459     EVT_TREE_ITEM_COLLAPSING(TreeListCtrlId, WxGimmick::OnItemCollapsing)
2460
2461   // SELECTION
2462     EVT_TREE_SEL_CHANGED(TreeListCtrlId, WxGimmick::OnSelChanged)
2463     EVT_TREE_SEL_CHANGING(TreeListCtrlId, WxGimmick::OnSelChanging)
2464   // KEY
2465     EVT_TREE_KEY_DOWN(TreeListCtrlId, WxGimmick::OnTreeKeyDown)
2466   // ACTIVATION = DOUBLE CLICK OR ENTER ON SELECTED
2467     EVT_TREE_ITEM_ACTIVATED(TreeListCtrlId, WxGimmick::OnItemActivated)
2468
2469   // so many differents ways to handle right mouse button clicks...
2470   //    EVT_CONTEXT_MENU(WxGimmick::OnContextMenu)
2471   // EVT_TREE_ITEM_MENU is the preferred event for creating context menus
2472   // on a tree control, because it includes the point of the click or item,
2473   // meaning that no additional placement calculations are required.
2474   //    EVT_TREE_ITEM_MENU(TreeListCtrlId, WxGimmick::OnItemMenu)
2475     
2476     EVT_TREE_ITEM_RIGHT_CLICK(TreeListCtrlId, WxGimmick::OnItemRightClick)
2477
2478   // UNUSED
2479   //    EVT_RIGHT_DOWN(WxGimmick::OnRMouseDown)
2480   //    EVT_RIGHT_UP(WxGimmick::OnRMouseUp)
2481   //    EVT_RIGHT_DCLICK(WxGimmick::OnRMouseDClick)
2482     END_EVENT_TABLE()
2483
2484   //IMPLEMENT_DYNAMIC_CLASS(WxGimmick, wxTreeListCtrl)
2485
2486   /*
2487     wxTree::wxTree(wxWindow *parent, const wxWindowID id,
2488     const wxPoint& pos, const wxSize& size,
2489     long style)
2490     : wxTreeListCtrl(parent, id, pos, size, style)
2491     {
2492     m_reverseSort = false;
2493
2494     CreateImageList();
2495
2496     // Add some items to the tree
2497     AddTestItemsToTree(5, 2);
2498     }
2499   */
2500
2501
2502
2503 #if USE_GENERIC_TREECTRL || !defined(__WXMSW__)
2504     void WxGimmick::CreateButtonsImageList(int size)
2505   {
2506     /*
2507       if ( size == -1 )
2508       {
2509       mTreeListCtrl->SetButtonsImageList(NULL);
2510       return;
2511       }
2512
2513       // Make an image list containing small icons
2514       wxImageList *images = new wxImageList(size, size, true);
2515
2516       // should correspond to TreeListCtrlIcon_xxx enum
2517       wxBusyCursor wait;
2518       wxIcon icons[4];
2519       icons[0] = wxIcon(icon3_xpm);   // closed
2520       icons[1] = wxIcon(icon3_xpm);   // closed, selected
2521       icons[2] = wxIcon(icon5_xpm);   // open
2522       icons[3] = wxIcon(icon5_xpm);   // open, selected
2523
2524       for ( size_t i = 0; i < WXSIZEOF(icons); i++ )
2525       {
2526       int sizeOrig = icons[i].GetWidth();
2527       if ( size == sizeOrig )
2528       {
2529       images->Add(icons[i]);
2530       }
2531       else
2532       {
2533       images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
2534       }
2535       }
2536
2537       mTreeListCtrl->AssignButtonsImageList(images);
2538     */
2539 #else
2540     void WxGimmick::CreateButtonsImageList(int WXUNUSED(size))
2541     {
2542 #endif
2543     }
2544
2545     /*
2546       int WxGimmick::OnCompareItems(const wxTreeItemId& item1,
2547       const wxTreeItemId& item2)
2548       {
2549       if ( m_reverseSort )
2550       {
2551       // just exchange 1st and 2nd items
2552       return mTreeListCtrl->OnCompareItems(item2, item1);
2553       }
2554       else
2555       {
2556       return mTreeListCtrl->OnCompareItems(item1, item2);
2557       }
2558       }
2559
2560
2561       void WxGimmick::DoToggleIcon(const wxTreeItemId& item)
2562       {
2563   
2564       int image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_Folder)
2565       ? TreeIcon_File
2566       : TreeIcon_Folder;
2567       mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Normal);
2568
2569       image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_FolderSelected)
2570       ? TreeIcon_FileSelected
2571       : TreeIcon_FolderSelected;
2572       mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Selected);
2573       }
2574
2575       void WxGimmick::LogEvent(const wxChar *name, const wxTreeEvent& event)
2576       {
2577       wxTreeItemId item = event.GetItem();
2578       wxString text;
2579       if ( item.IsOk() )
2580       text << _T('"') << mTreeListCtrl->GetItemText(item).c_str() << _T('"');
2581       else
2582       text = _T("invalid item");
2583       //    wxLogMessage(wxT("%s(%s)"), name, text.c_str());
2584       }
2585
2586     */
2587     // avoid repetition
2588 #define TREE_EVENT_HANDLER(name)                                \
2589     void WxGimmick::name(wxTreeEvent& event)    \
2590     {                                                           \
2591       /*    LogEvent(_T(#name), event); */                      \
2592       /*    SetLastItem(mTreeListCtrl->wxTreeItemId()) *;*/     \
2593       event.Skip();                                             \
2594     }
2595
2596     TREE_EVENT_HANDLER(OnBeginRDrag)
2597       TREE_EVENT_HANDLER(OnDeleteItem)
2598       TREE_EVENT_HANDLER(OnGetInfo)
2599       TREE_EVENT_HANDLER(OnSetInfo)
2600       //TREE_EVENT_HANDLER(OnItemExpanded)
2601       TREE_EVENT_HANDLER(OnItemExpanding)
2602       //TREE_EVENT_HANDLER(OnItemCollapsed)
2603       //TREE_EVENT_HANDLER(OnSelChanged)
2604       //      TREE_EVENT_HANDLER(OnSelChanging)
2605
2606
2607       void WxGimmick::OnItemCollapsed(wxTreeEvent& event)                   
2608       {
2609         //    std::cout << "* Collapsed *"<<std::endl;
2610       }
2611
2612 #undef TREE_EVENT_HANDLER
2613
2614     void WxGimmick::OnTreeKeyDown(wxTreeEvent& event)
2615     {
2616       /*
2617       //  LogKeyEvent(wxT("Tree key down "), event.GetKeyEvent());
2618       std::cout << "* Key down *"<<std::endl;
2619       if (event.GetKeyCode()==WXK_RIGHT)
2620         {
2621           std::cout << "Right"<<std::endl;
2622           wxTreeItemId itemId =  mTreeListCtrl->GetSelection();
2623           if (itemId.IsOk())
2624             {
2625               std::cout << "item is ok"<<std::endl;
2626               wxPoint clientpt = event.GetPoint();
2627               wxPoint screenpt = ClientToScreen(clientpt);
2628               ShowMenu(itemId, clientpt);
2629             }     
2630           event.Veto();
2631           return;
2632         }
2633       std::cout << "NOT Right"<<std::endl;
2634       */
2635       event.Skip();       
2636     }
2637
2638     void WxGimmick::OnBeginDrag(wxTreeEvent& event)
2639     {
2640       wxTreeItemId id = event.GetItem();
2641       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2642       //    std::cout << "OnBeginDrag("<<id<<")"<<std::endl;
2643       if (data->IsDatabase())
2644         {
2645           //      std::cout << "-- IS ROOT"<<std::endl;
2646           //  event.Allow();
2647         }
2648       else if (data->IsDicomNode())
2649         {
2650           //      std::cout << "-- IS NODE"<<std::endl;
2651         }
2652       /*
2653       // need to explicitly allow drag
2654       if ( event.GetItem() != GetDatabaseItem() )
2655       {
2656       m_draggedItem = event.GetItem();
2657
2658       wxPoint clientpt = event.GetPoint();
2659       wxPoint screenpt = ClientToScreen(clientpt);
2660
2661       wxLogMessage(wxT("OnBeginDrag: started dragging %s at screen coords (%i,%i)"),
2662       GetItemText(m_draggedItem).c_str(),
2663       screenpt.x, screenpt.y);
2664
2665       event.Allow();
2666       }
2667       else
2668       {
2669       wxLogMessage(wxT("OnBeginDrag: this item can't be dragged."));
2670       }
2671       */
2672     }
2673
2674     void WxGimmick::OnEndDrag(wxTreeEvent& event)
2675     {
2676       wxTreeItemId id = event.GetItem();
2677       //      std::cout << "OnEndDrag("<<id<<")"<<std::endl;
2678       if (!id.IsOk()) return;
2679       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2680       if (data->IsDatabase())
2681         {
2682           //      std::cout << "-- IS ROOT"<<std::endl;
2683         }
2684       else if (data->IsDicomNode())
2685         {
2686           //      std::cout << "-- IS NODE"<<std::endl;
2687         }
2688
2689       /*
2690         wxTreeItemId itemSrc = m_draggedItem,
2691         itemDst = event.GetItem();
2692         m_draggedItem = (wxTreeItemId)0l;
2693
2694         // where to copy the item?
2695         if ( itemDst.IsOk() && !ItemHasChildren(itemDst) )
2696         {
2697         // copy to the parent then
2698         itemDst = GetItemParent(itemDst);
2699         }
2700
2701         if ( !itemDst.IsOk() )
2702         {
2703         wxLogMessage(wxT("OnEndDrag: can't drop here."));
2704
2705         return;
2706         }
2707
2708         wxString text = GetItemText(itemSrc);
2709         wxLogMessage(wxT("OnEndDrag: '%s' copied to '%s'."),
2710         text.c_str(), GetItemText(itemDst).c_str());
2711
2712         // just do append here - we could also insert it just before/after the item
2713         // on which it was dropped, but this requires slightly more work... we also
2714         // completely ignore the client data and icon of the old item but could
2715         // copy them as well.
2716         //
2717         // Finally, we only copy one item here but we might copy the entire tree if
2718         // we were dragging a folder.
2719         int image = wxGetApp().ShowImages() ? TreeIcon_File : -1;
2720         AppendItem(itemDst, text, image);
2721       */
2722     }
2723
2724
2725     //====================================================================
2726     void WxGimmick::OnBeginLabelEdit(wxTreeEvent& event)
2727     {
2728       //      std::cout << "OnBeginLabelEdit"<<std::endl;
2729       wxTreeItemId id = event.GetItem();
2730       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2731       // If not a root : veto
2732       if (data->IsDatabase()) 
2733         { 
2734           event.Allow();
2735           return;
2736         }
2737       event.Veto();
2738     }
2739     //====================================================================
2740
2741     //====================================================================
2742     void WxGimmick::OnEndLabelEdit(wxTreeEvent& event)
2743     {
2744       //      std::cout << "OnEndLabelEdit"<<std::endl;
2745       wxTreeItemId id = event.GetItem();
2746       TreeItemData *data = GetItemData(id);
2747       // If not a database : bug !
2748       if (data->IsDatabase()) 
2749         { 
2750           data->GetDicomNode()->GetDicomDatabase()->SetName(wx2std(event.GetLabel()));
2751           mFieldsView->UpdateValues(data->GetDicomNode());
2752         }
2753       else
2754         {
2755           std::cerr<< "!!!! Internal error : send bug report !!!!"<<std::endl;
2756         }
2757     }
2758     //====================================================================
2759
2760
2761     void WxGimmick::OnItemCollapsing(wxTreeEvent& event)
2762     {
2763       //    wxLogMessage(wxT("OnItemCollapsing"));
2764
2765       // for testing, prevent the user from collapsing the first child folder
2766       wxTreeItemId itemId = event.GetItem();
2767
2768       /*
2769         if ( IsTestItem(itemId) )
2770         {
2771         wxMessageBox(wxT("You can't collapse this item."));
2772
2773         event.Veto();
2774         }
2775       */
2776     }
2777
2778
2779     //====================================================================
2780     void WxGimmick::ShowHelp()
2781     {
2782       /*
2783       if (mHelpWindow==0)
2784         {
2785           mHelpWindow = new WxGimmickHelpWindow(this);
2786         }
2787       mHelpWindow->CenterOnParent();
2788       mHelpWindow->ShowModal();
2789       */
2790     }
2791     //====================================================================
2792
2793
2794
2795
2796
2797     //================================================================
2798     //================================================================
2799     //================================================================
2800     //================================================================
2801     //================================================================
2802     // WxGimmickEvent
2803     //================================================================
2804     //================================================================
2805     //================================================================
2806     //================================================================
2807     //================================================================
2808
2809
2810
2811
2812
2813     // ----------------------------------------------------------------------------
2814     // events
2815     // ----------------------------------------------------------------------------
2816     /*
2817       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG)
2818       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG)
2819       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM)
2820       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO)
2821       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO)
2822       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED)
2823       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING)
2824       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
2825       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING)
2826     */
2827
2828     DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT)
2829       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT)
2830
2831
2832       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGED)
2833       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGING)
2834       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_KEY_DOWN)
2835       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_CONTEXTUAL_MENU)
2836       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_ITEM_STYLE_CHANGED)
2837       /*
2838         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED)
2839         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK)
2840         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK)
2841         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG)
2842         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK)
2843         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP)
2844         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU)
2845       */
2846       // ----------------------------------------------------------------------------
2847       // Tree event
2848       // ----------------------------------------------------------------------------
2849
2850       IMPLEMENT_ABSTRACT_CLASS(WxGimmickEvent, wxNotifyEvent)
2851   
2852   
2853       WxGimmickEvent::WxGimmickEvent(wxEventType commandType,
2854                                                                  WxGimmick *tree,
2855                                                                  const wxTreeItemId& item)
2856       : 
2857       wxNotifyEvent(commandType, tree->GetId()),
2858       m_item(item),
2859       mDicomNode(0)
2860         {
2861           //      m_editCancelled = false;
2862       
2863           SetEventObject(tree);
2864       
2865           if ( item.IsOk() )
2866             SetClientObject(tree->mTreeListCtrl->GetItemData(item));
2867         }
2868   
2869       WxGimmickEvent::WxGimmickEvent(wxEventType commandType, int id)
2870         : 
2871         wxNotifyEvent(commandType, id),
2872         mDicomNode(0)
2873           {
2874             m_itemOld = 0l;
2875             //      m_editCancelled = false;
2876           }
2877     
2878         WxGimmickEvent::WxGimmickEvent(const WxGimmickEvent & event)
2879           : 
2880           wxNotifyEvent(event),
2881           mDicomNode(0)
2882
2883             {
2884               m_evtKey = event.m_evtKey;
2885               m_item = event.m_item;
2886               m_itemOld = event.m_itemOld;
2887               mColor = event.mColor;
2888               mUserData = event.mUserData;
2889               //    m_pointDrag = event.m_pointDrag;
2890               //    m_label = event.m_label;
2891               //    m_editCancelled = event.m_editCancelled;
2892             }
2893       
2894       
2895
2896
2897
2898
2899
2900
2901           //================================================================
2902           //================================================================
2903           //================================================================
2904           //================================================================
2905           //================================================================
2906           WxGimmickFrame::WxGimmickFrame( wxWindow *parent, 
2907                                           wxString title, 
2908                                           wxSize size)
2909             : wxFrame((wxFrame *)parent, -1, title, wxDefaultPosition, size)
2910             {   
2911               wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
2912               mWxGimmick = new WxGimmick(this,-1,
2913                                          wxDefaultPosition,
2914                                          wxDefaultSize);
2915               sizer->Add(mWxGimmick,1,wxGROW);
2916               SetSizer(sizer);
2917               SetAutoLayout(true);
2918               Layout();
2919             }
2920             //================================================================
2921
2922             //================================================================
2923             WxGimmickFrame::~WxGimmickFrame()
2924               {
2925               }
2926             //================================================================
2927
2928             //================================================================
2929             void WxGimmickFrame::OnSelChanged(WxGimmickEvent& event)
2930             {
2931               //    std::cout << "+++++ WxGimmickFrame::OnSelChanged ++++++++++"
2932               //              <<std::endl;
2933               std::vector<std::string> file;
2934               //    mWxGimmick->GetSelectedImages(file);
2935               /*
2936                 std::vector<std::string>::iterator i;
2937                 for (i=file.begin();i!=file.end();++i)
2938                 {
2939                 std::cout << "'" << *i << "'" << std::endl;
2940                 }
2941                 std::cout << "++++++++++++++++++++" << std::endl;
2942               */
2943             }
2944             //================================================================
2945
2946             //================================================================
2947             BEGIN_EVENT_TABLE(WxGimmickFrame, wxFrame)
2948               EVT_TREEVIEWLIST_SEL_CHANGED(-1,WxGimmickFrame::OnSelChanged)
2949               END_EVENT_TABLE()
2950               //================================================================
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973             
2974
2975
2976
2977   }