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