]> Creatis software - creaImageIO.git/blob - src/creaImageIOWxGimmick.cpp
*** empty log message ***
[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       }
2082     
2083     mViewer->SetInput( im );
2084     mViewer->SetSlice( 0 );
2085     mInteractor->Render();
2086   } 
2087   //================================================================
2088   
2089
2090
2091
2092
2093
2094   //================================================================
2095   void WxGimmick::
2096   OnMultiThreadImageReaderEvent(const std::string& filename,
2097                                 MultiThreadImageReaderUser::EventType e,
2098                                 vtkImageData* image)
2099   {
2100     if (filename.size()==0)
2101       {
2102         mImageEventQueue.push_back(ImageEventType(image));
2103         return;
2104       }
2105     std::map<std::string,DicomNode*>::iterator i;
2106     i = mImageFileNameToNode.find(filename);
2107     if (i!=mImageFileNameToNode.end())
2108       {
2109         wxTreeItemId id = i->second->GetData<NodeData*>()->GetTreeItemData()->GetItemId();
2110         mImageEventQueue.push_back(ImageEventType(id,image));
2111       }
2112   }
2113   //================================================================
2114
2115   //================================================================
2116   // Processes the queue of image events 
2117   void WxGimmick::ProcessImageEvents()
2118   {
2119     //    std::cout << "++++++++++ ProcessImageEvents " << std::endl;
2120     MultiThreadImageReaderEventLock();
2121
2122
2123     while (!mImageEventQueue.empty())
2124       {
2125         ImageEventType e = mImageEventQueue.front();
2126         mImageEventQueue.pop_front();
2127         if( e.image!=0 ) 
2128           {
2129             if (e.item.IsOk()) 
2130               {
2131                 mTreeListCtrl->SetItemTextColour(e.item,
2132                                                  mSettings.LoadedImageColour());//wxImageLoadedColour);
2133                 TreeItemData *data = 
2134                   (TreeItemData *)mTreeListCtrl->GetItemData(e.item);
2135                 data->SetLoaded(true);
2136
2137                 if (mCurImageItemToShow == e.item)
2138                   {
2139                     ShowImage(e.image);
2140                   }
2141               }
2142             else if (!mCurImageItemToShow.IsOk())
2143               {
2144                 ShowImage(e.image);
2145               }
2146           }
2147         else if (e.item.IsOk())
2148           {
2149             mTreeListCtrl->SetItemTextColour(e.item,mSettings.Colour(DicomNode::Image)); //.wxImageUnloadedColour);
2150             TreeItemData *data = 
2151               (TreeItemData *)mTreeListCtrl->GetItemData(e.item);
2152             data->SetLoaded(false);
2153           }
2154       }
2155     mImageEventQueue.clear();
2156     MultiThreadImageReaderEventUnlock();
2157     //    std::cout << "++++++++++ END ProcessImageEvents " << std::endl;
2158   }
2159   //================================================================
2160
2161   //================================================================
2162   void  WxGimmick::OnInternalIdle()
2163   {
2164     ProcessImageEvents();
2165     /*
2166     if (mJustStarted)
2167       {
2168
2169         mJustStarted = false;
2170         }
2171     */
2172     //
2173   }
2174   //================================================================
2175  
2176
2177   //================================================================
2178   // LG : For the moment any selection is valid but in the future 
2179   // incomplete selections can be invalid...
2180   bool WxGimmick::IsSelectionValid() 
2181   { 
2182     return (mTreeListCtrl->GetSelectionSize()>0); 
2183   } 
2184   //================================================================
2185
2186   //================================================================
2187   void WxGimmick::GetSelectedFiles(std::vector<std::string>& f)
2188   {
2189     wxArrayTreeItemIds id;
2190     // TO DO : TEST THAT STYLE IS MULTIPLE 
2191     unsigned int nb = mTreeListCtrl->GetSelections(id);
2192     f.clear();
2193     for (unsigned int i=0; i<nb; ++i)
2194       {
2195         TreeItemData *data = 
2196           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2197         if ((data) && (data->IsDicomNode()))
2198           {
2199             if (data->GetDicomNode()->GetType()==DicomNode::Image)
2200               {
2201                 f.push_back ( data->GetDicomNode()->ImageGetFullFileName() );
2202               }
2203             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2204               {
2205                 DicomNode::ChildrenListType::iterator j;
2206                 for (j =data->GetDicomNode()->GetChildrenList().begin();
2207                      j!=data->GetDicomNode()->GetChildrenList().end();
2208                      j++) 
2209                   {
2210                     f.push_back((*j)->ImageGetFullFileName());
2211                   }
2212               }
2213           }
2214       }
2215   }
2216   //================================================================
2217
2218   //================================================================
2219   void WxGimmick::GetSelectedImages(std::vector<vtkImageData*>& f)
2220   {
2221     wxArrayTreeItemIds id;
2222     // TO DO : TEST THAT STYLE IS MULTIPLE 
2223     unsigned int nb = mTreeListCtrl->GetSelections(id);
2224     f.clear();
2225
2226     // Collect the brute vector of Image nodes
2227     std::vector<DicomNode*> im;
2228     for (unsigned int i=0; i<nb; ++i)
2229       {
2230         TreeItemData *data = 
2231           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2232         if ((data) && (data->IsDicomNode()))
2233           {
2234             if (data->GetDicomNode()->GetType()==DicomNode::Image)
2235               {
2236                 im.push_back ( data->GetDicomNode() );
2237
2238               }
2239             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2240               {
2241                 DicomNode::ChildrenListType::iterator j;
2242                 for (j =data->GetDicomNode()->GetChildrenList().begin();
2243                      j!=data->GetDicomNode()->GetChildrenList().end();
2244                      j++) 
2245                   {
2246                     im.push_back ( *j );
2247                   }
2248               }
2249           }
2250       }
2251     // Create the output data
2252     if (im.size()==1) 
2253       {
2254         // Only one image : give it
2255         vtkImageData* out = vtkImageData::New();
2256         out->ShallowCopy(mReader.GetImage(im.front()->ImageGetFullFileName()));
2257         f.push_back( out );
2258       }
2259     else if (im.size()>1)
2260       {
2261         vtkImageData* first = mReader.GetImage( im.front()->ImageGetFullFileName() );
2262         if (first->GetDataDimension()==2) 
2263           {     
2264             // n2D to 3D
2265             vtkImageData* out = vtkImageData::New();
2266             out->CopyStructure(first);  
2267             out->SetScalarType(first->GetScalarType());
2268             int ext[6];
2269             first->GetExtent(ext);
2270             ext[5] = im.size();
2271             out->SetExtent(ext);
2272             // LG : TODO : Z Spacing  ?
2273             
2274             out->AllocateScalars();
2275             
2276             //first->Print(std::cout);
2277             //      out->Print(std::cout);
2278             
2279             int dim[3];
2280             first->GetDimensions(dim);
2281             unsigned long imsize = 
2282               ( (unsigned long)first->GetScalarPointer(0,1,0)
2283                 - (unsigned long)first->GetScalarPointer(0,0,0))
2284               *dim[1];
2285
2286             int slice = 0;
2287             std::vector<DicomNode*>::iterator it;
2288             for (it=im.begin(); it!=im.end(); ++it) 
2289               {
2290                 //std::cout << "copying slice "<<slice <<std::endl;
2291                 vtkImageData* cur = mReader.GetImage( (*it)->ImageGetFullFileName() );
2292                 
2293                 void* src = cur->GetScalarPointer(0,0,0);
2294                 void* dst = out->GetScalarPointer(0,0,slice);
2295                 //              std::cout << "src="<<src<<std::endl;
2296                 //              std::cout << "dst="<<dst<<std::endl;
2297                 //              std::cout << "siz="<<imsize<<std::endl;
2298                 memcpy(dst,src,imsize);
2299
2300                 /*
2301                 // verif
2302                 int ii,jj;
2303                 for (ii=1;ii<4;ii++) {
2304                   for (jj=1;jj<4;jj++) {
2305                     int x = (int)(ii*dim[0] / 4);
2306                     int y = (int)(jj*dim[1] / 4);
2307                     std::cout << cur->GetScalarComponentAsFloat(x,y,0,0)
2308                               << " vs "
2309                               << out->GetScalarComponentAsFloat(x,y,slice,0)
2310                               << std::endl;
2311                   }
2312                 }
2313                 */
2314
2315                 slice++;
2316               }
2317             f.push_back(out);
2318           }
2319         else 
2320           {
2321             // n3D
2322             std::vector<DicomNode*>::iterator it;
2323             for (it=im.begin(); it!=im.end(); ++it) 
2324               {
2325                 vtkImageData* out = vtkImageData::New();
2326                 out->ShallowCopy(mReader.GetImage((*it)->ImageGetFullFileName()));
2327                 f.push_back(out);
2328               }
2329           }
2330       }
2331   }
2332   //================================================================
2333
2334
2335   //================================================================
2336   void WxGimmick::GetSelectedDicomNodes(std::vector<DicomNode*>& f)
2337   {
2338     wxArrayTreeItemIds id;
2339     // TO DO : TEST THAT STYLE IS MULTIPLE 
2340     unsigned int nb = mTreeListCtrl->GetSelections(id);
2341     f.clear();
2342     for (unsigned int i=0; i<nb; ++i)
2343       {
2344         TreeItemData *data = 
2345           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2346         if ((data) && (data->IsDicomNode()))
2347           {
2348             f.push_back ( data->GetDicomNode() );
2349           }
2350         /*
2351
2352         if (data->GetDicomNode()->GetType()==DicomNode::Image)
2353         {
2354         f.push_back ( data->GetDicomNode() ); //->ImageGetFullFileName() );
2355         }  
2356         else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2357         {
2358         DicomNode::ChildrenListType::iterator j;
2359         for (j =data->GetDicomNode()->GetChildrenList().begin();
2360         j!=data->GetDicomNode()->GetChildrenList().end();
2361         j++) 
2362         {
2363         f.push_back((*j)); //->ImageGetFullFileName() );        }
2364         }
2365         }
2366         */
2367       }
2368   }
2369   //================================================================
2370
2371   //================================================================
2372   void WxGimmick::GetSelectedItems(std::vector<wxTreeItemId>& f)
2373   {
2374     wxArrayTreeItemIds id;
2375     // TO DO : TEST THAT STYLE IS MULTIPLE 
2376     unsigned int nb = mTreeListCtrl->GetSelections(id);
2377     f.clear();
2378     for (unsigned int i=0; i<nb; ++i)
2379       {
2380         f.push_back(id[i]);
2381       }
2382   }
2383   //================================================================
2384
2385   //================================================================
2386   DicomNode* WxGimmick::GetDicomNodeOfItem(const wxTreeItemId& i)
2387   {
2388     TreeItemData *data = 
2389       (TreeItemData *)mTreeListCtrl->GetItemData(i);
2390     if (data) return ( data->GetDicomNode() );
2391     return 0;
2392   }
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   BEGIN_EVENT_TABLE(WxGimmick, wxPanel)
2420   // POP UP MENU
2421     EVT_MENU(PopUp_NewCollection,WxGimmick::OnPopUpNewCollection)
2422     EVT_MENU(PopUp_OpenCollection,WxGimmick::OnPopUpOpenCollection)
2423     EVT_MENU(PopUp_CloseCollection,WxGimmick::OnPopUpCloseCollection)
2424     EVT_MENU(PopUp_DeleteCollection,WxGimmick::OnPopUpDeleteCollection)
2425     EVT_MENU(PopUp_AddFile, WxGimmick::OnPopUpAddFile)
2426     EVT_MENU(PopUp_AddRawFile, WxGimmick::OnPopUpAddRawFile)
2427     EVT_MENU(PopUp_AddDirectory, WxGimmick::OnPopUpAddDirectory)
2428     EVT_MENU(PopUp_Remove, WxGimmick::OnPopUpRemove)
2429     EVT_MENU(PopUp_About, WxGimmick::OnPopUpAbout)
2430     EVT_MENU(PopUp_Settings, WxGimmick::OnPopUpSettings)
2431     
2432     EVT_MENU_RANGE(PopUp_Sort, PopUp_Sort+99,  WxGimmick::OnPopUpSort)
2433     EVT_MENU_RANGE(PopUp_User, PopUp_User+99,  WxGimmick::OnPopUpUser)
2434     
2435     
2436     
2437   // DRAG
2438     EVT_TREE_BEGIN_DRAG(TreeListCtrlId, WxGimmick::OnBeginDrag)
2439     EVT_TREE_BEGIN_RDRAG(TreeListCtrlId, WxGimmick::OnBeginRDrag)
2440     EVT_TREE_END_DRAG(TreeListCtrlId, WxGimmick::OnEndDrag)
2441
2442   // LABEL
2443     EVT_TREE_BEGIN_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnBeginLabelEdit)
2444     EVT_TREE_END_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnEndLabelEdit)
2445
2446   //DELETE : UNUSED
2447     EVT_TREE_DELETE_ITEM(TreeListCtrlId, WxGimmick::OnDeleteItem)
2448 #if 0       // there are so many of those that logging them causes flicker
2449     EVT_TREE_GET_INFO(TreeListCtrlId, WxGimmick::OnGetInfo)
2450 #endif
2451   // UNUSED
2452     EVT_TREE_SET_INFO(TreeListCtrlId, WxGimmick::OnSetInfo)
2453
2454   // EXPAND/COLLAPSE
2455     EVT_TREE_ITEM_EXPANDED(TreeListCtrlId, WxGimmick::OnItemExpanded)
2456     EVT_TREE_ITEM_EXPANDING(TreeListCtrlId, WxGimmick::OnItemExpanding)
2457     EVT_TREE_ITEM_COLLAPSED(TreeListCtrlId, WxGimmick::OnItemCollapsed)
2458     EVT_TREE_ITEM_COLLAPSING(TreeListCtrlId, WxGimmick::OnItemCollapsing)
2459
2460   // SELECTION
2461     EVT_TREE_SEL_CHANGED(TreeListCtrlId, WxGimmick::OnSelChanged)
2462     EVT_TREE_SEL_CHANGING(TreeListCtrlId, WxGimmick::OnSelChanging)
2463   // KEY
2464     EVT_TREE_KEY_DOWN(TreeListCtrlId, WxGimmick::OnTreeKeyDown)
2465   // ACTIVATION = DOUBLE CLICK OR ENTER ON SELECTED
2466     EVT_TREE_ITEM_ACTIVATED(TreeListCtrlId, WxGimmick::OnItemActivated)
2467
2468   // so many differents ways to handle right mouse button clicks...
2469   //    EVT_CONTEXT_MENU(WxGimmick::OnContextMenu)
2470   // EVT_TREE_ITEM_MENU is the preferred event for creating context menus
2471   // on a tree control, because it includes the point of the click or item,
2472   // meaning that no additional placement calculations are required.
2473   //    EVT_TREE_ITEM_MENU(TreeListCtrlId, WxGimmick::OnItemMenu)
2474     
2475     EVT_TREE_ITEM_RIGHT_CLICK(TreeListCtrlId, WxGimmick::OnItemRightClick)
2476
2477   // UNUSED
2478   //    EVT_RIGHT_DOWN(WxGimmick::OnRMouseDown)
2479   //    EVT_RIGHT_UP(WxGimmick::OnRMouseUp)
2480   //    EVT_RIGHT_DCLICK(WxGimmick::OnRMouseDClick)
2481     END_EVENT_TABLE()
2482
2483   //IMPLEMENT_DYNAMIC_CLASS(WxGimmick, wxTreeListCtrl)
2484
2485   /*
2486     wxTree::wxTree(wxWindow *parent, const wxWindowID id,
2487     const wxPoint& pos, const wxSize& size,
2488     long style)
2489     : wxTreeListCtrl(parent, id, pos, size, style)
2490     {
2491     m_reverseSort = false;
2492
2493     CreateImageList();
2494
2495     // Add some items to the tree
2496     AddTestItemsToTree(5, 2);
2497     }
2498   */
2499
2500
2501
2502 #if USE_GENERIC_TREECTRL || !defined(__WXMSW__)
2503     void WxGimmick::CreateButtonsImageList(int size)
2504   {
2505     /*
2506       if ( size == -1 )
2507       {
2508       mTreeListCtrl->SetButtonsImageList(NULL);
2509       return;
2510       }
2511
2512       // Make an image list containing small icons
2513       wxImageList *images = new wxImageList(size, size, true);
2514
2515       // should correspond to TreeListCtrlIcon_xxx enum
2516       wxBusyCursor wait;
2517       wxIcon icons[4];
2518       icons[0] = wxIcon(icon3_xpm);   // closed
2519       icons[1] = wxIcon(icon3_xpm);   // closed, selected
2520       icons[2] = wxIcon(icon5_xpm);   // open
2521       icons[3] = wxIcon(icon5_xpm);   // open, selected
2522
2523       for ( size_t i = 0; i < WXSIZEOF(icons); i++ )
2524       {
2525       int sizeOrig = icons[i].GetWidth();
2526       if ( size == sizeOrig )
2527       {
2528       images->Add(icons[i]);
2529       }
2530       else
2531       {
2532       images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
2533       }
2534       }
2535
2536       mTreeListCtrl->AssignButtonsImageList(images);
2537     */
2538 #else
2539     void WxGimmick::CreateButtonsImageList(int WXUNUSED(size))
2540     {
2541 #endif
2542     }
2543
2544     /*
2545       int WxGimmick::OnCompareItems(const wxTreeItemId& item1,
2546       const wxTreeItemId& item2)
2547       {
2548       if ( m_reverseSort )
2549       {
2550       // just exchange 1st and 2nd items
2551       return mTreeListCtrl->OnCompareItems(item2, item1);
2552       }
2553       else
2554       {
2555       return mTreeListCtrl->OnCompareItems(item1, item2);
2556       }
2557       }
2558
2559
2560       void WxGimmick::DoToggleIcon(const wxTreeItemId& item)
2561       {
2562   
2563       int image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_Folder)
2564       ? TreeIcon_File
2565       : TreeIcon_Folder;
2566       mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Normal);
2567
2568       image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_FolderSelected)
2569       ? TreeIcon_FileSelected
2570       : TreeIcon_FolderSelected;
2571       mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Selected);
2572       }
2573
2574       void WxGimmick::LogEvent(const wxChar *name, const wxTreeEvent& event)
2575       {
2576       wxTreeItemId item = event.GetItem();
2577       wxString text;
2578       if ( item.IsOk() )
2579       text << _T('"') << mTreeListCtrl->GetItemText(item).c_str() << _T('"');
2580       else
2581       text = _T("invalid item");
2582       //    wxLogMessage(wxT("%s(%s)"), name, text.c_str());
2583       }
2584
2585     */
2586     // avoid repetition
2587 #define TREE_EVENT_HANDLER(name)                                \
2588     void WxGimmick::name(wxTreeEvent& event)    \
2589     {                                                           \
2590       /*    LogEvent(_T(#name), event); */                      \
2591       /*    SetLastItem(mTreeListCtrl->wxTreeItemId()) *;*/     \
2592       event.Skip();                                             \
2593     }
2594
2595     TREE_EVENT_HANDLER(OnBeginRDrag)
2596       TREE_EVENT_HANDLER(OnDeleteItem)
2597       TREE_EVENT_HANDLER(OnGetInfo)
2598       TREE_EVENT_HANDLER(OnSetInfo)
2599       //TREE_EVENT_HANDLER(OnItemExpanded)
2600       TREE_EVENT_HANDLER(OnItemExpanding)
2601       //TREE_EVENT_HANDLER(OnItemCollapsed)
2602       //TREE_EVENT_HANDLER(OnSelChanged)
2603       //      TREE_EVENT_HANDLER(OnSelChanging)
2604
2605
2606       void WxGimmick::OnItemCollapsed(wxTreeEvent& event)                   
2607       {
2608         //    std::cout << "* Collapsed *"<<std::endl;
2609       }
2610
2611 #undef TREE_EVENT_HANDLER
2612
2613     void WxGimmick::OnTreeKeyDown(wxTreeEvent& event)
2614     {
2615       /*
2616       //  LogKeyEvent(wxT("Tree key down "), event.GetKeyEvent());
2617       std::cout << "* Key down *"<<std::endl;
2618       if (event.GetKeyCode()==WXK_RIGHT)
2619         {
2620           std::cout << "Right"<<std::endl;
2621           wxTreeItemId itemId =  mTreeListCtrl->GetSelection();
2622           if (itemId.IsOk())
2623             {
2624               std::cout << "item is ok"<<std::endl;
2625               wxPoint clientpt = event.GetPoint();
2626               wxPoint screenpt = ClientToScreen(clientpt);
2627               ShowMenu(itemId, clientpt);
2628             }     
2629           event.Veto();
2630           return;
2631         }
2632       std::cout << "NOT Right"<<std::endl;
2633       */
2634       event.Skip();       
2635     }
2636
2637     void WxGimmick::OnBeginDrag(wxTreeEvent& event)
2638     {
2639       wxTreeItemId id = event.GetItem();
2640       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2641       //    std::cout << "OnBeginDrag("<<id<<")"<<std::endl;
2642       if (data->IsDatabase())
2643         {
2644           //      std::cout << "-- IS ROOT"<<std::endl;
2645           //  event.Allow();
2646         }
2647       else if (data->IsDicomNode())
2648         {
2649           //      std::cout << "-- IS NODE"<<std::endl;
2650         }
2651       /*
2652       // need to explicitly allow drag
2653       if ( event.GetItem() != GetDatabaseItem() )
2654       {
2655       m_draggedItem = event.GetItem();
2656
2657       wxPoint clientpt = event.GetPoint();
2658       wxPoint screenpt = ClientToScreen(clientpt);
2659
2660       wxLogMessage(wxT("OnBeginDrag: started dragging %s at screen coords (%i,%i)"),
2661       GetItemText(m_draggedItem).c_str(),
2662       screenpt.x, screenpt.y);
2663
2664       event.Allow();
2665       }
2666       else
2667       {
2668       wxLogMessage(wxT("OnBeginDrag: this item can't be dragged."));
2669       }
2670       */
2671     }
2672
2673     void WxGimmick::OnEndDrag(wxTreeEvent& event)
2674     {
2675       wxTreeItemId id = event.GetItem();
2676       //      std::cout << "OnEndDrag("<<id<<")"<<std::endl;
2677       if (!id.IsOk()) return;
2678       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2679       if (data->IsDatabase())
2680         {
2681           //      std::cout << "-- IS ROOT"<<std::endl;
2682         }
2683       else if (data->IsDicomNode())
2684         {
2685           //      std::cout << "-- IS NODE"<<std::endl;
2686         }
2687
2688       /*
2689         wxTreeItemId itemSrc = m_draggedItem,
2690         itemDst = event.GetItem();
2691         m_draggedItem = (wxTreeItemId)0l;
2692
2693         // where to copy the item?
2694         if ( itemDst.IsOk() && !ItemHasChildren(itemDst) )
2695         {
2696         // copy to the parent then
2697         itemDst = GetItemParent(itemDst);
2698         }
2699
2700         if ( !itemDst.IsOk() )
2701         {
2702         wxLogMessage(wxT("OnEndDrag: can't drop here."));
2703
2704         return;
2705         }
2706
2707         wxString text = GetItemText(itemSrc);
2708         wxLogMessage(wxT("OnEndDrag: '%s' copied to '%s'."),
2709         text.c_str(), GetItemText(itemDst).c_str());
2710
2711         // just do append here - we could also insert it just before/after the item
2712         // on which it was dropped, but this requires slightly more work... we also
2713         // completely ignore the client data and icon of the old item but could
2714         // copy them as well.
2715         //
2716         // Finally, we only copy one item here but we might copy the entire tree if
2717         // we were dragging a folder.
2718         int image = wxGetApp().ShowImages() ? TreeIcon_File : -1;
2719         AppendItem(itemDst, text, image);
2720       */
2721     }
2722
2723
2724     //====================================================================
2725     void WxGimmick::OnBeginLabelEdit(wxTreeEvent& event)
2726     {
2727       //      std::cout << "OnBeginLabelEdit"<<std::endl;
2728       wxTreeItemId id = event.GetItem();
2729       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2730       // If not a root : veto
2731       if (data->IsDatabase()) 
2732         { 
2733           event.Allow();
2734           return;
2735         }
2736       event.Veto();
2737     }
2738     //====================================================================
2739
2740     //====================================================================
2741     void WxGimmick::OnEndLabelEdit(wxTreeEvent& event)
2742     {
2743       //      std::cout << "OnEndLabelEdit"<<std::endl;
2744       wxTreeItemId id = event.GetItem();
2745       TreeItemData *data = GetItemData(id);
2746       // If not a database : bug !
2747       if (data->IsDatabase()) 
2748         { 
2749           data->GetDicomNode()->GetDicomDatabase()->SetName(wx2std(event.GetLabel()));
2750           mFieldsView->UpdateValues(data->GetDicomNode());
2751         }
2752       else
2753         {
2754           std::cerr<< "!!!! Internal error : send bug report !!!!"<<std::endl;
2755         }
2756     }
2757     //====================================================================
2758
2759
2760     void WxGimmick::OnItemCollapsing(wxTreeEvent& event)
2761     {
2762       //    wxLogMessage(wxT("OnItemCollapsing"));
2763
2764       // for testing, prevent the user from collapsing the first child folder
2765       wxTreeItemId itemId = event.GetItem();
2766
2767       /*
2768         if ( IsTestItem(itemId) )
2769         {
2770         wxMessageBox(wxT("You can't collapse this item."));
2771
2772         event.Veto();
2773         }
2774       */
2775     }
2776
2777
2778     //====================================================================
2779     void WxGimmick::ShowHelp()
2780     {
2781       /*
2782       if (mHelpWindow==0)
2783         {
2784           mHelpWindow = new WxGimmickHelpWindow(this);
2785         }
2786       mHelpWindow->CenterOnParent();
2787       mHelpWindow->ShowModal();
2788       */
2789     }
2790     //====================================================================
2791
2792
2793
2794
2795
2796     //================================================================
2797     //================================================================
2798     //================================================================
2799     //================================================================
2800     //================================================================
2801     // WxGimmickEvent
2802     //================================================================
2803     //================================================================
2804     //================================================================
2805     //================================================================
2806     //================================================================
2807
2808
2809
2810
2811
2812     // ----------------------------------------------------------------------------
2813     // events
2814     // ----------------------------------------------------------------------------
2815     /*
2816       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG)
2817       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG)
2818       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM)
2819       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO)
2820       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO)
2821       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED)
2822       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING)
2823       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
2824       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING)
2825     */
2826
2827     DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT)
2828       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT)
2829
2830
2831       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGED)
2832       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGING)
2833       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_KEY_DOWN)
2834       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_CONTEXTUAL_MENU)
2835       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_ITEM_STYLE_CHANGED)
2836       /*
2837         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED)
2838         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK)
2839         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK)
2840         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG)
2841         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK)
2842         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP)
2843         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU)
2844       */
2845       // ----------------------------------------------------------------------------
2846       // Tree event
2847       // ----------------------------------------------------------------------------
2848
2849       IMPLEMENT_ABSTRACT_CLASS(WxGimmickEvent, wxNotifyEvent)
2850   
2851   
2852       WxGimmickEvent::WxGimmickEvent(wxEventType commandType,
2853                                                                  WxGimmick *tree,
2854                                                                  const wxTreeItemId& item)
2855       : 
2856       wxNotifyEvent(commandType, tree->GetId()),
2857       m_item(item),
2858       mDicomNode(0)
2859         {
2860           //      m_editCancelled = false;
2861       
2862           SetEventObject(tree);
2863       
2864           if ( item.IsOk() )
2865             SetClientObject(tree->mTreeListCtrl->GetItemData(item));
2866         }
2867   
2868       WxGimmickEvent::WxGimmickEvent(wxEventType commandType, int id)
2869         : 
2870         wxNotifyEvent(commandType, id),
2871         mDicomNode(0)
2872           {
2873             m_itemOld = 0l;
2874             //      m_editCancelled = false;
2875           }
2876     
2877         WxGimmickEvent::WxGimmickEvent(const WxGimmickEvent & event)
2878           : 
2879           wxNotifyEvent(event),
2880           mDicomNode(0)
2881
2882             {
2883               m_evtKey = event.m_evtKey;
2884               m_item = event.m_item;
2885               m_itemOld = event.m_itemOld;
2886               mColor = event.mColor;
2887               mUserData = event.mUserData;
2888               //    m_pointDrag = event.m_pointDrag;
2889               //    m_label = event.m_label;
2890               //    m_editCancelled = event.m_editCancelled;
2891             }
2892       
2893       
2894
2895
2896
2897
2898
2899
2900           //================================================================
2901           //================================================================
2902           //================================================================
2903           //================================================================
2904           //================================================================
2905           WxGimmickFrame::WxGimmickFrame( wxWindow *parent, 
2906                                           wxString title, 
2907                                           wxSize size)
2908             : wxFrame((wxFrame *)parent, -1, title, wxDefaultPosition, size)
2909             {   
2910               wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
2911               mWxGimmick = new WxGimmick(this,-1,
2912                                          wxDefaultPosition,
2913                                          wxDefaultSize);
2914               sizer->Add(mWxGimmick,1,wxGROW);
2915               SetSizer(sizer);
2916               SetAutoLayout(true);
2917               Layout();
2918             }
2919             //================================================================
2920
2921             //================================================================
2922             WxGimmickFrame::~WxGimmickFrame()
2923               {
2924               }
2925             //================================================================
2926
2927             //================================================================
2928             void WxGimmickFrame::OnSelChanged(WxGimmickEvent& event)
2929             {
2930               //    std::cout << "+++++ WxGimmickFrame::OnSelChanged ++++++++++"
2931               //              <<std::endl;
2932               std::vector<std::string> file;
2933               //    mWxGimmick->GetSelectedImages(file);
2934               /*
2935                 std::vector<std::string>::iterator i;
2936                 for (i=file.begin();i!=file.end();++i)
2937                 {
2938                 std::cout << "'" << *i << "'" << std::endl;
2939                 }
2940                 std::cout << "++++++++++++++++++++" << std::endl;
2941               */
2942             }
2943             //================================================================
2944
2945             //================================================================
2946             BEGIN_EVENT_TABLE(WxGimmickFrame, wxFrame)
2947               EVT_TREEVIEWLIST_SEL_CHANGED(-1,WxGimmickFrame::OnSelChanged)
2948               END_EVENT_TABLE()
2949               //================================================================
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   }