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) | ... | ... |