]> Creatis software - creaImageIO.git/blob - src/creaImageIOWxGimmick.cpp
c009da4542d6729abe43a3a7cd3c626f3a7599b1
[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             out->AllocateScalars();
2310             
2311             //first->Print(std::cout);
2312             //      out->Print(std::cout);
2313             
2314             int dim[3];
2315             first->GetDimensions(dim);
2316             unsigned long imsize = 
2317               ( (unsigned long)first->GetScalarPointer(0,1,0)
2318                 - (unsigned long)first->GetScalarPointer(0,0,0))
2319               *dim[1];
2320
2321             int slice = 0;
2322             std::vector<DicomNode*>::iterator it;
2323             for (it=im.begin(); it!=im.end(); ++it) 
2324               {
2325                 //std::cout << "copying slice "<<slice <<std::endl;
2326                 vtkImageData* cur = mReader.GetImage( (*it)->ImageGetFullFileName() );
2327                 
2328                 void* src = cur->GetScalarPointer(0,0,0);
2329                 void* dst = out->GetScalarPointer(0,0,slice);
2330                 //              std::cout << "src="<<src<<std::endl;
2331                 //              std::cout << "dst="<<dst<<std::endl;
2332                 //              std::cout << "siz="<<imsize<<std::endl;
2333                 memcpy(dst,src,imsize);
2334
2335                 /*
2336                 // verif
2337                 int ii,jj;
2338                 for (ii=1;ii<4;ii++) {
2339                   for (jj=1;jj<4;jj++) {
2340                     int x = (int)(ii*dim[0] / 4);
2341                     int y = (int)(jj*dim[1] / 4);
2342                     std::cout << cur->GetScalarComponentAsFloat(x,y,0,0)
2343                               << " vs "
2344                               << out->GetScalarComponentAsFloat(x,y,slice,0)
2345                               << std::endl;
2346                   }
2347                 }
2348                 */
2349
2350                 slice++;
2351               }
2352             f.push_back(out);
2353           }
2354         else 
2355           {
2356             // n3D
2357             std::vector<DicomNode*>::iterator it;
2358             for (it=im.begin(); it!=im.end(); ++it) 
2359               {
2360                 vtkImageData* out = vtkImageData::New();
2361                 out->ShallowCopy(mReader.GetImage((*it)->ImageGetFullFileName()));
2362                 f.push_back(out);
2363               }
2364           }
2365       }
2366   }
2367   //================================================================
2368
2369
2370   //================================================================
2371   void WxGimmick::GetSelectedDicomNodes(std::vector<DicomNode*>& f)
2372   {
2373     wxArrayTreeItemIds id;
2374     // TO DO : TEST THAT STYLE IS MULTIPLE 
2375     unsigned int nb = mTreeListCtrl->GetSelections(id);
2376     f.clear();
2377     for (unsigned int i=0; i<nb; ++i)
2378       {
2379         TreeItemData *data = 
2380           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2381         if ((data) && (data->IsDicomNode()))
2382           {
2383             f.push_back ( data->GetDicomNode() );
2384           }
2385         /*
2386
2387         if (data->GetDicomNode()->GetType()==DicomNode::Image)
2388         {
2389         f.push_back ( data->GetDicomNode() ); //->ImageGetFullFileName() );
2390         }  
2391         else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2392         {
2393         DicomNode::ChildrenListType::iterator j;
2394         for (j =data->GetDicomNode()->GetChildrenList().begin();
2395         j!=data->GetDicomNode()->GetChildrenList().end();
2396         j++) 
2397         {
2398         f.push_back((*j)); //->ImageGetFullFileName() );        }
2399         }
2400         }
2401         */
2402       }
2403   }
2404   //================================================================
2405
2406   //================================================================
2407   void WxGimmick::GetSelectedItems(std::vector<wxTreeItemId>& f)
2408   {
2409     wxArrayTreeItemIds id;
2410     // TO DO : TEST THAT STYLE IS MULTIPLE 
2411     unsigned int nb = mTreeListCtrl->GetSelections(id);
2412     f.clear();
2413     for (unsigned int i=0; i<nb; ++i)
2414       {
2415         f.push_back(id[i]);
2416       }
2417   }
2418   //================================================================
2419
2420   //================================================================
2421   DicomNode* WxGimmick::GetDicomNodeOfItem(const wxTreeItemId& i)
2422   {
2423     TreeItemData *data = 
2424       (TreeItemData *)mTreeListCtrl->GetItemData(i);
2425     if (data) return ( data->GetDicomNode() );
2426     return 0;
2427   }
2428   //================================================================
2429
2430   //================================================================
2431   //================================================================
2432   //================================================================
2433   //================================================================
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449   //================================================================
2450   //================================================================
2451   //================================================================
2452   //================================================================
2453   
2454   BEGIN_EVENT_TABLE(WxGimmick, wxPanel)
2455   // POP UP MENU
2456     EVT_MENU(PopUp_NewCollection,WxGimmick::OnPopUpNewCollection)
2457     EVT_MENU(PopUp_OpenCollection,WxGimmick::OnPopUpOpenCollection)
2458     EVT_MENU(PopUp_CloseCollection,WxGimmick::OnPopUpCloseCollection)
2459     EVT_MENU(PopUp_DeleteCollection,WxGimmick::OnPopUpDeleteCollection)
2460     EVT_MENU(PopUp_AddFile, WxGimmick::OnPopUpAddFile)
2461     EVT_MENU(PopUp_AddRawFile, WxGimmick::OnPopUpAddRawFile)
2462     EVT_MENU(PopUp_AddDirectory, WxGimmick::OnPopUpAddDirectory)
2463     EVT_MENU(PopUp_Remove, WxGimmick::OnPopUpRemove)
2464     EVT_MENU(PopUp_About, WxGimmick::OnPopUpAbout)
2465     EVT_MENU(PopUp_Settings, WxGimmick::OnPopUpSettings)
2466     
2467     EVT_MENU_RANGE(PopUp_Sort, PopUp_Sort+99,  WxGimmick::OnPopUpSort)
2468     EVT_MENU_RANGE(PopUp_User, PopUp_User+99,  WxGimmick::OnPopUpUser)
2469     
2470     
2471     
2472   // DRAG
2473     EVT_TREE_BEGIN_DRAG(TreeListCtrlId, WxGimmick::OnBeginDrag)
2474     EVT_TREE_BEGIN_RDRAG(TreeListCtrlId, WxGimmick::OnBeginRDrag)
2475     EVT_TREE_END_DRAG(TreeListCtrlId, WxGimmick::OnEndDrag)
2476
2477   // LABEL
2478     EVT_TREE_BEGIN_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnBeginLabelEdit)
2479     EVT_TREE_END_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnEndLabelEdit)
2480
2481   //DELETE : UNUSED
2482     EVT_TREE_DELETE_ITEM(TreeListCtrlId, WxGimmick::OnDeleteItem)
2483 #if 0       // there are so many of those that logging them causes flicker
2484     EVT_TREE_GET_INFO(TreeListCtrlId, WxGimmick::OnGetInfo)
2485 #endif
2486   // UNUSED
2487     EVT_TREE_SET_INFO(TreeListCtrlId, WxGimmick::OnSetInfo)
2488
2489   // EXPAND/COLLAPSE
2490     EVT_TREE_ITEM_EXPANDED(TreeListCtrlId, WxGimmick::OnItemExpanded)
2491     EVT_TREE_ITEM_EXPANDING(TreeListCtrlId, WxGimmick::OnItemExpanding)
2492     EVT_TREE_ITEM_COLLAPSED(TreeListCtrlId, WxGimmick::OnItemCollapsed)
2493     EVT_TREE_ITEM_COLLAPSING(TreeListCtrlId, WxGimmick::OnItemCollapsing)
2494
2495   // SELECTION
2496     EVT_TREE_SEL_CHANGED(TreeListCtrlId, WxGimmick::OnSelChanged)
2497     EVT_TREE_SEL_CHANGING(TreeListCtrlId, WxGimmick::OnSelChanging)
2498   // KEY
2499     EVT_TREE_KEY_DOWN(TreeListCtrlId, WxGimmick::OnTreeKeyDown)
2500   // ACTIVATION = DOUBLE CLICK OR ENTER ON SELECTED
2501     EVT_TREE_ITEM_ACTIVATED(TreeListCtrlId, WxGimmick::OnItemActivated)
2502
2503   // so many differents ways to handle right mouse button clicks...
2504   //    EVT_CONTEXT_MENU(WxGimmick::OnContextMenu)
2505   // EVT_TREE_ITEM_MENU is the preferred event for creating context menus
2506   // on a tree control, because it includes the point of the click or item,
2507   // meaning that no additional placement calculations are required.
2508   //    EVT_TREE_ITEM_MENU(TreeListCtrlId, WxGimmick::OnItemMenu)
2509     
2510     EVT_TREE_ITEM_RIGHT_CLICK(TreeListCtrlId, WxGimmick::OnItemRightClick)
2511
2512   // UNUSED
2513   //    EVT_RIGHT_DOWN(WxGimmick::OnRMouseDown)
2514   //    EVT_RIGHT_UP(WxGimmick::OnRMouseUp)
2515   //    EVT_RIGHT_DCLICK(WxGimmick::OnRMouseDClick)
2516     END_EVENT_TABLE()
2517
2518   //IMPLEMENT_DYNAMIC_CLASS(WxGimmick, wxTreeListCtrl)
2519
2520   /*
2521     wxTree::wxTree(wxWindow *parent, const wxWindowID id,
2522     const wxPoint& pos, const wxSize& size,
2523     long style)
2524     : wxTreeListCtrl(parent, id, pos, size, style)
2525     {
2526     m_reverseSort = false;
2527
2528     CreateImageList();
2529
2530     // Add some items to the tree
2531     AddTestItemsToTree(5, 2);
2532     }
2533   */
2534
2535
2536
2537 #if USE_GENERIC_TREECTRL || !defined(__WXMSW__)
2538     void WxGimmick::CreateButtonsImageList(int size)
2539   {
2540     /*
2541       if ( size == -1 )
2542       {
2543       mTreeListCtrl->SetButtonsImageList(NULL);
2544       return;
2545       }
2546
2547       // Make an image list containing small icons
2548       wxImageList *images = new wxImageList(size, size, true);
2549
2550       // should correspond to TreeListCtrlIcon_xxx enum
2551       wxBusyCursor wait;
2552       wxIcon icons[4];
2553       icons[0] = wxIcon(icon3_xpm);   // closed
2554       icons[1] = wxIcon(icon3_xpm);   // closed, selected
2555       icons[2] = wxIcon(icon5_xpm);   // open
2556       icons[3] = wxIcon(icon5_xpm);   // open, selected
2557
2558       for ( size_t i = 0; i < WXSIZEOF(icons); i++ )
2559       {
2560       int sizeOrig = icons[i].GetWidth();
2561       if ( size == sizeOrig )
2562       {
2563       images->Add(icons[i]);
2564       }
2565       else
2566       {
2567       images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
2568       }
2569       }
2570
2571       mTreeListCtrl->AssignButtonsImageList(images);
2572     */
2573 #else
2574     void WxGimmick::CreateButtonsImageList(int WXUNUSED(size))
2575     {
2576 #endif
2577     }
2578
2579     /*
2580       int WxGimmick::OnCompareItems(const wxTreeItemId& item1,
2581       const wxTreeItemId& item2)
2582       {
2583       if ( m_reverseSort )
2584       {
2585       // just exchange 1st and 2nd items
2586       return mTreeListCtrl->OnCompareItems(item2, item1);
2587       }
2588       else
2589       {
2590       return mTreeListCtrl->OnCompareItems(item1, item2);
2591       }
2592       }
2593
2594
2595       void WxGimmick::DoToggleIcon(const wxTreeItemId& item)
2596       {
2597   
2598       int image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_Folder)
2599       ? TreeIcon_File
2600       : TreeIcon_Folder;
2601       mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Normal);
2602
2603       image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_FolderSelected)
2604       ? TreeIcon_FileSelected
2605       : TreeIcon_FolderSelected;
2606       mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Selected);
2607       }
2608
2609       void WxGimmick::LogEvent(const wxChar *name, const wxTreeEvent& event)
2610       {
2611       wxTreeItemId item = event.GetItem();
2612       wxString text;
2613       if ( item.IsOk() )
2614       text << _T('"') << mTreeListCtrl->GetItemText(item).c_str() << _T('"');
2615       else
2616       text = _T("invalid item");
2617       //    wxLogMessage(wxT("%s(%s)"), name, text.c_str());
2618       }
2619
2620     */
2621     // avoid repetition
2622 #define TREE_EVENT_HANDLER(name)                                \
2623     void WxGimmick::name(wxTreeEvent& event)    \
2624     {                                                           \
2625       /*    LogEvent(_T(#name), event); */                      \
2626       /*    SetLastItem(mTreeListCtrl->wxTreeItemId()) *;*/     \
2627       event.Skip();                                             \
2628     }
2629
2630     TREE_EVENT_HANDLER(OnBeginRDrag)
2631       TREE_EVENT_HANDLER(OnDeleteItem)
2632       TREE_EVENT_HANDLER(OnGetInfo)
2633       TREE_EVENT_HANDLER(OnSetInfo)
2634       //TREE_EVENT_HANDLER(OnItemExpanded)
2635       TREE_EVENT_HANDLER(OnItemExpanding)
2636       //TREE_EVENT_HANDLER(OnItemCollapsed)
2637       //TREE_EVENT_HANDLER(OnSelChanged)
2638       //      TREE_EVENT_HANDLER(OnSelChanging)
2639
2640
2641       void WxGimmick::OnItemCollapsed(wxTreeEvent& event)                   
2642       {
2643         //    std::cout << "* Collapsed *"<<std::endl;
2644       }
2645
2646 #undef TREE_EVENT_HANDLER
2647
2648     void WxGimmick::OnTreeKeyDown(wxTreeEvent& event)
2649     {
2650       /*
2651       //  LogKeyEvent(wxT("Tree key down "), event.GetKeyEvent());
2652       std::cout << "* Key down *"<<std::endl;
2653       if (event.GetKeyCode()==WXK_RIGHT)
2654         {
2655           std::cout << "Right"<<std::endl;
2656           wxTreeItemId itemId =  mTreeListCtrl->GetSelection();
2657           if (itemId.IsOk())
2658             {
2659               std::cout << "item is ok"<<std::endl;
2660               wxPoint clientpt = event.GetPoint();
2661               wxPoint screenpt = ClientToScreen(clientpt);
2662               ShowMenu(itemId, clientpt);
2663             }     
2664           event.Veto();
2665           return;
2666         }
2667       std::cout << "NOT Right"<<std::endl;
2668       */
2669       event.Skip();       
2670     }
2671
2672     void WxGimmick::OnBeginDrag(wxTreeEvent& event)
2673     {
2674       wxTreeItemId id = event.GetItem();
2675       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2676       //    std::cout << "OnBeginDrag("<<id<<")"<<std::endl;
2677       if (data->IsDatabase())
2678         {
2679           //      std::cout << "-- IS ROOT"<<std::endl;
2680           //  event.Allow();
2681         }
2682       else if (data->IsDicomNode())
2683         {
2684           //      std::cout << "-- IS NODE"<<std::endl;
2685         }
2686       /*
2687       // need to explicitly allow drag
2688       if ( event.GetItem() != GetDatabaseItem() )
2689       {
2690       m_draggedItem = event.GetItem();
2691
2692       wxPoint clientpt = event.GetPoint();
2693       wxPoint screenpt = ClientToScreen(clientpt);
2694
2695       wxLogMessage(wxT("OnBeginDrag: started dragging %s at screen coords (%i,%i)"),
2696       GetItemText(m_draggedItem).c_str(),
2697       screenpt.x, screenpt.y);
2698
2699       event.Allow();
2700       }
2701       else
2702       {
2703       wxLogMessage(wxT("OnBeginDrag: this item can't be dragged."));
2704       }
2705       */
2706     }
2707
2708     void WxGimmick::OnEndDrag(wxTreeEvent& event)
2709     {
2710       wxTreeItemId id = event.GetItem();
2711       //      std::cout << "OnEndDrag("<<id<<")"<<std::endl;
2712       if (!id.IsOk()) return;
2713       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2714       if (data->IsDatabase())
2715         {
2716           //      std::cout << "-- IS ROOT"<<std::endl;
2717         }
2718       else if (data->IsDicomNode())
2719         {
2720           //      std::cout << "-- IS NODE"<<std::endl;
2721         }
2722
2723       /*
2724         wxTreeItemId itemSrc = m_draggedItem,
2725         itemDst = event.GetItem();
2726         m_draggedItem = (wxTreeItemId)0l;
2727
2728         // where to copy the item?
2729         if ( itemDst.IsOk() && !ItemHasChildren(itemDst) )
2730         {
2731         // copy to the parent then
2732         itemDst = GetItemParent(itemDst);
2733         }
2734
2735         if ( !itemDst.IsOk() )
2736         {
2737         wxLogMessage(wxT("OnEndDrag: can't drop here."));
2738
2739         return;
2740         }
2741
2742         wxString text = GetItemText(itemSrc);
2743         wxLogMessage(wxT("OnEndDrag: '%s' copied to '%s'."),
2744         text.c_str(), GetItemText(itemDst).c_str());
2745
2746         // just do append here - we could also insert it just before/after the item
2747         // on which it was dropped, but this requires slightly more work... we also
2748         // completely ignore the client data and icon of the old item but could
2749         // copy them as well.
2750         //
2751         // Finally, we only copy one item here but we might copy the entire tree if
2752         // we were dragging a folder.
2753         int image = wxGetApp().ShowImages() ? TreeIcon_File : -1;
2754         AppendItem(itemDst, text, image);
2755       */
2756     }
2757
2758
2759     //====================================================================
2760     void WxGimmick::OnBeginLabelEdit(wxTreeEvent& event)
2761     {
2762       //      std::cout << "OnBeginLabelEdit"<<std::endl;
2763       wxTreeItemId id = event.GetItem();
2764       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2765       // If not a root : veto
2766       if (data->IsDatabase()) 
2767         { 
2768           event.Allow();
2769           return;
2770         }
2771       event.Veto();
2772     }
2773     //====================================================================
2774
2775     //====================================================================
2776     void WxGimmick::OnEndLabelEdit(wxTreeEvent& event)
2777     {
2778       //      std::cout << "OnEndLabelEdit"<<std::endl;
2779       wxTreeItemId id = event.GetItem();
2780       TreeItemData *data = GetItemData(id);
2781       // If not a database : bug !
2782       if (data->IsDatabase()) 
2783         { 
2784           data->GetDicomNode()->GetDicomDatabase()->SetName(wx2std(event.GetLabel()));
2785           mFieldsView->UpdateValues(data->GetDicomNode());
2786         }
2787       else
2788         {
2789           std::cerr<< "!!!! Internal error : send bug report !!!!"<<std::endl;
2790         }
2791     }
2792     //====================================================================
2793
2794
2795     void WxGimmick::OnItemCollapsing(wxTreeEvent& event)
2796     {
2797       //    wxLogMessage(wxT("OnItemCollapsing"));
2798
2799       // for testing, prevent the user from collapsing the first child folder
2800       wxTreeItemId itemId = event.GetItem();
2801
2802       /*
2803         if ( IsTestItem(itemId) )
2804         {
2805         wxMessageBox(wxT("You can't collapse this item."));
2806
2807         event.Veto();
2808         }
2809       */
2810     }
2811
2812
2813     //====================================================================
2814     void WxGimmick::ShowHelp()
2815     {
2816       /*
2817       if (mHelpWindow==0)
2818         {
2819           mHelpWindow = new WxGimmickHelpWindow(this);
2820         }
2821       mHelpWindow->CenterOnParent();
2822       mHelpWindow->ShowModal();
2823       */
2824     }
2825     //====================================================================
2826
2827
2828
2829
2830
2831     //================================================================
2832     //================================================================
2833     //================================================================
2834     //================================================================
2835     //================================================================
2836     // WxGimmickEvent
2837     //================================================================
2838     //================================================================
2839     //================================================================
2840     //================================================================
2841     //================================================================
2842
2843
2844
2845
2846
2847     // ----------------------------------------------------------------------------
2848     // events
2849     // ----------------------------------------------------------------------------
2850     /*
2851       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG)
2852       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG)
2853       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM)
2854       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO)
2855       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO)
2856       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED)
2857       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING)
2858       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
2859       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING)
2860     */
2861
2862     DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT)
2863       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT)
2864
2865
2866       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGED)
2867       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGING)
2868       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_KEY_DOWN)
2869       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_CONTEXTUAL_MENU)
2870       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_ITEM_STYLE_CHANGED)
2871       /*
2872         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED)
2873         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK)
2874         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK)
2875         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG)
2876         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK)
2877         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP)
2878         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU)
2879       */
2880       // ----------------------------------------------------------------------------
2881       // Tree event
2882       // ----------------------------------------------------------------------------
2883
2884       IMPLEMENT_ABSTRACT_CLASS(WxGimmickEvent, wxNotifyEvent)
2885   
2886   
2887       WxGimmickEvent::WxGimmickEvent(wxEventType commandType,
2888                                                                  WxGimmick *tree,
2889                                                                  const wxTreeItemId& item)
2890       : 
2891       wxNotifyEvent(commandType, tree->GetId()),
2892       m_item(item),
2893       mDicomNode(0)
2894         {
2895           //      m_editCancelled = false;
2896       
2897           SetEventObject(tree);
2898       
2899           if ( item.IsOk() )
2900             SetClientObject(tree->mTreeListCtrl->GetItemData(item));
2901         }
2902   
2903       WxGimmickEvent::WxGimmickEvent(wxEventType commandType, int id)
2904         : 
2905         wxNotifyEvent(commandType, id),
2906         mDicomNode(0)
2907           {
2908             m_itemOld = 0l;
2909             //      m_editCancelled = false;
2910           }
2911     
2912         WxGimmickEvent::WxGimmickEvent(const WxGimmickEvent & event)
2913           : 
2914           wxNotifyEvent(event),
2915           mDicomNode(0)
2916
2917             {
2918               m_evtKey = event.m_evtKey;
2919               m_item = event.m_item;
2920               m_itemOld = event.m_itemOld;
2921               mColor = event.mColor;
2922               mUserData = event.mUserData;
2923               //    m_pointDrag = event.m_pointDrag;
2924               //    m_label = event.m_label;
2925               //    m_editCancelled = event.m_editCancelled;
2926             }
2927       
2928       
2929
2930
2931
2932
2933
2934
2935           //================================================================
2936           //================================================================
2937           //================================================================
2938           //================================================================
2939           //================================================================
2940           WxGimmickFrame::WxGimmickFrame( wxWindow *parent, 
2941                                           wxString title, 
2942                                           wxSize size)
2943             : wxFrame((wxFrame *)parent, -1, title, wxDefaultPosition, size)
2944             {   
2945               wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
2946               mWxGimmick = new WxGimmick(this,-1,
2947                                          wxDefaultPosition,
2948                                          wxDefaultSize);
2949               sizer->Add(mWxGimmick,1,wxGROW);
2950               SetSizer(sizer);
2951               SetAutoLayout(true);
2952               Layout();
2953             }
2954             //================================================================
2955
2956             //================================================================
2957             WxGimmickFrame::~WxGimmickFrame()
2958               {
2959               }
2960             //================================================================
2961
2962             //================================================================
2963             void WxGimmickFrame::OnSelChanged(WxGimmickEvent& event)
2964             {
2965               //    std::cout << "+++++ WxGimmickFrame::OnSelChanged ++++++++++"
2966               //              <<std::endl;
2967               std::vector<std::string> file;
2968               //    mWxGimmick->GetSelectedImages(file);
2969               /*
2970                 std::vector<std::string>::iterator i;
2971                 for (i=file.begin();i!=file.end();++i)
2972                 {
2973                 std::cout << "'" << *i << "'" << std::endl;
2974                 }
2975                 std::cout << "++++++++++++++++++++" << std::endl;
2976               */
2977             }
2978             //================================================================
2979
2980             //================================================================
2981             BEGIN_EVENT_TABLE(WxGimmickFrame, wxFrame)
2982               EVT_TREEVIEWLIST_SEL_CHANGED(-1,WxGimmickFrame::OnSelChanged)
2983               END_EVENT_TABLE()
2984               //================================================================
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007             
3008
3009
3010
3011   }