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