Commit 1a15b12cdce9ad70e461fd3177fe10d77d35f52d

Authored by tatiana
1 parent 4d583c07

ADD: Project close feature (under devel)

invesalius/constants.py
... ... @@ -85,10 +85,18 @@ SLICE_POSITION = {AXIAL:[AXIAL_SLICE_CAM_VIEW_UP, AXIAL_SLICE_CAM_POSITION],
85 85 PROJ_NEW = 0
86 86 PROJ_OPEN = 1
87 87 PROJ_CHANGE = 2
  88 +PROJ_CLOSE = 3
88 89  
89 90 PROJ_MAX = 4
90 91  
91 92  
  93 +####
  94 +MODE_RP = 0
  95 +MODE_NAVIGATOR = 1
  96 +MODE_RADIOLOGY = 2
  97 +MODE_ODONTOLOGY = 3
  98 +
  99 +
92 100  
93 101 #Color Table from Slice
94 102 #NumberOfColors, SaturationRange, HueRange, ValueRange
... ...
invesalius/control.py
... ... @@ -27,7 +27,8 @@ import constants as const
27 27 import project as prj
28 28  
29 29 import data.imagedata_utils as utils
30   -import data.surface as surface
  30 +import data.mask as msk
  31 +import data.surface as srf
31 32 import data.volume as volume
32 33 import reader.dicom_grouper as dg
33 34 import gui.dialogs as dialog
... ... @@ -40,7 +41,7 @@ DEFAULT_THRESH_MODE = 0
40 41 class Controller():
41 42  
42 43 def __init__(self, frame):
43   - self.surface_manager = surface.SurfaceManager()
  44 + self.surface_manager = srf.SurfaceManager()
44 45 self.volume = volume.Volume()
45 46 self.__bind_events()
46 47 self.frame = frame
... ... @@ -51,7 +52,6 @@ class Controller():
51 52  
52 53 def __bind_events(self):
53 54 ps.Publisher().subscribe(self.OnImportMedicalImages, 'Import directory')
54   - #ps.Publisher().subscribe(self.StartImportPanel, "Load data to import panel")
55 55 ps.Publisher().subscribe(self.OnShowDialogImportDirectory,
56 56 'Show import directory dialog')
57 57 ps.Publisher().subscribe(self.OnShowDialogOpenProject,
... ... @@ -68,8 +68,6 @@ class Controller():
68 68 ps.Publisher().subscribe(self.Progress, "Update dicom load")
69 69 ps.Publisher().subscribe(self.OnLoadImportPanel, "End dicom load")
70 70 ps.Publisher().subscribe(self.OnCancelImport, 'Cancel DICOM load')
71   - #ps.Publisher().subscribe(self.OnSaveProject, 'Save Project')
72   - #ps.Publisher().subscribe(self.OnOpenProject, 'Open Project')
73 71 ps.Publisher().subscribe(self.OnCloseProject, 'Close Project')
74 72  
75 73  
... ... @@ -110,6 +108,12 @@ class Controller():
110 108 session = ses.Session()
111 109 session.OpenProject(path)
112 110  
  111 + mask = msk.Mask()
  112 + mask._set_class_index(proj.last_mask_index)
  113 +
  114 + surface = srf.Surface()
  115 + surface._set_class_index(proj.last_surface_index)
  116 +
113 117 self.LoadProject()
114 118  
115 119 def ShowDialogSaveProject(self, saveas=False):
... ... @@ -139,6 +143,26 @@ class Controller():
139 143 proj = prj.Project()
140 144 prj.Project().SavePlistProject(dirpath, filename)
141 145  
  146 + def CloseProject(self):
  147 + print "Close Project"
  148 + session = ses.Session()
  149 + session.CloseProject()
  150 +
  151 + proj = prj.Project()
  152 + proj.Close()
  153 +
  154 + # TODO:
  155 + # Remove items from combo of masks
  156 + # Remove items from combo of surfaces
  157 + # Remove items from dictionaries
  158 + # Slice
  159 + # Surface
  160 + # --------------
  161 + #
  162 +
  163 + ps.Publisher().sendMessage('Hide content panel')
  164 +
  165 +
142 166 ##################################
143 167  
144 168  
... ... @@ -348,11 +372,15 @@ class Controller():
348 372 answer = dialog.SaveChangesDialog(filename)
349 373 if not answer:
350 374 print "Close without changes"
  375 + self.CloseProject()
351 376 elif answer == 1:
  377 + self.ShowDialogSaveProject()
352 378 print "Save changes and close"
  379 + self.CloseProject()
353 380 #else:
354 381 # print "Cancel"
355 382 else:
356 383 print ":) Close without changes"
  384 + self.CloseProject()
357 385  
358 386  
... ...
invesalius/data/mask.py
... ... @@ -78,4 +78,5 @@ class Mask():
78 78 else:
79 79 setattr(self, key, mask[key])
80 80  
81   -
  81 + def _set_class_index(self, index):
  82 + Mask.general_index = index
... ...
invesalius/data/slice_.py
... ... @@ -85,6 +85,19 @@ class Slice(object):
85 85 ps.Publisher().subscribe(self.InputImageWidget, 'Input Image in the widget')
86 86 ps.Publisher().subscribe(self.OnExportMask,'Export mask to file')
87 87  
  88 + ps.Publisher().subscribe(self.OnCloseProject, 'Close Project')
  89 +
  90 + def OnCloseProject(self, pubsub_evt):
  91 + self.CloseProject()
  92 +
  93 + def CloseProject(self):
  94 + self.imagedata = None
  95 + self.current_mask = None
  96 + self.blend_filter = None
  97 + #self.blend_filter = None
  98 + #self.num_gradient = 0
  99 +
  100 +
88 101 def __set_current_mask_threshold_limits(self, pubsub_evt):
89 102 thresh_min = pubsub_evt.data[0]
90 103 thresh_max = pubsub_evt.data[1]
... ... @@ -523,8 +536,8 @@ class Slice(object):
523 536  
524 537 # insert new mask into project and retrieve its index
525 538 proj = Project()
526   - proj.AddMask(future_mask.index, future_mask)
527   -
  539 + index = proj.AddMask(future_mask)
  540 + future_mask.index = index
528 541  
529 542 # update gui related to mask
530 543 ps.Publisher().sendMessage('Add mask',
... ...
invesalius/data/surface.py
... ... @@ -71,7 +71,8 @@ class Surface():
71 71 else:
72 72 setattr(self, key, surface[key])
73 73  
74   -
  74 + def _set_class_index(self, index):
  75 + Surface.general_index = index
75 76  
76 77  
77 78 # TODO: will be initialized inside control as it is being done?
... ... @@ -102,6 +103,15 @@ class SurfaceManager():
102 103 ps.Publisher().subscribe(self.OnShowSurface, 'Show surface')
103 104 ps.Publisher().subscribe(self.OnExportSurface,'Export surface to file')
104 105 ps.Publisher().subscribe(self.OnLoadSurfaceDict, 'Load surface dict')
  106 + ps.Publisher().subscribe(self.OnCloseProject, 'Close Project')
  107 +
  108 + def OnCloseProject(self, pubsub_evt):
  109 + self.CloseProject()
  110 +
  111 + def CloseProject(self):
  112 + del self.actors_dict
  113 + self.actors_dict = {}
  114 +
105 115  
106 116 def OnLoadSurfaceDict(self, pubsub_evt):
107 117 surface_dict = pubsub_evt.data
... ... @@ -291,7 +301,8 @@ class SurfaceManager():
291 301  
292 302 # Append surface into Project.surface_dict
293 303 proj = prj.Project()
294   - proj.surface_dict[surface.index] = surface
  304 + index = proj.AddSurface(surface)
  305 + surface.index = index
295 306  
296 307  
297 308 session = ses.Session()
... ...
invesalius/gui/data_notebook.py
... ... @@ -84,7 +84,13 @@ class MasksListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin):
84 84 'Change mask colour in notebook')
85 85  
86 86 ps.Publisher().subscribe(self.OnChangeCurrentMask, 'Change mask selected')
87   -
  87 + ps.Publisher().subscribe(self.OnCloseProject, 'Close Project')
  88 +
  89 + def OnCloseProject(self, pubsub_evt):
  90 + self.DeleteAllItems()
  91 + self.mask_list_index = {}
  92 + self.mask_bmp_idx_to_name = {}
  93 +
88 94 def OnChangeCurrentMask(self, pubsub_evt):
89 95  
90 96 mask_index = pubsub_evt.data
... ... @@ -211,6 +217,12 @@ class SurfacesListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin):
211 217 'Set surface transparency')
212 218 ps.Publisher().subscribe(self.EditSurfaceColour,
213 219 'Set surface colour')
  220 + ps.Publisher().subscribe(self.OnCloseProject, 'Close Project')
  221 +
  222 + def OnCloseProject(self, pubsub_evt):
  223 + self.DeleteAllItems()
  224 + self.surface_list_index = {}
  225 + self.surface_bmp_idx_to_name = {}
214 226  
215 227 def __bind_events_wx(self):
216 228 self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
... ...
invesalius/gui/dialogs.py
... ... @@ -132,13 +132,9 @@ WILDCARD_OPEN = "InVesalius 3 project (*.inv3)|*.inv3|"\
132 132  
133 133 def ShowOpenProjectDialog():
134 134 # Default system path
135   - if sys.platform == 'win32':
136   - default_path = ""
137   - else:
138   - default_path = os.getcwd()
139 135  
140 136 dlg = wx.FileDialog(None, message="Open InVesalius 3 project...",
141   - defaultDir=default_path,
  137 + defaultDir="",
142 138 defaultFile="", wildcard=WILDCARD_OPEN,
143 139 style=wx.OPEN|wx.CHANGE_DIR)
144 140  
... ...
invesalius/gui/frame.py
... ... @@ -89,7 +89,7 @@ class Frame(wx.Frame):
89 89 ps.Publisher().subscribe(self.HideImportPanel, 'Hide import panel')
90 90 ps.Publisher().subscribe(self.BeginBusyCursor, 'Begin busy cursor')
91 91 ps.Publisher().subscribe(self.EndBusyCursor, 'End busy cursor')
92   -
  92 + ps.Publisher().subscribe(self.HideContentPanel, 'Hide content panel')
93 93  
94 94 def EndBusyCursor(self, pubsub_evt=None):
95 95 wx.EndBusyCursor()
... ... @@ -209,6 +209,12 @@ class Frame(wx.Frame):
209 209 aui_manager.GetPane("Tasks").Show(1)
210 210 aui_manager.Update()
211 211  
  212 + def HideContentPanel(self, pubsub_evt):
  213 + aui_manager = self.aui_manager
  214 + aui_manager.GetPane("Data").Show(0)
  215 + aui_manager.GetPane("Tasks").Show(1)
  216 + aui_manager.Update()
  217 +
212 218 def OnSize(self, evt):
213 219 ps.Publisher().sendMessage(('ProgressBar Reposition'))
214 220 evt.Skip()
... ...
invesalius/gui/task_slice.py
... ... @@ -291,6 +291,19 @@ class MaskProperties(wx.Panel):
291 291 'Set threshold values in gradient')
292 292 ps.Publisher().subscribe(self.SelectMaskName, 'Select mask name in combo')
293 293 ps.Publisher().subscribe(self.ChangeMaskName, 'Change mask name')
  294 + ps.Publisher().subscribe(self.OnCloseProject, 'Close Project')
  295 +
  296 + def OnCloseProject(self, pubsub_evt):
  297 + self.CloseProject()
  298 +
  299 + def CloseProject(self):
  300 + n = self.combo_mask_name.GetCount()
  301 + for i in xrange(n-1, -1, -1):
  302 + self.combo_mask_name.Delete(i)
  303 + n = self.combo_thresh.GetCount()
  304 + for i in xrange(n-1, -1, -1):
  305 + self.combo_thresh.Delete(i)
  306 +
294 307  
295 308 def __bind_events_wx(self):
296 309 self.Bind(grad.EVT_THRESHOLD_CHANGE, self.OnSlideChanged, self.gradient)
... ...
invesalius/gui/task_surface.py
... ... @@ -339,11 +339,19 @@ class SurfaceProperties(wx.Panel):
339 339 def __bind_events(self):
340 340 ps.Publisher().subscribe(self.InsertNewSurface,
341 341 'Update surface info in GUI')
342   - ps.Publisher().subscribe(self.ChangeMaskName,
  342 + ps.Publisher().subscribe(self.ChangeSurfaceName,
343 343 'Change surface name')
  344 + ps.Publisher().subscribe(self.OnCloseProject, 'Close Project')
344 345  
  346 + def OnCloseProject(self, pubsub_evt):
  347 + self.CloseProject()
345 348  
346   - def ChangeMaskName(self, pubsub_evt):
  349 + def CloseProject(self):
  350 + n = self.combo_surface_name.GetCount()
  351 + for i in xrange(n-1, -1, -1):
  352 + self.combo_surface_name.Delete(i)
  353 +
  354 + def ChangeSurfaceName(self, pubsub_evt):
347 355 index, name = pubsub_evt.data
348 356 self.combo_surface_name.SetString(index, name)
349 357 self.combo_surface_name.Refresh()
... ...
invesalius/project.py
... ... @@ -43,80 +43,61 @@ class Project(object):
43 43 __metaclass__= Singleton
44 44  
45 45 def __init__(self):
46   - # TODO: Discuss
47   - # [Tati] Will this type of data be written on project file? What if user
48   - # changes file name and directory? I guess no... But, who knows...
49   - #self.name = "Default"
50   - #self.dir_ = "C:\\"
51   -
52   - # Original vtkImageData, build based on medical images read.
53   - # To be used for general 2D slices rendering both on 2D and 3D
54   - # coordinate systems. It might be used, as well, for 3D raycasting.
55   - # rendering.
56   - # TODO: Discuss when this will be used.
57   - self.imagedata = ''
58   -
  46 + # Patient/ acquistion information
59 47 self.name = ''
60 48 #self.dicom = ''
61 49 self.modality = ''
62   - self.original_orientation = -1
63   -
64   - # Masks are related to vtkImageData
65   - self.mask_dict = {}
66   - # Predefined threshold values
  50 + self.original_orientation = ''
67 51 self.min_threshold = ''
68 52 self.max_threshold = ''
69   -
70 53 self.window = ''
71 54 self.level = ''
72 55  
  56 + # Original imagedata (shouldn't be changed)
  57 + self.imagedata = ''
  58 +
  59 + # Masks (vtkImageData)
  60 + self.mask_dict = {}
  61 + self.last_mask_index = 0
  62 +
  63 + # Surfaces are (vtkPolyData)
  64 + self.surface_dict = {}
  65 + self.last_surface_index = -1
  66 +
  67 + # TODO: Future
  68 + self.measure_dict = {}
  69 +
  70 + # TODO: Future ++
  71 + self.annotation_dict = {}
  72 +
  73 + # InVesalius related data
  74 + # So we can find bugs and reproduce user-related problems
  75 + self.invesalius_version = version.get_svn_revision()
  76 +
73 77 self.presets = Presets()
  78 +
74 79 self.threshold_modes = self.presets.thresh_ct
75 80 self.threshold_range = ''
76   -
77   - self.original_orientation = ''
78   - # MRI ? CT?
79 81  
  82 + self.raycasting_preset = ''
80 83  
81   - # TODO: define how we will relate these threshold values to
82   - # default threshold labels
83   - # TODO: Future +
84   - # Allow insertion of new threshold modes
85 84  
86   - # Surfaces are related to vtkPolyDataa
87   - self.surface_dict = {}
88 85 #self.surface_quality_list = ["Low", "Medium", "High", "Optimal *",
89   - # "Custom"]
  86 + # "Custom"i]
  87 +
90 88 # TOOD: define how we will relate this quality possibilities to
91 89 # values set as decimate / smooth
92 90 # TODO: Future +
93 91 # Allow insertion of new surface quality modes
94 92  
95   - self.measure_dict = {}
  93 + def Close(self):
  94 + for name in self.__dict__:
  95 + attr = getattr(self, name)
  96 + del attr
96 97  
97   - # TODO: Future ++
98   - #self.annotation_dict = {}
  98 + self.__init__()
99 99  
100   - # TODO: Future +
101   - # Volume rendering modes related to vtkImageData
102   - # this will need to be inserted both in the project and in the user
103   - # InVesalius configuration file
104   - # self.render_mode = {}
105   -
106   - # The raycasting preset setted in this project
107   - self.raycasting_preset = ''
108   -
109   - self.invesalius_version = version.get_svn_revision()
110   - print self.invesalius_version
111   -
112   - #self.save_as = True
113   -
114   - #self.path = ""
115   - self.debug = 0
116   -
117   - ####### MASK OPERATIONS
118   -
119   - def AddMask(self, index, mask):
  100 + def AddMask(self, mask):
120 101 """
121 102 Insert new mask (Mask) into project data.
122 103  
... ... @@ -126,11 +107,37 @@ class Project(object):
126 107 output
127 108 @ index: index of item that was inserted
128 109 """
  110 + self.last_mask_index = mask.index
  111 + index = len(self.mask_dict)
129 112 self.mask_dict[index] = mask
  113 + return index
  114 +
  115 + def RemoveMask(self, index):
  116 + new_dict = {}
  117 + for i in self.mask_dict:
  118 + if i < index:
  119 + new_dict[i] = self.mask_dict[i]
  120 + if i > index:
  121 + new_dict[i-1] = self.mask_dict[i]
  122 + self.mask_dict = new_dict
130 123  
131 124 def GetMask(self, index):
132 125 return self.mask_dict[index]
133 126  
  127 + def AddSurface(self, surface):
  128 + self.last_surface_index = surface.index
  129 + index = len(self.surface_dict)
  130 + self.surface_dict[index] = surface
  131 + return index
  132 +
  133 + def RemoveSurface(self, index):
  134 + new_dict = {}
  135 + for i in self.surface_dict:
  136 + if i < index:
  137 + new_dict[i] = self.surface_dict[i]
  138 + if i > index:
  139 + new_dict[i-1] = self.surface_dict[i]
  140 + self.surface_dict = new_dict
134 141  
135 142 def SetAcquisitionModality(self, type_=None):
136 143 if type_ is None:
... ...
invesalius/session.py
... ... @@ -11,10 +11,11 @@ class Session(object):
11 11 def __init__(self):
12 12 self.project_path = ()
13 13  
14   - self.project_status = const.PROJ_NEW
15   - # const.PROJ_NEW*, const.PROJ_OPEN, const.PROJ_CHANGE*
  14 + self.project_status = const.PROJ_CLOSE
  15 + # const.PROJ_NEW*, const.PROJ_OPEN, const.PROJ_CHANGE*,
  16 + # const.PROJ_CLOSE
16 17  
17   - self.mode = ""
  18 + self.mode = const.MODE_RP
18 19 # const.MODE_RP, const.MODE_NAVIGATOR, const.MODE_RADIOLOGY,
19 20 # const.MODE_ODONTOLOGY
20 21  
... ... @@ -30,6 +31,11 @@ class Session(object):
30 31 # Recent projects list
31 32 self.recent_projects = []
32 33  
  34 + def CloseProject(self):
  35 + self.project_path = ()
  36 + self.project_status = const.PROJ_CLOSE
  37 + self.mode = const.MODE_RP
  38 + self.temp_item = False
33 39  
34 40 def SaveProject(self, path=()):
35 41 self.project_status = const.PROJ_OPEN
... ...