]> Creatis software - creaImageIO.git/blob - src/creaImageIOWxGimmick.cpp
6a203a37d3d5bd05f5c92f5333d1829f38052259
[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             /*
1294             std::string str("&Remove ");
1295             str += data->GetDicomNode()->GetTypeName();
1296             menu.Append(PopUp_Remove, std2wx(str));
1297             */
1298           }
1299       
1300         if ((data->GetDicomNode()>0)&&
1301             ( data->GetDicomNode()->GetType()<DicomNode::Image))
1302           {
1303             int ctype = data->GetDicomNode()->GetType()+1;
1304             if (mSettings.HasActiveComparator(ctype))
1305               {
1306                 wxMenu* sortmenu = new wxMenu;
1307                 int n = 0;
1308                 Settings::ComparatorsList::iterator i;
1309                 for (i =mSettings.GetComparatorsList(ctype).begin();
1310                      i !=mSettings.GetComparatorsList(ctype).end();
1311                      ++i)
1312                   {
1313                     sortmenu->AppendRadioItem(PopUp_Sort+n, std2wx(i->GetName()));
1314                     n++;
1315                   }    
1316               
1317                 sortmenu->Check(PopUp_Sort+
1318                                 mSettings.GetActiveComparatorIndex(ctype)
1319                                 ,true);
1320               
1321                 std::string sortmenustr("&Sort ");
1322                 sortmenustr += DicomNode::GetPluralTypeName(ctype);
1323                 sortmenustr += " by...";
1324                 if (menu.GetMenuItemCount()>0) menu.AppendSeparator();
1325                 menu.AppendSubMenu(sortmenu,std2wx(sortmenustr));
1326               
1327                 /*
1328                   item->GetDicomNode()->SortChildren
1329                   ( mSettings.GetActiveComparator
1330                   (item->GetDicomNode()->GetType()+1)
1331                   );
1332                   std::cout << "ok"<<std::endl;
1333                 */
1334               }
1335           }
1336       }
1337     // Event : user can customize the menu 
1338     WxGimmickEvent 
1339       ev(wxEVT_COMMAND_TREEVIEWLIST_CONTEXTUAL_MENU,this,id);
1340     ev.SetMenu(&menu);
1341     if (data)
1342       {
1343         ev.SetDicomNode(data->GetDicomNode());
1344       }
1345     GetEventHandler()->ProcessEvent(ev);
1346     //
1347   
1348     if (menu.GetMenuItemCount()>0) menu.AppendSeparator();
1349     menu.Append(PopUp_Settings, wxT("&Settings..."));
1350     menu.Append(PopUp_About, wxT("&About..."));
1351   
1352
1353   
1354     /*
1355       wxMenu* newmenu = new wxMenu;
1356       wxMenu* openmenu = new wxMenu;
1357       Tree::RootHandlerListType::iterator h;
1358       int i=0;
1359       for (h= Tree::GetRootHandlerList().begin();
1360       h!=Tree::GetRootHandlerList().end();
1361       h++)
1362       {
1363       if ((*h)->SupportsNew()) 
1364       {
1365       newmenu->Append(PopUp_New+i, std2wx((*h)->GetName()));
1366       }
1367       if ((*h)->SupportsOpen()) 
1368       openmenu->Append(PopUp_Open+i, std2wx((*h)->GetName()));
1369       i++;
1370       }
1371     
1372       menu.AppendSubMenu(openmenu, _T("&Open"));
1373       menu.AppendSubMenu(newmenu, _T("&New"));
1374
1375       if (data)
1376       { 
1377       if ((data->IsDatabase())||(data->IsDicomNode()))
1378       {
1379       Root* itroot = data->GetDicomNode()->GetDicomDatabase();
1380       //        if (!itroot) itroot = data->GetDicomNode()->GetRoot();
1381       wxMenu* insertmenu = new wxMenu;
1382       bool hasone = false;
1383       i = 0;
1384       Tree::RootListType::iterator j;
1385       for (j  = mTree->GetDatabaseList().begin();
1386       j != mTree->GetDatabaseList().end();
1387       j++)
1388       {
1389       //            std::cout << (*j)->GetName() << " " 
1390       //                      <<  (*j)->GetTypeName()
1391       //                      << " i="<<(*j)->SupportsInsert()<<std::endl;
1392       if ( ((*j)!=itroot) && ((*j)->SupportsInsert()) ) 
1393       {
1394       insertmenu->Append(PopUp_Insert+i, 
1395       std2wx((*j)->GetName()));
1396       hasone = true;
1397       }
1398       i++;
1399       }
1400             
1401       if (hasone) menu.AppendSubMenu(insertmenu, _T("&Insert into"));
1402       }
1403       if (data->IsDatabase())
1404       {
1405       menu.Append(PopUp_Close, wxT("&Close"));
1406       }
1407       if (data->IsDicomNode() && data->GetDicomNode()->GetDicomDatabase()->SupportsRemove())
1408       {
1409       menu.Append(PopUp_Remove, wxT("&Remove"));
1410       }
1411       }
1412     */
1413
1414  
1415
1416  
1417     PopupMenu(&menu, pt);
1418 #endif // wxUSE_MENUS
1419
1420     //    std::cout << "EO ShowMenu" <<std::endl;
1421   }
1422   //=====================================================================
1423
1424   //=====================================================================
1425   // Pop up menu callbacks
1426   void  WxGimmick::OnPopUpAbout(wxCommandEvent& event)
1427   {
1428     wxMessageBox( _T("Give me my medical images quick ! \n\n  (c) CREATIS-LRMN 2008\n      laurent.guigues@creatis.insa-lyon.fr"),
1429                   _T("Gimmick!"),
1430                   wxOK | wxICON_INFORMATION, this);
1431   }
1432   //=====================================================================
1433
1434   //=====================================================================
1435   void  WxGimmick::OnPopUpSettings(wxCommandEvent& event)
1436   {
1437     WxGimmickSettingsDialog* s = 
1438       new WxGimmickSettingsDialog(this);
1439     s->ShowModal();
1440     delete s;
1441   }
1442   //=====================================================================
1443
1444   //=====================================================================
1445   void  WxGimmick::OnPopUpNewCollection(wxCommandEvent& event)
1446   {
1447     wxBusyCursor busy;
1448     OpenOrNewDatabase(false);
1449   }
1450   //=====================================================================
1451   
1452
1453  
1454   //=====================================================================
1455   void  WxGimmick::OnPopUpOpenCollection(wxCommandEvent& event)
1456   {
1457     wxBusyCursor busy;
1458     OpenOrNewDatabase(true);
1459   }
1460   //=====================================================================
1461
1462
1463   //=====================================================================
1464   void  WxGimmick::OnPopUpCloseCollection(wxCommandEvent& event)
1465   {
1466     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;
1467    
1468     wxBusyCursor busy;
1469     //   std::cout << "OnPopUpClose"<<std::endl;
1470     //  wxTreeItemId id = event.GetId();
1471     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1472     DicomDatabase* r = data->GetDicomNode()->GetDicomDatabase();
1473     //   std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1474     DeleteDicomDatabase(mItemOfMenu,r);
1475   }
1476   //=====================================================================
1477
1478   //=====================================================================
1479   void  WxGimmick::OnPopUpDeleteCollection(wxCommandEvent& event)
1480   {
1481     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;
1482     
1483     wxBusyCursor busy;
1484
1485    
1486     //   std::cout << "OnPopUpClose"<<std::endl;
1487     //  wxTreeItemId id = event.GetId();
1488     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1489     DicomDatabase* r = data->GetDicomNode()->GetDicomDatabase();
1490
1491     wxRemoveFile(std2wx(r->GetFileName()));
1492     //   std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1493     DeleteDicomDatabase(mItemOfMenu,r);
1494     
1495   }
1496   //=====================================================================
1497   
1498   void DisplayUpdateSummary( DicomDatabase::UpdateSummary& summary,
1499                              wxWindow* parent )
1500   {
1501     std::stringstream mess;
1502     mess << "Dirs\tscanned\t\t\t: " << summary.scanned_dirs << "\n";
1503     mess << "Files\tscanned\t\t\t: " << summary.scanned_files << "\n";
1504     mess << "Files\thandled\t\t\t: " << summary.handled_images << "\n\n";
1505     mess << "Patients\tadded\t\t: " << summary.added_patients<< "\n";
1506     mess << "Studies\tadded\t\t: " << summary.added_studies<< "\n";
1507     mess << "Series\tadded\t\t: " << summary.added_series<< "\n";
1508     mess << "Images\tadded\t\t: " << summary.added_images<< "\n\n";
1509     char times[500];
1510     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",
1511             summary.parse_time,
1512             (int)( summary.parse_time*100./summary.total_time),
1513             summary.file_scan_time,
1514             (int)(summary.file_scan_time*100./summary.total_time),
1515             summary.update_structs_time,
1516             (int)(summary.update_structs_time*100./summary.total_time),
1517             summary.update_database_time,
1518             (int)(summary.update_database_time*100./summary.total_time),
1519             summary.total_time );
1520     
1521     mess << times;
1522     
1523     wxMessageBox(std2wx(mess.str()),_T("Update summary"),wxOK,parent);
1524   }
1525   
1526   
1527   //=====================================================================
1528   void  WxGimmick::OnPopUpAddFile(wxCommandEvent& event)
1529   {
1530     long style = wxOPEN | wxFILE_MUST_EXIST | wxFD_MULTIPLE;
1531     std::string wc("*.*");
1532     wxFileDialog* FD = new wxFileDialog( 0, 
1533                                          _T("Select file"),
1534                                          mCurrentDirectory,
1535                                          _T(""),
1536                                          std2wx(wc),
1537                                          style,
1538                                          wxDefaultPosition);
1539     
1540     if (FD->ShowModal()==wxID_OK)
1541       {
1542         wxBusyCursor busy;
1543
1544         mCurrentDirectory = FD->GetDirectory();
1545         wxArrayString files;
1546         FD->GetPaths(files);
1547         unsigned int i;
1548         std::vector<std::string> filenames;
1549         for (i=0;i<files.GetCount();++i)
1550           filenames.push_back(wx2std(files[i]));
1551
1552        
1553         TreeItemData *data = 
1554           (TreeItemData *)
1555           mTreeListCtrl->GetItemData(mItemOfMenu);
1556         DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1557         DicomDatabase::UpdateSummary summary;
1558         wxProgressDialog* progress = 
1559           new wxProgressDialog(_T("Adding file(s)"),
1560                                _T(""),
1561                                1000,
1562                                this,
1563                                wxPD_ELAPSED_TIME |
1564                                wxPD_ESTIMATED_TIME | 
1565                                wxPD_REMAINING_TIME |
1566                                wxPD_CAN_ABORT );
1567        
1568         db->AddFiles(filenames,progress,summary);
1569         
1570         progress->Pulse(_T("Updating view..."));
1571         UpdateDicomDatabaseView(db);
1572         delete progress;
1573         DisplayUpdateSummary(summary,this);
1574       }
1575   
1576   }
1577   //=====================================================================
1578
1579   //=====================================================================
1580   void  WxGimmick::OnPopUpAddRawFile(wxCommandEvent& event)
1581   {
1582     wxMessageBox(_T("Not yet implemented !"),_T("Sorry"),wxOK,this);
1583   }
1584   //=====================================================================
1585
1586   //=====================================================================
1587   void  WxGimmick::OnPopUpAddDirectory(wxCommandEvent& event)
1588   {
1589     long style = wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST;
1590     wxDirDialog* FD = 
1591       new wxDirDialog( 0, 
1592                        _T("Select directory"),
1593                        mCurrentDirectory,
1594                        style);
1595    
1596     if (FD->ShowModal()==wxID_OK)
1597       {
1598
1599         bool recurse = false;
1600         if (wxMessageBox(_T("Recurse into sub-directories ?"),
1601                          _T("Scan directory"),
1602                          wxYES_NO,this ) == wxYES)
1603           {
1604             recurse = true;
1605           }
1606        
1607         wxBusyCursor busy;
1608         wxProgressDialog* progress = 
1609           new wxProgressDialog(_T("Scanning directory"),
1610                                _T("Parsing directory"),
1611                                1000,
1612                                this,
1613                                wxPD_ELAPSED_TIME |
1614                                wxPD_ESTIMATED_TIME | 
1615                                wxPD_REMAINING_TIME |
1616                                wxPD_CAN_ABORT );
1617         DicomDatabase::UpdateSummary summary;
1618
1619         std::string dirname = wx2std (FD->GetPath()) ;
1620         mCurrentDirectory = FD->GetPath();
1621         TreeItemData *data = 
1622           (TreeItemData *)
1623           mTreeListCtrl->GetItemData(mItemOfMenu);
1624         DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1625         db->AddDirectory(dirname,recurse,progress,summary);
1626
1627         progress->Pulse(_T("Updating view..."));
1628         UpdateDicomDatabaseView(db);
1629
1630         delete progress;    
1631         DisplayUpdateSummary(summary,this);
1632         /*    
1633               if (summary.cancelled_by_user)
1634               {
1635               std::cout << "!! Cancelled by user !!"<<std::endl;
1636               }
1637         */
1638
1639       }
1640   }
1641   //=====================================================================
1642
1643   //=====================================================================
1644   void  WxGimmick::OnPopUpRemove(wxCommandEvent& event)
1645   {
1646
1647     /*
1648       wxMessageBox(_T("Not yet implemented"),_T("Sorry !"),wxOK);
1649       return;
1650     */
1651
1652     //  wxTreeItemId id = event.GetId();
1653     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1654
1655     std::string mess("Remove ");
1656     mess += data->GetDicomNode()->GetTypeName();
1657     mess += " from collection ?";
1658     int answer = wxMessageBox(std2wx(mess), _T("Confirm"), wxYES_NO);
1659     if (answer == wxNO) return;
1660    
1661     if ( mTreeListCtrl->IsSelected(mItemOfMenu) )
1662       {
1663         wxTreeItemId next = mTreeListCtrl->GetNextSibling(mItemOfMenu);
1664         if (next.IsOk()) 
1665           {
1666             mTreeListCtrl->SelectItem(next);
1667           }
1668         else 
1669           {
1670             return;
1671           }
1672       }
1673
1674     DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1675     db->Remove(data->GetDicomNode());
1676     //   std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1677     // TODO : Optimize update only parent's branch
1678     UpdateDicomDatabaseView(db);
1679     //   DeleteDicomDatabase(mItemOfMenu,r);
1680   }
1681   //=====================================================================
1682
1683   //=====================================================================
1684   void  WxGimmick::OnPopUpSort(wxCommandEvent& event)
1685   {
1686     wxBusyCursor busy;
1687     //    std::cout << "OnPopUpSort"<<std::endl;
1688     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1689     int index = event.GetId() - PopUp_Sort;
1690     DicomNode* node = data->GetDicomNode();
1691     DicomNode::Type ctype = node->GetType()+1;
1692     mSettings.SetActiveComparatorIndex(ctype,index);
1693
1694     if (node->ChildrenLoaded())
1695       {
1696         // Remove children
1697         mTreeListCtrl->DeleteChildren(mItemOfMenu);
1698
1699         /*      std::cout << "Sorting using '"
1700           << mSettings.GetActiveComparator(ctype).GetName() 
1701           << "' ... ";
1702         */
1703         node->SortChildren ( mSettings.GetActiveComparator(ctype) );
1704         //      std::cout << "ok"<<std::endl;
1705
1706         
1707         // Update tree
1708         CreateChildrenColumnsTitles(mItemOfMenu,ctype);
1709         DicomNode::ChildrenListType::iterator i;
1710         for (i=node->GetChildrenList().begin();
1711              i!=node->GetChildrenList().end();
1712              i++)
1713           {
1714             UpdateDicomNodeView(*i,mItemOfMenu);
1715           }
1716       }
1717   }
1718   //=====================================================================
1719
1720
1721   //=====================================================================
1722   void  WxGimmick::OnPopUpUser(wxCommandEvent& event)
1723   {
1724     //    std::cout << "OnPopUpUser"<<std::endl;
1725     event.Skip();
1726   }
1727   //=====================================================================
1728
1729   //=================================================
1730   void WxGimmick::CreateImageList(int size)
1731   {
1732     if ( size == -1 )
1733       {
1734         mTreeListCtrl->SetImageList(NULL);
1735         return;
1736       }
1737     if ( size == 0 )
1738       size = m_imageSize;
1739     else
1740       m_imageSize = size;
1741     
1742     wxIcon icons[20];
1743     // should correspond to Icon_xxx enum
1744     icons[Icon_Patient] = wxIcon(patient_xpm);
1745     icons[Icon_Study] = wxIcon(study_xpm);
1746     icons[Icon_Series] = wxIcon(series_xpm);
1747     icons[Icon_Image] = wxIcon(image_xpm);
1748     icons[Icon_Database] = wxIcon(database_xpm);
1749     icons[Icon_Folder] = wxIcon(folder_xpm);
1750     icons[Icon_DicomDir] = wxIcon(dicomdir_xpm);
1751     icons[Icon_Root] = wxIcon(root_xpm);
1752
1753
1754     //    mFirstRootIconIndex = 8;
1755     //    int i=0;
1756     /*
1757       Tree::RootHandlerListType::iterator h;
1758
1759       for (h= Tree::GetDatabaseHandlerList().begin();
1760       h!=Tree::GetDatabaseHandlerList().end();
1761       h++)
1762       {
1763       icons[mFirstRootIconIndex+i] = (*h)->GetIcon();
1764       i++;
1765       }
1766     */
1767     unsigned int NbIcons = 8;//mFirstRootIconIndex + i;
1768     // Make an image list containing small icons
1769     wxImageList *images = new wxImageList(size, size, true);
1770     
1771     int sizeOrig = icons[0].GetWidth();
1772     for ( size_t i = 0; i < NbIcons; i++ )
1773       {
1774         if ( size == sizeOrig )
1775           {
1776             images->Add(icons[i]);
1777           }
1778         else
1779           {
1780             images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
1781           }
1782       }
1783     mTreeListCtrl->AssignImageList(images);
1784   }
1785   //=================================================
1786
1787
1788
1789
1790
1791
1792
1793
1794   //================================================================
1795   bool WxGimmick::IsImageSelectable(DicomNode* node)                   
1796   {
1797     int rows = node->ImageGetRows();
1798     int cols = node->ImageGetColumns();
1799     int frms = node->ImageGetFrames();
1800     
1801     //    std::cout << "R/C/F = " << rows << "/"<< cols <<"/"<<frms<<std::endl;
1802
1803     int dim = 0;
1804     if (frms>0) dim=3;
1805     else if (cols>0) dim=2;
1806     else if (rows>0) dim=1;
1807     
1808     if (dim == 0) 
1809       {
1810         std::cout << "Unknown image dimension : cannot select !" 
1811                   << std::endl;
1812         return false;
1813       }
1814     else if (dim>mSelectionMaxImageDimension)
1815       {
1816         std::cout << "Selecting "<<dim<<"D images is not allowed !" 
1817                   << std::endl;
1818         return false;
1819       }
1820     
1821     if ( mTreeListCtrl->GetSelectionSize() == 0 ) 
1822       {
1823         mCurrentSelectionImageSize[0] = cols;
1824         mCurrentSelectionImageSize[1] = rows;
1825         mCurrentSelectionImageSize[2] = frms;
1826         return true;
1827       }
1828     else 
1829       {
1830         if ( dim == mSelectionMaxImageDimension )
1831           {
1832             std::cout << "Cannot add this image to selection : would result in a "<<dim+1<<"D image !" << std::endl;
1833             return false;
1834           }
1835         if ( ( cols != mCurrentSelectionImageSize[0] ) ||
1836              ( rows != mCurrentSelectionImageSize[1] ) ||
1837              ( frms != mCurrentSelectionImageSize[2] ) )
1838           {
1839             std::cout << "Cannot add this image to selection : image size is incomptatible with currently selected images" << std::endl; 
1840             return false;
1841           }
1842       }
1843     //    std::cout << "Selecting : "<<node->ImageGetFullFileName() << std::endl;
1844     return true;
1845   }
1846   //================================================================
1847
1848   //================================================================
1849   void WxGimmick::OnSelChanging(wxTreeEvent& event)                   
1850   {
1851     event.Veto();
1852     wxTreeItemId id = event.GetItem();
1853     if (!id.IsOk()) 
1854       {
1855         std::cout << "INTERNAL ERROR : ID NOT OK"<<std::endl;
1856         return;
1857       }
1858
1859
1860     TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
1861     if (data->IsDicomNode())
1862       {
1863         if (data->GetDicomNode()>0)
1864           {
1865             // An image was selected 
1866             if (data->GetDicomNode()->GetType()==DicomNode::Image)
1867               {
1868                 if (IsImageSelectable(data->GetDicomNode())) event.Allow();
1869               }
1870             // A series was selected 
1871             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
1872               {
1873                 // If images not loaded do it 
1874                 LoadChildren(id);
1875                 // can be selected if all its images can
1876                 wxTreeItemId child;
1877                 wxTreeItemIdValue cookie;
1878                 for (child = mTreeListCtrl->GetFirstChild(id,cookie);
1879                      child.IsOk();
1880                      child = mTreeListCtrl->GetNextChild(id,cookie))
1881                   {    
1882                     TreeItemData *cdata = 
1883                       (TreeItemData *)mTreeListCtrl->GetItemData(child);
1884                     if ((cdata->IsDicomNode())&&
1885                         (cdata->GetDicomNode()>0)&&
1886                         (cdata->GetDicomNode()->GetType()==DicomNode::Image)&&
1887                         (!IsImageSelectable(cdata->GetDicomNode())))
1888                       return;
1889                   }
1890                 event.Allow();
1891               }
1892           }
1893       }
1894   }
1895   //================================================================
1896
1897   //================================================================
1898   void WxGimmick::OnSelChanged(wxTreeEvent& event)                   
1899   {
1900     //    wxBusyCursor busy;
1901     //    std::vector<wxTreeItemId> items;
1902     //    GetSelectedItems(items);
1903     /*
1904       std::vector<DicomNode*>::iterator i;
1905       for (i=nodes.begin();i!=nodes.end();++i)
1906       {
1907       std::cout << "'" << (*i)->GetFieldValue("FullFileName") 
1908       << "'" << std::endl;
1909       }
1910       std::cout << "++++++++++++++++++++" << std::endl;
1911     */
1912     //    ShowImage(mReader.GetImage(""));
1913
1914      bool no_image = true;
1915
1916     static int max = 1000;
1917
1918     
1919     //    if (items.size()>0) 
1920     //      {
1921
1922         // Update image preview : send requests to the MTImageReader
1923     //  bool first = true;
1924     //  std::vector<wxTreeItemId>::iterator i;
1925     //  for (i=items.begin();i!=items.end();++i)
1926     //    {
1927
1928             /*
1929             if (first)
1930               {
1931                 DicomNode* node = GetDicomNodeOfItem(items[0]);
1932                 if (!node) return;
1933                 // Update dicom fields panel
1934                 mFieldsView->UpdateValues(node);
1935               }
1936             */
1937
1938     wxTreeItemId item =  mTreeListCtrl->GetCurrent();
1939     
1940     DicomNode* n = GetDicomNodeOfItem(item);
1941
1942     if (n) mFieldsView->UpdateValues(n);    
1943
1944     if ( (n!=0) &&
1945          (n->GetType()==DicomNode::Image) )
1946       {
1947
1948         //                
1949         no_image = false;
1950         //if (i==items.begin()) 
1951         mCurImageItemToShow = item;
1952         
1953         int maxprio = mReader.GetMaximalPriority();
1954         int prio = maxprio + 1000;
1955         wxTreeItemId sib = item; //GetTreeListCtrl()->GetNextSibling(*i);
1956         while (sib.IsOk())
1957           {
1958             DicomNode* nsib = GetDicomNodeOfItem(sib);
1959             if (nsib>0) 
1960               {
1961                 //                      std::cout << "-- Request '"
1962                 //                                << nsib->GetFieldValue("FullFileName")
1963                 //                                << "' prio="<<prio<<std::endl;
1964                 mReader.Request(this,
1965                                 nsib->ImageGetFullFileName(), 
1966                                 prio);
1967                 mImageFileNameToNode[nsib->ImageGetFullFileName()] =
1968                   nsib;
1969                 prio--;
1970               }
1971             sib = GetTreeListCtrl()->GetNextSibling(sib);
1972           }
1973         prio = maxprio + 1000;
1974         sib = GetTreeListCtrl()->GetPrevSibling(item);
1975         while (sib.IsOk())
1976           {
1977             DicomNode* nsib = GetDicomNodeOfItem(sib);
1978             if (nsib>0) 
1979               {
1980                 //                      std::cout << "-- Request '"
1981                 //                                << nsib->GetFieldValue("FullFileName")
1982                 //                                << "' prio="<<prio<<std::endl;
1983                 mReader.Request(this,
1984                                 nsib->ImageGetFullFileName(), 
1985                                 prio);
1986                 mImageFileNameToNode[nsib->ImageGetFullFileName()] =
1987                   nsib;
1988                 prio--;
1989               }
1990             sib = GetTreeListCtrl()->GetPrevSibling(sib);
1991           }
1992         //              mImageFileNameToNode[n->GetFieldValue("FullFileName")] = n;
1993         max += 1000;
1994         
1995         ProcessImageEvents();
1996       }
1997     //  std::cout << "* Selection changed * (im)"<<std::endl;
1998
1999     //---------------------------------------------------------------------
2000     // Send event
2001     WxGimmickEvent ev(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGED,
2002                                     this,
2003                                     event.GetItem());
2004     
2005     GetEventHandler()->ProcessEvent(ev);
2006
2007     if (no_image) ShowImage(mReader.GetImage(""));
2008     
2009   }
2010   //================================================================
2011
2012   //================================================================
2013   void WxGimmick::ShowImage(vtkImageData* im)
2014   {
2015     //  wxBusyCursor busy;
2016     
2017     int x1,x2,y1,y2,z1,z2;
2018     double spx,spy,spz;
2019     im->GetSpacing(spx,spy,spz);
2020     im->GetExtent (x1,x2,y1,y2,z1,z2);
2021     
2022     /*
2023       std::cout << x1 << "-"<<x2<<std::endl; 
2024       std::cout << y1 << "-"<<y2<<std::endl; 
2025       std::cout << z1 << "-"<<z2<<std::endl; 
2026       std::cout << spx << "-"<<spy<<"-"<<spz<<std::endl; 
2027     */
2028     
2029     if ((x1!=mx1) ||
2030         (x2!=mx2) ||
2031         (y1!=my1) ||
2032         (y2!=my2) ||
2033         (z1!=mz1) ||
2034         (z2!=mz2) ||
2035         (spx!=mspx) ||
2036         (spy!=mspy) ||
2037         (spz!=mspz) 
2038         )
2039       {
2040         mx1 = x1;
2041         mx2 = x2;
2042         my1 = y1;
2043         my2 = y2;
2044         mz1 = z1;
2045         mz2 = z2;
2046         mspx = spx;
2047         mspy = spy;
2048         mspz = spz;
2049         
2050         vtkCamera *camera = mViewer->GetRenderer()->GetActiveCamera();
2051         
2052         camera->SetViewUp ( spx*0, -spy*1, spz*0);
2053         camera->SetPosition( spx*(x1+x2)/2, spy*(y1+y2)/2, -spz*10000000); 
2054         camera->SetFocalPoint   ( spx*(x1+x2)/2 , spy*(y1+y2)/2 , spz*0); 
2055         
2056         camera->ComputeViewPlaneNormal();
2057         camera->SetParallelScale(  spx*(x2-x1)/2.0 );
2058         
2059       }
2060     
2061     mViewer->SetInput( im );
2062     mViewer->SetSlice( 0 );
2063     mInteractor->Render();
2064   } 
2065   //================================================================
2066   
2067
2068
2069
2070
2071
2072   //================================================================
2073   void WxGimmick::
2074   OnMultiThreadImageReaderEvent(const std::string& filename,
2075                                 MultiThreadImageReaderUser::EventType e,
2076                                 vtkImageData* image)
2077   {
2078     if (filename.size()==0)
2079       {
2080         mImageEventQueue.push_back(ImageEventType(image));
2081         return;
2082       }
2083     std::map<std::string,DicomNode*>::iterator i;
2084     i = mImageFileNameToNode.find(filename);
2085     if (i!=mImageFileNameToNode.end())
2086       {
2087         wxTreeItemId id = i->second->GetData<NodeData*>()->GetTreeItemData()->GetItemId();
2088         mImageEventQueue.push_back(ImageEventType(id,image));
2089       }
2090   }
2091   //================================================================
2092
2093   //================================================================
2094   // Processes the queue of image events 
2095   void WxGimmick::ProcessImageEvents()
2096   {
2097     //    std::cout << "++++++++++ ProcessImageEvents " << std::endl;
2098     MultiThreadImageReaderEventLock();
2099
2100
2101     while (!mImageEventQueue.empty())
2102       {
2103         ImageEventType e = mImageEventQueue.front();
2104         mImageEventQueue.pop_front();
2105         if( e.image!=0 ) 
2106           {
2107             if (e.item.IsOk()) 
2108               {
2109                 mTreeListCtrl->SetItemTextColour(e.item,
2110                                                  mSettings.LoadedImageColour());//wxImageLoadedColour);
2111                 TreeItemData *data = 
2112                   (TreeItemData *)mTreeListCtrl->GetItemData(e.item);
2113                 data->SetLoaded(true);
2114
2115                 if (mCurImageItemToShow == e.item)
2116                   {
2117                     ShowImage(e.image);
2118                   }
2119               }
2120             else if (!mCurImageItemToShow.IsOk())
2121               {
2122                 ShowImage(e.image);
2123               }
2124           }
2125         else if (e.item.IsOk())
2126           {
2127             mTreeListCtrl->SetItemTextColour(e.item,mSettings.Colour(DicomNode::Image)); //.wxImageUnloadedColour);
2128             TreeItemData *data = 
2129               (TreeItemData *)mTreeListCtrl->GetItemData(e.item);
2130             data->SetLoaded(false);
2131           }
2132       }
2133     mImageEventQueue.clear();
2134     MultiThreadImageReaderEventUnlock();
2135     //    std::cout << "++++++++++ END ProcessImageEvents " << std::endl;
2136   }
2137   //================================================================
2138
2139   //================================================================
2140   void  WxGimmick::OnInternalIdle()
2141   {
2142     ProcessImageEvents();
2143     if (mJustStarted)
2144       {
2145         // Show tip if no collection
2146         if (GetDicomDatabaseList().size()==0)
2147           {
2148             ShowHelp();
2149           }
2150         mJustStarted = false;
2151       }
2152     //
2153   }
2154   //================================================================
2155  
2156
2157   //================================================================
2158   // LG : For the moment any selection is valid but in the future 
2159   // incomplete selections can be invalid...
2160   bool WxGimmick::IsSelectionValid() 
2161   { 
2162     return (mTreeListCtrl->GetSelectionSize()>0); 
2163   } 
2164   //================================================================
2165
2166   //================================================================
2167   void WxGimmick::GetSelectedFiles(std::vector<std::string>& f)
2168   {
2169     wxArrayTreeItemIds id;
2170     // TO DO : TEST THAT STYLE IS MULTIPLE 
2171     unsigned int nb = mTreeListCtrl->GetSelections(id);
2172     f.clear();
2173     for (unsigned int i=0; i<nb; ++i)
2174       {
2175         TreeItemData *data = 
2176           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2177         if ((data) && (data->IsDicomNode()))
2178           {
2179             if (data->GetDicomNode()->GetType()==DicomNode::Image)
2180               {
2181                 f.push_back ( data->GetDicomNode()->ImageGetFullFileName() );
2182               }
2183             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2184               {
2185                 DicomNode::ChildrenListType::iterator j;
2186                 for (j =data->GetDicomNode()->GetChildrenList().begin();
2187                      j!=data->GetDicomNode()->GetChildrenList().end();
2188                      j++) 
2189                   {
2190                     f.push_back((*j)->ImageGetFullFileName());
2191                   }
2192               }
2193           }
2194       }
2195   }
2196   //================================================================
2197
2198   //================================================================
2199   void WxGimmick::GetSelectedImages(std::vector<vtkImageData*>& f)
2200   {
2201     wxArrayTreeItemIds id;
2202     // TO DO : TEST THAT STYLE IS MULTIPLE 
2203     unsigned int nb = mTreeListCtrl->GetSelections(id);
2204     f.clear();
2205
2206     // Collect the brute vector of Image nodes
2207     std::vector<DicomNode*> im;
2208     for (unsigned int i=0; i<nb; ++i)
2209       {
2210         TreeItemData *data = 
2211           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2212         if ((data) && (data->IsDicomNode()))
2213           {
2214             if (data->GetDicomNode()->GetType()==DicomNode::Image)
2215               {
2216                 im.push_back ( data->GetDicomNode() );
2217
2218               }
2219             else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2220               {
2221                 DicomNode::ChildrenListType::iterator j;
2222                 for (j =data->GetDicomNode()->GetChildrenList().begin();
2223                      j!=data->GetDicomNode()->GetChildrenList().end();
2224                      j++) 
2225                   {
2226                     im.push_back ( *j );
2227                   }
2228               }
2229           }
2230       }
2231     // Create the output data
2232     if (im.size()==1) 
2233       {
2234         // Only one image : give it
2235         vtkImageData* out = vtkImageData::New();
2236         out->ShallowCopy(mReader.GetImage(im.front()->ImageGetFullFileName()));
2237         f.push_back( out );
2238       }
2239     else if (im.size()>1)
2240       {
2241         vtkImageData* first = mReader.GetImage( im.front()->ImageGetFullFileName() );
2242         if (first->GetDataDimension()==2) 
2243           {     
2244             // n2D to 3D
2245             vtkImageData* out = vtkImageData::New();
2246             out->CopyStructure(first);  
2247             out->SetScalarType(first->GetScalarType());
2248             int ext[6];
2249             first->GetExtent(ext);
2250             ext[5] = im.size();
2251             out->SetExtent(ext);
2252             // LG : TODO : Z Spacing  ?
2253             
2254             out->AllocateScalars();
2255             
2256             //first->Print(std::cout);
2257             //      out->Print(std::cout);
2258             
2259             int dim[3];
2260             first->GetDimensions(dim);
2261             unsigned long imsize = 
2262               ( (unsigned long)first->GetScalarPointer(0,1,0)
2263                 - (unsigned long)first->GetScalarPointer(0,0,0))
2264               *dim[1];
2265
2266             int slice = 0;
2267             std::vector<DicomNode*>::iterator it;
2268             for (it=im.begin(); it!=im.end(); ++it) 
2269               {
2270                 //std::cout << "copying slice "<<slice <<std::endl;
2271                 vtkImageData* cur = mReader.GetImage( (*it)->ImageGetFullFileName() );
2272                 
2273                 void* src = cur->GetScalarPointer(0,0,0);
2274                 void* dst = out->GetScalarPointer(0,0,slice);
2275                 //              std::cout << "src="<<src<<std::endl;
2276                 //              std::cout << "dst="<<dst<<std::endl;
2277                 //              std::cout << "siz="<<imsize<<std::endl;
2278                 memcpy(dst,src,imsize);
2279
2280                 /*
2281                 // verif
2282                 int ii,jj;
2283                 for (ii=1;ii<4;ii++) {
2284                   for (jj=1;jj<4;jj++) {
2285                     int x = (int)(ii*dim[0] / 4);
2286                     int y = (int)(jj*dim[1] / 4);
2287                     std::cout << cur->GetScalarComponentAsFloat(x,y,0,0)
2288                               << " vs "
2289                               << out->GetScalarComponentAsFloat(x,y,slice,0)
2290                               << std::endl;
2291                   }
2292                 }
2293                 */
2294
2295                 slice++;
2296               }
2297             f.push_back(out);
2298           }
2299         else 
2300           {
2301             // n3D
2302             std::vector<DicomNode*>::iterator it;
2303             for (it=im.begin(); it!=im.end(); ++it) 
2304               {
2305                 vtkImageData* out = vtkImageData::New();
2306                 out->ShallowCopy(mReader.GetImage((*it)->ImageGetFullFileName()));
2307                 f.push_back(out);
2308               }
2309           }
2310       }
2311   }
2312   //================================================================
2313
2314
2315   //================================================================
2316   void WxGimmick::GetSelectedDicomNodes(std::vector<DicomNode*>& f)
2317   {
2318     wxArrayTreeItemIds id;
2319     // TO DO : TEST THAT STYLE IS MULTIPLE 
2320     unsigned int nb = mTreeListCtrl->GetSelections(id);
2321     f.clear();
2322     for (unsigned int i=0; i<nb; ++i)
2323       {
2324         TreeItemData *data = 
2325           (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2326         if ((data) && (data->IsDicomNode()))
2327           {
2328             f.push_back ( data->GetDicomNode() );
2329           }
2330         /*
2331
2332         if (data->GetDicomNode()->GetType()==DicomNode::Image)
2333         {
2334         f.push_back ( data->GetDicomNode() ); //->ImageGetFullFileName() );
2335         }  
2336         else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2337         {
2338         DicomNode::ChildrenListType::iterator j;
2339         for (j =data->GetDicomNode()->GetChildrenList().begin();
2340         j!=data->GetDicomNode()->GetChildrenList().end();
2341         j++) 
2342         {
2343         f.push_back((*j)); //->ImageGetFullFileName() );        }
2344         }
2345         }
2346         */
2347       }
2348   }
2349   //================================================================
2350
2351   //================================================================
2352   void WxGimmick::GetSelectedItems(std::vector<wxTreeItemId>& f)
2353   {
2354     wxArrayTreeItemIds id;
2355     // TO DO : TEST THAT STYLE IS MULTIPLE 
2356     unsigned int nb = mTreeListCtrl->GetSelections(id);
2357     f.clear();
2358     for (unsigned int i=0; i<nb; ++i)
2359       {
2360         f.push_back(id[i]);
2361       }
2362   }
2363   //================================================================
2364
2365   //================================================================
2366   DicomNode* WxGimmick::GetDicomNodeOfItem(const wxTreeItemId& i)
2367   {
2368     TreeItemData *data = 
2369       (TreeItemData *)mTreeListCtrl->GetItemData(i);
2370     if (data) return ( data->GetDicomNode() );
2371     return 0;
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   
2399   BEGIN_EVENT_TABLE(WxGimmick, wxPanel)
2400   // POP UP MENU
2401     EVT_MENU(PopUp_NewCollection,WxGimmick::OnPopUpNewCollection)
2402     EVT_MENU(PopUp_OpenCollection,WxGimmick::OnPopUpOpenCollection)
2403     EVT_MENU(PopUp_CloseCollection,WxGimmick::OnPopUpCloseCollection)
2404     EVT_MENU(PopUp_DeleteCollection,WxGimmick::OnPopUpDeleteCollection)
2405     EVT_MENU(PopUp_AddFile, WxGimmick::OnPopUpAddFile)
2406     EVT_MENU(PopUp_AddRawFile, WxGimmick::OnPopUpAddRawFile)
2407     EVT_MENU(PopUp_AddDirectory, WxGimmick::OnPopUpAddDirectory)
2408     EVT_MENU(PopUp_Remove, WxGimmick::OnPopUpRemove)
2409     EVT_MENU(PopUp_About, WxGimmick::OnPopUpAbout)
2410     EVT_MENU(PopUp_Settings, WxGimmick::OnPopUpSettings)
2411     
2412     EVT_MENU_RANGE(PopUp_Sort, PopUp_Sort+99,  WxGimmick::OnPopUpSort)
2413     EVT_MENU_RANGE(PopUp_User, PopUp_User+99,  WxGimmick::OnPopUpUser)
2414     
2415     
2416     
2417   // DRAG
2418     EVT_TREE_BEGIN_DRAG(TreeListCtrlId, WxGimmick::OnBeginDrag)
2419     EVT_TREE_BEGIN_RDRAG(TreeListCtrlId, WxGimmick::OnBeginRDrag)
2420     EVT_TREE_END_DRAG(TreeListCtrlId, WxGimmick::OnEndDrag)
2421
2422   // LABEL
2423     EVT_TREE_BEGIN_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnBeginLabelEdit)
2424     EVT_TREE_END_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnEndLabelEdit)
2425
2426   //DELETE : UNUSED
2427     EVT_TREE_DELETE_ITEM(TreeListCtrlId, WxGimmick::OnDeleteItem)
2428 #if 0       // there are so many of those that logging them causes flicker
2429     EVT_TREE_GET_INFO(TreeListCtrlId, WxGimmick::OnGetInfo)
2430 #endif
2431   // UNUSED
2432     EVT_TREE_SET_INFO(TreeListCtrlId, WxGimmick::OnSetInfo)
2433
2434   // EXPAND/COLLAPSE
2435     EVT_TREE_ITEM_EXPANDED(TreeListCtrlId, WxGimmick::OnItemExpanded)
2436     EVT_TREE_ITEM_EXPANDING(TreeListCtrlId, WxGimmick::OnItemExpanding)
2437     EVT_TREE_ITEM_COLLAPSED(TreeListCtrlId, WxGimmick::OnItemCollapsed)
2438     EVT_TREE_ITEM_COLLAPSING(TreeListCtrlId, WxGimmick::OnItemCollapsing)
2439
2440   // SELECTION
2441     EVT_TREE_SEL_CHANGED(TreeListCtrlId, WxGimmick::OnSelChanged)
2442     EVT_TREE_SEL_CHANGING(TreeListCtrlId, WxGimmick::OnSelChanging)
2443   // KEY
2444     EVT_TREE_KEY_DOWN(TreeListCtrlId, WxGimmick::OnTreeKeyDown)
2445   // ACTIVATION = DOUBLE CLICK OR ENTER ON SELECTED
2446     EVT_TREE_ITEM_ACTIVATED(TreeListCtrlId, WxGimmick::OnItemActivated)
2447
2448   // so many differents ways to handle right mouse button clicks...
2449   //    EVT_CONTEXT_MENU(WxGimmick::OnContextMenu)
2450   // EVT_TREE_ITEM_MENU is the preferred event for creating context menus
2451   // on a tree control, because it includes the point of the click or item,
2452   // meaning that no additional placement calculations are required.
2453   //    EVT_TREE_ITEM_MENU(TreeListCtrlId, WxGimmick::OnItemMenu)
2454     
2455     EVT_TREE_ITEM_RIGHT_CLICK(TreeListCtrlId, WxGimmick::OnItemRightClick)
2456
2457   // UNUSED
2458   //    EVT_RIGHT_DOWN(WxGimmick::OnRMouseDown)
2459   //    EVT_RIGHT_UP(WxGimmick::OnRMouseUp)
2460   //    EVT_RIGHT_DCLICK(WxGimmick::OnRMouseDClick)
2461     END_EVENT_TABLE()
2462
2463   //IMPLEMENT_DYNAMIC_CLASS(WxGimmick, wxTreeListCtrl)
2464
2465   /*
2466     wxTree::wxTree(wxWindow *parent, const wxWindowID id,
2467     const wxPoint& pos, const wxSize& size,
2468     long style)
2469     : wxTreeListCtrl(parent, id, pos, size, style)
2470     {
2471     m_reverseSort = false;
2472
2473     CreateImageList();
2474
2475     // Add some items to the tree
2476     AddTestItemsToTree(5, 2);
2477     }
2478   */
2479
2480
2481
2482 #if USE_GENERIC_TREECTRL || !defined(__WXMSW__)
2483     void WxGimmick::CreateButtonsImageList(int size)
2484   {
2485     /*
2486       if ( size == -1 )
2487       {
2488       mTreeListCtrl->SetButtonsImageList(NULL);
2489       return;
2490       }
2491
2492       // Make an image list containing small icons
2493       wxImageList *images = new wxImageList(size, size, true);
2494
2495       // should correspond to TreeListCtrlIcon_xxx enum
2496       wxBusyCursor wait;
2497       wxIcon icons[4];
2498       icons[0] = wxIcon(icon3_xpm);   // closed
2499       icons[1] = wxIcon(icon3_xpm);   // closed, selected
2500       icons[2] = wxIcon(icon5_xpm);   // open
2501       icons[3] = wxIcon(icon5_xpm);   // open, selected
2502
2503       for ( size_t i = 0; i < WXSIZEOF(icons); i++ )
2504       {
2505       int sizeOrig = icons[i].GetWidth();
2506       if ( size == sizeOrig )
2507       {
2508       images->Add(icons[i]);
2509       }
2510       else
2511       {
2512       images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
2513       }
2514       }
2515
2516       mTreeListCtrl->AssignButtonsImageList(images);
2517     */
2518 #else
2519     void WxGimmick::CreateButtonsImageList(int WXUNUSED(size))
2520     {
2521 #endif
2522     }
2523
2524     /*
2525       int WxGimmick::OnCompareItems(const wxTreeItemId& item1,
2526       const wxTreeItemId& item2)
2527       {
2528       if ( m_reverseSort )
2529       {
2530       // just exchange 1st and 2nd items
2531       return mTreeListCtrl->OnCompareItems(item2, item1);
2532       }
2533       else
2534       {
2535       return mTreeListCtrl->OnCompareItems(item1, item2);
2536       }
2537       }
2538
2539
2540       void WxGimmick::DoToggleIcon(const wxTreeItemId& item)
2541       {
2542   
2543       int image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_Folder)
2544       ? TreeIcon_File
2545       : TreeIcon_Folder;
2546       mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Normal);
2547
2548       image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_FolderSelected)
2549       ? TreeIcon_FileSelected
2550       : TreeIcon_FolderSelected;
2551       mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Selected);
2552       }
2553
2554       void WxGimmick::LogEvent(const wxChar *name, const wxTreeEvent& event)
2555       {
2556       wxTreeItemId item = event.GetItem();
2557       wxString text;
2558       if ( item.IsOk() )
2559       text << _T('"') << mTreeListCtrl->GetItemText(item).c_str() << _T('"');
2560       else
2561       text = _T("invalid item");
2562       //    wxLogMessage(wxT("%s(%s)"), name, text.c_str());
2563       }
2564
2565     */
2566     // avoid repetition
2567 #define TREE_EVENT_HANDLER(name)                                \
2568     void WxGimmick::name(wxTreeEvent& event)    \
2569     {                                                           \
2570       /*    LogEvent(_T(#name), event); */                      \
2571       /*    SetLastItem(mTreeListCtrl->wxTreeItemId()) *;*/     \
2572       event.Skip();                                             \
2573     }
2574
2575     TREE_EVENT_HANDLER(OnBeginRDrag)
2576       TREE_EVENT_HANDLER(OnDeleteItem)
2577       TREE_EVENT_HANDLER(OnGetInfo)
2578       TREE_EVENT_HANDLER(OnSetInfo)
2579       //TREE_EVENT_HANDLER(OnItemExpanded)
2580       TREE_EVENT_HANDLER(OnItemExpanding)
2581       //TREE_EVENT_HANDLER(OnItemCollapsed)
2582       //TREE_EVENT_HANDLER(OnSelChanged)
2583       //      TREE_EVENT_HANDLER(OnSelChanging)
2584
2585
2586       void WxGimmick::OnItemCollapsed(wxTreeEvent& event)                   
2587       {
2588         //    std::cout << "* Collapsed *"<<std::endl;
2589       }
2590
2591 #undef TREE_EVENT_HANDLER
2592
2593     void WxGimmick::OnTreeKeyDown(wxTreeEvent& event)
2594     {
2595       /*
2596       //  LogKeyEvent(wxT("Tree key down "), event.GetKeyEvent());
2597       std::cout << "* Key down *"<<std::endl;
2598       if (event.GetKeyCode()==WXK_RIGHT)
2599         {
2600           std::cout << "Right"<<std::endl;
2601           wxTreeItemId itemId =  mTreeListCtrl->GetSelection();
2602           if (itemId.IsOk())
2603             {
2604               std::cout << "item is ok"<<std::endl;
2605               wxPoint clientpt = event.GetPoint();
2606               wxPoint screenpt = ClientToScreen(clientpt);
2607               ShowMenu(itemId, clientpt);
2608             }     
2609           event.Veto();
2610           return;
2611         }
2612       std::cout << "NOT Right"<<std::endl;
2613       */
2614       event.Skip();       
2615     }
2616
2617     void WxGimmick::OnBeginDrag(wxTreeEvent& event)
2618     {
2619       wxTreeItemId id = event.GetItem();
2620       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2621       //    std::cout << "OnBeginDrag("<<id<<")"<<std::endl;
2622       if (data->IsDatabase())
2623         {
2624           //      std::cout << "-- IS ROOT"<<std::endl;
2625           //  event.Allow();
2626         }
2627       else if (data->IsDicomNode())
2628         {
2629           //      std::cout << "-- IS NODE"<<std::endl;
2630         }
2631       /*
2632       // need to explicitly allow drag
2633       if ( event.GetItem() != GetDatabaseItem() )
2634       {
2635       m_draggedItem = event.GetItem();
2636
2637       wxPoint clientpt = event.GetPoint();
2638       wxPoint screenpt = ClientToScreen(clientpt);
2639
2640       wxLogMessage(wxT("OnBeginDrag: started dragging %s at screen coords (%i,%i)"),
2641       GetItemText(m_draggedItem).c_str(),
2642       screenpt.x, screenpt.y);
2643
2644       event.Allow();
2645       }
2646       else
2647       {
2648       wxLogMessage(wxT("OnBeginDrag: this item can't be dragged."));
2649       }
2650       */
2651     }
2652
2653     void WxGimmick::OnEndDrag(wxTreeEvent& event)
2654     {
2655       wxTreeItemId id = event.GetItem();
2656       //      std::cout << "OnEndDrag("<<id<<")"<<std::endl;
2657       if (!id.IsOk()) return;
2658       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2659       if (data->IsDatabase())
2660         {
2661           //      std::cout << "-- IS ROOT"<<std::endl;
2662         }
2663       else if (data->IsDicomNode())
2664         {
2665           //      std::cout << "-- IS NODE"<<std::endl;
2666         }
2667
2668       /*
2669         wxTreeItemId itemSrc = m_draggedItem,
2670         itemDst = event.GetItem();
2671         m_draggedItem = (wxTreeItemId)0l;
2672
2673         // where to copy the item?
2674         if ( itemDst.IsOk() && !ItemHasChildren(itemDst) )
2675         {
2676         // copy to the parent then
2677         itemDst = GetItemParent(itemDst);
2678         }
2679
2680         if ( !itemDst.IsOk() )
2681         {
2682         wxLogMessage(wxT("OnEndDrag: can't drop here."));
2683
2684         return;
2685         }
2686
2687         wxString text = GetItemText(itemSrc);
2688         wxLogMessage(wxT("OnEndDrag: '%s' copied to '%s'."),
2689         text.c_str(), GetItemText(itemDst).c_str());
2690
2691         // just do append here - we could also insert it just before/after the item
2692         // on which it was dropped, but this requires slightly more work... we also
2693         // completely ignore the client data and icon of the old item but could
2694         // copy them as well.
2695         //
2696         // Finally, we only copy one item here but we might copy the entire tree if
2697         // we were dragging a folder.
2698         int image = wxGetApp().ShowImages() ? TreeIcon_File : -1;
2699         AppendItem(itemDst, text, image);
2700       */
2701     }
2702
2703
2704     //====================================================================
2705     void WxGimmick::OnBeginLabelEdit(wxTreeEvent& event)
2706     {
2707       //      std::cout << "OnBeginLabelEdit"<<std::endl;
2708       wxTreeItemId id = event.GetItem();
2709       TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2710       // If not a root : veto
2711       if (data->IsDatabase()) 
2712         { 
2713           event.Allow();
2714           return;
2715         }
2716       event.Veto();
2717     }
2718     //====================================================================
2719
2720     //====================================================================
2721     void WxGimmick::OnEndLabelEdit(wxTreeEvent& event)
2722     {
2723       //      std::cout << "OnEndLabelEdit"<<std::endl;
2724       wxTreeItemId id = event.GetItem();
2725       TreeItemData *data = GetItemData(id);
2726       // If not a database : bug !
2727       if (data->IsDatabase()) 
2728         { 
2729           data->GetDicomNode()->GetDicomDatabase()->SetName(wx2std(event.GetLabel()));
2730           mFieldsView->UpdateValues(data->GetDicomNode());
2731         }
2732       else
2733         {
2734           std::cerr<< "!!!! Internal error : send bug report !!!!"<<std::endl;
2735         }
2736     }
2737     //====================================================================
2738
2739
2740     void WxGimmick::OnItemCollapsing(wxTreeEvent& event)
2741     {
2742       //    wxLogMessage(wxT("OnItemCollapsing"));
2743
2744       // for testing, prevent the user from collapsing the first child folder
2745       wxTreeItemId itemId = event.GetItem();
2746
2747       /*
2748         if ( IsTestItem(itemId) )
2749         {
2750         wxMessageBox(wxT("You can't collapse this item."));
2751
2752         event.Veto();
2753         }
2754       */
2755     }
2756
2757
2758     //====================================================================
2759     void WxGimmick::ShowHelp()
2760     {
2761       if (mHelpWindow==0)
2762         {
2763           mHelpWindow = new WxGimmickHelpWindow(this);
2764         }
2765       mHelpWindow->CenterOnParent();
2766       mHelpWindow->ShowModal();
2767     }
2768     //====================================================================
2769
2770
2771
2772
2773
2774     //================================================================
2775     //================================================================
2776     //================================================================
2777     //================================================================
2778     //================================================================
2779     // WxGimmickEvent
2780     //================================================================
2781     //================================================================
2782     //================================================================
2783     //================================================================
2784     //================================================================
2785
2786
2787
2788
2789
2790     // ----------------------------------------------------------------------------
2791     // events
2792     // ----------------------------------------------------------------------------
2793     /*
2794       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG)
2795       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG)
2796       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM)
2797       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO)
2798       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO)
2799       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED)
2800       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING)
2801       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
2802       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING)
2803     */
2804
2805     DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT)
2806       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT)
2807
2808
2809       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGED)
2810       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGING)
2811       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_KEY_DOWN)
2812       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_CONTEXTUAL_MENU)
2813       DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_ITEM_STYLE_CHANGED)
2814       /*
2815         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED)
2816         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK)
2817         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK)
2818         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG)
2819         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK)
2820         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP)
2821         DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU)
2822       */
2823       // ----------------------------------------------------------------------------
2824       // Tree event
2825       // ----------------------------------------------------------------------------
2826
2827       IMPLEMENT_ABSTRACT_CLASS(WxGimmickEvent, wxNotifyEvent)
2828   
2829   
2830       WxGimmickEvent::WxGimmickEvent(wxEventType commandType,
2831                                                                  WxGimmick *tree,
2832                                                                  const wxTreeItemId& item)
2833       : 
2834       wxNotifyEvent(commandType, tree->GetId()),
2835       m_item(item),
2836       mDicomNode(0)
2837         {
2838           //      m_editCancelled = false;
2839       
2840           SetEventObject(tree);
2841       
2842           if ( item.IsOk() )
2843             SetClientObject(tree->mTreeListCtrl->GetItemData(item));
2844         }
2845   
2846       WxGimmickEvent::WxGimmickEvent(wxEventType commandType, int id)
2847         : 
2848         wxNotifyEvent(commandType, id),
2849         mDicomNode(0)
2850           {
2851             m_itemOld = 0l;
2852             //      m_editCancelled = false;
2853           }
2854     
2855         WxGimmickEvent::WxGimmickEvent(const WxGimmickEvent & event)
2856           : 
2857           wxNotifyEvent(event),
2858           mDicomNode(0)
2859
2860             {
2861               m_evtKey = event.m_evtKey;
2862               m_item = event.m_item;
2863               m_itemOld = event.m_itemOld;
2864               mColor = event.mColor;
2865               mUserData = event.mUserData;
2866               //    m_pointDrag = event.m_pointDrag;
2867               //    m_label = event.m_label;
2868               //    m_editCancelled = event.m_editCancelled;
2869             }
2870       
2871       
2872
2873
2874
2875
2876
2877
2878           //================================================================
2879           //================================================================
2880           //================================================================
2881           //================================================================
2882           //================================================================
2883           WxGimmickFrame::WxGimmickFrame( wxWindow *parent, 
2884                                           wxString title, 
2885                                           wxSize size)
2886             : wxFrame((wxFrame *)parent, -1, title, wxDefaultPosition, size)
2887             {   
2888               wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
2889               mWxGimmick = new WxGimmick(this,-1,
2890                                          wxDefaultPosition,
2891                                          wxDefaultSize);
2892               sizer->Add(mWxGimmick,1,wxGROW);
2893               SetSizer(sizer);
2894               SetAutoLayout(true);
2895               Layout();
2896             }
2897             //================================================================
2898
2899             //================================================================
2900             WxGimmickFrame::~WxGimmickFrame()
2901               {
2902               }
2903             //================================================================
2904
2905             //================================================================
2906             void WxGimmickFrame::OnSelChanged(WxGimmickEvent& event)
2907             {
2908               //    std::cout << "+++++ WxGimmickFrame::OnSelChanged ++++++++++"
2909               //              <<std::endl;
2910               std::vector<std::string> file;
2911               //    mWxGimmick->GetSelectedImages(file);
2912               /*
2913                 std::vector<std::string>::iterator i;
2914                 for (i=file.begin();i!=file.end();++i)
2915                 {
2916                 std::cout << "'" << *i << "'" << std::endl;
2917                 }
2918                 std::cout << "++++++++++++++++++++" << std::endl;
2919               */
2920             }
2921             //================================================================
2922
2923             //================================================================
2924             BEGIN_EVENT_TABLE(WxGimmickFrame, wxFrame)
2925               EVT_TREEVIEWLIST_SEL_CHANGED(-1,WxGimmickFrame::OnSelChanged)
2926               END_EVENT_TABLE()
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
2954   }