Commit 1743ebf81204c3c6bd326f02bea3c0c902e38468
1 parent
f879b8b8
Exists in
master
and in
5 other branches
ADD: Added beginning of the PACS client
Showing
5 changed files
with
736 additions
and
2 deletions
Show diff stats
.gitattributes
@@ -839,7 +839,10 @@ invesalius/.svnignore -text | @@ -839,7 +839,10 @@ invesalius/.svnignore -text | ||
839 | invesalius/data/bases.py -text | 839 | invesalius/data/bases.py -text |
840 | invesalius/data/co_registration.py -text | 840 | invesalius/data/co_registration.py -text |
841 | invesalius/data/converters.py -text | 841 | invesalius/data/converters.py -text |
842 | +invesalius/gui/import_network_panel.py -text | ||
842 | invesalius/gui/preferences.py -text | 843 | invesalius/gui/preferences.py -text |
844 | +invesalius/net/__init__.py -text | ||
845 | +invesalius/net/dicom.py -text | ||
843 | locale/de/LC_MESSAGES/invesalius.mo -text | 846 | locale/de/LC_MESSAGES/invesalius.mo -text |
844 | locale/el/LC_MESSAGES/invesalius.mo -text | 847 | locale/el/LC_MESSAGES/invesalius.mo -text |
845 | locale/en/LC_MESSAGES/invesalius.mo -text | 848 | locale/en/LC_MESSAGES/invesalius.mo -text |
invesalius/gui/frame.py
@@ -32,6 +32,7 @@ import default_tasks as tasks | @@ -32,6 +32,7 @@ import default_tasks as tasks | ||
32 | import default_viewers as viewers | 32 | import default_viewers as viewers |
33 | import gui.dialogs as dlg | 33 | import gui.dialogs as dlg |
34 | import import_panel as imp | 34 | import import_panel as imp |
35 | +import import_network_panel as imp_net | ||
35 | import project as prj | 36 | import project as prj |
36 | import session as ses | 37 | import session as ses |
37 | import utils | 38 | import utils |
@@ -58,7 +59,7 @@ class Frame(wx.Frame): | @@ -58,7 +59,7 @@ class Frame(wx.Frame): | ||
58 | icon_path = os.path.join(const.ICON_DIR, "invesalius.ico") | 59 | icon_path = os.path.join(const.ICON_DIR, "invesalius.ico") |
59 | self.SetIcon(wx.Icon(icon_path, wx.BITMAP_TYPE_ICO)) | 60 | self.SetIcon(wx.Icon(icon_path, wx.BITMAP_TYPE_ICO)) |
60 | if sys.platform != 'darwin': | 61 | if sys.platform != 'darwin': |
61 | - self.Maximize() | 62 | + ####self.Maximize() ##DESCOMENTAR PAULO |
62 | #Necessary update AUI (statusBar in special) | 63 | #Necessary update AUI (statusBar in special) |
63 | #when maximized in the Win 7 and XP | 64 | #when maximized in the Win 7 and XP |
64 | #self.SetSize(self.GetSize()) | 65 | #self.SetSize(self.GetSize()) |
@@ -94,6 +95,7 @@ class Frame(wx.Frame): | @@ -94,6 +95,7 @@ class Frame(wx.Frame): | ||
94 | sub(self._SetProjectName, 'Set project name') | 95 | sub(self._SetProjectName, 'Set project name') |
95 | sub(self._ShowContentPanel, 'Show content panel') | 96 | sub(self._ShowContentPanel, 'Show content panel') |
96 | sub(self._ShowImportPanel, 'Show import panel in frame') | 97 | sub(self._ShowImportPanel, 'Show import panel in frame') |
98 | + sub(self._ShowImportNetwork, 'Show retrieve dicom panel') | ||
97 | sub(self._ShowTask, 'Show task panel') | 99 | sub(self._ShowTask, 'Show task panel') |
98 | sub(self._UpdateAUI, 'Update AUI') | 100 | sub(self._UpdateAUI, 'Update AUI') |
99 | sub(self._Exit, 'Exit') | 101 | sub(self._Exit, 'Exit') |
@@ -140,6 +142,12 @@ class Frame(wx.Frame): | @@ -140,6 +142,12 @@ class Frame(wx.Frame): | ||
140 | MaximizeButton(True).Floatable(True). | 142 | MaximizeButton(True).Floatable(True). |
141 | Caption(caption).CaptionVisible(True)) | 143 | Caption(caption).CaptionVisible(True)) |
142 | 144 | ||
145 | + ncaption = _("Retrieve DICOM from PACS") | ||
146 | + aui_manager.AddPane(imp_net.Panel(self), wx.aui.AuiPaneInfo(). | ||
147 | + Name("Retrieve").Centre().Hide(). | ||
148 | + MaximizeButton(True).Floatable(True). | ||
149 | + Caption(ncaption).CaptionVisible(True)) | ||
150 | + | ||
143 | # Add toolbars to manager | 151 | # Add toolbars to manager |
144 | # This is pretty tricky -- order on win32 is inverted when | 152 | # This is pretty tricky -- order on win32 is inverted when |
145 | # compared to linux2 & darwin | 153 | # compared to linux2 & darwin |
@@ -253,6 +261,18 @@ class Frame(wx.Frame): | @@ -253,6 +261,18 @@ class Frame(wx.Frame): | ||
253 | aui_manager.GetPane("Tasks").Show(1) | 261 | aui_manager.GetPane("Tasks").Show(1) |
254 | aui_manager.Update() | 262 | aui_manager.Update() |
255 | 263 | ||
264 | + def _ShowImportNetwork(self, evt_pubsub): | ||
265 | + """ | ||
266 | + Show viewers and task, hide import panel. | ||
267 | + """ | ||
268 | + ps.Publisher().sendMessage("Set layout button full") | ||
269 | + aui_manager = self.aui_manager | ||
270 | + aui_manager.GetPane("Retrieve").Show(1) | ||
271 | + aui_manager.GetPane("Data").Show(0) | ||
272 | + aui_manager.GetPane("Tasks").Show(0) | ||
273 | + aui_manager.GetPane("Import").Show(0) | ||
274 | + aui_manager.Update() | ||
275 | + | ||
256 | def _ShowImportPanel(self, evt_pubsub): | 276 | def _ShowImportPanel(self, evt_pubsub): |
257 | """ | 277 | """ |
258 | Show only DICOM import panel. | 278 | Show only DICOM import panel. |
@@ -316,7 +336,9 @@ class Frame(wx.Frame): | @@ -316,7 +336,9 @@ class Frame(wx.Frame): | ||
316 | elif id == const.ID_START: | 336 | elif id == const.ID_START: |
317 | self.ShowGettingStarted() | 337 | self.ShowGettingStarted() |
318 | elif id == const.ID_PREFERENCES: | 338 | elif id == const.ID_PREFERENCES: |
319 | - self.ShowPreferences() | 339 | + self.ShowPreferences() |
340 | + elif id == const.ID_DICOM_NETWORK: | ||
341 | + self.ShowRetrieveDicomPanel() | ||
320 | 342 | ||
321 | def OnSize(self, evt): | 343 | def OnSize(self, evt): |
322 | """ | 344 | """ |
@@ -365,6 +387,10 @@ class Frame(wx.Frame): | @@ -365,6 +387,10 @@ class Frame(wx.Frame): | ||
365 | """ | 387 | """ |
366 | ps.Publisher().sendMessage('Show import directory dialog') | 388 | ps.Publisher().sendMessage('Show import directory dialog') |
367 | 389 | ||
390 | + def ShowRetrieveDicomPanel(self): | ||
391 | + print "teste.............." | ||
392 | + ps.Publisher().sendMessage('Show retrieve dicom panel') | ||
393 | + | ||
368 | def ShowOpenProject(self): | 394 | def ShowOpenProject(self): |
369 | """ | 395 | """ |
370 | Show open project dialog. | 396 | Show open project dialog. |
@@ -432,6 +458,7 @@ class MenuBar(wx.MenuBar): | @@ -432,6 +458,7 @@ class MenuBar(wx.MenuBar): | ||
432 | file_menu = wx.Menu() | 458 | file_menu = wx.Menu() |
433 | app = file_menu.Append | 459 | app = file_menu.Append |
434 | app(const.ID_DICOM_IMPORT, _("Import DICOM...\tCtrl+I")) | 460 | app(const.ID_DICOM_IMPORT, _("Import DICOM...\tCtrl+I")) |
461 | + app(const.ID_DICOM_NETWORK, _("Retrieve DICOM from PACS")) | ||
435 | file_menu.AppendMenu(const.ID_IMPORT_OTHERS_FILES, _("Import Others Files"), others_file_menu) | 462 | file_menu.AppendMenu(const.ID_IMPORT_OTHERS_FILES, _("Import Others Files"), others_file_menu) |
436 | app(const.ID_PROJECT_OPEN, _("Open Project...\tCtrl+O")) | 463 | app(const.ID_PROJECT_OPEN, _("Open Project...\tCtrl+O")) |
437 | app(const.ID_PROJECT_SAVE, _("Save Project\tCtrl+S")) | 464 | app(const.ID_PROJECT_SAVE, _("Save Project\tCtrl+S")) |
@@ -0,0 +1,660 @@ | @@ -0,0 +1,660 @@ | ||
1 | +#-------------------------------------------------------------------------- | ||
2 | +# Software: InVesalius - Software de Reconstrucao 3D de Imagens Medicas | ||
3 | +# Copyright: (C) 2001 Centro de Pesquisas Renato Archer | ||
4 | +# Homepage: http://www.softwarepublico.gov.br | ||
5 | +# Contact: invesalius@cti.gov.br | ||
6 | +# License: GNU - GPL 2 (LICENSE.txt/LICENCA.txt) | ||
7 | +#-------------------------------------------------------------------------- | ||
8 | +# Este programa e software livre; voce pode redistribui-lo e/ou | ||
9 | +# modifica-lo sob os termos da Licenca Publica Geral GNU, conforme | ||
10 | +# publicada pela Free Software Foundation; de acordo com a versao 2 | ||
11 | +# da Licenca. | ||
12 | +# | ||
13 | +# Este programa eh distribuido na expectativa de ser util, mas SEM | ||
14 | +# QUALQUER GARANTIA; sem mesmo a garantia implicita de | ||
15 | +# COMERCIALIZACAO ou de ADEQUACAO A QUALQUER PROPOSITO EM | ||
16 | +# PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais | ||
17 | +# detalhes. | ||
18 | +#-------------------------------------------------------------------------- | ||
19 | +import wx | ||
20 | +import sys | ||
21 | +import wx.gizmos as gizmos | ||
22 | +import wx.lib.pubsub as ps | ||
23 | +import wx.lib.splitter as spl | ||
24 | + | ||
25 | +import constants as const | ||
26 | +import gui.dialogs as dlg | ||
27 | +#import dicom_preview_panel as dpp | ||
28 | +import reader.dicom_grouper as dcm | ||
29 | +import net.dicom as dcm_net | ||
30 | + | ||
31 | +from wx.lib.mixins.listctrl import CheckListCtrlMixin | ||
32 | +#from dicionario import musicdata | ||
33 | +import wx.lib.mixins.listctrl as listmix | ||
34 | + | ||
35 | + | ||
36 | +myEVT_SELECT_SERIE = wx.NewEventType() | ||
37 | +EVT_SELECT_SERIE = wx.PyEventBinder(myEVT_SELECT_SERIE, 1) | ||
38 | + | ||
39 | +myEVT_SELECT_SLICE = wx.NewEventType() | ||
40 | +EVT_SELECT_SLICE = wx.PyEventBinder(myEVT_SELECT_SLICE, 1) | ||
41 | + | ||
42 | +myEVT_SELECT_PATIENT = wx.NewEventType() | ||
43 | +EVT_SELECT_PATIENT = wx.PyEventBinder(myEVT_SELECT_PATIENT, 1) | ||
44 | + | ||
45 | +myEVT_SELECT_SERIE_TEXT = wx.NewEventType() | ||
46 | +EVT_SELECT_SERIE_TEXT = wx.PyEventBinder(myEVT_SELECT_SERIE_TEXT, 1) | ||
47 | + | ||
48 | +class SelectEvent(wx.PyCommandEvent): | ||
49 | + def __init__(self , evtType, id): | ||
50 | + super(SelectEvent, self).__init__(evtType, id) | ||
51 | + | ||
52 | + def GetSelectID(self): | ||
53 | + return self.SelectedID | ||
54 | + | ||
55 | + def SetSelectedID(self, id): | ||
56 | + self.SelectedID = id | ||
57 | + | ||
58 | + def GetItemData(self): | ||
59 | + return self.data | ||
60 | + | ||
61 | + def SetItemData(self, data): | ||
62 | + self.data = data | ||
63 | + | ||
64 | + | ||
65 | +class Panel(wx.Panel): | ||
66 | + def __init__(self, parent): | ||
67 | + wx.Panel.__init__(self, parent, pos=wx.Point(5, 5))#, | ||
68 | + #size=wx.Size(280, 656)) | ||
69 | + | ||
70 | + sizer = wx.BoxSizer(wx.VERTICAL) | ||
71 | + sizer.Add(InnerPanel(self), 1, wx.EXPAND|wx.GROW|wx.ALL, 5) | ||
72 | + | ||
73 | + self.SetSizer(sizer) | ||
74 | + sizer.Fit(self) | ||
75 | + | ||
76 | + self.Layout() | ||
77 | + self.Update() | ||
78 | + self.SetAutoLayout(1) | ||
79 | + | ||
80 | + | ||
81 | +# Inner fold panel | ||
82 | +class InnerPanel(wx.Panel): | ||
83 | + def __init__(self, parent): | ||
84 | + wx.Panel.__init__(self, parent, pos=wx.Point(5, 5))#, | ||
85 | + #size=wx.Size(680, 656)) | ||
86 | + | ||
87 | + self.patients = [] | ||
88 | + self.first_image_selection = None | ||
89 | + self.last_image_selection = None | ||
90 | + self._init_ui() | ||
91 | + self._bind_events() | ||
92 | + self._bind_pubsubevt() | ||
93 | + | ||
94 | + def _init_ui(self): | ||
95 | + splitter = spl.MultiSplitterWindow(self, style=wx.SP_LIVE_UPDATE) | ||
96 | + splitter.SetOrientation(wx.VERTICAL) | ||
97 | + self.splitter = splitter | ||
98 | + | ||
99 | + panel = wx.Panel(self) | ||
100 | + self.btn_cancel = wx.Button(panel, wx.ID_CANCEL) | ||
101 | + self.btn_ok = wx.Button(panel, wx.ID_OK, _("Import")) | ||
102 | + | ||
103 | + btnsizer = wx.StdDialogButtonSizer() | ||
104 | + btnsizer.AddButton(self.btn_ok) | ||
105 | + btnsizer.AddButton(self.btn_cancel) | ||
106 | + btnsizer.Realize() | ||
107 | + | ||
108 | + self.combo_interval = wx.ComboBox(panel, -1, "", choices=const.IMPORT_INTERVAL, | ||
109 | + style=wx.CB_DROPDOWN|wx.CB_READONLY) | ||
110 | + self.combo_interval.SetSelection(0) | ||
111 | + | ||
112 | + inner_sizer = wx.BoxSizer(wx.HORIZONTAL) | ||
113 | + inner_sizer.AddSizer(btnsizer, 0, wx.LEFT|wx.TOP, 5) | ||
114 | + inner_sizer.Add(self.combo_interval, 0, wx.LEFT|wx.RIGHT|wx.TOP, 5) | ||
115 | + panel.SetSizer(inner_sizer) | ||
116 | + inner_sizer.Fit(panel) | ||
117 | + | ||
118 | + sizer = wx.BoxSizer(wx.VERTICAL) | ||
119 | + sizer.Add(splitter, 20, wx.EXPAND) | ||
120 | + sizer.Add(panel, 1, wx.EXPAND|wx.LEFT, 90) | ||
121 | + | ||
122 | + self.SetSizer(sizer) | ||
123 | + sizer.Fit(self) | ||
124 | + | ||
125 | + self.image_panel = HostFindPanel(splitter) | ||
126 | + splitter.AppendWindow(self.image_panel, 250) | ||
127 | + | ||
128 | + self.text_panel = TextPanel(splitter) | ||
129 | + splitter.AppendWindow(self.text_panel, 250) | ||
130 | + | ||
131 | + | ||
132 | + self.Layout() | ||
133 | + self.Update() | ||
134 | + self.SetAutoLayout(1) | ||
135 | + | ||
136 | + def _bind_pubsubevt(self): | ||
137 | + #ps.Publisher().subscribe(self.ShowDicomPreview, "Load import panel") | ||
138 | + #ps.Publisher().subscribe(self.GetSelectedImages ,"Selected Import Images") | ||
139 | + pass | ||
140 | + | ||
141 | + def GetSelectedImages(self, pubsub_evt): | ||
142 | + self.first_image_selection = pubsub_evt.data[0] | ||
143 | + self.last_image_selection = pubsub_evt.data[1] | ||
144 | + | ||
145 | + def _bind_events(self): | ||
146 | + self.Bind(EVT_SELECT_SERIE, self.OnSelectSerie) | ||
147 | + self.Bind(EVT_SELECT_SLICE, self.OnSelectSlice) | ||
148 | + self.Bind(EVT_SELECT_PATIENT, self.OnSelectPatient) | ||
149 | + self.btn_ok.Bind(wx.EVT_BUTTON, self.OnClickOk) | ||
150 | + self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnClickCancel) | ||
151 | + self.text_panel.Bind(EVT_SELECT_SERIE_TEXT, self.OnDblClickTextPanel) | ||
152 | + | ||
153 | + def ShowDicomPreview(self, pubsub_evt): | ||
154 | + dicom_groups = pubsub_evt.data | ||
155 | + self.patients.extend(dicom_groups) | ||
156 | + self.text_panel.Populate(dicom_groups) | ||
157 | + | ||
158 | + def OnSelectSerie(self, evt): | ||
159 | + patient_id, serie_number = evt.GetSelectID() | ||
160 | + self.text_panel.SelectSerie(evt.GetSelectID()) | ||
161 | + for patient in self.patients: | ||
162 | + if patient_id == patient.GetDicomSample().patient.id: | ||
163 | + for group in patient.GetGroups(): | ||
164 | + if serie_number == group.GetDicomSample().acquisition.serie_number: | ||
165 | + self.image_panel.SetSerie(group) | ||
166 | + | ||
167 | + def OnSelectSlice(self, evt): | ||
168 | + pass | ||
169 | + | ||
170 | + def OnSelectPatient(self, evt): | ||
171 | + pass | ||
172 | + | ||
173 | + def OnDblClickTextPanel(self, evt): | ||
174 | + group = evt.GetItemData() | ||
175 | + self.LoadDicom(group) | ||
176 | + | ||
177 | + def OnClickOk(self, evt): | ||
178 | + group = self.text_panel.GetSelection() | ||
179 | + | ||
180 | + if group: | ||
181 | + self.LoadDicom(group) | ||
182 | + | ||
183 | + def OnClickCancel(self, evt): | ||
184 | + #ps.Publisher().sendMessage("Cancel DICOM load") | ||
185 | + pass | ||
186 | + | ||
187 | + def LoadDicom(self, group): | ||
188 | + interval = self.combo_interval.GetSelection() | ||
189 | + | ||
190 | + if not isinstance(group, dcm.DicomGroup): | ||
191 | + group = max(group.GetGroups(), key=lambda g: g.nslices) | ||
192 | + | ||
193 | + slice_amont = group.nslices | ||
194 | + if (self.first_image_selection != None) and (self.first_image_selection != self.last_image_selection): | ||
195 | + slice_amont = (self.last_image_selection) - self.first_image_selection | ||
196 | + slice_amont += 1 | ||
197 | + if slice_amont == 0: | ||
198 | + slice_amont = group.nslices | ||
199 | + | ||
200 | + nslices_result = slice_amont / (interval + 1) | ||
201 | + if (nslices_result > 1): | ||
202 | + #ps.Publisher().sendMessage('Open DICOM group', (group, interval, | ||
203 | + # [self.first_image_selection, self.last_image_selection])) | ||
204 | + pass | ||
205 | + else: | ||
206 | + dlg.MissingFilesForReconstruction() | ||
207 | + | ||
208 | +class TextPanel(wx.Panel): | ||
209 | + def __init__(self, parent): | ||
210 | + wx.Panel.__init__(self, parent, -1) | ||
211 | + | ||
212 | + self._selected_by_user = True | ||
213 | + self.idserie_treeitem = {} | ||
214 | + self.treeitem_idpatient = {} | ||
215 | + | ||
216 | + self.__init_gui() | ||
217 | + self.__bind_events_wx() | ||
218 | + self.__bind_pubsub_evt() | ||
219 | + | ||
220 | + def __bind_pubsub_evt(self): | ||
221 | + #ps.Publisher().subscribe(self.SelectSeries, 'Select series in import panel') | ||
222 | + pass | ||
223 | + | ||
224 | + def __bind_events_wx(self): | ||
225 | + self.Bind(wx.EVT_SIZE, self.OnSize) | ||
226 | + | ||
227 | + def __init_gui(self): | ||
228 | + tree = gizmos.TreeListCtrl(self, -1, style = | ||
229 | + wx.TR_DEFAULT_STYLE | ||
230 | + | wx.TR_HIDE_ROOT | ||
231 | + | wx.TR_ROW_LINES | ||
232 | + | wx.TR_COLUMN_LINES | ||
233 | + | wx.TR_FULL_ROW_HIGHLIGHT | ||
234 | + | wx.TR_SINGLE | ||
235 | + ) | ||
236 | + | ||
237 | + | ||
238 | + tree.AddColumn(_("Patient name")) | ||
239 | + tree.AddColumn(_("Patient ID")) | ||
240 | + tree.AddColumn(_("Age")) | ||
241 | + tree.AddColumn(_("Gender")) | ||
242 | + tree.AddColumn(_("Study description")) | ||
243 | + tree.AddColumn(_("Modality")) | ||
244 | + tree.AddColumn(_("Date acquired")) | ||
245 | + tree.AddColumn(_("# Images")) | ||
246 | + tree.AddColumn(_("Institution")) | ||
247 | + tree.AddColumn(_("Date of birth")) | ||
248 | + tree.AddColumn(_("Accession Number")) | ||
249 | + tree.AddColumn(_("Referring physician")) | ||
250 | + | ||
251 | + tree.SetMainColumn(0) # the one with the tree in it... | ||
252 | + tree.SetColumnWidth(0, 280) # Patient name | ||
253 | + tree.SetColumnWidth(1, 110) # Patient ID | ||
254 | + tree.SetColumnWidth(2, 40) # Age | ||
255 | + tree.SetColumnWidth(3, 60) # Gender | ||
256 | + tree.SetColumnWidth(4, 160) # Study description | ||
257 | + tree.SetColumnWidth(5, 70) # Modality | ||
258 | + tree.SetColumnWidth(6, 200) # Date acquired | ||
259 | + tree.SetColumnWidth(7, 70) # Number Images | ||
260 | + tree.SetColumnWidth(8, 130) # Institution | ||
261 | + tree.SetColumnWidth(9, 100) # Date of birth | ||
262 | + tree.SetColumnWidth(10, 140) # Accession Number | ||
263 | + tree.SetColumnWidth(11, 160) # Referring physician | ||
264 | + | ||
265 | + self.root = tree.AddRoot(_("InVesalius Database")) | ||
266 | + self.tree = tree | ||
267 | + | ||
268 | + def SelectSeries(self, pubsub_evt): | ||
269 | + group_index = pubsub_evt.data | ||
270 | + | ||
271 | + def Populate(self, patient_list): | ||
272 | + tree = self.tree | ||
273 | + | ||
274 | + first = 0 | ||
275 | + for patient in patient_list: | ||
276 | + if not isinstance(patient, dcm.PatientGroup): | ||
277 | + return None | ||
278 | + ngroups = patient.ngroups | ||
279 | + dicom = patient.GetDicomSample() | ||
280 | + title = dicom.patient.name + " (%d series)"%(ngroups) | ||
281 | + date_time = "%s %s"%(dicom.acquisition.date, | ||
282 | + dicom.acquisition.time) | ||
283 | + | ||
284 | + parent = tree.AppendItem(self.root, title) | ||
285 | + | ||
286 | + if not first: | ||
287 | + parent_select = parent | ||
288 | + first += 1 | ||
289 | + | ||
290 | + tree.SetItemPyData(parent, patient) | ||
291 | + tree.SetItemText(parent, "%s" % dicom.patient.id, 1) | ||
292 | + tree.SetItemText(parent, "%s" % dicom.patient.age, 2) | ||
293 | + tree.SetItemText(parent, "%s" % dicom.patient.gender, 3) | ||
294 | + tree.SetItemText(parent, "%s" % dicom.acquisition.study_description, 4) | ||
295 | + tree.SetItemText(parent, "%s" % dicom.acquisition.modality, 5) | ||
296 | + tree.SetItemText(parent, "%s" % date_time, 6) | ||
297 | + tree.SetItemText(parent, "%s" % patient.nslices, 7) | ||
298 | + tree.SetItemText(parent, "%s" % dicom.acquisition.institution, 8) | ||
299 | + tree.SetItemText(parent, "%s" % dicom.patient.birthdate, 9) | ||
300 | + tree.SetItemText(parent, "%s" % dicom.acquisition.accession_number, 10) | ||
301 | + tree.SetItemText(parent, "%s" % dicom.patient.physician, 11) | ||
302 | + | ||
303 | + group_list = patient.GetGroups() | ||
304 | + for n, group in enumerate(group_list): | ||
305 | + dicom = group.GetDicomSample() | ||
306 | + | ||
307 | + child = tree.AppendItem(parent, group.title) | ||
308 | + tree.SetItemPyData(child, group) | ||
309 | + | ||
310 | + tree.SetItemText(child, "%s" % group.title, 0) | ||
311 | + tree.SetItemText(child, "%s" % dicom.acquisition.protocol_name, 4) | ||
312 | + tree.SetItemText(child, "%s" % dicom.acquisition.modality, 5) | ||
313 | + tree.SetItemText(child, "%s" % date_time, 6) | ||
314 | + tree.SetItemText(child, "%s" % group.nslices, 7) | ||
315 | + | ||
316 | + self.idserie_treeitem[(dicom.patient.id, | ||
317 | + dicom.acquisition.serie_number)] = child | ||
318 | + | ||
319 | + tree.Expand(self.root) | ||
320 | + tree.SelectItem(parent_select) | ||
321 | + tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate) | ||
322 | + tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged) | ||
323 | + | ||
324 | + def OnSelChanged(self, evt): | ||
325 | + item = self.tree.GetSelection() | ||
326 | + if self._selected_by_user: | ||
327 | + group = self.tree.GetItemPyData(item) | ||
328 | + if isinstance(group, dcm.DicomGroup): | ||
329 | + #ps.Publisher().sendMessage('Load group into import panel', | ||
330 | + # group) | ||
331 | + pass | ||
332 | + | ||
333 | + elif isinstance(group, dcm.PatientGroup): | ||
334 | + id = group.GetDicomSample().patient.id | ||
335 | + my_evt = SelectEvent(myEVT_SELECT_PATIENT, self.GetId()) | ||
336 | + my_evt.SetSelectedID(id) | ||
337 | + self.GetEventHandler().ProcessEvent(my_evt) | ||
338 | + | ||
339 | + #ps.Publisher().sendMessage('Load patient into import panel', | ||
340 | + # group) | ||
341 | + else: | ||
342 | + parent_id = self.tree.GetItemParent(item) | ||
343 | + self.tree.Expand(parent_id) | ||
344 | + evt.Skip() | ||
345 | + | ||
346 | + def OnActivate(self, evt): | ||
347 | + item = evt.GetItem() | ||
348 | + group = self.tree.GetItemPyData(item) | ||
349 | + my_evt = SelectEvent(myEVT_SELECT_SERIE_TEXT, self.GetId()) | ||
350 | + my_evt.SetItemData(group) | ||
351 | + self.GetEventHandler().ProcessEvent(my_evt) | ||
352 | + | ||
353 | + def OnSize(self, evt): | ||
354 | + self.tree.SetSize(self.GetSize()) | ||
355 | + | ||
356 | + def SelectSerie(self, serie): | ||
357 | + self._selected_by_user = False | ||
358 | + item = self.idserie_treeitem[serie] | ||
359 | + self.tree.SelectItem(item) | ||
360 | + self._selected_by_user = True | ||
361 | + | ||
362 | + def GetSelection(self): | ||
363 | + """Get selected item""" | ||
364 | + item = self.tree.GetSelection() | ||
365 | + group = self.tree.GetItemPyData(item) | ||
366 | + return group | ||
367 | + | ||
368 | + | ||
369 | + | ||
370 | + | ||
371 | + | ||
372 | + | ||
373 | + | ||
374 | + | ||
375 | + | ||
376 | + | ||
377 | + | ||
378 | + | ||
379 | +class FindPanel(wx.Panel): | ||
380 | + def __init__(self, parent): | ||
381 | + wx.Panel.__init__(self, parent, -1) | ||
382 | + | ||
383 | + self.sizer = wx.BoxSizer(wx.VERTICAL) | ||
384 | + | ||
385 | + sizer_word_label = wx.BoxSizer(wx.HORIZONTAL) | ||
386 | + sizer_word_label.Add((5, 0), 0, wx.EXPAND|wx.HORIZONTAL) | ||
387 | + find_label = wx.StaticText(self, -1, _("Word")) | ||
388 | + sizer_word_label.Add(find_label) | ||
389 | + | ||
390 | + sizer_txt_find = wx.BoxSizer(wx.HORIZONTAL) | ||
391 | + sizer_txt_find.Add((5, 0), 0, wx.EXPAND|wx.HORIZONTAL) | ||
392 | + find_txt = wx.TextCtrl(self, -1,size=(225, -1)) | ||
393 | + | ||
394 | + self.btn_find = wx.Button(self, -1, _("Search")) | ||
395 | + | ||
396 | + | ||
397 | + sizer_txt_find.Add(find_txt) | ||
398 | + sizer_txt_find.Add(self.btn_find) | ||
399 | + | ||
400 | + self.sizer.Add((0, 5), 0, wx.EXPAND|wx.HORIZONTAL) | ||
401 | + self.sizer.AddSizer(sizer_word_label) | ||
402 | + self.sizer.AddSizer(sizer_txt_find) | ||
403 | + | ||
404 | + #self.sizer.Add(self.serie_preview, 1, wx.EXPAND | wx.ALL, 5) | ||
405 | + #self.sizer.Add(self.dicom_preview, 1, wx.EXPAND | wx.ALL, 5) | ||
406 | + self.sizer.Fit(self) | ||
407 | + | ||
408 | + self.SetSizer(self.sizer) | ||
409 | + | ||
410 | + self.Layout() | ||
411 | + self.Update() | ||
412 | + self.SetAutoLayout(1) | ||
413 | + | ||
414 | + self.__bind_evt() | ||
415 | + self._bind_gui_evt() | ||
416 | + | ||
417 | + def __bind_evt(self): | ||
418 | + #ps.Publisher().subscribe(self.ShowDicomSeries, 'Load dicom preview') | ||
419 | + #ps.Publisher().subscribe(self.SetDicomSeries, 'Load group into import panel') | ||
420 | + #ps.Publisher().subscribe(self.SetPatientSeries, 'Load patient into import panel') | ||
421 | + pass | ||
422 | + | ||
423 | + def _bind_gui_evt(self): | ||
424 | + #self.serie_preview.Bind(dpp.EVT_CLICK_SERIE, self.OnSelectSerie) | ||
425 | + #self.dicom_preview.Bind(dpp.EVT_CLICK_SLICE, self.OnSelectSlice) | ||
426 | + self.Bind(wx.EVT_BUTTON, self.OnButtonFind, self.btn_find) | ||
427 | + | ||
428 | + def OnButtonFind(self, evt): | ||
429 | + print "clicked...." | ||
430 | + | ||
431 | + | ||
432 | +class HostFindPanel(wx.Panel): | ||
433 | + def __init__(self, parent): | ||
434 | + wx.Panel.__init__(self, parent, -1) | ||
435 | + self._init_ui() | ||
436 | + self._bind_events() | ||
437 | + | ||
438 | + def _init_ui(self): | ||
439 | + splitter = spl.MultiSplitterWindow(self, style=wx.SP_LIVE_UPDATE) | ||
440 | + splitter.SetOrientation(wx.HORIZONTAL) | ||
441 | + self.splitter = splitter | ||
442 | + | ||
443 | + splitter.ContainingSizer = wx.BoxSizer(wx.HORIZONTAL) | ||
444 | + | ||
445 | + sizer = wx.BoxSizer(wx.HORIZONTAL) | ||
446 | + sizer.Add(splitter, 1, wx.EXPAND) | ||
447 | + self.SetSizer(sizer) | ||
448 | + | ||
449 | + self.image_panel = NodesPanel(splitter) | ||
450 | + splitter.AppendWindow(self.image_panel, 500) | ||
451 | + | ||
452 | + self.text_panel = FindPanel(splitter) | ||
453 | + splitter.AppendWindow(self.text_panel, 750) | ||
454 | + | ||
455 | + self.SetSizer(sizer) | ||
456 | + sizer.Fit(self) | ||
457 | + | ||
458 | + self.Layout() | ||
459 | + self.Update() | ||
460 | + self.SetAutoLayout(1) | ||
461 | + | ||
462 | + def _bind_events(self): | ||
463 | + self.text_panel.Bind(EVT_SELECT_SERIE, self.OnSelectSerie) | ||
464 | + self.text_panel.Bind(EVT_SELECT_SLICE, self.OnSelectSlice) | ||
465 | + | ||
466 | + def OnSelectSerie(self, evt): | ||
467 | + evt.Skip() | ||
468 | + | ||
469 | + def OnSelectSlice(self, evt): | ||
470 | + self.image_panel.dicom_preview.ShowSlice(evt.GetSelectID()) | ||
471 | + evt.Skip() | ||
472 | + | ||
473 | + def SetSerie(self, serie): | ||
474 | + self.image_panel.dicom_preview.SetDicomGroup(serie) | ||
475 | + | ||
476 | + | ||
477 | +class NodesTree(wx.ListCtrl, CheckListCtrlMixin,listmix.ListCtrlAutoWidthMixin, | ||
478 | + listmix.TextEditMixin): | ||
479 | + | ||
480 | + def __init__(self, parent): | ||
481 | + self.item = 0 | ||
482 | + self.col_locs = [0] | ||
483 | + self.editorBgColour = wx.Colour(255, 255, 255, 255) | ||
484 | + wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT |wx.LC_HRULES) | ||
485 | + listmix.CheckListCtrlMixin.__init__(self) | ||
486 | + listmix.TextEditMixin.__init__(self) | ||
487 | + | ||
488 | + def OnCheckItem(self, index, flag): | ||
489 | + ps.Publisher().sendMessage("Check item dict", [index, flag]) | ||
490 | + | ||
491 | + def OpenEditor(self, col, row): | ||
492 | + | ||
493 | + if col >= 1 and col < 4: | ||
494 | + listmix.TextEditMixin.OpenEditor(self, col, row) | ||
495 | + else: | ||
496 | + listmix.CheckListCtrlMixin.ToggleItem(self, self.item) | ||
497 | + | ||
498 | + def SetSelected(self, item): | ||
499 | + self.item = item | ||
500 | + | ||
501 | + def SetDeselected(self, item): | ||
502 | + self.item = item | ||
503 | + | ||
504 | + | ||
505 | +class NodesPanel(wx.Panel): | ||
506 | + def __init__(self, parent): | ||
507 | + | ||
508 | + self.selected_item = None | ||
509 | + self.hosts = {} | ||
510 | + | ||
511 | + wx.Panel.__init__(self, parent, -1) | ||
512 | + self.__init_gui() | ||
513 | + self.__bind_evt() | ||
514 | + | ||
515 | + | ||
516 | + def __bind_evt(self): | ||
517 | + | ||
518 | + self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.RightButton, self.tree_node) | ||
519 | + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.tree_node) | ||
520 | + self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self.tree_node) | ||
521 | + self.Bind(wx.EVT_BUTTON, self.OnButtonAdd, self.btn_add) | ||
522 | + self.Bind(wx.EVT_BUTTON, self.OnButtonRemove, self.btn_remove) | ||
523 | + self.Bind(wx.EVT_BUTTON, self.OnButtonCheck, self.btn_check) | ||
524 | + | ||
525 | + self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.EndEdition, self.tree_node) | ||
526 | + | ||
527 | + ps.Publisher().subscribe(self.CheckItemDict, "Check item dict") | ||
528 | + #ps.Publisher().subscribe(self.UnCheckItemDict, "Uncheck item dict") | ||
529 | + | ||
530 | + | ||
531 | + def __init_gui(self): | ||
532 | + self.tree_node = NodesTree(self) | ||
533 | + | ||
534 | + self.tree_node.InsertColumn(0, _("Active")) | ||
535 | + self.tree_node.InsertColumn(1, _("Host")) | ||
536 | + self.tree_node.InsertColumn(2, _("Port")) | ||
537 | + self.tree_node.InsertColumn(3, _("AETitle")) | ||
538 | + self.tree_node.InsertColumn(4, _("Status")) | ||
539 | + | ||
540 | + self.tree_node.SetColumnWidth(0,50) | ||
541 | + self.tree_node.SetColumnWidth(1, 150) | ||
542 | + self.tree_node.SetColumnWidth(2, 50) | ||
543 | + self.tree_node.SetColumnWidth(3, 150) | ||
544 | + self.tree_node.SetColumnWidth(4, 80) | ||
545 | + | ||
546 | + self.hosts[0] = [True, "localhost", "", "invesalius"] | ||
547 | + index = self.tree_node.InsertStringItem(sys.maxint, "") | ||
548 | + self.tree_node.SetStringItem(index, 1, "localhost") | ||
549 | + self.tree_node.SetStringItem(index, 2, "") | ||
550 | + self.tree_node.SetStringItem(index, 3, "invesalius") | ||
551 | + self.tree_node.SetStringItem(index, 4, "ok") | ||
552 | + self.tree_node.CheckItem(index) | ||
553 | + self.tree_node.SetItemBackgroundColour(index, wx.Colour(245,245,245)) | ||
554 | + #print ">>>>>>>>>>>>>>>>>>>>>", sys.maxint | ||
555 | + #index = self.tree_node.InsertStringItem(sys.maxint, "")#adiciona vazio a coluna de check | ||
556 | + #self.tree_node.SetStringItem(index, 1, "200.144.114.19") | ||
557 | + #self.tree_node.SetStringItem(index, 2, "80") | ||
558 | + #self.tree_node.SetItemData(index, 0) | ||
559 | + | ||
560 | + #index2 = self.tree_node.InsertStringItem(sys.maxint, "")#adiciona vazio a coluna de check | ||
561 | + #self.tree_node.SetStringItem(index2, 1, "200.144.114.19") | ||
562 | + #self.tree_node.SetStringItem(index2, 2, "80") | ||
563 | + #self.tree_node.SetItemData(index2, 0) | ||
564 | + | ||
565 | + self.btn_add = wx.Button(self, -1, _("Add")) | ||
566 | + self.btn_remove = wx.Button(self, -1, _("Remove")) | ||
567 | + self.btn_check = wx.Button(self, -1, _("Check status")) | ||
568 | + | ||
569 | + | ||
570 | + sizer_btn = wx.BoxSizer(wx.HORIZONTAL) | ||
571 | + sizer_btn.Add((90, 0), 0, wx.EXPAND|wx.HORIZONTAL) | ||
572 | + sizer_btn.Add(self.btn_add, 10) | ||
573 | + sizer_btn.Add(self.btn_remove, 10) | ||
574 | + sizer_btn.Add(self.btn_check, 0, wx.ALIGN_CENTER_HORIZONTAL) | ||
575 | + | ||
576 | + sizer = wx.BoxSizer(wx.VERTICAL) | ||
577 | + sizer.Add(self.tree_node, 85, wx.GROW|wx.EXPAND) | ||
578 | + sizer.AddSizer(sizer_btn, 15) | ||
579 | + sizer.Fit(self) | ||
580 | + self.SetSizer(sizer) | ||
581 | + self.Layout() | ||
582 | + self.Update() | ||
583 | + self.SetAutoLayout(1) | ||
584 | + self.sizer = sizer | ||
585 | + | ||
586 | + def EndEdition(self, evt): | ||
587 | + index = evt.m_itemIndex | ||
588 | + item = evt.m_item | ||
589 | + col = item.GetColumn() | ||
590 | + txt = item.GetText() | ||
591 | + | ||
592 | + values = self.hosts[index] | ||
593 | + values[col] = str(txt) | ||
594 | + self.hosts[index] = values | ||
595 | + | ||
596 | + def OnButtonAdd(self, evt): | ||
597 | + #adiciona vazio a coluna de check | ||
598 | + index = self.tree_node.InsertStringItem(sys.maxint, "") | ||
599 | + | ||
600 | + self.hosts[index] = [True, "localhost", "80", ""] | ||
601 | + self.tree_node.SetStringItem(index, 1, "localhost") | ||
602 | + self.tree_node.SetStringItem(index, 2, "80") | ||
603 | + self.tree_node.SetStringItem(index, 3, "") | ||
604 | + self.tree_node.CheckItem(index) | ||
605 | + | ||
606 | + def OnLeftDown(self, evt): | ||
607 | + evt.Skip() | ||
608 | + | ||
609 | + def OnButtonRemove(self, evt): | ||
610 | + if self.selected_item != None and self.selected_item != 0: | ||
611 | + self.tree_node.DeleteItem(self.selected_item) | ||
612 | + self.hosts.pop(self.selected_item) | ||
613 | + self.selected_item = None | ||
614 | + | ||
615 | + k = self.hosts.keys() | ||
616 | + tmp_cont = 0 | ||
617 | + | ||
618 | + tmp_host = {} | ||
619 | + for x in k: | ||
620 | + tmp_host[tmp_cont] = self.hosts[x] | ||
621 | + tmp_cont += 1 | ||
622 | + self.hosts = tmp_host | ||
623 | + | ||
624 | + | ||
625 | + | ||
626 | + def OnButtonCheck(self, evt): | ||
627 | + for key in self.hosts.keys(): | ||
628 | + if key != 0: | ||
629 | + dn = dcm_net.DicomNet() | ||
630 | + dn.SetHost(self.hosts[key][1]) | ||
631 | + dn.SetPort(self.hosts[key][2]) | ||
632 | + dn.SetAETitleCall(self.hosts[key][3]) | ||
633 | + dn.SetAETitle(self.hosts[0][3]) | ||
634 | + | ||
635 | + if dn.RunCEcho(): | ||
636 | + self.tree_node.SetStringItem(key, 4, _("ok")) | ||
637 | + else: | ||
638 | + self.tree_node.SetStringItem(key, 4, _("error")) | ||
639 | + | ||
640 | + | ||
641 | + | ||
642 | + | ||
643 | + def RightButton(self,evt): | ||
644 | + event.Skip() | ||
645 | + | ||
646 | + def OnItemSelected(self, evt): | ||
647 | + self.selected_item = evt.m_itemIndex | ||
648 | + self.tree_node.SetSelected(evt.m_itemIndex) | ||
649 | + | ||
650 | + def OnItemDeselected(self, evt): | ||
651 | + if evt.m_itemIndex != 0: | ||
652 | + self.tree_node.SetDeselected(evt.m_itemIndex) | ||
653 | + | ||
654 | + | ||
655 | + def CheckItemDict(self, evt_pub): | ||
656 | + index, flag = evt_pub.data | ||
657 | + if index != 0: | ||
658 | + self.hosts[index][0] = flag | ||
659 | + else: | ||
660 | + self.tree_node.CheckItem(0) |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +#-------------------------------------------------------------------------- | ||
2 | +# Software: InVesalius - Software de Reconstrucao 3D de Imagens Medicas | ||
3 | +# Copyright: (C) 2001 Centro de Pesquisas Renato Archer | ||
4 | +# Homepage: http://www.softwarepublico.gov.br | ||
5 | +# Contact: invesalius@cti.gov.br | ||
6 | +# License: GNU - GPL 2 (LICENSE.txt/LICENCA.txt) | ||
7 | +#-------------------------------------------------------------------------- | ||
8 | +# Este programa e software livre; voce pode redistribui-lo e/ou | ||
9 | +# modifica-lo sob os termos da Licenca Publica Geral GNU, conforme | ||
10 | +# publicada pela Free Software Foundation; de acordo com a versao 2 | ||
11 | +# da Licenca. | ||
12 | +# | ||
13 | +# Este programa eh distribuido na expectativa de ser util, mas SEM | ||
14 | +# QUALQUER GARANTIA; sem mesmo a garantia implicita de | ||
15 | +# COMERCIALIZACAO ou de ADEQUACAO A QUALQUER PROPOSITO EM | ||
16 | +# PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais | ||
17 | +# detalhes. | ||
18 | +#-------------------------------------------------------------------------- |
@@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
1 | +import gdcm | ||
2 | + | ||
3 | +class DicomNet: | ||
4 | + | ||
5 | + def __init__(self): | ||
6 | + self.address = '' | ||
7 | + self.port = '' | ||
8 | + self.aetitle_call = '' | ||
9 | + self.aetitle = '' | ||
10 | + | ||
11 | + def SetHost(self, address): | ||
12 | + self.address = address | ||
13 | + | ||
14 | + def SetPort(self, port): | ||
15 | + self.port = port | ||
16 | + | ||
17 | + def SetAETitleCall(self, name): | ||
18 | + self.aetitle_call = name | ||
19 | + | ||
20 | + def SetAETitle(self, ae_title): | ||
21 | + self.aetitle = ae_title | ||
22 | + | ||
23 | + def RunCEcho(self): | ||
24 | + cnf = gdcm.CompositeNetworkFunctions() | ||
25 | + return cnf.CEcho(self.address, int(self.port),\ | ||
26 | + self.aetitle, self.aetitle_call) |