]> Creatis software - creaImageIO.git/blob - src/creaImageIOWxGimmick.cpp
3e744982e179fec219f04c1b232bd2090b9310f1
[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 << "==> Loading collections from '"<<mDatabaseListFile
936     //        <<"'"<<std::endl;
937
938     std::ifstream s;
939     s.open(mDatabaseListFile.c_str());
940     if (s.good())
941         {
942         while (!s.eof()) 
943           {
944             std::string str;
945             std::getline(s,str);
946             if (str.size()==0) continue;
947
948             std::vector<std::string> tokens;        
949             boost::split( tokens, str, boost::is_any_of("\t") );
950
951             DicomDatabase* db = new DicomDatabase(tokens[0]);
952             
953             //  std::cout << "  -> Loading collection '"<<tokens[0]<<"'"<<std::endl;
954             
955             if (tokens.size()==2) 
956               {
957                 db->SetName(tokens[1]);
958               }
959             
960             if (db->Open()) 
961               {
962                 GetDicomDatabaseList().push_back(db);
963                 db->DBLoadChildren(db,DicomNode::Patient);
964                 if (mSettings.HasActiveComparator(DicomNode::Patient))
965                   {
966                     db->SortChildren
967                       ( mSettings.GetActiveComparator(DicomNode::Patient)  );
968                   }
969               }
970             else 
971               {
972                 //          std::cout << "    ... ERROR !"<<std::endl;
973                 delete db;
974               }
975           }
976         s.close();
977         }
978         else 
979         {
980                 std::cout << "ERROR opening "<<mDatabaseListFile<<std::endl;
981         }
982
983         
984     mTreeListCtrl->SetBackgroundColour(mSettings.BgColour(DicomNode::Database));
985     if (GetDicomDatabaseList().begin() != 
986         GetDicomDatabaseList().end() )
987       {
988         mFieldsView->UpdateFields(*GetDicomDatabaseList().begin());
989       }
990
991     RebuildView();
992       
993   }
994   //================================================================
995   
996   //================================================================
997   void WxGimmick::SaveConfiguration()
998   {
999     wxBusyCursor busy;
1000     creaMessage("Gimmick!",1,"Gimmick! : Saving configuration..."<<std::endl);
1001     
1002     creaMessage("Gimmick!",1,"Gimmick! : ==> Saving collections in '"
1003                 <<mDatabaseListFile<<"'"<<std::endl);
1004     
1005     std::ofstream s;
1006     s.open(mDatabaseListFile.c_str());
1007     if (!s.good())
1008       {
1009         creaError("Gimmick! : error opening '"<<mDatabaseListFile<<"'"); 
1010       }
1011     
1012     DicomDatabaseListType::iterator i;
1013     for (i =GetDicomDatabaseList().begin();
1014          i!=GetDicomDatabaseList().end();
1015          ++i)
1016       {  
1017         s << (*i)->GetFileName() << "\t";
1018         s << (*i)->GetName() << std::endl;
1019       }
1020     
1021     s.close();
1022
1023   }
1024   //================================================================
1025
1026   /*
1027   //================================================================
1028   void  WxGimmick::OnClose(wxCloseEvent& event)
1029   {
1030   if (mSaveConfigurationOnClose) SaveConfiguration();
1031   }
1032   //================================================================
1033   */
1034   //================================================================
1035   void WxGimmick::OnItemActivated(wxTreeEvent& event)
1036   {  
1037     event.Skip();
1038     return;
1039
1040     wxBusyCursor busy;
1041     //    std::cout << "OnItemActivated" <<std::endl;
1042     wxTreeItemId itemId = event.GetItem();
1043     if (mTreeListCtrl->IsExpanded(itemId))
1044       {
1045         mTreeListCtrl->Collapse(itemId);
1046       }
1047     else 
1048       {
1049         mTreeListCtrl->Expand(itemId);
1050       }
1051   }
1052   //================================================================
1053
1054   //================================================================
1055   void WxGimmick::LoadChildren(wxTreeItemId& id)
1056   {
1057     TreeItemData *item = (TreeItemData *)mTreeListCtrl->GetItemData(id);
1058     if (item)
1059       {
1060         if ( ( item->IsDicomNode() || item->IsDatabase() ) &&
1061              ( ! item->GetDicomNode()->ChildrenLoaded() ) )
1062           {
1063             
1064             // If children not already loaded : do it 
1065             if (
1066                 item->GetDicomNode()->GetDicomDatabase()->DBLoadChildren
1067                 (item->GetDicomNode(),item->GetDicomNode()->GetType()+1)
1068                 > 0 )
1069               {
1070                 // Some new children loaded
1071                 // Sort them
1072                 if (mSettings.HasActiveComparator
1073                     (item->GetDicomNode()->GetType()+1))
1074                   {
1075                     /*                  std::cout << "Sorting using '"
1076                       << mSettings.GetActiveComparator
1077                       (item->GetDicomNode()->GetType()+1).GetName() 
1078                       << "' ... ";
1079                     */
1080                     item->GetDicomNode()->SortChildren
1081                       ( mSettings.GetActiveComparator
1082                         (item->GetDicomNode()->GetType()+1)
1083                         );
1084                     //                  std::cout << "ok"<<std::endl;
1085                   }
1086                 // Update tree
1087                 DicomNode::ChildrenListType::iterator i;
1088                 for (i=item->GetDicomNode()->GetChildrenList().begin();
1089                      i!=item->GetDicomNode()->GetChildrenList().end();
1090                      i++)
1091                   {
1092                     UpdateDicomNodeView(*i,id);
1093                   }
1094               }
1095             // EO If children not already loaded 
1096           }
1097       } 
1098   }
1099   //================================================================
1100
1101
1102   //================================================================
1103   void WxGimmick::OnItemExpanded(wxTreeEvent& event)                   
1104   {
1105
1106     //    std::cout << "* Expanded *"<<std::endl;
1107     //  }
1108
1109     wxBusyCursor busy;
1110     
1111     wxTreeItemId itemId = event.GetItem();
1112     LoadChildren(itemId);
1113     
1114     return;
1115
1116     // expand if collapsed and collapse if expanded ...
1117     TreeItemData *item = 
1118       (TreeItemData *)mTreeListCtrl->GetItemData(itemId);
1119     if (item)
1120       {
1121         if ( ( item->IsDicomNode() || item->IsDatabase() ) &&
1122              ( ! item->GetDicomNode()->ChildrenLoaded() ) )
1123           {
1124                 
1125             // If children not already loaded : do it 
1126             if (
1127                 item->GetDicomNode()->GetDicomDatabase()->DBLoadChildren
1128                 (item->GetDicomNode(),item->GetDicomNode()->GetType()+1)
1129                 > 0 )
1130               {
1131                     
1132                 // Some new children loaded
1133                 // Sort them
1134                 if (mSettings.HasActiveComparator
1135                     (item->GetDicomNode()->GetType()+1))
1136                   {
1137                     /*                  std::cout << "Sorting using '"
1138                       << mSettings.GetActiveComparator
1139                       (item->GetDicomNode()->GetType()+1).GetName() 
1140                       << "' ... ";
1141                     */
1142                     item->GetDicomNode()->SortChildren
1143                       ( mSettings.GetActiveComparator
1144                         (item->GetDicomNode()->GetType()+1)
1145                         );
1146                     //                  std::cout << "ok"<<std::endl;
1147                   }
1148                 /*              
1149                 // If images : sort them 
1150                 if (item->IsDicomNode())
1151                 {
1152                 if (item->GetDicomNode()->GetType()==DicomNode::Series)
1153                 {  
1154                 // SORT
1155                    
1156                 LexicographicalDicomNodeComparator compare;
1157                 // DicomNodeImageImageNumberComparator c1;
1158                     
1159                 DicomNodeImageSliceLocationComparator c1;
1160                 DicomNodeImageImageNumberComparator c2;
1161                 DicomNodeImageFileNameComparator cn;
1162                 compare.Add(c1);
1163                 compare.Add(c2);
1164                 compare.Add(cn);
1165                 //              std::cout << "SORT"<<std::endl;
1166                 item->GetDicomNode()->SortChildren(compare);
1167                 //              std::cout << "EO SORT"<<std::endl;
1168                 //
1169                     
1170                 }
1171                 }
1172                 */
1173                     
1174                 // Update tree
1175                 DicomNode::ChildrenListType::iterator i;
1176                 for (i=item->GetDicomNode()->GetChildrenList().begin();
1177                      i!=item->GetDicomNode()->GetChildrenList().end();
1178                      i++)
1179                   {
1180                     UpdateDicomNodeView(*i,itemId);
1181                   }
1182               }
1183             // EO If children not already loaded 
1184           }
1185       }
1186     //  mTreeListCtrl->Expand(itemId);
1187      
1188   }
1189   //================================================================
1190
1191
1192   /*
1193   //=====================================================================
1194   void WxGimmick::InsertRoot(wxTreeItemId& id, Root* r)
1195   {
1196   wxBusyCursor busy;
1197   TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
1198   if (data)
1199   { 
1200         
1201   wxStopWatch sw;
1202   data->GetDicomNode()->GetDicomDatabase()->LoadAll();
1203   printf(">>>>>> Time to load all = %ldms \n",sw.Time());
1204
1205   UpdateRootView(data->GetDicomNode()->GetDicomDatabase());
1206     
1207
1208   if (data->IsDicomNode())
1209   {
1210   wxStopWatch sw1;
1211   r->Insert(data->GetDicomNode());
1212   printf(">>>>>> Time to insert = %ldms \n",sw1.Time());
1213   UpdateRootView(r);
1214   }
1215   else if (data->IsDatabase())
1216   {     
1217   wxStopWatch sw1;
1218   DicomNode::ChildrenListType::iterator j;
1219   for (j= data->GetDicomNode()->GetChildrenList().begin();
1220   j!=data->GetDicomNode()->GetChildrenList().end();
1221   j++)
1222   {
1223   r->Insert(*j);
1224   }
1225   printf(">>>>>> Time to insert = %ldms \n",sw1.Time());
1226   UpdateRootView(r);    
1227   }
1228
1229   }
1230   }
1231   //=====================================================================
1232   */
1233
1234   
1235   //=================================================
1236   void WxGimmick::DeleteDicomDatabase(wxTreeItemId& id, 
1237                                                     DicomDatabase* db)
1238   {
1239     wxBusyCursor busy;
1240     DicomDatabaseListType::iterator i = find(GetDicomDatabaseList().begin(),
1241                                              GetDicomDatabaseList().end(),
1242                                              db);
1243     delete (*i);
1244     GetDicomDatabaseList().erase(i);
1245     mTreeListCtrl->Delete(id);
1246   }
1247   //=================================================
1248
1249
1250
1251   //=====================================================================
1252   
1253   void WxGimmick::OnItemRightClick(wxTreeEvent& event)
1254   {
1255
1256     wxTreeItemId itemId = event.GetItem();
1257     if (itemId.IsOk())
1258       {
1259         wxPoint clientpt = event.GetPoint();
1260         wxPoint screenpt = ClientToScreen(clientpt);
1261         ShowMenu(itemId, clientpt);
1262       }
1263     event.Skip();
1264   }
1265   //=====================================================================
1266   
1267
1268
1269   //=====================================================================
1270   void WxGimmick::ShowMenu(wxTreeItemId id, const wxPoint& pt)
1271   { 
1272
1273     //  std::cout << "ShowMenu" <<std::endl;
1274     mItemOfMenu = id;
1275     TreeItemData *data = 
1276       (TreeItemData *)mTreeListCtrl->GetItemData(id);
1277   
1278     /*
1279       wxString title;
1280       if ( id.IsOk() )
1281       {
1282       title << wxT("Menu for ") << mTreeListCtrl->GetItemText(id);
1283       }
1284       else
1285       {
1286       title = wxT("Menu for no particular item");
1287       }
1288     */
1289
1290 #if wxUSE_MENUS
1291     wxMenu menu;
1292
1293     if (id==mCollectionsTitlesItemId)
1294       {
1295         menu.Append(PopUp_NewCollection, _T("&New collection"));
1296         menu.Append(PopUp_OpenCollection, _T("&Open collection"));
1297       }
1298     if (data)
1299       {
1300         if (data->IsDatabase())
1301           {
1302             wxMenu* addmenu = new wxMenu;
1303             addmenu->Append(PopUp_AddDirectory, _T("Scan &Directory"));
1304             addmenu->Append(PopUp_AddFile, _T("Select &File(s)"));
1305             //      addmenu->Append(PopUp_AddRawFile, _T("Add &Raw image"));
1306             menu.AppendSubMenu(addmenu, _T("&Add image(s) to collection..."));
1307             menu.Append(PopUp_CloseCollection, _T("&Close collection"));
1308             menu.Append(PopUp_DeleteCollection, _T("&Delete collection"));
1309           }
1310         if (data->IsDicomNode())
1311           {
1312             
1313             //      LG : BUGGY
1314             /*
1315             std::string str("&Remove ");
1316             str += data->GetDicomNode()->GetTypeName();
1317             menu.Append(PopUp_Remove, std2wx(str));
1318             */
1319           }
1320       
1321         if ((data->GetDicomNode()>0)&&
1322             ( data->GetDicomNode()->GetType()<DicomNode::Image))
1323           {
1324             int ctype = data->GetDicomNode()->GetType()+1;
1325             if (mSettings.HasActiveComparator(ctype))
1326               {
1327                 wxMenu* sortmenu = new wxMenu;
1328                 int n = 0;
1329                 Settings::ComparatorsList::iterator i;
1330                 for (i =mSettings.GetComparatorsList(ctype).begin();
1331                      i !=mSettings.GetComparatorsList(ctype).end();
1332                      ++i)
1333                   {
1334                     sortmenu->AppendRadioItem(PopUp_Sort+n, std2wx(i->GetName()));
1335                     n++;
1336                   }    
1337               
1338                 sortmenu->Check(PopUp_Sort+
1339                                 mSettings.GetActiveComparatorIndex(ctype)
1340                                 ,true);
1341               
1342                 std::string sortmenustr("&Sort ");
1343                 sortmenustr += DicomNode::GetPluralTypeName(ctype);
1344                 sortmenustr += " by...";
1345                 if (menu.GetMenuItemCount()>0) menu.AppendSeparator();
1346                 menu.AppendSubMenu(sortmenu,std2wx(sortmenustr));
1347               
1348                 /*
1349                   item->GetDicomNode()->SortChildren
1350                   ( mSettings.GetActiveComparator
1351                   (item->GetDicomNode()->GetType()+1)
1352                   );
1353                   std::cout << "ok"<<std::endl;
1354                 */
1355               }
1356           }
1357       }
1358     // Event : user can customize the menu 
1359     WxGimmickEvent 
1360       ev(wxEVT_COMMAND_TREEVIEWLIST_CONTEXTUAL_MENU,this,id);
1361     ev.SetMenu(&menu);
1362     if (data)
1363       {
1364         ev.SetDicomNode(data->GetDicomNode());
1365       }
1366     GetEventHandler()->ProcessEvent(ev);
1367     //
1368   
1369     if (menu.GetMenuItemCount()>0) menu.AppendSeparator();
1370     menu.Append(PopUp_Settings, wxT("&Settings..."));
1371     menu.Append(PopUp_About, wxT("&About..."));
1372   
1373
1374   
1375     /*
1376       wxMenu* newmenu = new wxMenu;
1377       wxMenu* openmenu = new wxMenu;
1378       Tree::RootHandlerListType::iterator h;
1379       int i=0;
1380       for (h= Tree::GetRootHandlerList().begin();
1381       h!=Tree::GetRootHandlerList().end();
1382       h++)
1383       {
1384       if ((*h)->SupportsNew()) 
1385       {
1386       newmenu->Append(PopUp_New+i, std2wx((*h)->GetName()));
1387       }
1388       if ((*h)->SupportsOpen()) 
1389       openmenu->Append(PopUp_Open+i, std2wx((*h)->GetName()));
1390       i++;
1391       }
1392     
1393       menu.AppendSubMenu(openmenu, _T("&Open"));
1394       menu.AppendSubMenu(newmenu, _T("&New"));
1395
1396       if (data)
1397       { 
1398       if ((data->IsDatabase())||(data->IsDicomNode()))
1399       {
1400       Root* itroot = data->GetDicomNode()->GetDicomDatabase();
1401       //        if (!itroot) itroot = data->GetDicomNode()->GetRoot();
1402       wxMenu* insertmenu = new wxMenu;
1403       bool hasone = false;
1404       i = 0;
1405       Tree::RootListType::iterator j;
1406       for (j  = mTree->GetDatabaseList().begin();
1407       j != mTree->GetDatabaseList().end();
1408       j++)
1409       {
1410       //            std::cout << (*j)->GetName() << " " 
1411       //                      <<  (*j)->GetTypeName()
1412       //                      << " i="<<(*j)->SupportsInsert()<<std::endl;
1413       if ( ((*j)!=itroot) && ((*j)->SupportsInsert()) ) 
1414       {
1415       insertmenu->Append(PopUp_Insert+i, 
1416       std2wx((*j)->GetName()));
1417       hasone = true;
1418       }
1419       i++;
1420       }
1421             
1422       if (hasone) menu.AppendSubMenu(insertmenu, _T("&Insert into"));
1423       }
1424       if (data->IsDatabase())
1425       {
1426       menu.Append(PopUp_Close, wxT("&Close"));
1427       }
1428       if (data->IsDicomNode() && data->GetDicomNode()->GetDicomDatabase()->SupportsRemove())
1429       {
1430       menu.Append(PopUp_Remove, wxT("&Remove"));
1431       }
1432       }
1433     */
1434
1435  
1436
1437  
1438     PopupMenu(&menu, pt);
1439 #endif // wxUSE_MENUS
1440
1441     //    std::cout << "EO ShowMenu" <<std::endl;
1442   }
1443   //=====================================================================
1444
1445   //=====================================================================
1446   // Pop up menu callbacks
1447   void  WxGimmick::OnPopUpAbout(wxCommandEvent& event)
1448   {
1449     wxMessageBox( _T("Give me my medical images quick ! \n\n  (c) CREATIS-LRMN 2008\n      laurent.guigues@creatis.insa-lyon.fr"),
1450                   _T("Gimmick!"),
1451                   wxOK | wxICON_INFORMATION, this);
1452   }
1453   //=====================================================================
1454
1455   //=====================================================================
1456   void  WxGimmick::OnPopUpSettings(wxCommandEvent& event)
1457   {
1458     WxGimmickSettingsDialog* s = 
1459       new WxGimmickSettingsDialog(this,&mSettings);
1460     s->ShowModal();
1461     delete s;
1462   }
1463   //=====================================================================
1464
1465   //=====================================================================
1466   void  WxGimmick::OnPopUpNewCollection(wxCommandEvent& event)
1467   {
1468     wxBusyCursor busy;
1469     OpenOrNewDatabase(false);
1470   }
1471   //=====================================================================
1472   
1473
1474  
1475   //=====================================================================
1476   void  WxGimmick::OnPopUpOpenCollection(wxCommandEvent& event)
1477   {
1478     wxBusyCursor busy;
1479     OpenOrNewDatabase(true);
1480   }
1481   //=====================================================================
1482
1483
1484   //=====================================================================
1485   void  WxGimmick::OnPopUpCloseCollection(wxCommandEvent& event)
1486   {
1487     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;
1488    
1489     wxBusyCursor busy;
1490     //   std::cout << "OnPopUpClose"<<std::endl;
1491     //  wxTreeItemId id = event.GetId();
1492     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1493     DicomDatabase* r = data->GetDicomNode()->GetDicomDatabase();
1494     //   std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1495     DeleteDicomDatabase(mItemOfMenu,r);
1496   }
1497   //=====================================================================
1498
1499   //=====================================================================
1500   void  WxGimmick::OnPopUpDeleteCollection(wxCommandEvent& event)
1501   {
1502     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;
1503     
1504     wxBusyCursor busy;
1505
1506    
1507     //   std::cout << "OnPopUpClose"<<std::endl;
1508     //  wxTreeItemId id = event.GetId();
1509     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1510     DicomDatabase* r = data->GetDicomNode()->GetDicomDatabase();
1511
1512     wxRemoveFile(std2wx(r->GetFileName()));
1513     //   std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1514     DeleteDicomDatabase(mItemOfMenu,r);
1515     
1516   }
1517   //=====================================================================
1518   
1519   void DisplayUpdateSummary( DicomDatabase::UpdateSummary& summary,
1520                              wxWindow* parent )
1521   {
1522     std::stringstream mess;
1523     mess << "Dirs\tscanned\t\t\t: " << summary.scanned_dirs << "\n";
1524     mess << "Files\tscanned\t\t\t: " << summary.scanned_files << "\n";
1525     mess << "Files\thandled\t\t\t: " << summary.handled_images << "\n\n";
1526     mess << "Patients\tadded\t\t: " << summary.added_patients<< "\n";
1527     mess << "Studies\tadded\t\t: " << summary.added_studies<< "\n";
1528     mess << "Series\tadded\t\t: " << summary.added_series<< "\n";
1529     mess << "Images\tadded\t\t: " << summary.added_images<< "\n\n";
1530     char times[500];
1531     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",
1532             summary.parse_time,
1533             (int)( summary.parse_time*100./summary.total_time),
1534             summary.file_scan_time,
1535             (int)(summary.file_scan_time*100./summary.total_time),
1536             summary.update_structs_time,
1537             (int)(summary.update_structs_time*100./summary.total_time),
1538             summary.update_database_time,
1539             (int)(summary.update_database_time*100./summary.total_time),
1540             summary.total_time );
1541     
1542     mess << times;
1543     
1544     wxMessageBox(std2wx(mess.str()),_T("Update summary"),wxOK,parent);
1545   }
1546   
1547   
1548   //=====================================================================
1549   void  WxGimmick::OnPopUpAddFile(wxCommandEvent& event)
1550   {
1551     long style = wxOPEN | wxFILE_MUST_EXIST | wxFD_MULTIPLE;
1552     std::string wc("*.*");
1553     wxFileDialog* FD = new wxFileDialog( 0, 
1554                                          _T("Select file"),
1555                                          mCurrentDirectory,
1556                                          _T(""),
1557                                          std2wx(wc),
1558                                          style,
1559                                          wxDefaultPosition);
1560     
1561     if (FD->ShowModal()==wxID_OK)
1562       {
1563         wxBusyCursor busy;
1564
1565         mCurrentDirectory = FD->GetDirectory();
1566         wxArrayString files;
1567         FD->GetPaths(files);
1568         unsigned int i;
1569         std::vector<std::string> filenames;
1570         for (i=0;i<files.GetCount();++i)
1571           filenames.push_back(wx2std(files[i]));
1572
1573        
1574         TreeItemData *data = 
1575           (TreeItemData *)
1576           mTreeListCtrl->GetItemData(mItemOfMenu);
1577         DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1578         DicomDatabase::UpdateSummary summary;
1579         wxProgressDialog* progress = 
1580           new wxProgressDialog(_T("Adding file(s)"),
1581                                _T(""),
1582                                1000,
1583                                this,
1584                                wxPD_ELAPSED_TIME |
1585                                wxPD_ESTIMATED_TIME | 
1586                                wxPD_REMAINING_TIME |
1587                                wxPD_CAN_ABORT );
1588        
1589         db->AddFiles(filenames,progress,summary);
1590         
1591         progress->Pulse(_T("Updating view..."));
1592         UpdateDicomDatabaseView(db);
1593         delete progress;
1594         DisplayUpdateSummary(summary,this);
1595       }
1596   
1597   }
1598   //=====================================================================
1599
1600   //=====================================================================
1601   void  WxGimmick::OnPopUpAddRawFile(wxCommandEvent& event)
1602   {
1603     wxMessageBox(_T("Not yet implemented !"),_T("Sorry"),wxOK,this);
1604   }
1605   //=====================================================================
1606
1607   //=====================================================================
1608   void  WxGimmick::OnPopUpAddDirectory(wxCommandEvent& event)
1609   {
1610     long style = wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST;
1611     wxDirDialog* FD = 
1612       new wxDirDialog( 0, 
1613                        _T("Select directory"),
1614                        mCurrentDirectory,
1615                        style);
1616    
1617     if (FD->ShowModal()==wxID_OK)
1618       {
1619
1620         bool recurse = false;
1621         if (wxMessageBox(_T("Recurse into sub-directories ?"),
1622                          _T("Scan directory"),
1623                          wxYES_NO,this ) == wxYES)
1624           {
1625             recurse = true;
1626           }
1627        
1628         wxBusyCursor busy;
1629         wxProgressDialog* progress = 
1630           new wxProgressDialog(_T("Scanning directory"),
1631                                _T("Parsing directory"),
1632                                1000,
1633                                this,
1634                                wxPD_ELAPSED_TIME |
1635                                wxPD_ESTIMATED_TIME | 
1636                                wxPD_REMAINING_TIME |
1637                                wxPD_CAN_ABORT );
1638         DicomDatabase::UpdateSummary summary;
1639
1640         std::string dirname = wx2std (FD->GetPath()) ;
1641         mCurrentDirectory = FD->GetPath();
1642         TreeItemData *data = 
1643           (TreeItemData *)
1644           mTreeListCtrl->GetItemData(mItemOfMenu);
1645         DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1646         db->AddDirectory(dirname,recurse,progress,summary);
1647
1648         progress->Pulse(_T("Updating view..."));
1649         UpdateDicomDatabaseView(db);
1650
1651         delete progress;    
1652         DisplayUpdateSummary(summary,this);
1653         /*    
1654               if (summary.cancelled_by_user)
1655               {
1656               std::cout << "!! Cancelled by user !!"<<std::endl;
1657               }
1658         */
1659
1660       }
1661   }
1662   //=====================================================================
1663
1664   //=====================================================================
1665   void  WxGimmick::OnPopUpRemove(wxCommandEvent& event)
1666   {
1667
1668     /*
1669       wxMessageBox(_T("Not yet implemented"),_T("Sorry !"),wxOK);
1670       return;
1671     */
1672
1673     //  wxTreeItemId id = event.GetId();
1674     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1675
1676     std::string mess("Remove ");
1677     mess += data->GetDicomNode()->GetTypeName();
1678     mess += " from collection ?";
1679     int answer = wxMessageBox(std2wx(mess), _T("Confirm"), wxYES_NO);
1680     if (answer == wxNO) return;
1681    
1682     if ( mTreeListCtrl->IsSelected(mItemOfMenu) )
1683       {
1684         wxTreeItemId next = mTreeListCtrl->GetNextSibling(mItemOfMenu);
1685         if (next.IsOk()) 
1686           {
1687             mTreeListCtrl->SelectItem(next);
1688           }
1689         else 
1690           {
1691             return;
1692           }
1693       }
1694
1695     DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1696     db->Remove(data->GetDicomNode());
1697     //   std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1698     // TODO : Optimize update only parent's branch
1699     UpdateDicomDatabaseView(db);
1700     //   DeleteDicomDatabase(mItemOfMenu,r);
1701   }
1702   //=====================================================================
1703
1704   //=====================================================================
1705   void  WxGimmick::OnPopUpSort(wxCommandEvent& event)
1706   {
1707     wxBusyCursor busy;
1708     //    std::cout << "OnPopUpSort"<<std::endl;
1709     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1710     int index = event.GetId() - PopUp_Sort;
1711     DicomNode* node = data->GetDicomNode();
1712     DicomNode::Type ctype = node->GetType()+1;
1713     mSettings.SetActiveComparatorIndex(ctype,index);
1714
1715     if (node->ChildrenLoaded())
1716       {
1717         // Remove children
1718         mTreeListCtrl->DeleteChildren(mItemOfMenu);
1719
1720         /*      std::cout << "Sorting using '"
1721           << mSettings.GetActiveComparator(ctype).GetName() 
1722           << "' ... ";
1723         */
1724         node->SortChildren ( mSettings.GetActiveComparator(ctype) );
1725         //      std::cout << "ok"<<std::endl;
1726
1727         
1728         // Update tree
1729         CreateChildrenColumnsTitles(mItemOfMenu,ctype);
1730         DicomNode::ChildrenListType::iterator i;
1731         for (i=node->GetChildrenList().begin();
1732              i!=node->GetChildrenList().end();
1733              i++)
1734           {
1735             UpdateDicomNodeView(*i,mItemOfMenu);
1736           }
1737       }
1738   }
1739   //=====================================================================
1740
1741
1742   //=====================================================================
1743   void  WxGimmick::OnPopUpUser(wxCommandEvent& event)
1744   {
1745     //    std::cout << "OnPopUpUser"<<std::endl;
1746     event.Skip();
1747   }
1748   //=====================================================================
1749
1750   //=================================================
1751   void WxGimmick::CreateImageList(int size)
1752   {
1753     if ( size == -1 )
1754       {
1755         mTreeListCtrl->SetImageList(NULL);
1756         return;
1757       }
1758     if ( size == 0 )
1759       size = m_imageSize;
1760     else
1761       m_imageSize = size;
1762     
1763     wxIcon icons[20];
1764     // should correspond to Icon_xxx enum
1765     icons[Icon_Patient] = wxIcon(patient_xpm);
1766     icons[Icon_Study] = wxIcon(study_xpm);
1767     icons[Icon_Series] = wxIcon(series_xpm);
1768     icons[Icon_Image] = wxIcon(image_xpm);
1769     icons[Icon_Database] = wxIcon(database_xpm);
1770     icons[Icon_Folder] = wxIcon(folder_xpm);
1771     icons[Icon_DicomDir] = wxIcon(dicomdir_xpm);
1772     icons[Icon_Root] = wxIcon(root_xpm);
1773
1774
1775     //    mFirstRootIconIndex = 8;
1776     //    int i=0;
1777     /*
1778       Tree::RootHandlerListType::iterator h;
1779
1780       for (h= Tree::GetDatabaseHandlerList().begin();
1781       h!=Tree::GetDatabaseHandlerList().end();
1782       h++)
1783       {
1784       icons[mFirstRootIconIndex+i] = (*h)->GetIcon();
1785       i++;
1786       }
1787     */
1788     unsigned int NbIcons = 8;//mFirstRootIconIndex + i;
1789     // Make an image list containing small icons
1790     wxImageList *images = new wxImageList(size, size, true);
1791     
1792     int sizeOrig = icons[0].GetWidth();
1793     for ( size_t i = 0; i < NbIcons; i++ )
1794       {
1795         if ( size == sizeOrig )
1796           {
1797             images->Add(icons[i]);
1798           }
1799         else
1800           {
1801             images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
1802           }
1803       }
1804     mTreeListCtrl->AssignImageList(images);
1805   }
1806   //=================================================
1807
1808
1809
1810
1811
1812
1813
1814
1815   //================================================================
1816   bool WxGimmick::IsImageSelectable(DicomNode* node)                   
1817   {
1818     int rows = node->ImageGetRows();
1819     int cols = node->ImageGetColumns();
1820     int frms = node->ImageGetFrames();
1821     
1822     //    std::cout << "R/C/F = " << rows << "/"<< cols <<"/"<<frms<<std::endl;
1823
1824     int dim = 0;
1825     if (frms>0) dim=3;
1826     else if (cols>0) dim=2;
1827     else if (rows>0) dim=1;
1828     
1829     if (dim == 0) 
1830       {
1831         std::cout << "Unknown image dimension : cannot select !" 
1832                   << std::endl;
1833         return false;
1834       }
1835     else if (dim>mSelectionMaxImageDimension)
1836       {
1837         std::cout << "Selecting "<<dim<<"D images is not allowed !" 
1838                   << std::endl;
1839         return false;
1840       }
1841     
1842     if ( mTreeListCtrl->GetSelectionSize() == 0 ) 
1843       {
1844         mCurrentSelectionImageSize[0] = cols;
1845         mCurrentSelectionImageSize[1] = rows;
1846         mCurrentSelectionImageSize[2] = frms;
1847         return true;
1848       }
1849     else 
1850       {
1851         if ( dim == mSelectionMaxImageDimension )
1852           {
1853             std::cout << "Cannot add this image to selection : would result in a "<<dim+1<<"D image !" << std::endl;
1854             return false;
1855           }
1856         if ( ( cols != mCurrentSelectionImageSize[0] ) ||
1857              ( rows != mCurrentSelectionImageSize[1] ) ||
1858              ( frms != mCurrentSelectionImageSize[2] ) )
1859           {
1860             std::cout << "Cannot add this image to selection : image size is incomptatible with currently selected images" << std::endl; 
1861             return false;
1862           }
1863       }
1864     //    std::cout << "Selecting : "<<node->ImageGetFullFileName() << std::endl;
1865     return true;
1866   }
1867   //================================================================
1868
1869   //================================================================
1870   void WxGimmick::OnSelChanging(wxTreeEvent& event)                   
1871   {
1872     event.Veto();
1873     wxTreeItemId id = event.GetItem();
1874     if (!id.IsOk()) 
1875       {
1876         std::cout << "INTERNAL ERROR : ID NOT OK"<<std::endl;
1877         return;
1878       }
1879
1880
1881     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
1882     if (data->IsDicomNode())
1883       {
1884         if (data->GetDicomNode()>0)
1885           {
1886             // An image was selected 
1887             if (data->GetDicomNode()->GetType()==DicomNode::Image)
1888               {
1889                 if (IsImageSelectable(data->GetDicomNode())) event.Allow();
1890               }
1891             // A series was selected 
1892             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
1893               {
1894                 // If images not loaded do it 
1895                 LoadChildren(id);
1896                 // can be selected if all its images can
1897                 wxTreeItemId child;
1898                 wxTreeItemIdValue cookie;
1899                 for (child = mTreeListCtrl->GetFirstChild(id,cookie);
1900                      child.IsOk();
1901                      child = mTreeListCtrl->GetNextChild(id,cookie))
1902                   {    
1903                     TreeItemData *cdata = 
1904                       (TreeItemData *)mTreeListCtrl->GetItemData(child);
1905                     if ((cdata->IsDicomNode())&&
1906                         (cdata->GetDicomNode()>0)&&
1907                         (cdata->GetDicomNode()->GetType()==DicomNode::Image)&&
1908                         (!IsImageSelectable(cdata->GetDicomNode())))
1909                       return;
1910                   }
1911                 event.Allow();
1912               }
1913           }
1914       }
1915   }
1916   //================================================================
1917
1918   //================================================================
1919   void WxGimmick::OnSelChanged(wxTreeEvent& event)                   
1920   {
1921     //    wxBusyCursor busy;
1922     //    std::vector<wxTreeItemId> items;
1923     //    GetSelectedItems(items);
1924     /*
1925       std::vector<DicomNode*>::iterator i;
1926       for (i=nodes.begin();i!=nodes.end();++i)
1927       {
1928       std::cout << "'" << (*i)->GetFieldValue("FullFileName") 
1929       << "'" << std::endl;
1930       }
1931       std::cout << "++++++++++++++++++++" << std::endl;
1932     */
1933     //    ShowImage(mReader.GetImage(""));
1934
1935      bool no_image = true;
1936
1937     static int max = 1000;
1938
1939     
1940     //    if (items.size()>0) 
1941     //      {
1942
1943         // Update image preview : send requests to the MTImageReader
1944     //  bool first = true;
1945     //  std::vector<wxTreeItemId>::iterator i;
1946     //  for (i=items.begin();i!=items.end();++i)
1947     //    {
1948
1949             /*
1950             if (first)
1951               {
1952                 DicomNode* node = GetDicomNodeOfItem(items[0]);
1953                 if (!node) return;
1954                 // Update dicom fields panel
1955                 mFieldsView->UpdateValues(node);
1956               }
1957             */
1958
1959     wxTreeItemId item =  mTreeListCtrl->GetCurrent();
1960     
1961     DicomNode* n = GetDicomNodeOfItem(item);
1962
1963     if (n) mFieldsView->UpdateValues(n);    
1964
1965     if ( (n!=0) &&
1966          (n->GetType()==DicomNode::Image) )
1967       {
1968
1969         //                
1970         no_image = false;
1971         //if (i==items.begin()) 
1972         mCurImageItemToShow = item;
1973         
1974         int maxprio = mReader.GetMaximalPriority();
1975         int prio = maxprio + 1000;
1976         wxTreeItemId sib = item; //GetTreeListCtrl()->GetNextSibling(*i);
1977         while (sib.IsOk())
1978           {
1979             DicomNode* nsib = GetDicomNodeOfItem(sib);
1980             if (nsib>0) 
1981               {
1982                 //                      std::cout << "-- Request '"
1983                 //                                << nsib->GetFieldValue("FullFileName")
1984                 //                                << "' prio="<<prio<<std::endl;
1985                 mReader.Request(this,
1986                                 nsib->ImageGetFullFileName(), 
1987                                 prio);
1988                 mImageFileNameToNode[nsib->ImageGetFullFileName()] =
1989                   nsib;
1990                 prio--;
1991               }
1992             sib = GetTreeListCtrl()->GetNextSibling(sib);
1993           }
1994         prio = maxprio + 1000;
1995         sib = GetTreeListCtrl()->GetPrevSibling(item);
1996         while (sib.IsOk())
1997           {
1998             DicomNode* nsib = GetDicomNodeOfItem(sib);
1999             if (nsib>0) 
2000               {
2001                 //                      std::cout << "-- Request '"
2002                 //                                << nsib->GetFieldValue("FullFileName")
2003                 //                                << "' prio="<<prio<<std::endl;
2004                 mReader.Request(this,
2005                                 nsib->ImageGetFullFileName(), 
2006                                 prio);
2007                 mImageFileNameToNode[nsib->ImageGetFullFileName()] =
2008                   nsib;
2009                 prio--;
2010               }
2011             sib = GetTreeListCtrl()->GetPrevSibling(sib);
2012           }
2013         //              mImageFileNameToNode[n->GetFieldValue("FullFileName")] = n;
2014         max += 1000;
2015         
2016         ProcessImageEvents();
2017       }
2018     //  std::cout << "* Selection changed * (im)"<<std::endl;
2019
2020     //---------------------------------------------------------------------
2021     // Send event
2022     WxGimmickEvent ev(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGED,
2023                                     this,
2024                                     event.GetItem());
2025     
2026     GetEventHandler()->ProcessEvent(ev);
2027
2028     if (no_image) ShowImage(mReader.GetImage(""));
2029     
2030   }
2031   //================================================================
2032
2033   //================================================================
2034   void WxGimmick::ShowImage(vtkImageData* im)
2035   {
2036     //  wxBusyCursor busy;
2037     
2038     int x1,x2,y1,y2,z1,z2;
2039     double spx,spy,spz;
2040     im->GetSpacing(spx,spy,spz);
2041     im->GetExtent (x1,x2,y1,y2,z1,z2);
2042     
2043     /*
2044       std::cout << x1 << "-"<<x2<<std::endl; 
2045       std::cout << y1 << "-"<<y2<<std::endl; 
2046       std::cout << z1 << "-"<<z2<<std::endl; 
2047       std::cout << spx << "-"<<spy<<"-"<<spz<<std::endl; 
2048     */
2049     
2050     if ((x1!=mx1) ||
2051         (x2!=mx2) ||
2052         (y1!=my1) ||
2053         (y2!=my2) ||
2054         (z1!=mz1) ||
2055         (z2!=mz2) ||
2056         (spx!=mspx) ||
2057         (spy!=mspy) ||
2058         (spz!=mspz) 
2059         )
2060       {
2061         mx1 = x1;
2062         mx2 = x2;
2063         my1 = y1;
2064         my2 = y2;
2065         mz1 = z1;
2066         mz2 = z2;
2067         mspx = spx;
2068         mspy = spy;
2069         mspz = spz;
2070         
2071         vtkCamera *camera = mViewer->GetRenderer()->GetActiveCamera();
2072         
2073         camera->SetViewUp ( spx*0, -spy*1, spz*0);
2074         camera->SetPosition( spx*(x1+x2)/2, spy*(y1+y2)/2, -spz*10000000); 
2075         camera->SetFocalPoint   ( spx*(x1+x2)/2 , spy*(y1+y2)/2 , spz*0); 
2076         
2077         camera->ComputeViewPlaneNormal();
2078         camera->SetParallelScale(  spx*(x2-x1)/2.0 );
2079         
2080       }
2081     
2082     mViewer->SetInput( im );
2083     mViewer->SetSlice( 0 );
2084     mInteractor->Render();
2085   } 
2086   //================================================================
2087   
2088
2089
2090
2091
2092
2093   //================================================================
2094   void WxGimmick::
2095   OnMultiThreadImageReaderEvent(const std::string& filename,
2096                                 MultiThreadImageReaderUser::EventType e,
2097                                 vtkImageData* image)
2098   {
2099     if (filename.size()==0)
2100       {
2101         mImageEventQueue.push_back(ImageEventType(image));
2102         return;
2103       }
2104     std::map<std::string,DicomNode*>::iterator i;
2105     i = mImageFileNameToNode.find(filename);
2106     if (i!=mImageFileNameToNode.end())
2107       {
2108         wxTreeItemId id = i->second->GetData<NodeData*>()->GetTreeItemData()->GetItemId();
2109         mImageEventQueue.push_back(ImageEventType(id,image));
2110       }
2111   }
2112   //================================================================
2113
2114   //================================================================
2115   // Processes the queue of image events 
2116   void WxGimmick::ProcessImageEvents()
2117   {
2118     //    std::cout << "++++++++++ ProcessImageEvents " << std::endl;
2119     MultiThreadImageReaderEventLock();
2120
2121
2122     while (!mImageEventQueue.empty())
2123       {
2124         ImageEventType e = mImageEventQueue.front();
2125         mImageEventQueue.pop_front();
2126         if( e.image!=0 ) 
2127           {
2128             if (e.item.IsOk()) 
2129               {
2130                 mTreeListCtrl->SetItemTextColour(e.item,
2131                                                  mSettings.LoadedImageColour());//wxImageLoadedColour);
2132                 TreeItemData *data = 
2133                   (TreeItemData *)mTreeListCtrl->GetItemData(e.item);
2134                 data->SetLoaded(true);
2135
2136                 if (mCurImageItemToShow == e.item)
2137                   {
2138                     ShowImage(e.image);
2139                   }
2140               }
2141             else if (!mCurImageItemToShow.IsOk())
2142               {
2143                 ShowImage(e.image);
2144               }
2145           }
2146         else if (e.item.IsOk())
2147           {
2148             mTreeListCtrl->SetItemTextColour(e.item,mSettings.Colour(DicomNode::Image)); //.wxImageUnloadedColour);
2149             TreeItemData *data = 
2150               (TreeItemData *)mTreeListCtrl->GetItemData(e.item);
2151             data->SetLoaded(false);
2152           }
2153       }
2154     mImageEventQueue.clear();
2155     MultiThreadImageReaderEventUnlock();
2156     //    std::cout << "++++++++++ END ProcessImageEvents " << std::endl;
2157   }
2158   //================================================================
2159
2160   //================================================================
2161   void  WxGimmick::OnInternalIdle()
2162   {
2163     ProcessImageEvents();
2164     /*
2165     if (mJustStarted)
2166       {
2167
2168         mJustStarted = false;
2169         }
2170     */
2171     //
2172   }
2173   //================================================================
2174  
2175
2176   //================================================================
2177   // LG : For the moment any selection is valid but in the future 
2178   // incomplete selections can be invalid...
2179   bool WxGimmick::IsSelectionValid() 
2180   { 
2181     return (mTreeListCtrl->GetSelectionSize()>0); 
2182   } 
2183   //================================================================
2184
2185   //================================================================
2186   void WxGimmick::GetSelectedFiles(std::vector<std::string>& f)
2187   {
2188     wxArrayTreeItemIds id;
2189     // TO DO : TEST THAT STYLE IS MULTIPLE 
2190     unsigned int nb = mTreeListCtrl->GetSelections(id);
2191     f.clear();
2192     for (unsigned int i=0; i<nb; ++i)
2193       {
2194         TreeItemData *data = 
2195           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2196         if ((data) && (data->IsDicomNode()))
2197           {
2198             if (data->GetDicomNode()->GetType()==DicomNode::Image)
2199               {
2200                 f.push_back ( data->GetDicomNode()->ImageGetFullFileName() );
2201               }
2202             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2203               {
2204                 DicomNode::ChildrenListType::iterator j;
2205                 for (j =data->GetDicomNode()->GetChildrenList().begin();
2206                      j!=data->GetDicomNode()->GetChildrenList().end();
2207                      j++) 
2208                   {
2209                     f.push_back((*j)->ImageGetFullFileName());
2210                   }
2211               }
2212           }
2213       }
2214   }
2215   //================================================================
2216
2217   //================================================================
2218   void WxGimmick::GetSelectedImages(std::vector<vtkImageData*>& f)
2219   {
2220     wxArrayTreeItemIds id;
2221     // TO DO : TEST THAT STYLE IS MULTIPLE 
2222     unsigned int nb = mTreeListCtrl->GetSelections(id);
2223     f.clear();
2224
2225     // Collect the brute vector of Image nodes
2226     std::vector<DicomNode*> im;
2227     for (unsigned int i=0; i<nb; ++i)
2228       {
2229         TreeItemData *data = 
2230           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2231         if ((data) && (data->IsDicomNode()))
2232           {
2233             if (data->GetDicomNode()->GetType()==DicomNode::Image)
2234               {
2235                 im.push_back ( data->GetDicomNode() );
2236
2237               }
2238             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2239               {
2240                 DicomNode::ChildrenListType::iterator j;
2241                 for (j =data->GetDicomNode()->GetChildrenList().begin();
2242                      j!=data->GetDicomNode()->GetChildrenList().end();
2243                      j++) 
2244                   {
2245                     im.push_back ( *j );
2246                   }
2247               }
2248           }
2249       }
2250     // Create the output data
2251     if (im.size()==1) 
2252       {
2253         // Only one image : give it
2254         vtkImageData* out = vtkImageData::New();
2255         out->ShallowCopy(mReader.GetImage(im.front()->ImageGetFullFileName()));
2256         f.push_back( out );
2257       }
2258     else if (im.size()>1)
2259       {
2260         vtkImageData* first = mReader.GetImage( im.front()->ImageGetFullFileName() );
2261         if (first->GetDataDimension()==2) 
2262           {     
2263             // n2D to 3D
2264             vtkImageData* out = vtkImageData::New();
2265             out->CopyStructure(first);  
2266             out->SetScalarType(first->GetScalarType());
2267             int ext[6];
2268             first->GetExtent(ext);
2269             ext[5] = im.size();
2270             out->SetExtent(ext);
2271             // LG : TODO : Z Spacing  ?
2272             
2273             out->AllocateScalars();
2274             
2275             //first->Print(std::cout);
2276             //      out->Print(std::cout);
2277             
2278             int dim[3];
2279             first->GetDimensions(dim);
2280             unsigned long imsize = 
2281               ( (unsigned long)first->GetScalarPointer(0,1,0)
2282                 - (unsigned long)first->GetScalarPointer(0,0,0))
2283               *dim[1];
2284
2285             int slice = 0;
2286             std::vector<DicomNode*>::iterator it;
2287             for (it=im.begin(); it!=im.end(); ++it) 
2288               {
2289                 //std::cout << "copying slice "<<slice <<std::endl;
2290                 vtkImageData* cur = mReader.GetImage( (*it)->ImageGetFullFileName() );
2291                 
2292                 void* src = cur->GetScalarPointer(0,0,0);
2293                 void* dst = out->GetScalarPointer(0,0,slice);
2294                 //              std::cout << "src="<<src<<std::endl;
2295                 //              std::cout << "dst="<<dst<<std::endl;
2296                 //              std::cout << "siz="<<imsize<<std::endl;
2297                 memcpy(dst,src,imsize);
2298
2299                 /*
2300                 // verif
2301                 int ii,jj;
2302                 for (ii=1;ii<4;ii++) {
2303                   for (jj=1;jj<4;jj++) {
2304                     int x = (int)(ii*dim[0] / 4);
2305                     int y = (int)(jj*dim[1] / 4);
2306                     std::cout << cur->GetScalarComponentAsFloat(x,y,0,0)
2307                               << " vs "
2308                               << out->GetScalarComponentAsFloat(x,y,slice,0)
2309                               << std::endl;
2310                   }
2311                 }
2312                 */
2313
2314                 slice++;
2315               }
2316             f.push_back(out);
2317           }
2318         else 
2319           {
2320             // n3D
2321             std::vector<DicomNode*>::iterator it;
2322             for (it=im.begin(); it!=im.end(); ++it) 
2323               {
2324                 vtkImageData* out = vtkImageData::New();
2325                 out->ShallowCopy(mReader.GetImage((*it)->ImageGetFullFileName()));
2326                 f.push_back(out);
2327               }
2328           }
2329       }
2330   }
2331   //================================================================
2332
2333
2334   //================================================================
2335   void WxGimmick::GetSelectedDicomNodes(std::vector<DicomNode*>& f)
2336   {
2337     wxArrayTreeItemIds id;
2338     // TO DO : TEST THAT STYLE IS MULTIPLE 
2339     unsigned int nb = mTreeListCtrl->GetSelections(id);
2340     f.clear();
2341     for (unsigned int i=0; i<nb; ++i)
2342       {
2343         TreeItemData *data = 
2344           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2345         if ((data) && (data->IsDicomNode()))
2346           {
2347             f.push_back ( data->GetDicomNode() );
2348           }
2349         /*
2350
2351         if (data->GetDicomNode()->GetType()==DicomNode::Image)
2352         {
2353         f.push_back ( data->GetDicomNode() ); //->ImageGetFullFileName() );
2354         }  
2355         else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2356         {
2357         DicomNode::ChildrenListType::iterator j;
2358         for (j =data->GetDicomNode()->GetChildrenList().begin();
2359         j!=data->GetDicomNode()->GetChildrenList().end();
2360         j++) 
2361         {
2362         f.push_back((*j)); //->ImageGetFullFileName() );        }
2363         }
2364         }
2365         */
2366       }
2367   }
2368   //================================================================
2369
2370   //================================================================
2371   void WxGimmick::GetSelectedItems(std::vector<wxTreeItemId>& f)
2372   {
2373     wxArrayTreeItemIds id;
2374     // TO DO : TEST THAT STYLE IS MULTIPLE 
2375     unsigned int nb = mTreeListCtrl->GetSelections(id);
2376     f.clear();
2377     for (unsigned int i=0; i<nb; ++i)
2378       {
2379         f.push_back(id[i]);
2380       }
2381   }
2382   //================================================================
2383
2384   //================================================================
2385   DicomNode* WxGimmick::GetDicomNodeOfItem(const wxTreeItemId& i)
2386   {
2387     TreeItemData *data = 
2388       (TreeItemData *)mTreeListCtrl->GetItemData(i);
2389     if (data) return ( data->GetDicomNode() );
2390     return 0;
2391   }
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   BEGIN_EVENT_TABLE(WxGimmick, wxPanel)
2419   // POP UP MENU
2420     EVT_MENU(PopUp_NewCollection,WxGimmick::OnPopUpNewCollection)
2421     EVT_MENU(PopUp_OpenCollection,WxGimmick::OnPopUpOpenCollection)
2422     EVT_MENU(PopUp_CloseCollection,WxGimmick::OnPopUpCloseCollection)
2423     EVT_MENU(PopUp_DeleteCollection,WxGimmick::OnPopUpDeleteCollection)
2424     EVT_MENU(PopUp_AddFile, WxGimmick::OnPopUpAddFile)
2425     EVT_MENU(PopUp_AddRawFile, WxGimmick::OnPopUpAddRawFile)
2426     EVT_MENU(PopUp_AddDirectory, WxGimmick::OnPopUpAddDirectory)
2427     EVT_MENU(PopUp_Remove, WxGimmick::OnPopUpRemove)
2428     EVT_MENU(PopUp_About, WxGimmick::OnPopUpAbout)
2429     EVT_MENU(PopUp_Settings, WxGimmick::OnPopUpSettings)
2430     
2431     EVT_MENU_RANGE(PopUp_Sort, PopUp_Sort+99,  WxGimmick::OnPopUpSort)
2432     EVT_MENU_RANGE(PopUp_User, PopUp_User+99,  WxGimmick::OnPopUpUser)
2433     
2434     
2435     
2436   // DRAG
2437     EVT_TREE_BEGIN_DRAG(TreeListCtrlId, WxGimmick::OnBeginDrag)
2438     EVT_TREE_BEGIN_RDRAG(TreeListCtrlId, WxGimmick::OnBeginRDrag)
2439     EVT_TREE_END_DRAG(TreeListCtrlId, WxGimmick::OnEndDrag)
2440
2441   // LABEL
2442     EVT_TREE_BEGIN_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnBeginLabelEdit)
2443     EVT_TREE_END_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnEndLabelEdit)
2444
2445   //DELETE : UNUSED
2446     EVT_TREE_DELETE_ITEM(TreeListCtrlId, WxGimmick::OnDeleteItem)
2447 #if 0       // there are so many of those that logging them causes flicker
2448     EVT_TREE_GET_INFO(TreeListCtrlId, WxGimmick::OnGetInfo)
2449 #endif
2450   // UNUSED
2451     EVT_TREE_SET_INFO(TreeListCtrlId, WxGimmick::OnSetInfo)
2452
2453   // EXPAND/COLLAPSE
2454     EVT_TREE_ITEM_EXPANDED(TreeListCtrlId, WxGimmick::OnItemExpanded)
2455     EVT_TREE_ITEM_EXPANDING(TreeListCtrlId, WxGimmick::OnItemExpanding)
2456     EVT_TREE_ITEM_COLLAPSED(TreeListCtrlId, WxGimmick::OnItemCollapsed)
2457     EVT_TREE_ITEM_COLLAPSING(TreeListCtrlId, WxGimmick::OnItemCollapsing)
2458
2459   // SELECTION
2460     EVT_TREE_SEL_CHANGED(TreeListCtrlId, WxGimmick::OnSelChanged)
2461     EVT_TREE_SEL_CHANGING(TreeListCtrlId, WxGimmick::OnSelChanging)
2462   // KEY
2463     EVT_TREE_KEY_DOWN(TreeListCtrlId, WxGimmick::OnTreeKeyDown)
2464   // ACTIVATION = DOUBLE CLICK OR ENTER ON SELECTED
2465     EVT_TREE_ITEM_ACTIVATED(TreeListCtrlId, WxGimmick::OnItemActivated)
2466
2467   // so many differents ways to handle right mouse button clicks...
2468   //    EVT_CONTEXT_MENU(WxGimmick::OnContextMenu)
2469   // EVT_TREE_ITEM_MENU is the preferred event for creating context menus
2470   // on a tree control, because it includes the point of the click or item,
2471   // meaning that no additional placement calculations are required.
2472   //    EVT_TREE_ITEM_MENU(TreeListCtrlId, WxGimmick::OnItemMenu)
2473     
2474     EVT_TREE_ITEM_RIGHT_CLICK(TreeListCtrlId, WxGimmick::OnItemRightClick)
2475
2476   // UNUSED
2477   //    EVT_RIGHT_DOWN(WxGimmick::OnRMouseDown)
2478   //    EVT_RIGHT_UP(WxGimmick::OnRMouseUp)
2479   //    EVT_RIGHT_DCLICK(WxGimmick::OnRMouseDClick)
2480     END_EVENT_TABLE()
2481
2482   //IMPLEMENT_DYNAMIC_CLASS(WxGimmick, wxTreeListCtrl)
2483
2484   /*
2485     wxTree::wxTree(wxWindow *parent, const wxWindowID id,
2486     const wxPoint& pos, const wxSize& size,
2487     long style)
2488     : wxTreeListCtrl(parent, id, pos, size, style)
2489     {
2490     m_reverseSort = false;
2491
2492     CreateImageList();
2493
2494     // Add some items to the tree
2495     AddTestItemsToTree(5, 2);
2496     }
2497   */
2498
2499
2500
2501 #if USE_GENERIC_TREECTRL || !defined(__WXMSW__)
2502     void WxGimmick::CreateButtonsImageList(int size)
2503   {
2504     /*
2505       if ( size == -1 )
2506       {
2507       mTreeListCtrl->SetButtonsImageList(NULL);
2508       return;
2509       }
2510
2511       // Make an image list containing small icons
2512       wxImageList *images = new wxImageList(size, size, true);
2513
2514       // should correspond to TreeListCtrlIcon_xxx enum
2515       wxBusyCursor wait;
2516       wxIcon icons[4];
2517       icons[0] = wxIcon(icon3_xpm);   // closed
2518       icons[1] = wxIcon(icon3_xpm);   // closed, selected
2519       icons[2] = wxIcon(icon5_xpm);   // open
2520       icons[3] = wxIcon(icon5_xpm);   // open, selected
2521
2522       for ( size_t i = 0; i < WXSIZEOF(icons); i++ )
2523       {
2524       int sizeOrig = icons[i].GetWidth();
2525       if ( size == sizeOrig )
2526       {
2527       images->Add(icons[i]);
2528       }
2529       else
2530       {
2531       images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
2532       }
2533       }
2534
2535       mTreeListCtrl->AssignButtonsImageList(images);
2536     */
2537 #else
2538     void WxGimmick::CreateButtonsImageList(int WXUNUSED(size))
2539     {
2540 #endif
2541     }
2542
2543     /*
2544       int WxGimmick::OnCompareItems(const wxTreeItemId& item1,
2545       const wxTreeItemId& item2)
2546       {
2547       if ( m_reverseSort )
2548       {
2549       // just exchange 1st and 2nd items
2550       return mTreeListCtrl->OnCompareItems(item2, item1);
2551       }
2552       else
2553       {
2554       return mTreeListCtrl->OnCompareItems(item1, item2);
2555       }
2556       }
2557
2558
2559       void WxGimmick::DoToggleIcon(const wxTreeItemId& item)
2560       {
2561   
2562       int image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_Folder)
2563       ? TreeIcon_File
2564       : TreeIcon_Folder;
2565       mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Normal);
2566
2567       image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_FolderSelected)
2568       ? TreeIcon_FileSelected
2569       : TreeIcon_FolderSelected;
2570       mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Selected);
2571       }
2572
2573       void WxGimmick::LogEvent(const wxChar *name, const wxTreeEvent& event)
2574       {
2575       wxTreeItemId item = event.GetItem();
2576       wxString text;
2577       if ( item.IsOk() )
2578       text << _T('"') << mTreeListCtrl->GetItemText(item).c_str() << _T('"');
2579       else
2580       text = _T("invalid item");
2581       //    wxLogMessage(wxT("%s(%s)"), name, text.c_str());
2582       }
2583
2584     */
2585     // avoid repetition
2586 #define TREE_EVENT_HANDLER(name)                                \
2587     void WxGimmick::name(wxTreeEvent& event)    \
2588     {                                                           \
2589       /*    LogEvent(_T(#name), event); */                      \
2590       /*    SetLastItem(mTreeListCtrl->wxTreeItemId()) *;*/     \
2591       event.Skip();                                             \
2592     }
2593
2594     TREE_EVENT_HANDLER(OnBeginRDrag)
2595       TREE_EVENT_HANDLER(OnDeleteItem)
2596       TREE_EVENT_HANDLER(OnGetInfo)
2597       TREE_EVENT_HANDLER(OnSetInfo)
2598       //TREE_EVENT_HANDLER(OnItemExpanded)
2599       TREE_EVENT_HANDLER(OnItemExpanding)
2600       //TREE_EVENT_HANDLER(OnItemCollapsed)
2601       //TREE_EVENT_HANDLER(OnSelChanged)
2602       //      TREE_EVENT_HANDLER(OnSelChanging)
2603
2604
2605       void WxGimmick::OnItemCollapsed(wxTreeEvent& event)                   
2606       {
2607         //    std::cout << "* Collapsed *"<<std::endl;
2608       }
2609
2610 #undef TREE_EVENT_HANDLER
2611
2612     void WxGimmick::OnTreeKeyDown(wxTreeEvent& event)
2613     {
2614       /*
2615       //  LogKeyEvent(wxT("Tree key down "), event.GetKeyEvent());
2616       std::cout << "* Key down *"<<std::endl;
2617       if (event.GetKeyCode()==WXK_RIGHT)
2618         {
2619           std::cout << "Right"<<std::endl;
2620           wxTreeItemId itemId =  mTreeListCtrl->GetSelection();
2621           if (itemId.IsOk())
2622             {
2623               std::cout << "item is ok"<<std::endl;
2624               wxPoint clientpt = event.GetPoint();
2625               wxPoint screenpt = ClientToScreen(clientpt);
2626               ShowMenu(itemId, clientpt);
2627             }     
2628           event.Veto();
2629           return;
2630         }
2631       std::cout << "NOT Right"<<std::endl;
2632       */
2633       event.Skip();       
2634     }
2635
2636     void WxGimmick::OnBeginDrag(wxTreeEvent& event)
2637     {
2638       wxTreeItemId id = event.GetItem();
2639       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2640       //    std::cout << "OnBeginDrag("<<id<<")"<<std::endl;
2641       if (data->IsDatabase())
2642         {
2643           //      std::cout << "-- IS ROOT"<<std::endl;
2644           //  event.Allow();
2645         }
2646       else if (data->IsDicomNode())
2647         {
2648           //      std::cout << "-- IS NODE"<<std::endl;
2649         }
2650       /*
2651       // need to explicitly allow drag
2652       if ( event.GetItem() != GetDatabaseItem() )
2653       {
2654       m_draggedItem = event.GetItem();
2655
2656       wxPoint clientpt = event.GetPoint();
2657       wxPoint screenpt = ClientToScreen(clientpt);
2658
2659       wxLogMessage(wxT("OnBeginDrag: started dragging %s at screen coords (%i,%i)"),
2660       GetItemText(m_draggedItem).c_str(),
2661       screenpt.x, screenpt.y);
2662
2663       event.Allow();
2664       }
2665       else
2666       {
2667       wxLogMessage(wxT("OnBeginDrag: this item can't be dragged."));
2668       }
2669       */
2670     }
2671
2672     void WxGimmick::OnEndDrag(wxTreeEvent& event)
2673     {
2674       wxTreeItemId id = event.GetItem();
2675       //      std::cout << "OnEndDrag("<<id<<")"<<std::endl;
2676       if (!id.IsOk()) return;
2677       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2678       if (data->IsDatabase())
2679         {
2680           //      std::cout << "-- IS ROOT"<<std::endl;
2681         }
2682       else if (data->IsDicomNode())
2683         {
2684           //      std::cout << "-- IS NODE"<<std::endl;
2685         }
2686
2687       /*
2688         wxTreeItemId itemSrc = m_draggedItem,
2689         itemDst = event.GetItem();
2690         m_draggedItem = (wxTreeItemId)0l;
2691
2692         // where to copy the item?
2693         if ( itemDst.IsOk() && !ItemHasChildren(itemDst) )
2694         {
2695         // copy to the parent then
2696         itemDst = GetItemParent(itemDst);
2697         }
2698
2699         if ( !itemDst.IsOk() )
2700         {
2701         wxLogMessage(wxT("OnEndDrag: can't drop here."));
2702
2703         return;
2704         }
2705
2706         wxString text = GetItemText(itemSrc);
2707         wxLogMessage(wxT("OnEndDrag: '%s' copied to '%s'."),
2708         text.c_str(), GetItemText(itemDst).c_str());
2709
2710         // just do append here - we could also insert it just before/after the item
2711         // on which it was dropped, but this requires slightly more work... we also
2712         // completely ignore the client data and icon of the old item but could
2713         // copy them as well.
2714         //
2715         // Finally, we only copy one item here but we might copy the entire tree if
2716         // we were dragging a folder.
2717         int image = wxGetApp().ShowImages() ? TreeIcon_File : -1;
2718         AppendItem(itemDst, text, image);
2719       */
2720     }
2721
2722
2723     //====================================================================
2724     void WxGimmick::OnBeginLabelEdit(wxTreeEvent& event)
2725     {
2726       //      std::cout << "OnBeginLabelEdit"<<std::endl;
2727       wxTreeItemId id = event.GetItem();
2728       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2729       // If not a root : veto
2730       if (data->IsDatabase()) 
2731         { 
2732           event.Allow();
2733           return;
2734         }
2735       event.Veto();
2736     }
2737     //====================================================================
2738
2739     //====================================================================
2740     void WxGimmick::OnEndLabelEdit(wxTreeEvent& event)
2741     {
2742       //      std::cout << "OnEndLabelEdit"<<std::endl;
2743       wxTreeItemId id = event.GetItem();
2744       TreeItemData *data = GetItemData(id);
2745       // If not a database : bug !
2746       if (data->IsDatabase()) 
2747         { 
2748           data->GetDicomNode()->GetDicomDatabase()->SetName(wx2std(event.GetLabel()));
2749           mFieldsView->UpdateValues(data->GetDicomNode());
2750         }
2751       else
2752         {
2753           std::cerr<< "!!!! Internal error : send bug report !!!!"<<std::endl;
2754         }
2755     }
2756     //====================================================================
2757
2758
2759     void WxGimmick::OnItemCollapsing(wxTreeEvent& event)
2760     {
2761       //    wxLogMessage(wxT("OnItemCollapsing"));
2762
2763       // for testing, prevent the user from collapsing the first child folder
2764       wxTreeItemId itemId = event.GetItem();
2765
2766       /*
2767         if ( IsTestItem(itemId) )
2768         {
2769         wxMessageBox(wxT("You can't collapse this item."));
2770
2771         event.Veto();
2772         }
2773       */
2774     }
2775
2776
2777     //====================================================================
2778     void WxGimmick::ShowHelp()
2779     {
2780       /*
2781       if (mHelpWindow==0)
2782         {
2783           mHelpWindow = new WxGimmickHelpWindow(this);
2784         }
2785       mHelpWindow->CenterOnParent();
2786       mHelpWindow->ShowModal();
2787       */
2788     }
2789     //====================================================================
2790
2791
2792
2793
2794
2795     //================================================================
2796     //================================================================
2797     //================================================================
2798     //================================================================
2799     //================================================================
2800     // WxGimmickEvent
2801     //================================================================
2802     //================================================================
2803     //================================================================
2804     //================================================================
2805     //================================================================
2806
2807
2808
2809
2810
2811     // ----------------------------------------------------------------------------
2812     // events
2813     // ----------------------------------------------------------------------------
2814     /*
2815       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG)
2816       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG)
2817       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM)
2818       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO)
2819       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO)
2820       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED)
2821       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING)
2822       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
2823       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING)
2824     */
2825
2826     DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT)
2827       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT)
2828
2829
2830       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGED)
2831       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGING)
2832       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_KEY_DOWN)
2833       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_CONTEXTUAL_MENU)
2834       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_ITEM_STYLE_CHANGED)
2835       /*
2836         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED)
2837         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK)
2838         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK)
2839         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG)
2840         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK)
2841         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP)
2842         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU)
2843       */
2844       // ----------------------------------------------------------------------------
2845       // Tree event
2846       // ----------------------------------------------------------------------------
2847
2848       IMPLEMENT_ABSTRACT_CLASS(WxGimmickEvent, wxNotifyEvent)
2849   
2850   
2851       WxGimmickEvent::WxGimmickEvent(wxEventType commandType,
2852                                                                  WxGimmick *tree,
2853                                                                  const wxTreeItemId& item)
2854       : 
2855       wxNotifyEvent(commandType, tree->GetId()),
2856       m_item(item),
2857       mDicomNode(0)
2858         {
2859           //      m_editCancelled = false;
2860       
2861           SetEventObject(tree);
2862       
2863           if ( item.IsOk() )
2864             SetClientObject(tree->mTreeListCtrl->GetItemData(item));
2865         }
2866   
2867       WxGimmickEvent::WxGimmickEvent(wxEventType commandType, int id)
2868         : 
2869         wxNotifyEvent(commandType, id),
2870         mDicomNode(0)
2871           {
2872             m_itemOld = 0l;
2873             //      m_editCancelled = false;
2874           }
2875     
2876         WxGimmickEvent::WxGimmickEvent(const WxGimmickEvent & event)
2877           : 
2878           wxNotifyEvent(event),
2879           mDicomNode(0)
2880
2881             {
2882               m_evtKey = event.m_evtKey;
2883               m_item = event.m_item;
2884               m_itemOld = event.m_itemOld;
2885               mColor = event.mColor;
2886               mUserData = event.mUserData;
2887               //    m_pointDrag = event.m_pointDrag;
2888               //    m_label = event.m_label;
2889               //    m_editCancelled = event.m_editCancelled;
2890             }
2891       
2892       
2893
2894
2895
2896
2897
2898
2899           //================================================================
2900           //================================================================
2901           //================================================================
2902           //================================================================
2903           //================================================================
2904           WxGimmickFrame::WxGimmickFrame( wxWindow *parent, 
2905                                           wxString title, 
2906                                           wxSize size)
2907             : wxFrame((wxFrame *)parent, -1, title, wxDefaultPosition, size)
2908             {   
2909               wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
2910               mWxGimmick = new WxGimmick(this,-1,
2911                                          wxDefaultPosition,
2912                                          wxDefaultSize);
2913               sizer->Add(mWxGimmick,1,wxGROW);
2914               SetSizer(sizer);
2915               SetAutoLayout(true);
2916               Layout();
2917             }
2918             //================================================================
2919
2920             //================================================================
2921             WxGimmickFrame::~WxGimmickFrame()
2922               {
2923               }
2924             //================================================================
2925
2926             //================================================================
2927             void WxGimmickFrame::OnSelChanged(WxGimmickEvent& event)
2928             {
2929               //    std::cout << "+++++ WxGimmickFrame::OnSelChanged ++++++++++"
2930               //              <<std::endl;
2931               std::vector<std::string> file;
2932               //    mWxGimmick->GetSelectedImages(file);
2933               /*
2934                 std::vector<std::string>::iterator i;
2935                 for (i=file.begin();i!=file.end();++i)
2936                 {
2937                 std::cout << "'" << *i << "'" << std::endl;
2938                 }
2939                 std::cout << "++++++++++++++++++++" << std::endl;
2940               */
2941             }
2942             //================================================================
2943
2944             //================================================================
2945             BEGIN_EVENT_TABLE(WxGimmickFrame, wxFrame)
2946               EVT_TREEVIEWLIST_SEL_CHANGED(-1,WxGimmickFrame::OnSelChanged)
2947               END_EVENT_TABLE()
2948               //================================================================
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   }