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