2 #include <creaImageIOWxGimmick.h>
3 #include <creaImageIODicomNodeComparators.h>
5 #include <creaMessageManager.h>
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>
19 #include <vtkCamera.h>
20 #include <vtkRenderer.h>
26 #include <boost/filesystem.hpp>
27 #include <boost/algorithm/string.hpp>
31 //================================================================
32 const int WxGimmick::UserMenuFirstId = 1000;
33 //================================================================
35 //================================================================
48 //================================================================
50 //================================================================
53 PopUp_NewCollection = 100,
54 PopUp_OpenCollection = 101,
55 PopUp_CloseCollection = 102,
56 PopUp_DeleteCollection = 103,
57 PopUp_AddDirectory = 110,
59 PopUp_AddRawFile = 112,
64 PopUp_User = WxGimmick::UserMenuFirstId,
66 //================================================================
68 //================================================================
69 #define TreeListCtrlId 10000
70 //================================================================
72 //================================================================
73 const icon_id Icon[5] = { Icon_Database,
78 //================================================================
81 //================================================================
82 class WxGimmickDicomNodeData : public DicomNodeData
85 WxGimmickDicomNodeData
86 (WxGimmickTreeItemData* d = 0) :
90 ~WxGimmickDicomNodeData();
92 WxGimmickTreeItemData* GetTreeItemData()
93 { return mTreeItemData; }
94 void SetTreeItemData( WxGimmickTreeItemData* d)
95 { mTreeItemData = d; }
96 inline bool IsLoaded() { return mLoaded; }
97 inline void SetLoaded(bool v) { mLoaded = v; }
100 WxGimmickTreeItemData* mTreeItemData;
103 //================================================================
106 //================================================================
107 class WxGimmickTreeItemData : public wxTreeItemData
110 WxGimmickTreeItemData(DicomNode* node)
120 WxGimmickDicomNodeData* data =
121 node->GetData<WxGimmickDicomNodeData*>();
124 if (data->GetTreeItemData()!=0)
126 std::cout << "WxGimmickTreeItemData ERROR ****"
130 data->SetTreeItemData(this);
133 node->SetData( new WxGimmickDicomNodeData(this) );
134 if (node->GetType()==DicomNode::Database)
144 ~WxGimmickTreeItemData()
148 WxGimmickDicomNodeData* data =
149 mDicomNode->GetData<WxGimmickDicomNodeData*>();
150 if (data) data->SetTreeItemData(0);
154 inline void ResetDicomNode()
159 inline void SetItemId ( const wxTreeItemId& item ) { mItemId = item; }
160 inline const wxTreeItemId& GetItemId() const { return mItemId; }
162 inline bool IsDefault() const { return (mType == 0); }
163 inline bool IsDatabase() const { return (mType == 2); }
164 inline bool IsDicomNode() const { return (mType == 1); }
166 inline DicomNode* GetDicomNode() { return mDicomNode; }
167 inline long& UpdateTime() { return mUpdateTime; }
168 inline bool IsLoaded()
170 mDicomNode->GetData<WxGimmickDicomNodeData*>()->IsLoaded();
172 inline void SetLoaded(bool v)
174 mDicomNode->GetData<WxGimmickDicomNodeData*>()->SetLoaded(v);
177 inline int GetUserFlags() const { return mUserFlags; }
178 inline void SetUserFlags(int f) { mUserFlags = f; }
181 // The type of item :
184 // 2 = DicomNode of type Database
186 wxTreeItemId mItemId;
187 DicomNode* mDicomNode;
192 //================================================================
195 //================================================================
196 WxGimmickDicomNodeData::~WxGimmickDicomNodeData()
200 mTreeItemData->ResetDicomNode();
203 //================================================================
212 //================================================================
213 class WxGimmickSettingsDialog : public wxDialog
216 WxGimmickSettingsDialog(wxWindow *parent);
217 ~WxGimmickSettingsDialog();
221 //================================================================
250 //================================================================
251 //================================================================
252 //================================================================
253 //================================================================
254 //================================================================
255 //================================================================
256 //================================================================
257 WxGimmick::WxGimmick(wxWindow *parent,
262 : wxPanel(parent,id,pos,size),
263 mSaveConfigurationOnClose(true),
266 // Start the threads ...
270 SetDatabaseExtension("sqlite3");
271 // Create the UserSettings dir if does not exist
272 CreateUserSettingsDirectory();
273 // Sets the current directory to the Setting dir
274 mCurrentDirectory = std2wx(GetUserSettingsDirectory());
276 // Window layout creation
277 wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
280 mSplitter1 = new wxSplitterWindow( this, -1);
282 // TreeCtrl on the left
287 //| wxTR_LINES_AT_ROOT
288 | wxTR_FULL_ROW_HIGHLIGHT
295 | wxTR_EDIT_LABELS //Use this style if you wish the user to be able to edit labels in the tree list control.
296 //wxTR_NO_BUTTONS For convenience to document that no buttons are to be drawn.
297 | wxTR_HAS_BUTTONS //Use this style to show + and - buttons to the left of parent items.
298 | 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.
299 //wxTR_NO_LINES Use this style to hide vertical level connectors.
300 | 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.)
301 | 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.
302 | 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.
303 // wxTR_ROW_LINES // Use this style to draw a contrasting border between displayed rows.
304 // 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.
305 // 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.
306 | 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.
307 | wxTR_EXTENDED // Use this style to allow disjoint items to be selected. (Only partially implemented; may not work in all cases.)
308 //wxTR_DEFAULT_STYLE The set of flags that are closest to the defaults for the native control for a particular toolkit.
309 //| wxTR_VIRTUAL //The application provides items text on demand.
312 mTreeListCtrl = new wxTreeListCtrl(mSplitter1,
318 mTreeListCtrl->SetIndent(0);
319 mTreeListCtrl->SetLineSpacing(5);
324 wxPanel *rpanel = new wxPanel( mSplitter1, -1 );
326 wxBoxSizer *rsizer = new wxBoxSizer(wxHORIZONTAL);
327 // Right panel top/bottom split
328 mSplitter2 = new wxSplitterWindow( rpanel , -1);
331 mPanelImage = new wxPanel(mSplitter2,-1);
332 mPanelImage->SetBackgroundColour( wxColour(0,0,0) );
334 wxBoxSizer *isizer = new wxBoxSizer(wxHORIZONTAL );
335 mPanelImage->SetSizer( isizer );
337 // Fields view (bottom)
338 mFieldsView = new WxGimmickFieldsView(mSplitter2,-1,
342 mFieldsView->SetColors
343 ( GetSettings().Colour(DicomNode::Database),
344 GetSettings().BgColour(DicomNode::Database),
345 GetSettings().Colour(DicomNode::Patient),
346 GetSettings().BgColour(DicomNode::Patient),
347 GetSettings().Colour(DicomNode::Study),
348 GetSettings().BgColour(DicomNode::Study),
349 GetSettings().Colour(DicomNode::Series),
350 GetSettings().BgColour(DicomNode::Series),
351 GetSettings().Colour(DicomNode::Image),
352 GetSettings().BgColour(DicomNode::Image));
356 int wsize = size.GetWidth();
357 int hsize = size.GetHeight();
358 int previewhsize = 150;
359 int previewwsize = 400;
361 mSplitter2->SetMinimumPaneSize( previewhsize );
362 mSplitter2->SplitHorizontally( mPanelImage, mFieldsView,
363 hsize - previewhsize);
365 rsizer->Add( mSplitter2,1,wxGROW ,0);
367 rpanel->SetAutoLayout(true);
368 rpanel->SetSizer( rsizer );
372 mInteractor = new wxVTKRenderWindowInteractor(mPanelImage,-1);
373 mInteractor->UseCaptureMouseOn();
375 mViewer = vtkImageViewer2::New();
376 mViewer->SetupInteractor ( mInteractor );
377 mViewer->SetInput(mReader.GetImage(""));
379 isizer-> Add( mInteractor ,1,wxGROW ,0);
381 topsizer->Add( mSplitter1,1,wxGROW ,0);
384 mSplitter1->SetMinimumPaneSize( 200 );
385 mSplitter1->SplitVertically(mTreeListCtrl,
387 wsize - previewwsize );
390 // ProcessImageEvents();
391 SetSizer( topsizer );
394 mDatabaseListFile = GetUserSettingsDirectory();
395 mDatabaseListFile += "collections.txt";
400 ShowImage(mReader.GetImage(""));
403 //================================================================
407 #define VALID_FILE_SEPARATOR "\\"
408 #define INVALID_FILE_SEPARATOR "/"
410 #define INVALID_FILE_SEPARATOR "\\"
411 #define VALID_FILE_SEPARATOR "/"
414 //================================================================
415 const std::string& WxGimmick::GetUserSettingsDirectory()
417 if (mUserSettingsDirectory.size()==0)
419 #if defined(__GNUC__)
420 mUserSettingsDirectory = getenv("HOME");
421 #elif defined(_WIN32)
422 mUserSettingsDirectory = getenv("USERPROFILE");
424 mUserSettingsDirectory += "/.gimmick/";
425 boost::algorithm::replace_all( mUserSettingsDirectory,
426 INVALID_FILE_SEPARATOR ,
427 VALID_FILE_SEPARATOR);
429 return mUserSettingsDirectory;
431 //================================================================
433 //========================================================================
434 void WxGimmick::CreateUserSettingsDirectory()
436 if (! boost::filesystem::is_directory( GetUserSettingsDirectory() ) )
438 creaMessage("Gimmick!",1,"==> Directory '"<<GetUserSettingsDirectory()<<"' "
439 << "does not exist : creating it"<<std::endl);
441 if ( ! boost::filesystem::create_directory( GetUserSettingsDirectory() ) )
443 creaMessage("Gimmick!",1,"!! ERROR CREATING '"<<GetUserSettingsDirectory()<<"'");
447 //========================================================================
449 //================================================================
450 WxGimmick::~WxGimmick()
452 // std::cout << "WxGimmick::~WxGimmick()" <<std::endl;
453 if (mSaveConfigurationOnClose) SaveConfiguration();
456 // std::cout << "Reader stopped"<<std::endl;
458 DicomDatabaseListType::iterator i;
459 for (i =GetDicomDatabaseList().begin();
460 i!=GetDicomDatabaseList().end();
468 //================================================================
471 //================================================================
472 void WxGimmick::RebuildView()
476 mTreeListCtrl->DeleteRoot(); //DeleteAllItems();
477 // mTreeDefaultItemId = wxTreeItemId();
480 int nbattr = mSettings.GetMaxNumberOfColumns();
482 for (int j=0;j<nbattr; j++)
484 mTreeListCtrl->AddColumn (_T(""),
485 200, //DEFAULT_COL_WIDTH,
491 mTreeListCtrl->SetMainColumn (0);
492 mTreeListCtrl->SetColumnEditable (0, true);
494 mTreeRootId = mTreeListCtrl->AddRoot( _T(""),Icon_Root,Icon_Root);
496 // The collections columns legends
497 mCollectionsTitlesItemId =
498 CreateChildrenColumnsTitles(mTreeRootId,DicomNode::Database);
500 DicomDatabaseListType::iterator i;
501 for (i =GetDicomDatabaseList().begin();
502 i!=GetDicomDatabaseList().end();
505 UpdateDicomDatabaseView(*i);
508 mTreeListCtrl->Expand(mTreeRootId);
510 // mTreeListCtrl->ExpandAll(mTreeRootId);
511 // std::cout << "EO RebuildAll"<<std::endl;
513 //================================================================
517 //================================================================
518 void WxGimmick::UpdateDicomDatabaseView(DicomDatabase* db)
524 // Does the db exist ?
525 wxTreeItemIdValue cookie;
526 for (dbid = mTreeListCtrl->GetFirstChild(mTreeRootId,cookie);
528 dbid = mTreeListCtrl->GetNextChild(mTreeRootId,cookie))
530 data = (TreeItemData *)mTreeListCtrl->GetItemData(dbid);
531 if ((data->IsDatabase())&&(data->GetDicomNode()==db)) break;
534 // Not found : create
538 int iconid = Icon[DicomNode::Database];
541 // std::cout << " -> Creating item for '"<<db->GetLabel()<<"'"<<std::endl;
542 data = new TreeItemData(db);
543 dbid = mTreeListCtrl->AppendItem( mTreeRootId,
544 std2wx(db->GetLabel()),
548 data->SetItemId(dbid);
549 mTreeListCtrl->SetItemTextColour
550 (dbid,mSettings.Colour(DicomNode::Database));
551 mTreeListCtrl->SetItemBackgroundColour
552 (dbid,mSettings.BgColour(DicomNode::Database));
554 // The patients columns legends
555 CreateChildrenColumnsTitles(dbid,DicomNode::Patient);
558 // Increase UpdateTime to detect obsolete items after
560 data->UpdateTime()++;
562 DicomNode::ChildrenListType::iterator j;
563 for (j= db->GetChildrenList().begin();
564 j!=db->GetChildrenList().end();
567 UpdateDicomNodeView(*j,dbid);
570 DeleteObsoleteChildren(dbid);
572 mTreeListCtrl->EnsureVisible(dbid);
575 //================================================================
577 //================================================================
578 void WxGimmick::UpdateDicomNodeView(DicomNode* n,
579 const wxTreeItemId& parent)
583 // std::cout << "* UpdateDicomNodeView("<<n->GetLabel()<<")"<<std::endl;
585 wxTreeItemId newparent = parent;
588 if ((!mSettings.MergeStudySeries()) ||
589 (n->GetType() != DicomNode::Study))
591 // Does the item exist ?
592 wxTreeItemIdValue cookie;
593 for (newparent = mTreeListCtrl->GetFirstChild(parent,cookie);
595 newparent = mTreeListCtrl->GetNextChild(parent,cookie))
597 data = (TreeItemData *)mTreeListCtrl->GetItemData(newparent);
598 if (data->GetDicomNode() == n) break;
600 // Not found : create
601 if (!newparent.IsOk())
603 int image(Icon[n->GetType()]);
604 wxColour *colour(&mSettings.Colour(n->GetType()));
605 wxColour *bgcolour(&mSettings.BgColour(n->GetType()));
607 if (n->GetType()==DicomNode::Image)
609 // std::cout << "!!!Image"<<std::endl;
610 if (n->GetData<NodeData*>()!=0)
612 // std::cout << ">> n->GetData<NodeData*>()!=0" << std::endl;
613 if (n->GetData<NodeData*>()->IsLoaded())
615 colour = &mSettings.LoadedImageColour();
617 // std::cout << "<< n->GetData<NodeData*>()!=0" << std::endl;
621 data = new TreeItemData(n);
622 newparent = mTreeListCtrl->AppendItem(parent,
626 data->SetItemId(newparent);
627 mTreeListCtrl->SetItemTextColour(newparent,*colour);
628 mTreeListCtrl->SetItemBackgroundColour(newparent,*bgcolour);
630 UpdateColumns(newparent);
633 if (n->GetType()!=DicomNode::Image)
635 CreateChildrenColumnsTitles(newparent,n->GetType()+1);
641 UpdateColumns(newparent,true);
644 // synchonise update time with parent
645 TreeItemData * parent_data =
646 (TreeItemData *)mTreeListCtrl->GetItemData(parent);
647 data->UpdateTime() = parent_data->UpdateTime();
650 DicomNode::ChildrenListType::iterator i;
651 for (i=n->GetChildrenList().begin();
652 i!=n->GetChildrenList().end();
655 UpdateDicomNodeView(*i,newparent);
658 if (n->GetType() != DicomNode::Image)
659 DeleteObsoleteChildren(newparent);
662 //================================================================
664 //================================================================
665 void WxGimmick::UpdateColumns(wxTreeItemId& item,
669 (TreeItemData *)mTreeListCtrl->GetItemData(item);
670 DicomNode* node = data->GetDicomNode();
674 // Update only the first field (for #children update)
675 DicomNode* node2 = node;
676 // If Study and Series level are merged and node type is Series
677 // then have to get back to the Study level
678 if ((mSettings.MergeStudySeries())&&
679 (node->GetType() == DicomNode::Series))
680 node2 = node->GetParent();
683 lab += node2->GetFieldValueMap()
684 [ mSettings.GetColumnList(node2->GetType())[0].Key ];
686 if (node->GetType() != DicomNode::Image)
688 if (node->GetChildrenList().size()>0)
691 sprintf(sz," [%d]",node->GetNumberOfChildren());
695 mTreeListCtrl->SetItemText(item,std2wx(lab));
701 Settings::ColumnListType::iterator col;
702 // If Study and Series level are merged and node type is Series
703 // then have to fill the Study level cols first
704 if ((mSettings.MergeStudySeries())&&
705 (node->GetType() == DicomNode::Series))
707 DicomNode* node2 = node->GetParent();
708 for (col = mSettings.GetColumnList(node2->GetType()).begin();
709 col != mSettings.GetColumnList(node2->GetType()).end();
712 std::string s = node2->GetFieldValueMap()[col->Key];
717 sprintf(sz," [%d]",node->GetNumberOfChildren());
720 mTreeListCtrl->SetItemText (item, c, std2wx(s));
725 for (col = mSettings.GetColumnList(node->GetType()).begin();
726 col != mSettings.GetColumnList(node->GetType()).end();
729 std::string s = node->GetFieldValueMap()[col->Key];
730 if ((c==0)&&(node->GetType() != DicomNode::Image))
733 sprintf(sz," [%d]",node->GetNumberOfChildren());
736 mTreeListCtrl->SetItemText (item, c, std2wx(s));
742 //================================================================
744 //================================================================
745 wxTreeItemId WxGimmick::CreateChildrenColumnsTitles
749 // Creates the sub-level columns titles
751 = new TreeItemData(0);
752 wxTreeItemId id = mTreeListCtrl->AppendItem( item,
758 mTreeListCtrl->SetItemFont(id, *wxITALIC_FONT);
759 mTreeListCtrl->SetItemTextColour(id, mSettings.Colour(t));
760 mTreeListCtrl->SetItemBackgroundColour(id, mSettings.BgColour(t));
761 UpdateColumnsTitles(id,t);
764 //================================================================
766 //================================================================
767 void WxGimmick::UpdateColumnsTitles(wxTreeItemId& item,
770 // std::cout << "Update columns titles "<<t<<std::endl;
772 Settings::ColumnListType::iterator col;
773 for (col = mSettings.GetColumnList(t).begin();
774 col != mSettings.GetColumnList(t).end();
777 // std::cout << col->Name << std::endl;
778 mTreeListCtrl->SetItemText (item, c, std2wx(col->Name));
782 //================================================================
785 //================================================================
786 void WxGimmick::DeleteObsoleteChildren(wxTreeItemId& id)
789 TreeItemData * parent_data =
790 (TreeItemData *)mTreeListCtrl->GetItemData(id);
793 wxTreeItemIdValue cookie;
794 std::vector<wxTreeItemId> children;
795 for (child = mTreeListCtrl->GetFirstChild(id,cookie);
797 child = mTreeListCtrl->GetNextChild(id,cookie))
799 children.push_back(child);
801 std::vector<wxTreeItemId>::iterator i;
802 for (i=children.begin();i!=children.end();++i)
805 (TreeItemData *)mTreeListCtrl->GetItemData(*i);
807 ((data->GetDicomNode()>0) &&
808 ((data->UpdateTime() != parent_data->UpdateTime()))) ||
809 ((data->IsDicomNode()) &&
810 (data->GetDicomNode()==0))
813 // std::cout << "DOBSC="<<mTreeListCtrl->GetItemText(*i)<<std::endl;
814 mTreeListCtrl->Delete(*i);
818 //================================================================
820 //================================================================
821 void WxGimmick::OpenOrNewDatabase(bool open)
825 long style = wxFD_SAVE | wxFD_OVERWRITE_PROMPT;
826 if (open) style = wxOPEN | wxFILE_MUST_EXIST;
827 std::string wc("*.");
828 wc += GetDatabaseExtension();
830 // TO DO : Handler give their wildcards
831 wxFileDialog* FD = new wxFileDialog( 0,
839 if (FD->ShowModal()!=wxID_OK) return;
841 std::string filename = wx2std (FD->GetPath());
842 mCurrentDirectory = FD->GetDirectory();
846 boost::filesystem::path filepath(filename);
847 boost::filesystem::change_extension(filepath,GetDatabaseExtension());
848 if ( boost::filesystem::exists(filepath) )
850 if ( ! boost::filesystem::remove(filepath) )
852 wxMessageBox(_T("Could not overwrite ")
853 +std2wx(filepath.string()),
862 DicomDatabase* db = new DicomDatabase(filename);
869 wxMessageBox(_T("An error occured while opening ")
879 wxGetTextFromUser(_T("Enter collection name"),_T("New collection"),
881 db->SetName(wx2std(collname));
886 wxMessageBox(_T("An error occured while creating ")
894 GetDicomDatabaseList().push_back(db);
895 UpdateDicomDatabaseView(db);
898 //================================================================
901 //================================================================
902 void WxGimmick::LoadConfiguration()
905 // std::cout << "WxGimmick : Reading config"<<std::endl;
907 // std::cout << "==> Loading collections from '"<<mDatabaseListFile
911 s.open(mDatabaseListFile.c_str());
918 if (str.size()==0) continue;
920 std::vector<std::string> tokens;
921 boost::split( tokens, str, boost::is_any_of("\t") );
923 DicomDatabase* db = new DicomDatabase(tokens[0]);
925 // std::cout << " -> Loading collection '"<<tokens[0]<<"'"<<std::endl;
927 if (tokens.size()==2)
929 db->SetName(tokens[1]);
934 GetDicomDatabaseList().push_back(db);
935 db->DBLoadChildren(db,DicomNode::Patient);
936 if (mSettings.HasActiveComparator(DicomNode::Patient))
939 ( mSettings.GetActiveComparator(DicomNode::Patient) );
944 // std::cout << " ... ERROR !"<<std::endl;
952 std::cout << "ERROR opening "<<mDatabaseListFile<<std::endl;
956 mTreeListCtrl->SetBackgroundColour(mSettings.BgColour(DicomNode::Database));
957 if (GetDicomDatabaseList().begin() !=
958 GetDicomDatabaseList().end() )
960 mFieldsView->UpdateFields(*GetDicomDatabaseList().begin());
966 //================================================================
968 //================================================================
969 void WxGimmick::SaveConfiguration()
972 creaMessage("Gimmick!",1,"Gimmick! : Saving configuration..."<<std::endl);
974 creaMessage("Gimmick!",1,"Gimmick! : ==> Saving collections in '"
975 <<mDatabaseListFile<<"'"<<std::endl);
978 s.open(mDatabaseListFile.c_str());
981 creaError("Gimmick! : error opening '"<<mDatabaseListFile<<"'");
984 DicomDatabaseListType::iterator i;
985 for (i =GetDicomDatabaseList().begin();
986 i!=GetDicomDatabaseList().end();
989 s << (*i)->GetFileName() << "\t";
990 s << (*i)->GetName() << std::endl;
996 //================================================================
999 //================================================================
1000 void WxGimmick::OnClose(wxCloseEvent& event)
1002 if (mSaveConfigurationOnClose) SaveConfiguration();
1004 //================================================================
1006 //================================================================
1007 void WxGimmick::OnItemActivated(wxTreeEvent& event)
1013 // std::cout << "OnItemActivated" <<std::endl;
1014 wxTreeItemId itemId = event.GetItem();
1015 if (mTreeListCtrl->IsExpanded(itemId))
1017 mTreeListCtrl->Collapse(itemId);
1021 mTreeListCtrl->Expand(itemId);
1024 //================================================================
1026 //================================================================
1027 void WxGimmick::OnItemExpanded(wxTreeEvent& event)
1030 // std::cout << "* Expanded *"<<std::endl;
1035 wxTreeItemId itemId = event.GetItem();
1037 // expand if collapsed and collapse if expanded ...
1038 TreeItemData *item =
1039 (TreeItemData *)mTreeListCtrl->GetItemData(itemId);
1042 if ( ( item->IsDicomNode() || item->IsDatabase() ) &&
1043 ( ! item->GetDicomNode()->ChildrenLoaded() ) )
1046 // If children not already loaded : do it
1048 item->GetDicomNode()->GetDicomDatabase()->DBLoadChildren
1049 (item->GetDicomNode(),item->GetDicomNode()->GetType()+1)
1053 // Some new children loaded
1055 if (mSettings.HasActiveComparator
1056 (item->GetDicomNode()->GetType()+1))
1058 /* std::cout << "Sorting using '"
1059 << mSettings.GetActiveComparator
1060 (item->GetDicomNode()->GetType()+1).GetName()
1063 item->GetDicomNode()->SortChildren
1064 ( mSettings.GetActiveComparator
1065 (item->GetDicomNode()->GetType()+1)
1067 // std::cout << "ok"<<std::endl;
1070 // If images : sort them
1071 if (item->IsDicomNode())
1073 if (item->GetDicomNode()->GetType()==DicomNode::Series)
1077 LexicographicalDicomNodeComparator compare;
1078 // DicomNodeImageImageNumberComparator c1;
1080 DicomNodeImageSliceLocationComparator c1;
1081 DicomNodeImageImageNumberComparator c2;
1082 DicomNodeImageFileNameComparator cn;
1086 // std::cout << "SORT"<<std::endl;
1087 item->GetDicomNode()->SortChildren(compare);
1088 // std::cout << "EO SORT"<<std::endl;
1096 DicomNode::ChildrenListType::iterator i;
1097 for (i=item->GetDicomNode()->GetChildrenList().begin();
1098 i!=item->GetDicomNode()->GetChildrenList().end();
1101 UpdateDicomNodeView(*i,itemId);
1104 // EO If children not already loaded
1107 // mTreeListCtrl->Expand(itemId);
1110 //================================================================
1114 //=====================================================================
1115 void WxGimmick::InsertRoot(wxTreeItemId& id, Root* r)
1118 TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
1123 data->GetDicomNode()->GetDicomDatabase()->LoadAll();
1124 printf(">>>>>> Time to load all = %ldms \n",sw.Time());
1126 UpdateRootView(data->GetDicomNode()->GetDicomDatabase());
1129 if (data->IsDicomNode())
1132 r->Insert(data->GetDicomNode());
1133 printf(">>>>>> Time to insert = %ldms \n",sw1.Time());
1136 else if (data->IsDatabase())
1139 DicomNode::ChildrenListType::iterator j;
1140 for (j= data->GetDicomNode()->GetChildrenList().begin();
1141 j!=data->GetDicomNode()->GetChildrenList().end();
1146 printf(">>>>>> Time to insert = %ldms \n",sw1.Time());
1152 //=====================================================================
1156 //=================================================
1157 void WxGimmick::DeleteDicomDatabase(wxTreeItemId& id,
1161 DicomDatabaseListType::iterator i = find(GetDicomDatabaseList().begin(),
1162 GetDicomDatabaseList().end(),
1165 GetDicomDatabaseList().erase(i);
1166 mTreeListCtrl->Delete(id);
1168 //=================================================
1172 //=====================================================================
1174 void WxGimmick::OnItemRightClick(wxTreeEvent& event)
1177 wxTreeItemId itemId = event.GetItem();
1180 wxPoint clientpt = event.GetPoint();
1181 wxPoint screenpt = ClientToScreen(clientpt);
1182 ShowMenu(itemId, clientpt);
1186 //=====================================================================
1190 //=====================================================================
1191 void WxGimmick::ShowMenu(wxTreeItemId id, const wxPoint& pt)
1194 // std::cout << "ShowMenu" <<std::endl;
1196 TreeItemData *data =
1197 (TreeItemData *)mTreeListCtrl->GetItemData(id);
1203 title << wxT("Menu for ") << mTreeListCtrl->GetItemText(id);
1207 title = wxT("Menu for no particular item");
1214 if (id==mCollectionsTitlesItemId)
1216 menu.Append(PopUp_NewCollection, _T("&New collection"));
1217 menu.Append(PopUp_OpenCollection, _T("&Open collection"));
1221 if (data->IsDatabase())
1223 wxMenu* addmenu = new wxMenu;
1224 addmenu->Append(PopUp_AddDirectory, _T("Scan &Directory"));
1225 addmenu->Append(PopUp_AddFile, _T("Select &File(s)"));
1226 // addmenu->Append(PopUp_AddRawFile, _T("Add &Raw image"));
1227 menu.AppendSubMenu(addmenu, _T("&Add image(s) to collection..."));
1228 menu.Append(PopUp_CloseCollection, _T("&Close collection"));
1229 menu.Append(PopUp_DeleteCollection, _T("&Delete collection"));
1231 if (data->IsDicomNode())
1235 std::string str("&Remove ");
1236 str += data->GetDicomNode()->GetTypeName();
1237 menu.Append(PopUp_Remove, std2wx(str));
1241 if ((data->GetDicomNode()>0)&&
1242 ( data->GetDicomNode()->GetType()<DicomNode::Image))
1244 int ctype = data->GetDicomNode()->GetType()+1;
1245 if (mSettings.HasActiveComparator(ctype))
1247 wxMenu* sortmenu = new wxMenu;
1249 Settings::ComparatorsList::iterator i;
1250 for (i =mSettings.GetComparatorsList(ctype).begin();
1251 i !=mSettings.GetComparatorsList(ctype).end();
1254 sortmenu->AppendRadioItem(PopUp_Sort+n, std2wx(i->GetName()));
1258 sortmenu->Check(PopUp_Sort+
1259 mSettings.GetActiveComparatorIndex(ctype)
1262 std::string sortmenustr("&Sort ");
1263 sortmenustr += DicomNode::GetPluralTypeName(ctype);
1264 sortmenustr += " by...";
1265 if (menu.GetMenuItemCount()>0) menu.AppendSeparator();
1266 menu.AppendSubMenu(sortmenu,std2wx(sortmenustr));
1269 item->GetDicomNode()->SortChildren
1270 ( mSettings.GetActiveComparator
1271 (item->GetDicomNode()->GetType()+1)
1273 std::cout << "ok"<<std::endl;
1278 // Event : user can customize the menu
1280 ev(wxEVT_COMMAND_TREEVIEWLIST_CONTEXTUAL_MENU,this,id);
1284 ev.SetDicomNode(data->GetDicomNode());
1286 GetEventHandler()->ProcessEvent(ev);
1289 if (menu.GetMenuItemCount()>0) menu.AppendSeparator();
1290 menu.Append(PopUp_Settings, wxT("&Settings..."));
1291 menu.Append(PopUp_About, wxT("&About..."));
1296 wxMenu* newmenu = new wxMenu;
1297 wxMenu* openmenu = new wxMenu;
1298 Tree::RootHandlerListType::iterator h;
1300 for (h= Tree::GetRootHandlerList().begin();
1301 h!=Tree::GetRootHandlerList().end();
1304 if ((*h)->SupportsNew())
1306 newmenu->Append(PopUp_New+i, std2wx((*h)->GetName()));
1308 if ((*h)->SupportsOpen())
1309 openmenu->Append(PopUp_Open+i, std2wx((*h)->GetName()));
1313 menu.AppendSubMenu(openmenu, _T("&Open"));
1314 menu.AppendSubMenu(newmenu, _T("&New"));
1318 if ((data->IsDatabase())||(data->IsDicomNode()))
1320 Root* itroot = data->GetDicomNode()->GetDicomDatabase();
1321 // if (!itroot) itroot = data->GetDicomNode()->GetRoot();
1322 wxMenu* insertmenu = new wxMenu;
1323 bool hasone = false;
1325 Tree::RootListType::iterator j;
1326 for (j = mTree->GetDatabaseList().begin();
1327 j != mTree->GetDatabaseList().end();
1330 // std::cout << (*j)->GetName() << " "
1331 // << (*j)->GetTypeName()
1332 // << " i="<<(*j)->SupportsInsert()<<std::endl;
1333 if ( ((*j)!=itroot) && ((*j)->SupportsInsert()) )
1335 insertmenu->Append(PopUp_Insert+i,
1336 std2wx((*j)->GetName()));
1342 if (hasone) menu.AppendSubMenu(insertmenu, _T("&Insert into"));
1344 if (data->IsDatabase())
1346 menu.Append(PopUp_Close, wxT("&Close"));
1348 if (data->IsDicomNode() && data->GetDicomNode()->GetDicomDatabase()->SupportsRemove())
1350 menu.Append(PopUp_Remove, wxT("&Remove"));
1358 PopupMenu(&menu, pt);
1359 #endif // wxUSE_MENUS
1361 // std::cout << "EO ShowMenu" <<std::endl;
1363 //=====================================================================
1365 //=====================================================================
1366 // Pop up menu callbacks
1367 void WxGimmick::OnPopUpAbout(wxCommandEvent& event)
1369 wxMessageBox( _T("Give me my medical images quick ! \n\n (c) CREATIS-LRMN 2008\n"),
1371 wxOK | wxICON_INFORMATION, this);
1373 //=====================================================================
1375 //=====================================================================
1376 void WxGimmick::OnPopUpSettings(wxCommandEvent& event)
1378 WxGimmickSettingsDialog* s =
1379 new WxGimmickSettingsDialog(this);
1383 //=====================================================================
1385 //=====================================================================
1386 void WxGimmick::OnPopUpNewCollection(wxCommandEvent& event)
1389 OpenOrNewDatabase(false);
1391 //=====================================================================
1395 //=====================================================================
1396 void WxGimmick::OnPopUpOpenCollection(wxCommandEvent& event)
1399 OpenOrNewDatabase(true);
1401 //=====================================================================
1404 //=====================================================================
1405 void WxGimmick::OnPopUpCloseCollection(wxCommandEvent& event)
1407 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;
1410 // std::cout << "OnPopUpClose"<<std::endl;
1411 // wxTreeItemId id = event.GetId();
1412 TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1413 DicomDatabase* r = data->GetDicomNode()->GetDicomDatabase();
1414 // std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1415 DeleteDicomDatabase(mItemOfMenu,r);
1417 //=====================================================================
1419 //=====================================================================
1420 void WxGimmick::OnPopUpDeleteCollection(wxCommandEvent& event)
1422 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;
1427 // std::cout << "OnPopUpClose"<<std::endl;
1428 // wxTreeItemId id = event.GetId();
1429 TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1430 DicomDatabase* r = data->GetDicomNode()->GetDicomDatabase();
1432 wxRemoveFile(std2wx(r->GetFileName()));
1433 // std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1434 DeleteDicomDatabase(mItemOfMenu,r);
1437 //=====================================================================
1439 void DisplayUpdateSummary( DicomDatabase::UpdateSummary& summary,
1442 std::stringstream mess;
1443 mess << "Dirs\tscanned\t\t\t: " << summary.scanned_dirs << "\n";
1444 mess << "Files\tscanned\t\t\t: " << summary.scanned_files << "\n";
1445 mess << "Files\thandled\t\t\t: " << summary.handled_images << "\n\n";
1446 mess << "Patients\tadded\t\t: " << summary.added_patients<< "\n";
1447 mess << "Studies\tadded\t\t: " << summary.added_studies<< "\n";
1448 mess << "Series\tadded\t\t: " << summary.added_series<< "\n";
1449 mess << "Images\tadded\t\t: " << summary.added_images<< "\n\n";
1451 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",
1453 (int)( summary.parse_time*100./summary.total_time),
1454 summary.file_scan_time,
1455 (int)(summary.file_scan_time*100./summary.total_time),
1456 summary.update_structs_time,
1457 (int)(summary.update_structs_time*100./summary.total_time),
1458 summary.update_database_time,
1459 (int)(summary.update_database_time*100./summary.total_time),
1460 summary.total_time );
1464 wxMessageBox(std2wx(mess.str()),_T("Update summary"),wxOK,parent);
1468 //=====================================================================
1469 void WxGimmick::OnPopUpAddFile(wxCommandEvent& event)
1471 long style = wxOPEN | wxFILE_MUST_EXIST | wxFD_MULTIPLE;
1472 std::string wc("*.*");
1473 wxFileDialog* FD = new wxFileDialog( 0,
1481 if (FD->ShowModal()==wxID_OK)
1485 mCurrentDirectory = FD->GetDirectory();
1486 wxArrayString files;
1487 FD->GetPaths(files);
1489 std::vector<std::string> filenames;
1490 for (i=0;i<files.GetCount();++i)
1491 filenames.push_back(wx2std(files[i]));
1494 TreeItemData *data =
1496 mTreeListCtrl->GetItemData(mItemOfMenu);
1497 DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1498 DicomDatabase::UpdateSummary summary;
1499 wxProgressDialog* progress =
1500 new wxProgressDialog(_T("Adding file(s)"),
1505 wxPD_ESTIMATED_TIME |
1506 wxPD_REMAINING_TIME |
1509 db->AddFiles(filenames,progress,summary);
1511 progress->Pulse(_T("Updating view..."));
1512 UpdateDicomDatabaseView(db);
1514 DisplayUpdateSummary(summary,this);
1518 //=====================================================================
1520 //=====================================================================
1521 void WxGimmick::OnPopUpAddRawFile(wxCommandEvent& event)
1523 wxMessageBox(_T("Not yet implemented !"),_T("Sorry"),wxOK,this);
1525 //=====================================================================
1527 //=====================================================================
1528 void WxGimmick::OnPopUpAddDirectory(wxCommandEvent& event)
1530 long style = wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST;
1533 _T("Select directory"),
1537 if (FD->ShowModal()==wxID_OK)
1540 bool recurse = false;
1541 if (wxMessageBox(_T("Recurse into sub-directories ?"),
1542 _T("Scan directory"),
1543 wxYES_NO,this ) == wxYES)
1549 wxProgressDialog* progress =
1550 new wxProgressDialog(_T("Scanning directory"),
1551 _T("Parsing directory"),
1555 wxPD_ESTIMATED_TIME |
1556 wxPD_REMAINING_TIME |
1558 DicomDatabase::UpdateSummary summary;
1560 std::string dirname = wx2std (FD->GetPath()) ;
1561 mCurrentDirectory = FD->GetPath();
1562 TreeItemData *data =
1564 mTreeListCtrl->GetItemData(mItemOfMenu);
1565 DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1566 db->AddDirectory(dirname,recurse,progress,summary);
1568 progress->Pulse(_T("Updating view..."));
1569 UpdateDicomDatabaseView(db);
1572 DisplayUpdateSummary(summary,this);
1574 if (summary.cancelled_by_user)
1576 std::cout << "!! Cancelled by user !!"<<std::endl;
1582 //=====================================================================
1584 //=====================================================================
1585 void WxGimmick::OnPopUpRemove(wxCommandEvent& event)
1589 wxMessageBox(_T("Not yet implemented"),_T("Sorry !"),wxOK);
1593 // wxTreeItemId id = event.GetId();
1594 TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1596 std::string mess("Remove ");
1597 mess += data->GetDicomNode()->GetTypeName();
1598 mess += " from collection ?";
1599 int answer = wxMessageBox(std2wx(mess), _T("Confirm"), wxYES_NO);
1600 if (answer == wxNO) return;
1602 if ( mTreeListCtrl->IsSelected(mItemOfMenu) )
1604 wxTreeItemId next = mTreeListCtrl->GetNextSibling(mItemOfMenu);
1607 mTreeListCtrl->SelectItem(next);
1615 DicomDatabase* db = data->GetDicomNode()->GetDicomDatabase();
1616 db->Remove(data->GetDicomNode());
1617 // std::cout << "OnPopUpClose '"<<r->GetName()<<"'"<<std::endl;
1618 // TODO : Optimize update only parent's branch
1619 UpdateDicomDatabaseView(db);
1620 // DeleteDicomDatabase(mItemOfMenu,r);
1622 //=====================================================================
1624 //=====================================================================
1625 void WxGimmick::OnPopUpSort(wxCommandEvent& event)
1628 // std::cout << "OnPopUpSort"<<std::endl;
1629 TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(mItemOfMenu);
1630 int index = event.GetId() - PopUp_Sort;
1631 DicomNode* node = data->GetDicomNode();
1632 DicomNode::Type ctype = node->GetType()+1;
1633 mSettings.SetActiveComparatorIndex(ctype,index);
1635 if (node->ChildrenLoaded())
1638 mTreeListCtrl->DeleteChildren(mItemOfMenu);
1640 /* std::cout << "Sorting using '"
1641 << mSettings.GetActiveComparator(ctype).GetName()
1644 node->SortChildren ( mSettings.GetActiveComparator(ctype) );
1645 // std::cout << "ok"<<std::endl;
1649 CreateChildrenColumnsTitles(mItemOfMenu,ctype);
1650 DicomNode::ChildrenListType::iterator i;
1651 for (i=node->GetChildrenList().begin();
1652 i!=node->GetChildrenList().end();
1655 UpdateDicomNodeView(*i,mItemOfMenu);
1659 //=====================================================================
1662 //=====================================================================
1663 void WxGimmick::OnPopUpUser(wxCommandEvent& event)
1665 // std::cout << "OnPopUpUser"<<std::endl;
1668 //=====================================================================
1670 //=================================================
1671 void WxGimmick::CreateImageList(int size)
1675 mTreeListCtrl->SetImageList(NULL);
1684 // should correspond to Icon_xxx enum
1685 icons[Icon_Patient] = wxIcon(patient_xpm);
1686 icons[Icon_Study] = wxIcon(study_xpm);
1687 icons[Icon_Series] = wxIcon(series_xpm);
1688 icons[Icon_Image] = wxIcon(image_xpm);
1689 icons[Icon_Database] = wxIcon(database_xpm);
1690 icons[Icon_Folder] = wxIcon(folder_xpm);
1691 icons[Icon_DicomDir] = wxIcon(dicomdir_xpm);
1692 icons[Icon_Root] = wxIcon(root_xpm);
1695 // mFirstRootIconIndex = 8;
1698 Tree::RootHandlerListType::iterator h;
1700 for (h= Tree::GetDatabaseHandlerList().begin();
1701 h!=Tree::GetDatabaseHandlerList().end();
1704 icons[mFirstRootIconIndex+i] = (*h)->GetIcon();
1708 unsigned int NbIcons = 8;//mFirstRootIconIndex + i;
1709 // Make an image list containing small icons
1710 wxImageList *images = new wxImageList(size, size, true);
1712 int sizeOrig = icons[0].GetWidth();
1713 for ( size_t i = 0; i < NbIcons; i++ )
1715 if ( size == sizeOrig )
1717 images->Add(icons[i]);
1721 images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
1724 mTreeListCtrl->AssignImageList(images);
1726 //=================================================
1728 //================================================================
1729 void WxGimmick::OnSelChanging(wxTreeEvent& event)
1731 wxTreeItemId id = event.GetItem();
1734 std::cout << "ERROR : ID NOT OK"<<std::endl;
1738 TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
1741 if (data->IsDicomNode())
1743 if ((data->GetDicomNode()>0)&&
1744 ( data->GetDicomNode()->GetType()==DicomNode::Image))
1750 //================================================================
1752 //================================================================
1753 void WxGimmick::OnSelChanged(wxTreeEvent& event)
1755 // wxBusyCursor busy;
1756 // std::vector<wxTreeItemId> items;
1757 // GetSelectedItems(items);
1759 std::vector<DicomNode*>::iterator i;
1760 for (i=nodes.begin();i!=nodes.end();++i)
1762 std::cout << "'" << (*i)->GetFieldValue("FullFileName")
1763 << "'" << std::endl;
1765 std::cout << "++++++++++++++++++++" << std::endl;
1767 // ShowImage(mReader.GetImage(""));
1769 bool no_image = true;
1771 static int max = 1000;
1774 // if (items.size()>0)
1777 // Update image preview : send requests to the MTImageReader
1778 // bool first = true;
1779 // std::vector<wxTreeItemId>::iterator i;
1780 // for (i=items.begin();i!=items.end();++i)
1786 DicomNode* node = GetDicomNodeOfItem(items[0]);
1788 // Update dicom fields panel
1789 mFieldsView->UpdateValues(node);
1793 wxTreeItemId item = mTreeListCtrl->GetCurrent();
1795 DicomNode* n = GetDicomNodeOfItem(item);
1797 if (n) mFieldsView->UpdateValues(n);
1800 (n->GetType()==DicomNode::Image) )
1805 //if (i==items.begin())
1806 mCurImageItemToShow = item;
1808 int maxprio = mReader.GetMaximalPriority();
1809 int prio = maxprio + 1000;
1810 wxTreeItemId sib = item; //GetTreeListCtrl()->GetNextSibling(*i);
1813 DicomNode* nsib = GetDicomNodeOfItem(sib);
1816 // std::cout << "-- Request '"
1817 // << nsib->GetFieldValue("FullFileName")
1818 // << "' prio="<<prio<<std::endl;
1819 mReader.Request(this,
1820 nsib->GetFieldValue("FullFileName"),
1822 mImageFileNameToNode[nsib->GetFieldValue("FullFileName")] =
1826 sib = GetTreeListCtrl()->GetNextSibling(sib);
1828 prio = maxprio + 1000;
1829 sib = GetTreeListCtrl()->GetPrevSibling(item);
1832 DicomNode* nsib = GetDicomNodeOfItem(sib);
1835 // std::cout << "-- Request '"
1836 // << nsib->GetFieldValue("FullFileName")
1837 // << "' prio="<<prio<<std::endl;
1838 mReader.Request(this,
1839 nsib->GetFieldValue("FullFileName"),
1841 mImageFileNameToNode[nsib->GetFieldValue("FullFileName")] =
1845 sib = GetTreeListCtrl()->GetPrevSibling(sib);
1847 // mImageFileNameToNode[n->GetFieldValue("FullFileName")] = n;
1850 ProcessImageEvents();
1852 // std::cout << "* Selection changed * (im)"<<std::endl;
1854 //---------------------------------------------------------------------
1856 WxGimmickEvent ev(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGED,
1860 GetEventHandler()->ProcessEvent(ev);
1862 if (no_image) ShowImage(mReader.GetImage(""));
1865 //================================================================
1867 //================================================================
1868 void WxGimmick::ShowImage(vtkImageData* im)
1870 // wxBusyCursor busy;
1872 int x1,x2,y1,y2,z1,z2;
1874 im->GetSpacing(spx,spy,spz);
1875 im->GetExtent (x1,x2,y1,y2,z1,z2);
1878 std::cout << x1 << "-"<<x2<<std::endl;
1879 std::cout << y1 << "-"<<y2<<std::endl;
1880 std::cout << z1 << "-"<<z2<<std::endl;
1881 std::cout << spx << "-"<<spy<<"-"<<spz<<std::endl;
1905 vtkCamera *camera = mViewer->GetRenderer()->GetActiveCamera();
1907 camera->SetViewUp ( spx*0, -spy*1, spz*0);
1908 camera->SetPosition( spx*(x1+x2)/2, spy*(y1+y2)/2, -spz*10000000);
1909 camera->SetFocalPoint ( spx*(x1+x2)/2 , spy*(y1+y2)/2 , spz*0);
1911 camera->ComputeViewPlaneNormal();
1912 camera->SetParallelScale( spx*(x2-x1)/2.0 );
1916 mViewer->SetInput( im );
1917 mViewer->SetSlice( 0 );
1918 mInteractor->Render();
1920 //================================================================
1927 //================================================================
1929 OnMultiThreadImageReaderEvent(const std::string& filename,
1930 MultiThreadImageReaderUser::EventType e,
1931 vtkImageData* image)
1933 if (filename.size()==0)
1935 mImageEventQueue.push_back(ImageEventType(image));
1938 std::map<std::string,DicomNode*>::iterator i;
1939 i = mImageFileNameToNode.find(filename);
1940 if (i!=mImageFileNameToNode.end())
1942 wxTreeItemId id = i->second->GetData<NodeData*>()->GetTreeItemData()->GetItemId();
1943 mImageEventQueue.push_back(ImageEventType(id,image));
1946 //================================================================
1948 //================================================================
1949 // Processes the queue of image events
1950 void WxGimmick::ProcessImageEvents()
1952 // std::cout << "++++++++++ ProcessImageEvents " << std::endl;
1953 MultiThreadImageReaderEventLock();
1956 while (!mImageEventQueue.empty())
1958 ImageEventType e = mImageEventQueue.front();
1959 mImageEventQueue.pop_front();
1964 mTreeListCtrl->SetItemTextColour(e.item,
1965 mSettings.LoadedImageColour());//wxImageLoadedColour);
1966 TreeItemData *data =
1967 (TreeItemData *)mTreeListCtrl->GetItemData(e.item);
1968 data->SetLoaded(true);
1970 if (mCurImageItemToShow == e.item)
1975 else if (!mCurImageItemToShow.IsOk())
1980 else if (e.item.IsOk())
1982 mTreeListCtrl->SetItemTextColour(e.item,mSettings.Colour(DicomNode::Image)); //.wxImageUnloadedColour);
1983 TreeItemData *data =
1984 (TreeItemData *)mTreeListCtrl->GetItemData(e.item);
1985 data->SetLoaded(false);
1988 mImageEventQueue.clear();
1989 MultiThreadImageReaderEventUnlock();
1990 // std::cout << "++++++++++ END ProcessImageEvents " << std::endl;
1992 //================================================================
1994 //================================================================
1995 void WxGimmick::OnInternalIdle()
1997 ProcessImageEvents();
1999 //================================================================
2003 //================================================================
2004 void WxGimmick::GetSelectedImages(std::vector<std::string>& f)
2006 wxArrayTreeItemIds id;
2007 // TO DO : TEST THAT STYLE IS MULTIPLE
2008 unsigned int nb = mTreeListCtrl->GetSelections(id);
2010 for (unsigned int i=0; i<nb; ++i)
2012 TreeItemData *data =
2013 (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2014 if ((data) && (data->IsDicomNode()))
2016 if (data->GetDicomNode()->GetType()==DicomNode::Image)
2018 f.push_back ( data->GetDicomNode()->GetFieldValue("FullFileName") );
2020 else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2022 DicomNode::ChildrenListType::iterator j;
2023 for (j =data->GetDicomNode()->GetChildrenList().begin();
2024 j!=data->GetDicomNode()->GetChildrenList().end();
2027 f.push_back((*j)->GetFieldValue("FullFileName"));
2033 //================================================================
2036 //================================================================
2037 void WxGimmick::GetSelectedDicomNodes(std::vector<DicomNode*>& f)
2039 wxArrayTreeItemIds id;
2040 // TO DO : TEST THAT STYLE IS MULTIPLE
2041 unsigned int nb = mTreeListCtrl->GetSelections(id);
2043 for (unsigned int i=0; i<nb; ++i)
2045 TreeItemData *data =
2046 (TreeItemData *)mTreeListCtrl->GetItemData(id[i]);
2047 if ((data) && (data->IsDicomNode()))
2049 f.push_back ( data->GetDicomNode() );
2053 if (data->GetDicomNode()->GetType()==DicomNode::Image)
2055 f.push_back ( data->GetDicomNode() ); //->GetFieldValue("FullFileName") );
2057 else if (data->GetDicomNode()->GetType()==DicomNode::Series)
2059 DicomNode::ChildrenListType::iterator j;
2060 for (j =data->GetDicomNode()->GetChildrenList().begin();
2061 j!=data->GetDicomNode()->GetChildrenList().end();
2064 f.push_back((*j)); //->GetFieldValue("FullFileName"));
2071 //================================================================
2073 //================================================================
2074 void WxGimmick::GetSelectedItems(std::vector<wxTreeItemId>& f)
2076 wxArrayTreeItemIds id;
2077 // TO DO : TEST THAT STYLE IS MULTIPLE
2078 unsigned int nb = mTreeListCtrl->GetSelections(id);
2080 for (unsigned int i=0; i<nb; ++i)
2085 //================================================================
2087 //================================================================
2088 DicomNode* WxGimmick::GetDicomNodeOfItem(const wxTreeItemId& i)
2090 TreeItemData *data =
2091 (TreeItemData *)mTreeListCtrl->GetItemData(i);
2092 if (data) return ( data->GetDicomNode() );
2095 //================================================================
2097 //================================================================
2098 //================================================================
2099 //================================================================
2100 //================================================================
2116 //================================================================
2117 //================================================================
2118 //================================================================
2119 //================================================================
2121 BEGIN_EVENT_TABLE(WxGimmick, wxPanel)
2123 EVT_MENU(PopUp_NewCollection,WxGimmick::OnPopUpNewCollection)
2124 EVT_MENU(PopUp_OpenCollection,WxGimmick::OnPopUpOpenCollection)
2125 EVT_MENU(PopUp_CloseCollection,WxGimmick::OnPopUpCloseCollection)
2126 EVT_MENU(PopUp_DeleteCollection,WxGimmick::OnPopUpDeleteCollection)
2127 EVT_MENU(PopUp_AddFile, WxGimmick::OnPopUpAddFile)
2128 EVT_MENU(PopUp_AddRawFile, WxGimmick::OnPopUpAddRawFile)
2129 EVT_MENU(PopUp_AddDirectory, WxGimmick::OnPopUpAddDirectory)
2130 EVT_MENU(PopUp_Remove, WxGimmick::OnPopUpRemove)
2131 EVT_MENU(PopUp_About, WxGimmick::OnPopUpAbout)
2132 EVT_MENU(PopUp_Settings, WxGimmick::OnPopUpSettings)
2134 EVT_MENU_RANGE(PopUp_Sort, PopUp_Sort+99, WxGimmick::OnPopUpSort)
2135 EVT_MENU_RANGE(PopUp_User, PopUp_User+99, WxGimmick::OnPopUpUser)
2140 EVT_TREE_BEGIN_DRAG(TreeListCtrlId, WxGimmick::OnBeginDrag)
2141 EVT_TREE_BEGIN_RDRAG(TreeListCtrlId, WxGimmick::OnBeginRDrag)
2142 EVT_TREE_END_DRAG(TreeListCtrlId, WxGimmick::OnEndDrag)
2145 EVT_TREE_BEGIN_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnBeginLabelEdit)
2146 EVT_TREE_END_LABEL_EDIT(TreeListCtrlId, WxGimmick::OnEndLabelEdit)
2149 EVT_TREE_DELETE_ITEM(TreeListCtrlId, WxGimmick::OnDeleteItem)
2150 #if 0 // there are so many of those that logging them causes flicker
2151 EVT_TREE_GET_INFO(TreeListCtrlId, WxGimmick::OnGetInfo)
2154 EVT_TREE_SET_INFO(TreeListCtrlId, WxGimmick::OnSetInfo)
2157 EVT_TREE_ITEM_EXPANDED(TreeListCtrlId, WxGimmick::OnItemExpanded)
2158 EVT_TREE_ITEM_EXPANDING(TreeListCtrlId, WxGimmick::OnItemExpanding)
2159 EVT_TREE_ITEM_COLLAPSED(TreeListCtrlId, WxGimmick::OnItemCollapsed)
2160 EVT_TREE_ITEM_COLLAPSING(TreeListCtrlId, WxGimmick::OnItemCollapsing)
2163 EVT_TREE_SEL_CHANGED(TreeListCtrlId, WxGimmick::OnSelChanged)
2164 EVT_TREE_SEL_CHANGING(TreeListCtrlId, WxGimmick::OnSelChanging)
2166 EVT_TREE_KEY_DOWN(TreeListCtrlId, WxGimmick::OnTreeKeyDown)
2167 // ACTIVATION = DOUBLE CLICK OR ENTER ON SELECTED
2168 EVT_TREE_ITEM_ACTIVATED(TreeListCtrlId, WxGimmick::OnItemActivated)
2170 // so many differents ways to handle right mouse button clicks...
2171 // EVT_CONTEXT_MENU(WxGimmick::OnContextMenu)
2172 // EVT_TREE_ITEM_MENU is the preferred event for creating context menus
2173 // on a tree control, because it includes the point of the click or item,
2174 // meaning that no additional placement calculations are required.
2175 // EVT_TREE_ITEM_MENU(TreeListCtrlId, WxGimmick::OnItemMenu)
2177 EVT_TREE_ITEM_RIGHT_CLICK(TreeListCtrlId, WxGimmick::OnItemRightClick)
2180 // EVT_RIGHT_DOWN(WxGimmick::OnRMouseDown)
2181 // EVT_RIGHT_UP(WxGimmick::OnRMouseUp)
2182 // EVT_RIGHT_DCLICK(WxGimmick::OnRMouseDClick)
2185 //IMPLEMENT_DYNAMIC_CLASS(WxGimmick, wxTreeListCtrl)
2188 wxTree::wxTree(wxWindow *parent, const wxWindowID id,
2189 const wxPoint& pos, const wxSize& size,
2191 : wxTreeListCtrl(parent, id, pos, size, style)
2193 m_reverseSort = false;
2197 // Add some items to the tree
2198 AddTestItemsToTree(5, 2);
2204 #if USE_GENERIC_TREECTRL || !defined(__WXMSW__)
2205 void WxGimmick::CreateButtonsImageList(int size)
2210 mTreeListCtrl->SetButtonsImageList(NULL);
2214 // Make an image list containing small icons
2215 wxImageList *images = new wxImageList(size, size, true);
2217 // should correspond to TreeListCtrlIcon_xxx enum
2220 icons[0] = wxIcon(icon3_xpm); // closed
2221 icons[1] = wxIcon(icon3_xpm); // closed, selected
2222 icons[2] = wxIcon(icon5_xpm); // open
2223 icons[3] = wxIcon(icon5_xpm); // open, selected
2225 for ( size_t i = 0; i < WXSIZEOF(icons); i++ )
2227 int sizeOrig = icons[i].GetWidth();
2228 if ( size == sizeOrig )
2230 images->Add(icons[i]);
2234 images->Add(wxBitmap(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size)));
2238 mTreeListCtrl->AssignButtonsImageList(images);
2241 void WxGimmick::CreateButtonsImageList(int WXUNUSED(size))
2247 int WxGimmick::OnCompareItems(const wxTreeItemId& item1,
2248 const wxTreeItemId& item2)
2250 if ( m_reverseSort )
2252 // just exchange 1st and 2nd items
2253 return mTreeListCtrl->OnCompareItems(item2, item1);
2257 return mTreeListCtrl->OnCompareItems(item1, item2);
2262 void WxGimmick::DoToggleIcon(const wxTreeItemId& item)
2265 int image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_Folder)
2268 mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Normal);
2270 image = (mTreeListCtrl->GetItemImage(item) == TreeIcon_FolderSelected)
2271 ? TreeIcon_FileSelected
2272 : TreeIcon_FolderSelected;
2273 mTreeListCtrl->SetItemImage(item, image, wxTreeItemIcon_Selected);
2276 void WxGimmick::LogEvent(const wxChar *name, const wxTreeEvent& event)
2278 wxTreeItemId item = event.GetItem();
2281 text << _T('"') << mTreeListCtrl->GetItemText(item).c_str() << _T('"');
2283 text = _T("invalid item");
2284 // wxLogMessage(wxT("%s(%s)"), name, text.c_str());
2289 #define TREE_EVENT_HANDLER(name) \
2290 void WxGimmick::name(wxTreeEvent& event) \
2292 /* LogEvent(_T(#name), event); */ \
2293 /* SetLastItem(mTreeListCtrl->wxTreeItemId()) *;*/ \
2297 TREE_EVENT_HANDLER(OnBeginRDrag)
2298 TREE_EVENT_HANDLER(OnDeleteItem)
2299 TREE_EVENT_HANDLER(OnGetInfo)
2300 TREE_EVENT_HANDLER(OnSetInfo)
2301 //TREE_EVENT_HANDLER(OnItemExpanded)
2302 TREE_EVENT_HANDLER(OnItemExpanding)
2303 //TREE_EVENT_HANDLER(OnItemCollapsed)
2304 //TREE_EVENT_HANDLER(OnSelChanged)
2305 // TREE_EVENT_HANDLER(OnSelChanging)
2308 void WxGimmick::OnItemCollapsed(wxTreeEvent& event)
2310 // std::cout << "* Collapsed *"<<std::endl;
2313 #undef TREE_EVENT_HANDLER
2315 void WxGimmick::OnTreeKeyDown(wxTreeEvent& event)
2318 // LogKeyEvent(wxT("Tree key down "), event.GetKeyEvent());
2319 std::cout << "* Key down *"<<std::endl;
2320 if (event.GetKeyCode()==WXK_RIGHT)
2322 std::cout << "Right"<<std::endl;
2323 wxTreeItemId itemId = mTreeListCtrl->GetSelection();
2326 std::cout << "item is ok"<<std::endl;
2327 wxPoint clientpt = event.GetPoint();
2328 wxPoint screenpt = ClientToScreen(clientpt);
2329 ShowMenu(itemId, clientpt);
2334 std::cout << "NOT Right"<<std::endl;
2339 void WxGimmick::OnBeginDrag(wxTreeEvent& event)
2341 wxTreeItemId id = event.GetItem();
2342 TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2343 // std::cout << "OnBeginDrag("<<id<<")"<<std::endl;
2344 if (data->IsDatabase())
2346 // std::cout << "-- IS ROOT"<<std::endl;
2349 else if (data->IsDicomNode())
2351 // std::cout << "-- IS NODE"<<std::endl;
2354 // need to explicitly allow drag
2355 if ( event.GetItem() != GetDatabaseItem() )
2357 m_draggedItem = event.GetItem();
2359 wxPoint clientpt = event.GetPoint();
2360 wxPoint screenpt = ClientToScreen(clientpt);
2362 wxLogMessage(wxT("OnBeginDrag: started dragging %s at screen coords (%i,%i)"),
2363 GetItemText(m_draggedItem).c_str(),
2364 screenpt.x, screenpt.y);
2370 wxLogMessage(wxT("OnBeginDrag: this item can't be dragged."));
2375 void WxGimmick::OnEndDrag(wxTreeEvent& event)
2377 wxTreeItemId id = event.GetItem();
2378 // std::cout << "OnEndDrag("<<id<<")"<<std::endl;
2379 if (!id.IsOk()) return;
2380 TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2381 if (data->IsDatabase())
2383 // std::cout << "-- IS ROOT"<<std::endl;
2385 else if (data->IsDicomNode())
2387 // std::cout << "-- IS NODE"<<std::endl;
2391 wxTreeItemId itemSrc = m_draggedItem,
2392 itemDst = event.GetItem();
2393 m_draggedItem = (wxTreeItemId)0l;
2395 // where to copy the item?
2396 if ( itemDst.IsOk() && !ItemHasChildren(itemDst) )
2398 // copy to the parent then
2399 itemDst = GetItemParent(itemDst);
2402 if ( !itemDst.IsOk() )
2404 wxLogMessage(wxT("OnEndDrag: can't drop here."));
2409 wxString text = GetItemText(itemSrc);
2410 wxLogMessage(wxT("OnEndDrag: '%s' copied to '%s'."),
2411 text.c_str(), GetItemText(itemDst).c_str());
2413 // just do append here - we could also insert it just before/after the item
2414 // on which it was dropped, but this requires slightly more work... we also
2415 // completely ignore the client data and icon of the old item but could
2416 // copy them as well.
2418 // Finally, we only copy one item here but we might copy the entire tree if
2419 // we were dragging a folder.
2420 int image = wxGetApp().ShowImages() ? TreeIcon_File : -1;
2421 AppendItem(itemDst, text, image);
2426 //====================================================================
2427 void WxGimmick::OnBeginLabelEdit(wxTreeEvent& event)
2429 // std::cout << "OnBeginLabelEdit"<<std::endl;
2430 wxTreeItemId id = event.GetItem();
2431 TreeItemData *data = (TreeItemData *)mTreeListCtrl->GetItemData(id);
2432 // If not a root : veto
2433 if (data->IsDatabase())
2440 //====================================================================
2442 //====================================================================
2443 void WxGimmick::OnEndLabelEdit(wxTreeEvent& event)
2445 // std::cout << "OnEndLabelEdit"<<std::endl;
2446 wxTreeItemId id = event.GetItem();
2447 TreeItemData *data = GetItemData(id);
2448 // If not a database : bug !
2449 if (data->IsDatabase())
2451 data->GetDicomNode()->GetDicomDatabase()->SetName(wx2std(event.GetLabel()));
2452 mFieldsView->UpdateValues(data->GetDicomNode());
2456 std::cerr<< "!!!! Internal error : send bug report !!!!"<<std::endl;
2459 //====================================================================
2462 void WxGimmick::OnItemCollapsing(wxTreeEvent& event)
2464 // wxLogMessage(wxT("OnItemCollapsing"));
2466 // for testing, prevent the user from collapsing the first child folder
2467 wxTreeItemId itemId = event.GetItem();
2470 if ( IsTestItem(itemId) )
2472 wxMessageBox(wxT("You can't collapse this item."));
2489 //================================================================
2490 //================================================================
2491 //================================================================
2492 //================================================================
2493 //================================================================
2495 //================================================================
2496 //================================================================
2497 //================================================================
2498 //================================================================
2499 //================================================================
2505 // ----------------------------------------------------------------------------
2507 // ----------------------------------------------------------------------------
2509 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG)
2510 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG)
2511 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM)
2512 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO)
2513 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO)
2514 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED)
2515 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING)
2516 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
2517 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING)
2520 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT)
2521 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT)
2524 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGED)
2525 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_SEL_CHANGING)
2526 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_KEY_DOWN)
2527 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_CONTEXTUAL_MENU)
2528 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREEVIEWLIST_ITEM_STYLE_CHANGED)
2530 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED)
2531 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK)
2532 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK)
2533 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG)
2534 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK)
2535 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP)
2536 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU)
2538 // ----------------------------------------------------------------------------
2540 // ----------------------------------------------------------------------------
2542 IMPLEMENT_ABSTRACT_CLASS(WxGimmickEvent, wxNotifyEvent)
2545 WxGimmickEvent::WxGimmickEvent(wxEventType commandType,
2547 const wxTreeItemId& item)
2549 wxNotifyEvent(commandType, tree->GetId()),
2553 // m_editCancelled = false;
2555 SetEventObject(tree);
2558 SetClientObject(tree->mTreeListCtrl->GetItemData(item));
2561 WxGimmickEvent::WxGimmickEvent(wxEventType commandType, int id)
2563 wxNotifyEvent(commandType, id),
2567 // m_editCancelled = false;
2570 WxGimmickEvent::WxGimmickEvent(const WxGimmickEvent & event)
2572 wxNotifyEvent(event),
2576 m_evtKey = event.m_evtKey;
2577 m_item = event.m_item;
2578 m_itemOld = event.m_itemOld;
2579 mColor = event.mColor;
2580 mUserData = event.mUserData;
2581 // m_pointDrag = event.m_pointDrag;
2582 // m_label = event.m_label;
2583 // m_editCancelled = event.m_editCancelled;
2593 //================================================================
2594 //================================================================
2595 //================================================================
2596 //================================================================
2597 //================================================================
2598 WxGimmickFrame::WxGimmickFrame( wxWindow *parent,
2601 : wxFrame((wxFrame *)parent, -1, title, wxDefaultPosition, size)
2603 wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
2604 long style = wxTR_DEFAULT_STYLE |
2605 #ifndef NO_VARIABLE_HEIGHT
2606 wxTR_HAS_VARIABLE_ROW_HEIGHT |
2608 wxTR_EDIT_LABELS | wxSUNKEN_BORDER;
2609 mWxGimmick = new WxGimmick(this,-1,wxDefaultPosition,wxDefaultSize,style);
2610 sizer->Add(mWxGimmick,1,wxGROW);
2612 SetAutoLayout(true);
2615 //================================================================
2617 //================================================================
2618 WxGimmickFrame::~WxGimmickFrame()
2621 //================================================================
2623 //================================================================
2624 void WxGimmickFrame::OnSelChanged(WxGimmickEvent& event)
2626 // std::cout << "+++++ WxGimmickFrame::OnSelChanged ++++++++++"
2628 std::vector<std::string> file;
2629 // mWxGimmick->GetSelectedImages(file);
2631 std::vector<std::string>::iterator i;
2632 for (i=file.begin();i!=file.end();++i)
2634 std::cout << "'" << *i << "'" << std::endl;
2636 std::cout << "++++++++++++++++++++" << std::endl;
2639 //================================================================
2641 //================================================================
2642 BEGIN_EVENT_TABLE(WxGimmickFrame, wxFrame)
2643 EVT_TREEVIEWLIST_SEL_CHANGED(-1,WxGimmickFrame::OnSelChanged)
2645 //================================================================
2668 //================================================================
2669 //================================================================
2670 //================================================================
2671 //================================================================
2673 //================================================================
2674 WxGimmickSettingsDialog::WxGimmickSettingsDialog(wxWindow *parent)
2690 //================================================================
2692 //================================================================
2693 WxGimmickSettingsDialog::~WxGimmickSettingsDialog()
2696 //================================================================