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