Commit 6e9eeb391c88e0815023573632646f4dc705e4b6

Authored by Thiago Franco de Moraes
Committed by GitHub
1 parent feaf214b
Exists in master

Session as dict (#156)

* session as dict almost working

* writing to json

* Better last projection handling

* was not closing when didn't have config

* Not reading status from config file

* removed unused fucntion

* reading from cfg specifing the types

* reading from cfg specifing the types

* Removed unused parts

* Added a get method to session

* Using default in session

* last folder to inv3 and other files in session

* last folder to export and import stl export screenshots and open bmp folder in session
@@ -147,9 +147,8 @@ class Inv3SplashScreen(SplashScreen): @@ -147,9 +147,8 @@ class Inv3SplashScreen(SplashScreen):
147 create_session = True 147 create_session = True
148 148
149 install_lang = 0 149 install_lang = 0
150 - # Check if there is a language set (if session file exists  
151 - if session.ReadLanguage():  
152 - lang = session.GetLanguage() 150 + lang = session.GetLanguage()
  151 + if lang:
153 if (lang != "False"): 152 if (lang != "False"):
154 _ = i18n.InstallLanguage(lang) 153 _ = i18n.InstallLanguage(lang)
155 install_lang = 1 154 install_lang = 1
@@ -179,7 +178,9 @@ class Inv3SplashScreen(SplashScreen): @@ -179,7 +178,9 @@ class Inv3SplashScreen(SplashScreen):
179 invdir = os.path.join(homedir, ".invesalius") 178 invdir = os.path.join(homedir, ".invesalius")
180 shutil.rmtree(invdir) 179 shutil.rmtree(invdir)
181 sys.exit() 180 sys.exit()
182 - 181 +
  182 + dialog.Destroy()
  183 +
183 # Session file should be created... So we set the recent 184 # Session file should be created... So we set the recent
184 # choosen language 185 # choosen language
185 if (create_session): 186 if (create_session):
@@ -187,7 +188,7 @@ class Inv3SplashScreen(SplashScreen): @@ -187,7 +188,7 @@ class Inv3SplashScreen(SplashScreen):
187 session.SetLanguage(lang) 188 session.SetLanguage(lang)
188 session.WriteSessionFile() 189 session.WriteSessionFile()
189 190
190 - session.SaveConfigFileBackup() 191 + # session.SaveConfigFileBackup()
191 192
192 193
193 # Only after language was defined, splash screen will be 194 # Only after language was defined, splash screen will be
invesalius/control.py
@@ -249,6 +249,7 @@ class Controller(): @@ -249,6 +249,7 @@ class Controller():
249 def ShowDialogCloseProject(self): 249 def ShowDialogCloseProject(self):
250 session = ses.Session() 250 session = ses.Session()
251 st = session.project_status 251 st = session.project_status
  252 + print('Status', st, type(st))
252 if st == const.PROJ_CLOSE: 253 if st == const.PROJ_CLOSE:
253 return -1 254 return -1
254 try: 255 try:
invesalius/data/surface.py
@@ -159,6 +159,28 @@ class SurfaceManager(): @@ -159,6 +159,28 @@ class SurfaceManager():
159 self.last_surface_index = 0 159 self.last_surface_index = 0
160 self.__bind_events() 160 self.__bind_events()
161 161
  162 + self._default_parameters = {
  163 + 'algorithm': 'Default',
  164 + 'quality': const.DEFAULT_SURFACE_QUALITY,
  165 + 'fill_holes': False,
  166 + 'keep_largest': False,
  167 + 'fill_border_holes': True,
  168 + }
  169 +
  170 + self._load_user_parameters()
  171 +
  172 + def _load_user_parameters(self):
  173 + session = ses.Session()
  174 +
  175 + if 'surface' in session:
  176 + self._default_parameters.update(session['surface'])
  177 + else:
  178 + session['surface'] = self._default_parameters
  179 + session.WriteSessionFile()
  180 +
  181 + print('Session', session)
  182 +
  183 +
162 def __bind_events(self): 184 def __bind_events(self):
163 Publisher.subscribe(self.AddNewActor, 'Create surface') 185 Publisher.subscribe(self.AddNewActor, 'Create surface')
164 Publisher.subscribe(self.SetActorTransparency, 186 Publisher.subscribe(self.SetActorTransparency,
invesalius/gui/dialogs.py
@@ -268,8 +268,10 @@ WILDCARD_MESH_FILES = "STL File format (*.stl)|*.stl|" \ @@ -268,8 +268,10 @@ WILDCARD_MESH_FILES = "STL File format (*.stl)|*.stl|" \
268 def ShowOpenProjectDialog(): 268 def ShowOpenProjectDialog():
269 # Default system path 269 # Default system path
270 current_dir = os.path.abspath(".") 270 current_dir = os.path.abspath(".")
  271 + session = ses.Session()
  272 + last_directory = session.get('paths', 'last_directory_inv3', '')
271 dlg = wx.FileDialog(None, message=_("Open InVesalius 3 project..."), 273 dlg = wx.FileDialog(None, message=_("Open InVesalius 3 project..."),
272 - defaultDir="", 274 + defaultDir=last_directory,
273 defaultFile="", wildcard=WILDCARD_OPEN, 275 defaultFile="", wildcard=WILDCARD_OPEN,
274 style=wx.FD_OPEN|wx.FD_CHANGE_DIR) 276 style=wx.FD_OPEN|wx.FD_CHANGE_DIR)
275 277
@@ -286,6 +288,10 @@ def ShowOpenProjectDialog(): @@ -286,6 +288,10 @@ def ShowOpenProjectDialog():
286 except(wx._core.PyAssertionError): # FIX: win64 288 except(wx._core.PyAssertionError): # FIX: win64
287 filepath = dlg.GetPath() 289 filepath = dlg.GetPath()
288 290
  291 + if filepath:
  292 + session['paths']['last_directory_inv3'] = os.path.split(filepath)[0]
  293 + session.WriteSessionFile()
  294 +
289 # Destroy the dialog. Don't do this until you are done with it! 295 # Destroy the dialog. Don't do this until you are done with it!
290 # BAD things can happen otherwise! 296 # BAD things can happen otherwise!
291 dlg.Destroy() 297 dlg.Destroy()
@@ -337,17 +343,19 @@ def ShowImportDirDialog(self): @@ -337,17 +343,19 @@ def ShowImportDirDialog(self):
337 def ShowImportBitmapDirDialog(self): 343 def ShowImportBitmapDirDialog(self):
338 current_dir = os.path.abspath(".") 344 current_dir = os.path.abspath(".")
339 345
340 - if sys.platform == 'win32' or sys.platform.startswith('linux'):  
341 - session = ses.Session() 346 + # if sys.platform == 'win32' or sys.platform.startswith('linux'):
  347 + # session = ses.Session()
342 348
343 - if (session.GetLastDicomFolder()):  
344 - folder = session.GetLastDicomFolder()  
345 - else:  
346 - folder = ''  
347 - else:  
348 - folder = '' 349 + # if (session.GetLastDicomFolder()):
  350 + # folder = session.GetLastDicomFolder()
  351 + # else:
  352 + # folder = ''
  353 + # else:
  354 + # folder = ''
  355 + session = ses.Session()
  356 + last_directory = session.get('paths', 'last_directory_bitmap', '')
349 357
350 - dlg = wx.DirDialog(self, _("Choose a folder with TIFF, BMP, JPG or PNG:"), folder, 358 + dlg = wx.DirDialog(self, _("Choose a folder with TIFF, BMP, JPG or PNG:"), last_directory,
351 style=wx.DD_DEFAULT_STYLE 359 style=wx.DD_DEFAULT_STYLE
352 | wx.DD_DIR_MUST_EXIST 360 | wx.DD_DIR_MUST_EXIST
353 | wx.DD_CHANGE_DIR) 361 | wx.DD_CHANGE_DIR)
@@ -363,9 +371,13 @@ def ShowImportBitmapDirDialog(self): @@ -363,9 +371,13 @@ def ShowImportBitmapDirDialog(self):
363 if (dlg.GetPath()): 371 if (dlg.GetPath()):
364 path = dlg.GetPath() 372 path = dlg.GetPath()
365 373
366 - if (sys.platform != 'darwin'):  
367 - if (path):  
368 - session.SetLastDicomFolder(path) 374 + # if (sys.platform != 'darwin'):
  375 + # if (path):
  376 + # session.SetLastDicomFolder(path)
  377 +
  378 + if path:
  379 + session['paths']['last_directory_bitmap'] = path
  380 + session.WriteSessionFile()
369 381
370 # Only destroy a dialog after you're done with it. 382 # Only destroy a dialog after you're done with it.
371 dlg.Destroy() 383 dlg.Destroy()
@@ -375,9 +387,10 @@ def ShowImportBitmapDirDialog(self): @@ -375,9 +387,10 @@ def ShowImportBitmapDirDialog(self):
375 387
376 def ShowImportOtherFilesDialog(id_type): 388 def ShowImportOtherFilesDialog(id_type):
377 # Default system path 389 # Default system path
378 - current_dir = os.path.abspath(".") 390 + session = ses.Session()
  391 + last_directory = session.get('paths', 'last_directory_%d' % id_type, '')
379 dlg = wx.FileDialog(None, message=_("Import Analyze 7.5 file"), 392 dlg = wx.FileDialog(None, message=_("Import Analyze 7.5 file"),
380 - defaultDir="", 393 + defaultDir=last_directory,
381 defaultFile="", wildcard=WILDCARD_ANALYZE, 394 defaultFile="", wildcard=WILDCARD_ANALYZE,
382 style=wx.FD_OPEN | wx.FD_CHANGE_DIR) 395 style=wx.FD_OPEN | wx.FD_CHANGE_DIR)
383 396
@@ -407,17 +420,22 @@ def ShowImportOtherFilesDialog(id_type): @@ -407,17 +420,22 @@ def ShowImportOtherFilesDialog(id_type):
407 if (dlg.GetPath()): 420 if (dlg.GetPath()):
408 filename = dlg.GetPath() 421 filename = dlg.GetPath()
409 422
  423 + if filename:
  424 + session['paths']['last_directory_%d' % id_type] = os.path.split(dlg.GetPath())[0]
  425 + session.WriteSessionFile()
410 # Destroy the dialog. Don't do this until you are done with it! 426 # Destroy the dialog. Don't do this until you are done with it!
411 # BAD things can happen otherwise! 427 # BAD things can happen otherwise!
412 dlg.Destroy() 428 dlg.Destroy()
413 - os.chdir(current_dir)  
414 return filename 429 return filename
415 430
416 431
417 def ShowImportMeshFilesDialog(): 432 def ShowImportMeshFilesDialog():
418 # Default system path 433 # Default system path
419 current_dir = os.path.abspath(".") 434 current_dir = os.path.abspath(".")
  435 + session = ses.Session()
  436 + last_directory = session.get('paths', 'last_directory_surface_import', '')
420 dlg = wx.FileDialog(None, message=_("Import surface file"), 437 dlg = wx.FileDialog(None, message=_("Import surface file"),
  438 + defaultDir=last_directory,
421 wildcard=WILDCARD_MESH_FILES, 439 wildcard=WILDCARD_MESH_FILES,
422 style=wx.FD_OPEN | wx.FD_CHANGE_DIR) 440 style=wx.FD_OPEN | wx.FD_CHANGE_DIR)
423 441
@@ -435,6 +453,10 @@ def ShowImportMeshFilesDialog(): @@ -435,6 +453,10 @@ def ShowImportMeshFilesDialog():
435 if (dlg.GetPath()): 453 if (dlg.GetPath()):
436 filename = dlg.GetPath() 454 filename = dlg.GetPath()
437 455
  456 + if filename:
  457 + session['paths']['last_directory_surface_import'] = os.path.split(filename)[0]
  458 + session.WriteSessionFile()
  459 +
438 # Destroy the dialog. Don't do this until you are done with it! 460 # Destroy the dialog. Don't do this until you are done with it!
439 # BAD things can happen otherwise! 461 # BAD things can happen otherwise!
440 dlg.Destroy() 462 dlg.Destroy()
@@ -444,9 +466,11 @@ def ShowImportMeshFilesDialog(): @@ -444,9 +466,11 @@ def ShowImportMeshFilesDialog():
444 466
445 def ShowSaveAsProjectDialog(default_filename=None): 467 def ShowSaveAsProjectDialog(default_filename=None):
446 current_dir = os.path.abspath(".") 468 current_dir = os.path.abspath(".")
  469 + session = ses.Session()
  470 + last_directory = session.get('paths', 'last_directory_inv3', '')
447 dlg = wx.FileDialog(None, 471 dlg = wx.FileDialog(None,
448 _("Save project as..."), # title 472 _("Save project as..."), # title
449 - "", # last used directory 473 + last_directory, # last used directory
450 default_filename, 474 default_filename,
451 WILDCARD_INV_SAVE, 475 WILDCARD_INV_SAVE,
452 wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) 476 wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
@@ -469,6 +493,10 @@ def ShowSaveAsProjectDialog(default_filename=None): @@ -469,6 +493,10 @@ def ShowSaveAsProjectDialog(default_filename=None):
469 if filename.split(".")[-1] != extension: 493 if filename.split(".")[-1] != extension:
470 filename = filename + "." + extension 494 filename = filename + "." + extension
471 495
  496 + if filename:
  497 + session['paths']['last_directory_inv3'] = os.path.split(filename)[0]
  498 + session.WriteSessionFile()
  499 +
472 wildcard = dlg.GetFilterIndex() 500 wildcard = dlg.GetFilterIndex()
473 os.chdir(current_dir) 501 os.chdir(current_dir)
474 return filename, wildcard == INV_COMPRESSED 502 return filename, wildcard == INV_COMPRESSED
@@ -1457,13 +1485,16 @@ def ExportPicture(type_=""): @@ -1457,13 +1485,16 @@ def ExportPicture(type_=""):
1457 utils.debug("ExportPicture") 1485 utils.debug("ExportPicture")
1458 project = proj.Project() 1486 project = proj.Project()
1459 1487
  1488 + session = ses.Session()
  1489 + last_directory = session.get('paths', 'last_directory_screenshot', '')
  1490 +
1460 project_name = "%s_%s" % (project.name, type_) 1491 project_name = "%s_%s" % (project.name, type_)
1461 if not sys.platform in ('win32', 'linux2', 'linux'): 1492 if not sys.platform in ('win32', 'linux2', 'linux'):
1462 project_name += ".jpg" 1493 project_name += ".jpg"
1463 1494
1464 dlg = wx.FileDialog(None, 1495 dlg = wx.FileDialog(None,
1465 "Save %s picture as..." %type_, 1496 "Save %s picture as..." %type_,
1466 - "", # last used directory 1497 + last_directory, # last used directory
1467 project_name, # filename 1498 project_name, # filename
1468 WILDCARD_SAVE_PICTURE, 1499 WILDCARD_SAVE_PICTURE,
1469 wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) 1500 wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
@@ -1474,6 +1505,8 @@ def ExportPicture(type_=""): @@ -1474,6 +1505,8 @@ def ExportPicture(type_=""):
1474 filetype = INDEX_TO_TYPE[filetype_index] 1505 filetype = INDEX_TO_TYPE[filetype_index]
1475 extension = INDEX_TO_EXTENSION[filetype_index] 1506 extension = INDEX_TO_EXTENSION[filetype_index]
1476 filename = dlg.GetPath() 1507 filename = dlg.GetPath()
  1508 + session['paths']['last_directory_screenshot'] = os.path.split(filename)[0]
  1509 + session.WriteSessionFile()
1477 if sys.platform != 'win32': 1510 if sys.platform != 'win32':
1478 if filename.split(".")[-1] != extension: 1511 if filename.split(".")[-1] != extension:
1479 filename = filename + "."+ extension 1512 filename = filename + "."+ extension
invesalius/gui/preferences.py
@@ -222,7 +222,7 @@ class Language(wx.Panel): @@ -222,7 +222,7 @@ class Language(wx.Panel):
222 class SurfaceCreation(wx.Panel): 222 class SurfaceCreation(wx.Panel):
223 def __init__(self, parent): 223 def __init__(self, parent):
224 wx.Panel.__init__(self, parent) 224 wx.Panel.__init__(self, parent)
225 - self.rb_fill_border = wx.RadioBox(self, -1, "Fill border holes", choices=[_('Yes'), _('No')], style=wx.RA_SPECIFY_COLS | wx.NO_BORDER) 225 + self.rb_fill_border = wx.RadioBox(self, -1, _("Fill border holes"), choices=[_('Yes'), _('No')], style=wx.RA_SPECIFY_COLS | wx.NO_BORDER)
226 226
227 sizer = wx.BoxSizer(wx.VERTICAL) 227 sizer = wx.BoxSizer(wx.VERTICAL)
228 sizer.Add(self.rb_fill_border) 228 sizer.Add(self.rb_fill_border)
invesalius/gui/task_exporter.py
@@ -33,6 +33,7 @@ from wx.lib.pubsub import pub as Publisher @@ -33,6 +33,7 @@ from wx.lib.pubsub import pub as Publisher
33 import invesalius.constants as const 33 import invesalius.constants as const
34 import invesalius.gui.dialogs as dlg 34 import invesalius.gui.dialogs as dlg
35 import invesalius.project as proj 35 import invesalius.project as proj
  36 +import invesalius.session as ses
36 37
37 BTN_MASK = wx.NewId() 38 BTN_MASK = wx.NewId()
38 BTN_PICTURE = wx.NewId() 39 BTN_PICTURE = wx.NewId()
@@ -318,10 +319,12 @@ class InnerTaskPanel(wx.Panel): @@ -318,10 +319,12 @@ class InnerTaskPanel(wx.Panel):
318 else: 319 else:
319 project_name = project.name+".stl" 320 project_name = project.name+".stl"
320 321
  322 + session = ses.Session()
  323 + last_directory = session.get('paths', 'last_directory_3d_surface', '')
321 324
322 dlg = wx.FileDialog(None, 325 dlg = wx.FileDialog(None,
323 _("Save 3D surface as..."), # title 326 _("Save 3D surface as..."), # title
324 - "", # last used directory 327 + last_directory, # last used directory
325 project_name, # filename 328 project_name, # filename
326 WILDCARD_SAVE_3D, 329 WILDCARD_SAVE_3D,
327 wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) 330 wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
@@ -335,6 +338,11 @@ class InnerTaskPanel(wx.Panel): @@ -335,6 +338,11 @@ class InnerTaskPanel(wx.Panel):
335 if sys.platform != 'win32': 338 if sys.platform != 'win32':
336 if filename.split(".")[-1] != extension: 339 if filename.split(".")[-1] != extension:
337 filename = filename + "."+ extension 340 filename = filename + "."+ extension
  341 +
  342 + if filename:
  343 + session['paths']['last_directory_3d_surface'] = os.path.split(filename)[0]
  344 + session.WriteSessionFile()
  345 +
338 Publisher.sendMessage('Export surface to file', 346 Publisher.sendMessage('Export surface to file',
339 filename=filename, filetype=filetype) 347 filename=filename, filetype=filetype)
340 if not os.path.exists(filename): 348 if not os.path.exists(filename):
invesalius/session.py
@@ -30,6 +30,8 @@ import sys @@ -30,6 +30,8 @@ import sys
30 from threading import Thread 30 from threading import Thread
31 import time 31 import time
32 import codecs 32 import codecs
  33 +import collections
  34 +import json
33 35
34 #import wx.lib.pubsub as ps 36 #import wx.lib.pubsub as ps
35 from wx.lib.pubsub import pub as Publisher 37 from wx.lib.pubsub import pub as Publisher
@@ -52,7 +54,8 @@ else: @@ -52,7 +54,8 @@ else:
52 USER_INV_DIR = os.path.join(USER_DIR, u'.invesalius') 54 USER_INV_DIR = os.path.join(USER_DIR, u'.invesalius')
53 USER_PRESET_DIR = os.path.join(USER_INV_DIR, u'presets') 55 USER_PRESET_DIR = os.path.join(USER_INV_DIR, u'presets')
54 USER_LOG_DIR = os.path.join(USER_INV_DIR, u'logs') 56 USER_LOG_DIR = os.path.join(USER_INV_DIR, u'logs')
55 -USER_INV_CFG_PATH = os.path.join(USER_INV_DIR, 'config.cfg') 57 +USER_INV_CFG_PATH = os.path.join(USER_INV_DIR, 'config.json')
  58 +OLD_USER_INV_CFG_PATH = os.path.join(USER_INV_DIR, 'config.cfg')
56 59
57 SESSION_ENCODING = 'utf8' 60 SESSION_ENCODING = 'utf8'
58 61
@@ -62,42 +65,98 @@ SESSION_ENCODING = 'utf8' @@ -62,42 +65,98 @@ SESSION_ENCODING = 'utf8'
62 class Session(with_metaclass(Singleton, object)): 65 class Session(with_metaclass(Singleton, object)):
63 66
64 def __init__(self): 67 def __init__(self):
  68 + self.project_path = ()
65 self.temp_item = False 69 self.temp_item = False
66 - # Initializing as project status closed.  
67 - # TODO: A better way to initialize project_status as closed (3)  
68 - self.project_status = 3  
69 70
70 - def CreateItens(self):  
71 - import invesalius.constants as const  
72 - self.project_path = ()  
73 - self.debug = False  
74 - self.project_status = const.PROJ_CLOSE  
75 - # const.PROJ_NEW*, const.PROJ_OPEN, const.PROJ_CHANGE*,  
76 - # const.PROJ_CLOSE 71 + self._values = collections.defaultdict(dict, {
  72 + 'session': {
  73 + 'status': 3,
  74 + 'language': '',
  75 + },
  76 + 'project': {
  77 + },
  78 +
  79 + 'paths': {
  80 + }
  81 + })
  82 +
  83 + self._map_attrs = {
  84 + 'mode': ('session', 'mode'),
  85 + 'project_status': ('session', 'status'),
  86 + 'debug': ('session', 'debug'),
  87 + 'language': ('session', 'language'),
  88 + 'random_id': ('session', 'random_id'),
  89 + 'surface_interpolation': ('session', 'surface_interpolation'),
  90 + 'rendering': ('session', 'rendering'),
  91 + 'slice_interpolation': ('session', 'slice_interpolation'),
  92 + 'recent_projects': ('project', 'recent_projects'),
  93 + 'homedir': ('paths', 'homedir'),
  94 + 'tempdir': ('paths', 'homedir'),
  95 + 'last_dicom_folder': ('paths', 'last_dicom_folder'),
  96 + }
77 97
78 - self.mode = const.MODE_RP  
79 - # const.MODE_RP, const.MODE_NAVIGATOR, const.MODE_RADIOLOGY,  
80 - # const.MODE_ODONTOLOGY  
81 98
82 - # InVesalius default projects' directory  
83 - homedir = self.homedir = USER_DIR  
84 - tempdir = os.path.join(homedir, u".invesalius", u"temp") 99 + def CreateItens(self):
  100 + import invesalius.constants as const
  101 + homedir = USER_DIR
  102 + tempdir = os.path.join(USER_DIR, u".invesalius", u"temp")
85 if not os.path.isdir(tempdir): 103 if not os.path.isdir(tempdir):
86 os.makedirs(tempdir) 104 os.makedirs(tempdir)
87 - self.tempdir = tempdir  
88 -  
89 - # GUI language  
90 - self.language = "" # "pt_BR", "es"  
91 105
92 - self.random_id = randint(0,pow(10,16))  
93 -  
94 - # Recent projects list  
95 - self.recent_projects = [(const.SAMPLE_DIR, u"Cranium.inv3")]  
96 - self.last_dicom_folder = ''  
97 - self.surface_interpolation = 1  
98 - self.slice_interpolation = 0  
99 - self.rendering = 0  
100 - self.WriteSessionFile() 106 + self._values = collections.defaultdict(dict, {
  107 + 'session': {
  108 + 'mode': const.MODE_RP,
  109 + 'status': const.PROJ_CLOSE,
  110 + 'debug': False,
  111 + 'language': "",
  112 + 'random_id': randint(0, pow(10,16)),
  113 + 'surface_interpolation': 1,
  114 + 'rendering': 0,
  115 + 'slice_interpolation': 0,
  116 + },
  117 +
  118 + 'project': {
  119 + 'recent_projects': [(const.SAMPLE_DIR, u"Cranium.inv3"), ],
  120 + },
  121 +
  122 + 'paths': {
  123 + 'homedir': USER_DIR,
  124 + 'tempdir': os.path.join(homedir, u".invesalius", u"temp"),
  125 + 'last_dicom_folder': '',
  126 + },
  127 + })
  128 +
  129 + def __contains__(self, key):
  130 + return key in self._values
  131 +
  132 + def __getitem__(self, key):
  133 + return self._values[key]
  134 +
  135 + def __setitem__(self, key, value):
  136 + self._values[key] = value
  137 +
  138 + def __getattr__(self, name):
  139 + map_attrs = object.__getattribute__(self, '_map_attrs')
  140 + if name not in map_attrs:
  141 + raise AttributeError(name)
  142 + session, key = map_attrs[name]
  143 + return object.__getattribute__(self, '_values')[session][key]
  144 +
  145 + def __setattr__(self, name, value):
  146 + if name in ("temp_item", "_map_attrs", "_values", "project_path"):
  147 + return object.__setattr__(self, name, value)
  148 + else:
  149 + session, key = self._map_attrs[name]
  150 + self._values[session][key] = value
  151 +
  152 + def __str__(self):
  153 + return self._values.__str__()
  154 +
  155 + def get(self, session, key, default_value):
  156 + try:
  157 + return self._values[session][key]
  158 + except KeyError:
  159 + return default_value
101 160
102 def IsOpen(self): 161 def IsOpen(self):
103 import invesalius.constants as const 162 import invesalius.constants as const
@@ -178,40 +237,17 @@ class Session(with_metaclass(Singleton, object)): @@ -178,40 +237,17 @@ class Session(with_metaclass(Singleton, object)):
178 self.temp_item = False 237 self.temp_item = False
179 238
180 def WriteSessionFile(self): 239 def WriteSessionFile(self):
181 - config = ConfigParser.RawConfigParser()  
182 -  
183 - config.add_section('session')  
184 - config.set('session', 'mode', self.mode)  
185 - config.set('session', 'status', self.project_status)  
186 - config.set('session','debug', self.debug)  
187 - config.set('session', 'language', self.language)  
188 - config.set('session', 'random_id', self.random_id)  
189 - config.set('session', 'surface_interpolation', self.surface_interpolation)  
190 - config.set('session', 'rendering', self.rendering)  
191 - config.set('session', 'slice_interpolation', self.slice_interpolation)  
192 -  
193 - config.add_section('project')  
194 - config.set('project', 'recent_projects', self.recent_projects)  
195 -  
196 - config.add_section('paths')  
197 - config.set('paths','homedir',self.homedir)  
198 - config.set('paths','tempdir',self.tempdir)  
199 - config.set('paths','last_dicom_folder',self.last_dicom_folder)  
200 -  
201 - path = os.path.join(self.homedir ,  
202 - '.invesalius', 'config.cfg') 240 + self._write_to_json(self._values, USER_INV_CFG_PATH)
203 241
204 - configfile = codecs.open(path, 'wb', SESSION_ENCODING)  
205 - try:  
206 - config.write(configfile)  
207 - except UnicodeDecodeError:  
208 - pass  
209 - configfile.close() 242 + def _write_to_json(self, cfg_dict, cfg_filename):
  243 + with open(cfg_filename, 'w') as cfg_file:
  244 + json.dump(cfg_dict, cfg_file, sort_keys=True, indent=4)
210 245
211 def __add_to_list(self, item): 246 def __add_to_list(self, item):
212 import invesalius.constants as const 247 import invesalius.constants as const
213 # Last projects list 248 # Last projects list
214 l = self.recent_projects 249 l = self.recent_projects
  250 + item = list(item)
215 251
216 # If item exists, remove it from list 252 # If item exists, remove it from list
217 if l.count(item): 253 if l.count(item):
@@ -219,11 +255,7 @@ class Session(with_metaclass(Singleton, object)): @@ -219,11 +255,7 @@ class Session(with_metaclass(Singleton, object)):
219 255
220 # Add new item 256 # Add new item
221 l.insert(0, item) 257 l.insert(0, item)
222 -  
223 - # Remove oldest projects from list  
224 - if len(l)>const.PROJ_MAX:  
225 - for i in range(len(l)-const.PROJ_MAX):  
226 - l.pop() 258 + self.recent_projects = l[:const.PROJ_MAX]
227 259
228 def GetLanguage(self): 260 def GetLanguage(self):
229 return self.language 261 return self.language
@@ -244,86 +276,59 @@ class Session(with_metaclass(Singleton, object)): @@ -244,86 +276,59 @@ class Session(with_metaclass(Singleton, object)):
244 self.last_dicom_folder = folder 276 self.last_dicom_folder = folder
245 self.WriteSessionFile() 277 self.WriteSessionFile()
246 278
247 - def ReadLanguage(self):  
248 - config = ConfigParser.ConfigParser()  
249 - path = os.path.join(USER_INV_DIR, 'config.cfg')  
250 - try:  
251 - f = codecs.open(path, 'rb', SESSION_ENCODING)  
252 - config.readfp(f)  
253 - f.close()  
254 - self.language = config.get('session','language')  
255 - return self.language  
256 - except IOError:  
257 - return False  
258 - except (ConfigParser.NoSectionError,  
259 - ConfigParser.NoOptionError,  
260 - ConfigParser.MissingSectionHeaderError):  
261 - return False  
262 -  
263 - def ReadRandomId(self):  
264 - config = ConfigParser.ConfigParser()  
265 - path = os.path.join(USER_INV_DIR, 'config.cfg')  
266 - try:  
267 - f = codecs.open(path, 'rb', SESSION_ENCODING)  
268 - config.readfp(f)  
269 - f.close()  
270 - self.random_id = config.get('session','random_id')  
271 - return self.random_id  
272 - except IOError:  
273 - return False  
274 - except (ConfigParser.NoSectionError,  
275 - ConfigParser.NoOptionError,  
276 - ConfigParser.MissingSectionHeaderError):  
277 - return False  
278 -  
279 - def ReadSession(self):  
280 - config = ConfigParser.ConfigParser()  
281 - path = USER_INV_CFG_PATH  
282 - try:  
283 - f = codecs.open(path, 'rb', SESSION_ENCODING)  
284 - config.readfp(f)  
285 - f.close()  
286 - self.mode = config.get('session', 'mode')  
287 - # Do not reading project status from the config file, since there  
288 - # isn't a recover sessession tool in InVesalius  
289 - #self.project_status = int(config.get('session', 'status'))  
290 - self.debug = config.get('session','debug')  
291 - self.language = config.get('session','language')  
292 - self.recent_projects = eval(config.get('project','recent_projects'))  
293 - self.homedir = config.get('paths','homedir')  
294 - self.tempdir = config.get('paths','tempdir')  
295 - self.last_dicom_folder = config.get('paths','last_dicom_folder')  
296 -  
297 - #if not(sys.platform == 'win32'):  
298 - # self.last_dicom_folder = self.last_dicom_folder.decode('utf-8')  
299 -  
300 - self.surface_interpolation = config.get('session', 'surface_interpolation')  
301 - self.slice_interpolation = config.get('session', 'slice_interpolation')  
302 -  
303 - self.rendering = config.get('session', 'rendering')  
304 - self.random_id = config.get('session','random_id')  
305 - return True 279 + def _update_cfg_from_dict(self, config, cfg_dict):
  280 + for session in cfg_dict:
  281 + if cfg_dict[session] and isinstance(cfg_dict[session], dict):
  282 + config.add_section(session)
  283 + for key in cfg_dict[session]:
  284 + config.set(session, key, cfg_dict[session][key])
306 285
307 - except IOError:  
308 - return False 286 + def _read_cfg_from_json(self, json_filename):
  287 + with open(json_filename, 'r') as cfg_file:
  288 + cfg_dict = json.load(cfg_file)
  289 + self._values.update(cfg_dict)
309 290
310 - except(ConfigParser.NoSectionError, ConfigParser.MissingSectionHeaderError,  
311 - ConfigParser.ParsingError): 291 + # Do not reading project status from the config file, since there
  292 + # isn't a recover session tool in InVesalius yet.
  293 + self.project_status = 3
312 294
313 - if (self.RecoveryConfigFile()):  
314 - self.ReadSession()  
315 - return True  
316 - else:  
317 - return False 295 + def _read_cfg_from_ini(self, cfg_filename):
  296 + f = codecs.open(cfg_filename, 'rb', SESSION_ENCODING)
  297 + config = ConfigParser.ConfigParser()
  298 + config.readfp(f)
  299 + f.close()
  300 +
  301 + self.mode = config.getint('session', 'mode')
  302 + # Do not reading project status from the config file, since there
  303 + # isn't a recover sessession tool in InVesalius
  304 + #self.project_status = int(config.get('session', 'status'))
  305 + self.debug = config.getboolean('session','debug')
  306 + self.language = config.get('session','language')
  307 + recent_projects = eval(config.get('project','recent_projects'))
  308 + self.recent_projects = [list(rp) for rp in recent_projects]
  309 + self.homedir = config.get('paths','homedir')
  310 + self.tempdir = config.get('paths','tempdir')
  311 + self.last_dicom_folder = config.get('paths','last_dicom_folder')
  312 +
  313 + # if not(sys.platform == 'win32'):
  314 + # self.last_dicom_folder = self.last_dicom_folder.decode('utf-8')
  315 +
  316 + self.surface_interpolation = config.getint('session', 'surface_interpolation')
  317 + self.slice_interpolation = config.getint('session', 'slice_interpolation')
  318 +
  319 + self.rendering = config.getint('session', 'rendering')
  320 + self.random_id = config.getint('session','random_id')
318 321
319 - except(ConfigParser.NoOptionError):  
320 - #Added to fix new version compatibility  
321 - self.surface_interpolation = 0  
322 - self.slice_interpolation = 0  
323 - self.rendering = 0  
324 - self.random_id = randint(0,pow(10,16)) 322 + def ReadSession(self):
  323 + try:
  324 + self._read_cfg_from_json(USER_INV_CFG_PATH)
  325 + except Exception as e1:
  326 + debug(e1)
325 try: 327 try:
326 - self.WriteSessionFile()  
327 - except AttributeError: 328 + self._read_cfg_from_ini(OLD_USER_INV_CFG_PATH)
  329 + except Exception as e2:
  330 + debug(e2)
328 return False 331 return False
329 - return True 332 +
  333 + self.WriteSessionFile()
  334 + return True
invesalius/utils.py
@@ -394,21 +394,14 @@ def UpdateCheck(): @@ -394,21 +394,14 @@ def UpdateCheck():
394 #msgdlg.Destroy() 394 #msgdlg.Destroy()
395 395
396 print("Checking updates...") 396 print("Checking updates...")
397 - 397 +
398 # Check if there is a language set 398 # Check if there is a language set
399 #import invesalius.i18n as i18n import invesalius.session as ses 399 #import invesalius.i18n as i18n import invesalius.session as ses
400 session = ses.Session() 400 session = ses.Session()
401 install_lang = 0 401 install_lang = 0
402 - if session.ReadLanguage():  
403 - lang = session.GetLanguage()  
404 - #if (lang != "False"):  
405 - #_ = i18n.InstallLanguage(lang)  
406 - #install_lang = 1  
407 - #if (install_lang==0):  
408 - #return  
409 - if session.ReadRandomId():  
410 - random_id = session.GetRandomId()  
411 - 402 + lang = session.GetLanguage()
  403 + random_id = session.GetRandomId()
  404 + if lang:
412 # Fetch update data from server 405 # Fetch update data from server
413 import invesalius.constants as const 406 import invesalius.constants as const
414 url = "https://www.cti.gov.br/dt3d/invesalius/update/checkupdate.php" 407 url = "https://www.cti.gov.br/dt3d/invesalius/update/checkupdate.php"