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