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