Commit 088d7b8b7090e0e55678f33f32c1d6085ee1b2e6

Authored by tatiana
1 parent a3665303

FIX: Save existing project under OSX

invesalius/constants.py
... ... @@ -78,10 +78,17 @@ SLICE_POSITION = {AXIAL:[AXIAL_SLICE_CAM_VIEW_UP, AXIAL_SLICE_CAM_POSITION],
78 78 SAGITAL:[SAGITAL_SLICE_CAM_VIEW_UP, SAGITAL_SLICE_CAM_POSITION],
79 79 CORONAL:[CORONAL_SLICE_CAM_VIEW_UP, CORONAL_SLICE_CAM_POSITION]}
80 80 #Project Status
81   -NEW_PROJECT = 0
82   -OPEN_PROJECT = 1
83   -CHANGE_PROJECT = 2
84   -SAVE_PROJECT = 3
  81 +#NEW_PROJECT = 0
  82 +#OPEN_PROJECT = 1
  83 +#CHANGE_PROJECT = 2
  84 +#SAVE_PROJECT = 3
  85 +PROJ_NEW = 0
  86 +PROJ_OPEN = 1
  87 +PROJ_CHANGE = 2
  88 +
  89 +PROJ_MAX = 4
  90 +
  91 +
85 92  
86 93 #Color Table from Slice
87 94 #NumberOfColors, SaturationRange, HueRange, ValueRange
... ...
invesalius/control.py
... ... @@ -33,7 +33,7 @@ import reader.dicom_grouper as dg
33 33 import gui.dialogs as dialog
34 34 import reader.dicom_reader as dcm
35 35 import reader.analyze_reader as analyze
36   -import session
  36 +import session as ses
37 37  
38 38 DEFAULT_THRESH_MODE = 0
39 39  
... ... @@ -47,7 +47,7 @@ class Controller():
47 47 self.progress_dialog = None
48 48 self.cancel_import = False
49 49 #Init session
50   - session.Session()
  50 + session = ses.Session()
51 51  
52 52 def __bind_events(self):
53 53 ps.Publisher().subscribe(self.OnImportMedicalImages, 'Import directory')
... ... @@ -63,6 +63,7 @@ class Controller():
63 63 ps.Publisher().subscribe(self.OnCancelImport, 'Cancel DICOM load')
64 64 ps.Publisher().subscribe(self.OnSaveProject, 'Save Project')
65 65 ps.Publisher().subscribe(self.OnOpenProject, 'Open Project')
  66 + ps.Publisher().subscribe(self.OnCloseProject, 'Close Project')
66 67  
67 68  
68 69 def OnCancelImport(self, pubsub_evt):
... ... @@ -136,6 +137,13 @@ class Controller():
136 137  
137 138 def LoadProject(self):
138 139 proj = prj.Project()
  140 +
  141 + const.THRESHOLD_OUTVALUE = proj.threshold_range[0]
  142 + const.THRESHOLD_INVALUE = proj.threshold_range[1]
  143 + const.WINDOW_LEVEL['Default'] = (proj.window, proj.level)
  144 + const.WINDOW_LEVEL['Manual'] = (proj.window, proj.level)
  145 +
  146 +
139 147 ps.Publisher().sendMessage('Set project name', proj.name)
140 148 ps.Publisher().sendMessage('Load slice to viewer',
141 149 (proj.imagedata,
... ... @@ -162,11 +170,6 @@ class Controller():
162 170 proj.window = proj.threshold_range[1] - proj.threshold_range[0]
163 171 proj.level = (0.5 * (proj.threshold_range[1] + proj.threshold_range[0]))
164 172  
165   - const.THRESHOLD_OUTVALUE = proj.threshold_range[0]
166   - const.THRESHOLD_INVALUE = proj.threshold_range[1]
167   - const.WINDOW_LEVEL['Default'] = (proj.window, proj.level)
168   - const.WINDOW_LEVEL['Manual'] = (proj.window, proj.level)
169   -
170 173  
171 174 def CreateDicomProject(self, imagedata, dicom):
172 175 name_to_const = {"AXIAL":const.AXIAL,
... ... @@ -185,10 +188,14 @@ class Controller():
185 188 proj.level = float(dicom.image.level)
186 189 proj.threshold_range = imagedata.GetScalarRange()
187 190  
188   - const.THRESHOLD_OUTVALUE = proj.threshold_range[0]
189   - const.THRESHOLD_INVALUE = proj.threshold_range[1]
190   - const.WINDOW_LEVEL['Default'] = (proj.window, proj.level)
191   - const.WINDOW_LEVEL['Manual'] = (proj.window, proj.level)
  191 +
  192 + ######
  193 + session = ses.Session()
  194 + filename = proj.name+".inv3"
  195 + dirpath = session.CreateProject(filename)
  196 + proj.SavePlistProject(dirpath, filename)
  197 +
  198 +
192 199  
193 200 def OnOpenDicomGroup(self, pubsub_evt):
194 201 group = pubsub_evt.data
... ... @@ -259,33 +266,68 @@ class Controller():
259 266 plistlib.writePlist(preset, preset_dir)
260 267  
261 268 def OnSaveProject(self, pubsub_evt):
  269 + session = ses.Session()
262 270  
263   - if not(pubsub_evt.data):
264   - filename = prj.Project().path
265   - else:
266   - filename = pubsub_evt.data
267   - dir_,filename = os.path.split(filename)
268   -
269   - if not (filename):
270   - filename = prj.Project().name
  271 + path = pubsub_evt.data
  272 + if path:
  273 + print "----- FILENAME"
  274 + dirpath, filename = os.path.split(path)
  275 + session.SaveProject((dirpath, filename))
271 276 else:
272   - filename = filename.replace(' ','_')
273   - prj.Project().name = filename
274   - prj.Project().path = filename
275   - print prj.Project().path
276   - prj.Project().SavePlistProject(dir_, filename)
277   - session.Session().project_status = const.SAVE_PROJECT
  277 + dirpath, filename = session.project_path
  278 +
  279 + print "$$$$$$$$$$$$$$$$$$$$$$$$$$"
  280 + print "filename: ", filename
  281 + print "dirpath: ", dirpath
  282 +
  283 + proj = prj.Project()
  284 + prj.Project().SavePlistProject(dirpath, filename)
  285 +
  286 +
  287 +
  288 +
  289 + #if not(pubsub_evt.data):
  290 + # filename = prj.Project().path
  291 + #else:
  292 + # filename = pubsub_evt.data
  293 + #dir_,filename = os.path.split(filename)
  294 +
  295 + #if not (filename):
  296 + # filename = prj.Project().name
  297 + #else:
  298 + # filename = filename.replace(' ','_')
  299 + # prj.Project().name = filename
  300 + #prj.Project().path = filename
  301 + #print prj.Project().path
  302 +
  303 + #prj.Project().SavePlistProject(dirpath, filename)
  304 +
  305 + #session.project_status = const.PROJ_OPEN
  306 + #session.project_path = (dirpath, filename)
278 307  
279 308 def OnOpenProject(self, pubsub_evt):
280   - filename = os.path.abspath(pubsub_evt.data)
281   - session.Session().project_status = const.OPEN_PROJECT
  309 + path = os.path.abspath(pubsub_evt.data)
  310 +
282 311 proj = prj.Project()
283   - proj.OpenPlistProject(filename)
  312 + proj.OpenPlistProject(path)
284 313 proj.SetAcquisitionModality(proj.modality)
285   - proj.save_as = False
286   - proj.path = filename
287   - const.THRESHOLD_OUTVALUE = proj.threshold_range[0]
288   - const.THRESHOLD_INVALUE = proj.threshold_range[1]
289   - const.WINDOW_LEVEL['Default'] = (proj.window, proj.level)
290   - const.WINDOW_LEVEL['Manual'] = (proj.window, proj.level)
  314 + ###proj.path = filename
  315 + ###proj.save_as = False
  316 +
  317 + session = ses.Session()
  318 + session.OpenProject(path)
  319 +
291 320 self.LoadProject()
  321 +
  322 + def OnCloseProject(self, pubsub_evt):
  323 + print "OnCloseProject"
  324 + session = ses.Session()
  325 + st = session.project_status
  326 + filename = session.project_path[1]
  327 + if (st == const.PROJ_NEW) or (st == const.PROJ_CHANGE):
  328 + answer = dialog.SaveChangesDialog(filename)
  329 + if not answer:
  330 + print "Delete all"
  331 + elif answer > 1:
  332 + print "Save"
  333 +
... ...
invesalius/data/slice_.py
... ... @@ -25,7 +25,7 @@ import constants as const
25 25 import imagedata_utils as iu
26 26 from mask import Mask
27 27 from project import Project
28   -import session
  28 +import session as ses
29 29 from utils import Singleton
30 30  
31 31  
... ... @@ -115,9 +115,10 @@ class Slice(object):
115 115 self.SetMaskEditionThreshold(index, threshold_range)
116 116  
117 117 def __set_current_mask_threshold(self, evt_pubsub):
  118 + session = ses.Session()
118 119 #FIXME: find a better way to implement this
119 120 if (self.num_gradient >= 2) or \
120   - (session.Session().project_status != const.OPEN_PROJECT):
  121 + (session.project_status != const.PROJ_OPEN):
121 122 threshold_range = evt_pubsub.data
122 123 index = self.current_mask.index
123 124 self.SetMaskThreshold(index, threshold_range)
... ... @@ -180,11 +181,19 @@ class Slice(object):
180 181 if update:
181 182 ps.Publisher().sendMessage('Update slice viewer')
182 183  
  184 + session = ses.Session()
  185 + session.ChangeProject()
  186 +
  187 +
183 188 def SetMaskName(self, index, name):
184 189 "Rename a mask given its index and the new name"
185 190 proj = Project()
186 191 proj.mask_dict[index].name = name
187 192  
  193 + session = ses.Session()
  194 + session.ChangeProject()
  195 +
  196 +
188 197 def SetMaskEditionThreshold(self, index, threshold_range):
189 198 "Set threshold bounds to be used while editing slice"
190 199 proj = Project()
... ... @@ -224,8 +233,13 @@ class Slice(object):
224 233 proj.mask_dict[index].threshold_range = threshold_range
225 234  
226 235 proj = Project()
227   - proj.mask_dict[self.current_mask.index ].threshold_range = threshold_range
228   -
  236 + proj.mask_dict[self.current_mask.index].threshold_range = threshold_range
  237 +
  238 + session = ses.Session()
  239 + session.ChangeProject()
  240 +
  241 +
  242 +
229 243  
230 244 def ShowMask(self, index, value):
231 245 "Show a mask given its index and 'show' value (0: hide, other: show)"
... ... @@ -246,6 +260,10 @@ class Slice(object):
246 260 imagedata = self.current_mask.imagedata
247 261 imagedata.SetScalarComponentFromDouble(x, y, z, 0, colour)
248 262 self.current_mask.edited_points[(x, y, z)] = colour
  263 +
  264 + session = ses.Session()
  265 + session.ChangeProject()
  266 +
249 267  
250 268 def DrawPixel(self, position, colour=None):
251 269 "Draw pixel, based on x, y and z position coordinates."
... ... @@ -255,6 +273,10 @@ class Slice(object):
255 273 imagedata.SetScalarComponentFromDouble(x, y, z, 0, colour)
256 274 self.current_mask.edited_points[(x, y, z)] = colour
257 275  
  276 + session = ses.Session()
  277 + session.ChangeProject()
  278 +
  279 +
258 280 def EditPixelBasedOnThreshold(self, position):
259 281 "Erase or draw pixel based on edition threshold range."
260 282 x, y, z = position
... ... @@ -264,6 +286,11 @@ class Slice(object):
264 286 self.DrawPixel(position, colour)
265 287 else:
266 288 self.ErasePixel(position)
  289 +
  290 + session = ses.Session()
  291 + session.ChangeProject()
  292 +
  293 +
267 294 #---------------------------------------------------------------------------
268 295 def SelectCurrentMask(self, index):
269 296 "Insert mask data, based on given index, into pipeline."
... ...
invesalius/data/surface.py
... ... @@ -25,9 +25,10 @@ import wx.lib.pubsub as ps
25 25  
26 26 import constants as const
27 27 import imagedata_utils as iu
  28 +import polydata_utils as pu
28 29 import project as prj
  30 +import session as ses
29 31 import vtk_utils as vu
30   -import polydata_utils as pu
31 32 from imagedata_utils import BuildEditedImage
32 33  
33 34 class Surface():
... ... @@ -292,6 +293,11 @@ class SurfaceManager():
292 293 proj = prj.Project()
293 294 proj.surface_dict[surface.index] = surface
294 295  
  296 +
  297 + session = ses.Session()
  298 + session.ChangeProject()
  299 +
  300 +
295 301 # Save actor for future management tasks
296 302 self.actors_dict[surface.index] = actor
297 303  
... ...
invesalius/gui/dialogs.py
... ... @@ -190,4 +190,18 @@ def ShowSaveAsProjectDialog(default_filename=None):
190 190 if sys.platform != 'win32':
191 191 if filename.split(".")[-1] != extension:
192 192 filename = filename + "." + extension
193   - return filename
  193 + return filename
  194 +
  195 +def SaveChangesDialog(filename):
  196 + dlg = wx.MessageDialog(None,
  197 + "InVesalius 3",
  198 + "Save changes to "+filename+"?",
  199 + wx.YES | wx.NO | wx.CANCEL | wx.ICON_INFORMATION)
  200 +
  201 + if dlg.ShowModal() == wx.ID_YES:
  202 + return 1
  203 + elif dlg.ShowModal() == wx.ID_NO:
  204 + return 0
  205 + else:
  206 + return -1
  207 +
... ...
invesalius/gui/frame.py
... ... @@ -30,7 +30,8 @@ import default_tasks as tasks
30 30 import default_viewers as viewers
31 31 import gui.dialogs as dlg
32 32 import import_panel as imp
33   -from project import Project
  33 +import project as prj
  34 +import session as ses
34 35  
35 36 # Object toolbar
36 37 OBJ_TOOLS = [ID_ZOOM, ID_ZOOM_SELECT, ID_ROTATE, ID_MOVE,
... ... @@ -216,12 +217,15 @@ class Frame(wx.Frame):
216 217 #ps.Publisher().sendMessage(("Event from GUI",
217 218 # evt.GetId()))
218 219 id = evt.GetId()
  220 + #proj = prj.Project()
  221 + session = ses.Session()
219 222 if id == const.ID_DICOM_IMPORT:
220 223 self.ImportDicom()
221 224 elif id == const.ID_PROJECT_OPEN:
222 225 self.OpenProject()
223 226 elif id == const.ID_PROJECT_SAVE:
224   - if Project().save_as:
  227 + #if proj.save_as:
  228 + if session.temp_item:
225 229 self.SaveAsProject()
226 230 else:
227 231 self.SaveProject()
... ... @@ -246,14 +250,20 @@ class Frame(wx.Frame):
246 250 self.SaveProject(True)
247 251  
248 252 def SaveProject(self, saveas=False):
249   - filename = (Project().name).replace(' ','_')
250   - if Project().save_as or saveas:
251   - filename = dlg.ShowSaveAsProjectDialog(filename)
252   - if filename:
253   - Project().save_as = False
  253 +
  254 + session = ses.Session()
  255 + if saveas:
  256 + proj = prj.Project()
  257 + filepath = dlg.ShowSaveAsProjectDialog(proj.name)
  258 + if filepath:
  259 + session.RemoveTemp()
  260 + session.OpenProject(filepath)
254 261 else:
255 262 return
256   - ps.Publisher().sendMessage('Save Project',filename)
  263 + else:
  264 + dirpath, filename = session.project_path
  265 + filepath = os.path.join(dirpath, filename)
  266 + ps.Publisher().sendMessage('Save Project',filepath)
257 267  
258 268  
259 269 def SaveAsOld(self):
... ... @@ -272,7 +282,7 @@ class Frame(wx.Frame):
272 282 ps.Publisher().sendMessage('Save Project',filename)
273 283  
274 284 def CloseProject(self):
275   - print "TODO: CloseProject"
  285 + ps.Publisher().sendMessage('Close Project')
276 286  
277 287 def Exit(self):
278 288 print "TODO: Exit"
... ... @@ -544,10 +554,10 @@ class ProjectToolBar(wx.ToolBar):
544 554 self.Realize()
545 555  
546 556 def __bind_events(self):
547   -
548   - self.Bind(wx.EVT_TOOL, self.OnToolSave, id=const.ID_PROJECT_SAVE)
549   - self.Bind(wx.EVT_TOOL, self.OnToolOpen, id=const.ID_PROJECT_OPEN)
550   - self.Bind(wx.EVT_TOOL, self.OnToolImport, id=const.ID_DICOM_IMPORT)
  557 + pass
  558 + #self.Bind(wx.EVT_TOOL, self.OnToolSave, id=const.ID_PROJECT_SAVE)
  559 + #self.Bind(wx.EVT_TOOL, self.OnToolOpen, id=const.ID_PROJECT_OPEN)
  560 + #self.Bind(wx.EVT_TOOL, self.OnToolImport, id=const.ID_DICOM_IMPORT)
551 561  
552 562 def OnToolImport(self, event):
553 563 dirpath = dlg.ShowImportDirDialog()
... ... @@ -562,11 +572,12 @@ class ProjectToolBar(wx.ToolBar):
562 572 event.Skip()
563 573  
564 574 def OnToolSave(self, event):
565   - filename = (Project().name).replace(' ','_')
566   - if Project().save_as:
  575 + proj = prj.Project()
  576 + filename = (prj.name).replace(' ','_')
  577 + if prj.save_as:
567 578 filename = dlg.ShowSaveAsProjectDialog(filename)
568 579 if filename:
569   - Project().save_as = False
  580 + prj.save_as = False
570 581 else:
571 582 return
572 583 ps.Publisher().sendMessage('Save Project',filename)
... ...
invesalius/project.py
... ... @@ -109,9 +109,9 @@ class Project(object):
109 109 self.invesalius_version = version.get_svn_revision()
110 110 print self.invesalius_version
111 111  
112   - self.save_as = True
  112 + #self.save_as = True
113 113  
114   - self.path = ""
  114 + #self.path = ""
115 115 self.debug = 0
116 116  
117 117 ####### MASK OPERATIONS
... ...
invesalius/reader/dicom.py
... ... @@ -1129,7 +1129,7 @@ class Parser():
1129 1129 data = self.vtkgdcm_reader.GetMedicalImageProperties()\
1130 1130 .GetPatientName()
1131 1131 if (data):
1132   - return data
  1132 + return data.strip()
1133 1133 return ""
1134 1134  
1135 1135 def GetPatientID(self):
... ...
invesalius/session.py
  1 +import os
  2 +
1 3 import constants as const
2 4 from utils import Singleton
3 5  
... ... @@ -7,4 +9,77 @@ class Session(object):
7 9 __metaclass__= Singleton
8 10  
9 11 def __init__(self):
10   - self.project_status = const.NEW_PROJECT
11 12 \ No newline at end of file
  13 + self.project_path = ()
  14 +
  15 + self.project_status = const.PROJ_NEW
  16 + # const.PROJ_NEW*, const.PROJ_OPEN, const.PROJ_CHANGE*
  17 +
  18 + self.mode = ""
  19 + # const.MODE_RP, const.MODE_NAVIGATOR, const.MODE_RADIOLOGY,
  20 + # const.MODE_ODONTOLOGY
  21 +
  22 + # InVesalius default projects' directory
  23 + homedir = os.path.expanduser('~')
  24 + invdir = os.path.join(homedir, ".invesalius", "temp")
  25 + if not os.path.isdir(invdir):
  26 + os.makedirs(invdir)
  27 + self.invdir = invdir
  28 +
  29 + self.temp_item = False
  30 +
  31 + # Recent projects list
  32 + self.recent_projects = []
  33 +
  34 +
  35 + def SaveProject(self, path=()):
  36 + self.project_status = const.PROJ_OPEN
  37 + if path:
  38 + self.project_path = path
  39 + self.__add_to_list(path)
  40 + if self.temp_item:
  41 + self.temp_item = False
  42 +
  43 + def ChangeProject(self):
  44 + self.project_status = const.PROJ_CHANGE
  45 +
  46 + def CreateProject(self, filename):
  47 + # Set session info
  48 + self.project_path = (self.invdir, filename)
  49 + self.project_status = const.PROJ_NEW
  50 + self.temp_item = True
  51 + return self.invdir
  52 +
  53 +
  54 + def OpenProject(self, filepath):
  55 + # Add item to recent projects list
  56 + item = (path, file) = os.path.split(filepath)
  57 + self.__add_to_list(item)
  58 +
  59 + # Set session info
  60 + self.project_path = item
  61 + self.project_status = const.PROJ_OPEN
  62 +
  63 + def RemoveTemp(self):
  64 + if self.temp_item:
  65 + (dirpath, file) = self.project_path
  66 + path = os.path.join(dirpath, file)
  67 + os.remove(path)
  68 + self.temp_item = False
  69 +
  70 +
  71 + def __add_to_list(self, item):
  72 + # Last projects list
  73 + l = self.recent_projects
  74 +
  75 + # If item exists, remove it from list
  76 + if l.count(item):
  77 + l.remove(item)
  78 +
  79 + # Add new item
  80 + l.insert(0, item)
  81 +
  82 + # Remove oldest projects from list
  83 + if len(l)>const.PROJ_MAX:
  84 + for i in xrange(len(l)-const.PROJ_MAX):
  85 + l.pop()
  86 +
... ...