]> Creatis software - creaImageIO.git/blob - src2/creaImageIOWxGimmickView.cpp
BUG Threads MacOs
[creaImageIO.git] / src2 / creaImageIOWxGimmickView.cpp
1 #include <creaImageIOWxGimmickView.h>
2 #include <creaImageIOWxTreeView.h>
3 #include <creaImageIOSystem.h>
4 using namespace crea;
5 // Icons
6 #include "icons/accept.xpm"
7 #include "icons/add.xpm"
8 #include "icons/folder-down.xpm"
9 #include "icons/page-down.xpm"
10 #include "icons/remove.xpm"
11 #include "icons/database-add.xpm"
12 #include "icons/help.xpm"
13
14 #include <wx/imaglist.h>
15
16 namespace creaImageIO
17 {
18   //======================================================================
19   // The ids of the different tools
20   enum
21     {
22       TOOL_ADDFILES_ID = 1,
23       TOOL_ADDDIR_ID = 2,
24       TOOL_REMOVE_ID = 3,
25       TOOL_ADDDATABASE_ID = 4,
26       TOOL_HELP_ID = 5
27     };
28   //======================================================================
29
30   //================================================================
31   // 
32   const int icon_number = 7;
33   // Icon ids
34   typedef enum
35     {
36       Icon_accept,
37       Icon_add,
38       Icon_folder_down,
39       Icon_page_down,
40       Icon_remove,
41       Icon_database_add,
42       Icon_help
43     }
44     icon_id;
45   //================================================================
46
47   //================================================================
48   /*
49   const icon_id Icon[5] = { Icon_Database,  
50                             Icon_Patient,
51                             Icon_Study,
52                             Icon_Series,
53                             Icon_Image };
54   */
55   //================================================================
56
57
58   //======================================================================
59   // CTor
60   WxGimmickView::WxGimmickView(Gimmick* gimmick,
61                                wxWindow *parent, 
62                                const wxWindowID id,
63                                const wxPoint& pos, const wxSize& size,
64                                int min_dim,
65                                    int max_dim,
66                                int number_of_threads)
67     : wxPanel(parent,id,pos,size),
68       GimmickView(gimmick, number_of_threads),
69       mProgressDialog(0),
70       mConstructed(false)
71   {
72     GimmickDebugMessage(1,"WxGimmickView::WxGimmickView"
73                         <<std::endl);
74     // Sets the current directory to the home dir
75     mCurrentDirectory =  std2wx(gimmick->GetHomeDirectory());
76
77      // Connect the AddProgress callback
78     gimmick->ConnectAddProgressObserver
79       ( boost::bind( &WxGimmickView::OnAddProgress , this, _1 ) );
80
81     // Create the list of icons (mIcon)
82     CreateIconList();
83
84     // Global sizer
85     wxBoxSizer  *sizer = new wxBoxSizer(wxVERTICAL);
86
87     // Create the tool bar
88     CreateToolBar(); 
89     sizer->Add( mToolBar ,0, wxGROW  ,0);
90
91     // Split part below toolbar into notebook for views and panel
92     // for preview, messages...
93     mSplitter = new wxSplitterWindow( this , -1);
94  
95    
96     // Notebook
97     mNotebook = new wxNotebook(mSplitter,
98                                -1,wxDefaultPosition, wxDefaultSize, 0);
99
100     //Gimmick
101     mGimmick=gimmick;
102
103       
104     mSelectionMaxDimension= max_dim;
105     mSelectionMinDimension= min_dim;
106     
107     // Create the views
108     CreateTreeViews();
109
110     // Bottom panel 
111     mBottomPanel = new wxPanel(mSplitter,-1);
112     
113           wxBoxSizer    *bottom_sizer = new wxBoxSizer(wxVERTICAL); //HORIZONTAL);
114     
115     
116     // Previewer
117     mViewer = new WxViewer(mBottomPanel, wxID_ANY, wxT("Gimmick! Viewer"),wxDefaultPosition, wxDefaultSize );
118         mViewer->SetMovieSize(1);
119         mViewer->SetImage(0,GetDefaultImage());
120           mViewer->ShowNextImage();
121
122     bottom_sizer->Add(mViewer,1,wxGROW,1);
123     //    mViewer->Show();
124
125           mText = new wxStaticText(mBottomPanel, wxID_ANY, wxT("Welcome to Gimmick!"));
126           bottom_sizer->Add(mText,0,wxGROW,0);
127
128           
129           
130     mBottomPanel->SetSizer(bottom_sizer);
131
132     // Splitting
133     int hsize = size.GetHeight();
134
135     int top_minsize = 450;
136     int bottom_minsize = 50;
137
138     mSplitter->SetMinimumPaneSize( bottom_minsize );
139     mSplitter->SplitHorizontally( mNotebook, mBottomPanel, 
140                                   top_minsize);
141
142     sizer->Add( mSplitter,1,wxGROW  ,0);
143
144
145     SetSizer( sizer );     
146     SetAutoLayout(true);
147     Layout();
148     
149     mConstructed = true;
150   }
151   //======================================================================
152
153   //======================================================================
154   /// Destructor
155   WxGimmickView::~WxGimmickView()
156   {
157     GimmickDebugMessage(1,"WxGimmickView::~WxGimmickView"
158                         <<std::endl);
159   }
160   //======================================================================
161   
162   //======================================================================
163   /// Creates the tool bar
164   void WxGimmickView::CreateToolBar()
165   {
166     long style = wxTB_HORIZONTAL | wxNO_BORDER | wxTB_TEXT;
167     mToolBar = new wxToolBar(this,-1,wxDefaultPosition,wxDefaultSize,
168                              style);
169
170     mToolAddFile = mToolBar->AddTool( TOOL_ADDFILES_ID, 
171                                       _T("Add file(s)"),
172                                       mIcon->GetBitmap(Icon_page_down),
173                                       _T("Add one or more file to database")
174                                       );
175     mToolAddDir = mToolBar->AddTool( TOOL_ADDDIR_ID, 
176                                       _T("Add folder"),
177                                       mIcon->GetBitmap(Icon_folder_down),
178                                       _T("Add the content of a folder to database")
179                                       );
180     mToolRemove = mToolBar->AddTool( TOOL_REMOVE_ID, 
181                                       _T("Remove"),
182                                       mIcon->GetBitmap(Icon_remove),
183                                       _T("Remove selected items")
184                                       );
185     mToolAddDatabase = mToolBar->AddTool( TOOL_ADDDATABASE_ID, 
186                                       _T("Open database"),
187                                       mIcon->GetBitmap(Icon_database_add),
188                                       _T("Open a local or distant database")
189                                       );
190     mToolHelp = mToolBar->AddTool( TOOL_HELP_ID, 
191                                       _T("Help"),
192                                       mIcon->GetBitmap(Icon_help),
193                                       _T("Open help window")
194                                       );
195     //const wxBitmap& bitmap1, const wxString& shortHelpString = "", wxItemKind kind = wxITEM_NORMAL)
196
197     mToolBar->Realize();
198   }
199   //======================================================================
200
201  
202   //======================================================================
203   /// Create the tree view for TreeHandler provided
204   void WxGimmickView::CreateTreeView( TreeHandler* h)
205   {
206     std::string name(h->GetTree().GetAttribute("Name"));
207     GimmickMessage(2,"Creating the tree view for '"<<
208                    name<<"'"<<std::endl);
209     // Create the WxTreeView
210     WxTreeView* view = new WxTreeView(h,this,mNotebook,-1);
211
212     // TO DO : TEST THAT A VIEW WITH SAME NAME IS NOT
213     // ALREADY IN THE MAP
214     GetTreeViewMap()[name] = view;
215
216     // Add Notebook page
217     mNotebook->AddPage( view, crea::std2wx(name) );
218
219   }
220
221   //======================================================================
222   /// Returns the selected Images so that they comply with the given parameter(4D)
223   void WxGimmickView::GetSelectedImages(std::vector<vtkImageData*>& s, int dim)
224   {
225         int level=GetTreeViewMap()["Local database"]->GetNumberOfLevels();
226         std::vector<tree::Node*> im=GetTreeViewMap()["Local database"]->GetSelected(level+1);
227         ReadImagesNotThreaded(s,im,dim);
228   }
229   //======================================================================
230   /// Returns the selected Images so that they comply with the given parameter(4D)
231   void WxGimmickView::GetSelectedFiles(std::vector<std::string>& s)
232   {
233         GetTreeViewMap()["Local database"]->GetSelectedAsString(s);
234   }
235   //=================================================
236   void WxGimmickView::CreateIconList()
237   {
238     // Size of the icons;
239     int size = 24;
240
241     wxIcon icons[20];
242     // should correspond to Icon_xxx enum
243     icons[Icon_accept] = wxIcon(accept_xpm);
244     icons[Icon_add] = wxIcon(add_xpm);
245     icons[Icon_folder_down] = wxIcon(folder_down_xpm);
246     icons[Icon_page_down] = wxIcon(page_down_xpm);
247     icons[Icon_remove] = wxIcon(remove_xpm);
248     icons[Icon_database_add] = wxIcon(database_add_xpm);
249     icons[Icon_help] = wxIcon(help_xpm);
250
251     //   unsigned int NbIcons = 8;
252     // Make an image list containing small icons
253     mIcon = new wxImageList(size,size,true);
254     
255     // Make all icons the same size = size of the first one
256     int sizeOrig = icons[0].GetWidth();
257     for ( size_t i = 0; i < icon_number; i++ )
258       {
259         if ( size == sizeOrig )
260           {
261             mIcon->Add(icons[i]);
262           }
263         else
264           {
265             mIcon->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
266           }
267       }
268   }
269   //=================================================
270
271
272   //=================================================
273   void WxGimmickView::OnAddFiles(wxCommandEvent& event)
274   {
275    long style = wxOPEN | wxFILE_MUST_EXIST | wxFD_MULTIPLE;
276     std::string wc("*.*");
277     wxFileDialog* FD = new wxFileDialog( 0, 
278                                          _T("Select file"),
279                                          _T(""),
280                                          _T(""),
281                                          crea::std2wx(wc),
282                                          style,
283                                          wxDefaultPosition);
284     
285     if (FD->ShowModal()==wxID_OK)
286       {
287         wxBusyCursor busy;
288
289         wxArrayString files;
290         FD->GetPaths(files);
291         unsigned int i;
292         std::vector<std::string> filenames;
293         for (i=0;i<files.GetCount();++i)
294         {
295           filenames.push_back(wx2std(files[i]));
296           GimmickMessage(2,"Adding File "<<files[i]<<"."<<std::endl);
297         }
298
299         mProgressDialog = 
300           new wxProgressDialog(_T("Adding file(s)"),
301                                _T(""),
302                                1000,
303                                this,
304                                wxPD_ELAPSED_TIME |
305                                //                              wxPD_ESTIMATED_TIME | 
306                                //                              wxPD_REMAINING_TIME |
307                                wxPD_CAN_ABORT );
308
309         // TO DO : select the current tree handler
310         mGimmick->AddFiles("Local database",filenames);
311
312         mProgressDialog->Pulse(_T("Updating view..."));
313
314         UpdateTreeViewLevel("Local database",1);
315         delete mProgressDialog;
316         DisplayAddSummary();    
317       }
318         
319   }
320   //=================================================
321
322   //=================================================
323   void WxGimmickView::OnAddDir(wxCommandEvent& event)
324   {
325     long style = wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST;
326     wxDirDialog* FD = 
327       new wxDirDialog( 0, 
328                        _T("Select directory"),
329                        mCurrentDirectory,
330                        style);
331     
332     if (FD->ShowModal()==wxID_OK)
333       {
334         
335         bool recurse = false;
336         if (wxMessageBox(_T("Recurse into sub-directories ?"),
337                          _T("Scan directory"),
338                          wxYES_NO,this ) == wxYES)
339           {
340             recurse = true;
341           }
342        
343         wxBusyCursor busy;
344         wxString title(_T("Adding directory"));
345         if (recurse) 
346           title = _T("Adding directory (recursive)");
347         mProgressDialog = 
348           new wxProgressDialog(_T("Adding directory"),
349                                _T(""),
350                                1000,
351                                this,
352                                wxPD_ELAPSED_TIME |
353                                //                              wxPD_ESTIMATED_TIME | 
354                                //                              wxPD_REMAINING_TIME |
355                                wxPD_CAN_ABORT );
356         std::string dirname = wx2std (FD->GetPath()) ;
357         mCurrentDirectory = FD->GetPath();  
358         
359         // TO DO : select the current tree handler
360         mGimmick->AddDir("Local database",dirname,recurse);
361         
362         mProgressDialog->Pulse(_T("Updating view..."));
363         
364         UpdateTreeViewLevel("Local database",1);
365         delete mProgressDialog;
366         DisplayAddSummary();
367       }
368   }
369   //=================================================
370
371   //=================================================
372   void WxGimmickView::OnSelectionChange(std::vector<tree::Node*>& sel)
373   {      
374     GimmickDebugMessage(5,
375                         "WxGimmickView::OnSelectionChange"
376                         <<std::endl);
377     wxBusyCursor busy;
378     bool valid = ValidateSelected(sel,
379                                   mSelectionMinDimension,
380                                   mSelectionMaxDimension );
381     mText->SetLabel(crea::std2wx(GetMessage()));
382     if(valid)
383       {
384         ReadImageThreaded(sel);
385       }
386     else
387       {
388         mViewer->SetMovieSize(1);
389         mViewer->SetImage(0,GetDefaultImage());
390         //      mViewer->Hide();
391       }
392
393     
394    }
395
396   //==================================================
397
398   //==================================================
399   ///Reads Images (Threaded)
400   void WxGimmickView::ReadImageThreaded(std::vector<tree::Node*> sel)
401   {     
402    GimmickDebugMessage(5,
403                        "ReadImageThreaded"
404                        <<std::endl);
405    int maxprio = GetMaximalPriority();
406    int prio = maxprio + 2000;
407
408    mViewer->SetMovieSize(sel.size());//ClearImages();
409    
410    //First load the selected images
411    mCurImageItemToShow = sel.front();
412    int index = 0;
413    std::vector<tree::Node*>::iterator selected;
414  
415    for(selected=sel.begin();selected!=sel.end();++selected)
416      {
417        GimmickDebugMessage(5,
418                            "Requesting image from selected "
419                            <<(*selected)->GetAttribute("FullFileName")
420                            <<std::endl);
421        RequestReading(*selected,prio,index);
422        //       AddEntryToMap(*selected);
423        prio--;
424        index++;
425      }
426         
427         //Going up
428         prio = maxprio + 20;
429         std::vector<tree::Node*> up;
430         GetTreeViewMap()["Local database"]->GetNodes(up,true);
431         std::vector<tree::Node*>::iterator iterUp;
432         for(iterUp=up.begin();iterUp!=up.end();++iterUp)
433         {
434                 GimmickDebugMessage(5,
435                                 "Requesting image from neighbors up "
436                                 <<(*iterUp)->GetAttribute("FullFileName")
437                                 <<std::endl);
438                 RequestReading(*iterUp,prio,-1);
439                 //              AddEntryToMap(*iterUp);
440                 prio--;
441                 if (prio == maxprio) break;
442         }
443
444         //Going down
445         prio = maxprio + 19;
446         std::vector<tree::Node*> down;
447         GetTreeViewMap()["Local database"]->GetNodes(down,false);
448         std::vector<tree::Node*>::iterator iterDown;
449         for(iterDown=down.begin();iterDown!=down.end();++iterDown)
450         {
451                 GimmickDebugMessage(5,
452                                 "Requesting image from neighbors down "
453                                 <<(*iterDown)->GetAttribute("FullFileName")
454                                 <<std::endl);
455                 RequestReading(*iterDown,prio,-1);
456                 //              AddEntryToMap(*iterDown);
457                 prio--;
458                 if (prio == maxprio) break;
459         }       
460   }
461
462   //==================================================
463
464   //==================================================
465   /// Processes the queue of image events 
466   void WxGimmickView::ProcessImageEvents()
467   {
468     if (!mConstructed) return;
469
470     //    int level=GetTreeViewMap()["Local database"]->GetNumberOfLevels();
471     //    std::vector<tree::Node*> sel=GetTreeViewMap()["Local database"]->GetSelected(level+1);
472     /*
473     GimmickDebugMessage(5,
474                         "Processing Images. Lock Started"
475                         <<std::endl);
476     */
477     MultiThreadImageReaderEventLock();
478     
479
480     while (!IsQueueEmpty())
481       {
482                   mViewer->StartPlayer();
483
484         GimmickDebugMessage(5,
485                             "Queue not empty"
486                             <<std::endl);
487         
488         vtkImageData* image = GetNextImageQueued();
489         if( image!=0 ) 
490           {
491             int index =  GetNextSelectionIndexQueued();
492             if (index>=0) 
493               {
494                 mViewer->SetImage(index,image);
495               }
496             
497           }
498         UnqueueNext();
499       }
500     
501     ClearQueue();
502
503     MultiThreadImageReaderEventUnlock();
504     /*
505         GimmickDebugMessage(5,
506                                 "Processing Images. Lock Ended"
507                                 <<std::endl);
508     */
509   }
510  
511   //==================================================
512
513   //==================================================
514    void  WxGimmickView::OnInternalIdle()
515   {
516    if (!mConstructed) return;
517    ProcessImageEvents();
518    static bool first_time = true;
519    if (false)
520      {
521         mViewer->SetMovieSize(1);
522         mViewer->SetImage(0,GetDefaultImage());
523         first_time = false;
524      }
525    //   GimmickMessage(1,"WxGimmickView : Refresh viewer"<<std::endl);
526         //  mViewer->StartPlayer();
527    if (mViewer->RefreshIfNecessary())
528      {
529        // mViewer->Refresh();
530        //       mViewer->SetFocus();
531      }
532   }
533
534    //==================================================
535
536   //==================================================
537    void  WxGimmickView::ClearSelection()
538   {
539         mViewer->SetMovieSize(1);
540         mViewer->SetImage(0,GetDefaultImage());
541         mViewer->RefreshIfNecessary();
542   }
543   
544   //=================================================
545  
546   //=================================================
547   void WxGimmickView::OnRemove(wxCommandEvent& event)
548   {
549         //TODO Select current tree handler       
550     wxBusyCursor busy;
551     GetTreeViewMap()["Local database"]->RemoveSelected(1);
552         ClearSelection();
553   }
554   //=================================================
555
556   //=================================================
557   /// AddProgress Gimmick callback
558   void WxGimmickView::OnAddProgress( Gimmick::AddProgress& p)
559   {
560
561     char mess[200];
562     sprintf(mess,"%i dirs - %i files - %i handled - %i added",
563            p.GetNumberScannedDirs(),
564            p.GetNumberScannedFiles(),
565            p.GetNumberHandledFiles(),
566            p.GetNumberAddedFiles());
567     //    std::cout << "OnAddProgress "<<mess<<std::endl;
568     wxString s(wxString::From8BitData(mess));
569     //  std::cout << "Pulse"<<std::endl;
570     if (!mProgressDialog->Pulse(s)) 
571       {
572         p.SetStop();
573       }
574     //  std::cout << "OnAddProgress ok"<<std::endl;
575   }
576   //=================================================
577
578   //=================================================
579   void WxGimmickView::DisplayAddSummary()
580   {
581     const Gimmick::AddProgress& p = mGimmick->GetAddProgress();
582     std::stringstream mess;
583     mess << "Dirs \tscanned\t: " << p.GetNumberScannedDirs()  << "\n";
584     mess << "Files\tscanned\t: " << p.GetNumberScannedFiles() << "\n";
585     mess << "Files\thandled\t: " << p.GetNumberHandledFiles() << "\n\n";
586     mess << "Files\tadded  \t: " << p.GetNumberAddedFiles()   << "\n\n";
587
588     /*    char times[500];
589     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",
590             summary.parse_time,
591             (int)( summary.parse_time*100./summary.total_time),
592             summary.file_scan_time,
593             (int)(summary.file_scan_time*100./summary.total_time),
594             summary.update_structs_time,
595             (int)(summary.update_structs_time*100./summary.total_time),
596             summary.update_database_time,
597             (int)(summary.update_database_time*100./summary.total_time),
598             summary.total_time );
599     
600     mess << times;
601     */
602     wxMessageBox(std2wx(mess.str()),_T("Addition result"),wxOK,this);
603   }
604
605    //=================================================
606
607    //=================================================
608   BEGIN_EVENT_TABLE(WxGimmickView, wxPanel)
609     EVT_TOOL(TOOL_ADDFILES_ID, WxGimmickView::OnAddFiles)
610     EVT_TOOL(TOOL_ADDDIR_ID, WxGimmickView::OnAddDir)
611         EVT_TOOL(TOOL_REMOVE_ID, WxGimmickView::OnRemove)
612   END_EVENT_TABLE()
613   //=================================================
614
615 } // EO namespace creaImageIO
616
617