Commit 6065ccb0 authored by eric pellegrini's avatar eric pellegrini
Browse files

Merge tag '1.0.1' into develop

1.0.1
parents 78e7f856 5850fcd5
Pipeline #1070 passed with stages
in 11 minutes and 23 seconds
......@@ -367,21 +367,6 @@ class Platform(object):
'''
pass
def preferences_file(self):
'''
Returns the path for MDANSE preferences file.
:return: the path for the MDANSE preferences file
:rtype: string
:note: this path is OS specific.
'''
# The preferences files will be located in the application directory.
appdir = self.application_directory()
return os.path.join(appdir, 'mdanse_preferences')
class PlatformPosix(Platform):
'''
Base class for POSIX derived OS.
......
#MDANSE : Molecular Dynamics Analysis for Neutron Scattering Experiments
#------------------------------------------------------------------------------------------
#Copyright (C)
#2015- Eric C. Pellegrini Institut Laue-Langevin
#BP 156
#6, rue Jules Horowitz
#38042 Grenoble Cedex 9
#France
#pellegrini[at]ill.fr
#goret[at]ill.fr
#aoun[at]ill.fr
#
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU Lesser General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#Lesser General Public License for more details.
#
#You should have received a copy of the GNU Lesser General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
'''
Created on Mar 30, 2015
:author: Eric C. Pellegrini
'''
import abc
import collections
import ConfigParser
import os
from MDANSE.Core.Platform import PLATFORM, PlatformError
from MDANSE.Core.Error import Error
from MDANSE.Core.Singleton import Singleton
class PreferencesError(Error):
'''
This class handles the errors that occurs in Preferences.
'''
pass
class PreferencesItem(object):
'''
This is the base class for defining a preferences item.
A preferences item implements is a light object used to check preferences before setting them
but also classify preferences according to their section for a further use in MDANSE GUI.
'''
__metaclass__ = abc.ABCMeta
def __init__(self, name, section, default, *args, **kwargs):
'''
Constructor a new prferences item.
:param name: the name of the preference item
:type name: str
:param section: the section of the preferences item
:type section: str
:param default: the default value for the preferences item
:type default: str
'''
self._name = name
self._section = section
self._default = default
self._value = self._default
@property
def default(self):
'''
Returns the default value of the preferences item.
:return: the default value of the preferences item
:rtype: str
'''
return self._default
def get_default(self):
'''
Returns the default value of the preferences item.
:return: the default value of the preferences item
:rtype: str
'''
return self._default
@property
def name(self):
'''
Returns the name of the preferences item.
:return: the name of the preferences item
:rtype: str
'''
return self._name
def get_name(self):
'''
Returns the name of the preferences item.
:return: the name of the preferences item
:rtype: str
'''
return self._name
@property
def section(self):
'''
Returns the section of the preferences item.
:return: the section of the preferences item
:rtype: str
'''
return self._section
def get_section(self):
'''
Returns the section of the preferences item.
:return: the section of the preferences item
:rtype: str
'''
return self._section
def reset(self):
'''
Reset the preferences item to its default value
'''
self._value = self._default
@property
def value(self):
'''
Returns the value of the preferences item.
:return: the value of the preferences item
:rtype: str
'''
return self._value
def get_value(self):
'''
Returns the value of the preferences item.
:return: the value of the preferences item
:rtype: str
'''
return self._value
@abc.abstractmethod
def check_value(self,value):
'''
Set the value of the preferences item.
:param value: the value of the preferences item
:type value: str
'''
pass
@abc.abstractmethod
def set_value(self,value):
'''
Set the value of the preferences item.
:param value: the value of the preferences item
:type value: str
'''
pass
class InputDirectory(PreferencesItem):
'''
This class implements a preferences item that handles an input directory.
When set to a given input directory, if this one does not exists, it will be be created.
'''
type = "input_directory"
def check_value(self,value):
'''
Check the value of the preferences item.
:param value: the value of the preferences item
:type value: str
:return: True if the value is correct, False otherwise.
:rtype: bool
'''
value = PLATFORM.get_path(value)
try:
PLATFORM.create_directory(value)
except PlatformError:
return False
else:
return True
def set_value(self, value):
'''
Set the value of the input directory preferences item.
:param value: the input directory
:type value: str
'''
value = PLATFORM.get_path(value)
try:
PLATFORM.create_directory(value)
except PlatformError:
raise PreferencesError('Invalid value for %r preferences item. Set the default value instead.' % self._name)
self._value = self._default
else:
self._value = value
def get_value(self):
return self._value
class Preferences(collections.OrderedDict):
'''
This class implements the MDANSE preferences.
:note: Preferences are defined using the ConfigParser python module that allows to read and write \
preferences stored in a formatted INI file (RFC822).
'''
__metaclass__ = Singleton
def __init__(self,*args,**kwargs):
'''
Constructs the preferences
'''
collections.OrderedDict.__init__(self,*args,**kwargs)
collections.OrderedDict.__setitem__(self,"working_directory",InputDirectory("working_directory", "paths", PLATFORM.home_directory()))
collections.OrderedDict.__setitem__(self,"macros_directory",InputDirectory("macros_directory", "paths", os.path.join(PLATFORM.home_directory(), "mdanse_macros")))
self._parser = ConfigParser.ConfigParser()
for s in self.values():
try:
self._parser.add_section(s.section)
except ConfigParser.DuplicateSectionError:
pass
# Overwrite the default preferences with the user defined loaded ones.
try:
self.load()
except PreferencesError:
pass
@property
def parser(self):
'''
Returns the configuration parser object used to serialize the preferences.
:return: the configuration parser bound to the preferences
:rtype: ConfigParser.ConfigParser
'''
return self._parser
def __setitem__(self,item,value):
pass
def clear(self):
pass
def __getitem__(self, item):
'''
Get the value of a selected preferences item.
:param item: the preferences item
:type item: str
:return: the values of the preferences item.
:rtype: ``PreferencesItem`` subclass
'''
try:
return collections.OrderedDict.__getitem__(self,item)
except KeyError:
raise PreferencesError("Unknown preferences item")
def load(self, path=None):
'''
Load the preferences from an existing Preferences file.
The default value is the default location for loading Preferences file.
:param path: the path for the preferences file
:type path: str
'''
if path is None:
path = PLATFORM.preferences_file()
if not isinstance(path,basestring):
raise PreferencesError("Invalid type for preferences filename: %s" % path)
if not os.path.exists(path):
raise PreferencesError("The preferences files %s does not exists. MDANSE will use the default preferences." % path)
try:
# Read the preferences and overwrites the MDANSE default preferences.
self._parser.read(path)
except ConfigParser.ParsingError as e:
raise PreferencesError(e)
for s in self._parser.sections():
for k, v in self._parser.items(s):
if self.has_key(k):
try:
self[k].set_value(v)
except PreferencesError:
continue
else:
self._parser.remove_option(s,k)
if not self._parser.items(s):
self._parser.remove_section(s)
def save(self,path=None):
'''
Save the preferences to a file.
The default value is the default location for loading Preferences file.
:param path: the path for the preferences file
:type path: str
'''
if path is None:
path = PLATFORM.preferences_file()
try:
f = open(path, "w")
except (IOError,TypeError) as e:
raise PreferencesError(e)
for v in self.values():
self._parser.set(v.section,v.name,v.value)
# Write the preferences.
self._parser.write(f)
# Closes the preferences file.
f.close()
PREFERENCES = Preferences()
\ No newline at end of file
......@@ -36,11 +36,12 @@ class ControllerPanel(wx.Panel):
il.Add(ICONS["log",16,16])
il.Add(ICONS["shell",16,16])
il.Add(ICONS["hourglass",16,16])
self._notebook.AssignImageList(il)
self._notebook.AddPage(self._pages["logger"], 'Logger')
self._notebook.AddPage(self._pages["console"], 'Console')
self._notebook.AddPage(self._pages["jobs"], 'Jobs')
self._notebook.AssignImageList(il)
self._notebook.SetPageImage(0, 0)
self._notebook.SetPageImage(1, 1)
......
......@@ -193,7 +193,6 @@ class MainFrame(wx.Frame):
elementsDatabaseButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["atom",32,32], 'Launch the elements database editor')
plotButton = self._toolbar.AddSimpleTool(wx.ID_ANY,ICONS["plot",32,32], 'Launch the NetCDF plotter')
udButton = self._toolbar.AddSimpleTool(wx.ID_ANY,ICONS["user",32,32], 'Launch the user definitions editor')
# preferencesButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["preferences",32,32], 'Launch the preferences editor')
registryButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["registry",32,32], 'Inspect MDANSE classes framework')
templateButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["template",32,32], 'Save a template for a new analysis')
apiButton = self._toolbar.AddSimpleTool(wx.ID_ANY, ICONS["api",32,32], 'Open MDANSE API')
......@@ -211,7 +210,6 @@ class MainFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.on_open_periodic_table, periodicTableButton)
self.Bind(wx.EVT_MENU, self.on_open_elements_database, elementsDatabaseButton)
self.Bind(wx.EVT_MENU, self.on_start_plotter, plotButton)
# self.Bind(wx.EVT_MENU, self.on_set_preferences, preferencesButton)
self.Bind(wx.EVT_MENU, self.on_open_user_definitions, udButton)
self.Bind(wx.EVT_MENU, self.on_open_classes_registry, registryButton)
self.Bind(wx.EVT_MENU, self.on_save_job_template, templateButton)
......@@ -379,16 +377,6 @@ or directly to the MDANSE mailing list:
d = wx.MessageDialog(None, 'Do you really want to quit ?', 'Question', wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
if d.ShowModal() == wx.ID_YES:
self.Destroy()
# def on_set_preferences(self, event):
#
# from MDANSE.GUI.PreferencesSettings import PreferencesSettings
#
# d = PreferencesSettings(self)
#
# d.ShowModal()
#
# d.Destroy()
def on_start_plotter(self, event = None):
......
#MDANSE : Molecular Dynamics Analysis for Neutron Scattering Experiments
#------------------------------------------------------------------------------------------
#Copyright (C)
#2015- Eric C. Pellegrini Institut Laue-Langevin
#BP 156
#6, rue Jules Horowitz
#38042 Grenoble Cedex 9
#France
#pellegrini[at]ill.fr
#goret[at]ill.fr
#aoun[at]ill.fr
#
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU Lesser General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#Lesser General Public License for more details.
#
#You should have received a copy of the GNU Lesser General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
'''
Created on May 28, 2015
:author: Eric C. Pellegrini
'''
import abc
import collections
import wx
import wx.aui as wxaui
import wx.lib.filebrowsebutton as wxfile
from MDANSE import LOGGER, PLATFORM, PREFERENCES
from MDANSE.Core.Preferences import PreferencesError
class WritableDirectoryValidator(wx.PyValidator):
def Clone(self):
return WritableDirectoryValidator()
def TransferToWindow(self):
return True
def TransferFromWindow(self):
return True
class PreferencesItemWidget(wx.Panel):
__metaclass__ = abc.ABCMeta
def __init__(self, parent, name, item, *args, **kwargs):
wx.Panel.__init__(self, parent, wx.ID_ANY, *args, **kwargs)
self._parent = parent
self._name = name
self._item = item
self.build_panel()
@abc.abstractmethod
def validate(self):
pass
@abc.abstractmethod
def get_value(self):
pass
@abc.abstractmethod
def set_value(self,value):
pass
class InputDirectoryWidget(PreferencesItemWidget):
type = "input_directory"
def build_panel(self):
sb = wx.StaticBox(self, wx.ID_ANY, label=self._item.name)
self._widget = wxfile.DirBrowseButton(self, wx.ID_ANY, labelText="", startDirectory=self._item.value)
self._widget.SetValidator(WritableDirectoryValidator())
self._widget.SetValue(self._item.value)
sizer = wx.StaticBoxSizer(sb, wx.HORIZONTAL)
sizer.Add(self._widget, 1, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
def get_value(self):
return self._widget.GetValue()
def set_value(self, value):
self._widget.SetValue(value)
def validate(self):
path = PLATFORM.get_path(self._widget.GetValue())
if PLATFORM.is_directory_writable(path):
return True
else:
wx.MessageBox("The directory %r is not writable." % path, "Invalid input",wx.OK | wx.ICON_ERROR)
return False
WIDGETS = dict([(v.type,v) for v in PreferencesItemWidget.__subclasses__()])
class PreferencesSettings(wx.Dialog):
def __init__(self, parent=None):
wx.Dialog.__init__(self, parent, wx.ID_ANY, title="Preferences settings", size=(400,400), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.MINIMIZE_BOX|wx.MAXIMIZE_BOX)
self._parent = parent
self.build_dialog()
def build_dialog(self):
self._notebook = wxaui.AuiNotebook(self, wx.ID_ANY)
self._sectionPanels = collections.OrderedDict()
self._sectionSizers = collections.OrderedDict()
self._widgets = collections.OrderedDict()
for item in PREFERENCES.values():
section = item.section
name = item.name
typ = item.type
if not self._sectionPanels.has_key(section):
self._sectionPanels[section] = wx.ScrolledWindow(self, wx.ID_ANY)
self._sectionPanels[section].SetScrollbars(1,1,200,200)
self._sectionSizers[section] = wx.BoxSizer(wx.VERTICAL)
self._widgets[name] = WIDGETS[typ](self._sectionPanels[section], name, item)
self._sectionSizers[section].Add(self._widgets[name], 0, wx.ALL|wx.EXPAND, 5)
for k,v in self._sectionPanels.items():
v.SetSizer(self._sectionSizers[k])
self._notebook.AddPage(v, k)
sb = wx.StaticBox(self, wx.ID_ANY)
sbSizer = wx.StaticBoxSizer(sb, wx.HORIZONTAL)
defaultButton = wx.Button(self, wx.ID_ANY, label="Default")
applyButton = wx.Button(self, wx.ID_ANY, label="Apply")
okButton = wx.Button(self, wx.ID_ANY, label="OK")
sbSizer.Add(defaultButton, 0, wx.ALL, 5)
sbSizer.Add((-1,-1), 1, wx.ALL|wx.EXPAND, 5)
sbSizer.Add(applyButton, 0, wx.ALL, 5)
sbSizer.Add(okButton, 0, wx.ALL, 5)
self._sizer = wx.BoxSizer(wx.VERTICAL)
self._sizer.Add(self._notebook, 1, wx.ALL|wx.EXPAND, 5)