Commit 1743ebf81204c3c6bd326f02bea3c0c902e38468
1 parent
f879b8b8
Exists in
master
and in
67 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 | 839 | invesalius/data/bases.py -text |
840 | 840 | invesalius/data/co_registration.py -text |
841 | 841 | invesalius/data/converters.py -text |
842 | +invesalius/gui/import_network_panel.py -text | |
842 | 843 | invesalius/gui/preferences.py -text |
844 | +invesalius/net/__init__.py -text | |
845 | +invesalius/net/dicom.py -text | |
843 | 846 | locale/de/LC_MESSAGES/invesalius.mo -text |
844 | 847 | locale/el/LC_MESSAGES/invesalius.mo -text |
845 | 848 | locale/en/LC_MESSAGES/invesalius.mo -text | ... | ... |
invesalius/gui/frame.py
... | ... | @@ -32,6 +32,7 @@ import default_tasks as tasks |
32 | 32 | import default_viewers as viewers |
33 | 33 | import gui.dialogs as dlg |
34 | 34 | import import_panel as imp |
35 | +import import_network_panel as imp_net | |
35 | 36 | import project as prj |
36 | 37 | import session as ses |
37 | 38 | import utils |
... | ... | @@ -58,7 +59,7 @@ class Frame(wx.Frame): |
58 | 59 | icon_path = os.path.join(const.ICON_DIR, "invesalius.ico") |
59 | 60 | self.SetIcon(wx.Icon(icon_path, wx.BITMAP_TYPE_ICO)) |
60 | 61 | if sys.platform != 'darwin': |
61 | - self.Maximize() | |
62 | + ####self.Maximize() ##DESCOMENTAR PAULO | |
62 | 63 | #Necessary update AUI (statusBar in special) |
63 | 64 | #when maximized in the Win 7 and XP |
64 | 65 | #self.SetSize(self.GetSize()) |
... | ... | @@ -94,6 +95,7 @@ class Frame(wx.Frame): |
94 | 95 | sub(self._SetProjectName, 'Set project name') |
95 | 96 | sub(self._ShowContentPanel, 'Show content panel') |
96 | 97 | sub(self._ShowImportPanel, 'Show import panel in frame') |
98 | + sub(self._ShowImportNetwork, 'Show retrieve dicom panel') | |
97 | 99 | sub(self._ShowTask, 'Show task panel') |
98 | 100 | sub(self._UpdateAUI, 'Update AUI') |
99 | 101 | sub(self._Exit, 'Exit') |
... | ... | @@ -140,6 +142,12 @@ class Frame(wx.Frame): |
140 | 142 | MaximizeButton(True).Floatable(True). |
141 | 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 | 151 | # Add toolbars to manager |
144 | 152 | # This is pretty tricky -- order on win32 is inverted when |
145 | 153 | # compared to linux2 & darwin |
... | ... | @@ -253,6 +261,18 @@ class Frame(wx.Frame): |
253 | 261 | aui_manager.GetPane("Tasks").Show(1) |
254 | 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 | 276 | def _ShowImportPanel(self, evt_pubsub): |
257 | 277 | """ |
258 | 278 | Show only DICOM import panel. |
... | ... | @@ -316,7 +336,9 @@ class Frame(wx.Frame): |
316 | 336 | elif id == const.ID_START: |
317 | 337 | self.ShowGettingStarted() |
318 | 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 | 343 | def OnSize(self, evt): |
322 | 344 | """ |
... | ... | @@ -365,6 +387,10 @@ class Frame(wx.Frame): |
365 | 387 | """ |
366 | 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 | 394 | def ShowOpenProject(self): |
369 | 395 | """ |
370 | 396 | Show open project dialog. |
... | ... | @@ -432,6 +458,7 @@ class MenuBar(wx.MenuBar): |
432 | 458 | file_menu = wx.Menu() |
433 | 459 | app = file_menu.Append |
434 | 460 | app(const.ID_DICOM_IMPORT, _("Import DICOM...\tCtrl+I")) |
461 | + app(const.ID_DICOM_NETWORK, _("Retrieve DICOM from PACS")) | |
435 | 462 | file_menu.AppendMenu(const.ID_IMPORT_OTHERS_FILES, _("Import Others Files"), others_file_menu) |
436 | 463 | app(const.ID_PROJECT_OPEN, _("Open Project...\tCtrl+O")) |
437 | 464 | app(const.ID_PROJECT_SAVE, _("Save Project\tCtrl+S")) | ... | ... |
... | ... | @@ -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 @@ |
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 @@ |
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) | ... | ... |