Exemplo n.º 1
0
    def _layout_function(self):
        """
        Do the layout for function related widgets
        """
        function_txt = wx.StaticText(self, -1, 'Function(x) : ')
        hint_function = "#Example:\n"
        hint_function += "if x <= 0:\n"
        hint_function += "    y = A + B\n"
        hint_function += "else:\n"
        hint_function += "    y = A + B * cos(2 * pi * x)\n"
        hint_function += "return y\n"
        math_txt = wx.StaticText(self, -1, '*Useful math functions: ')
        math_combo = self._fill_math_combo()

        newid = wx.NewId()
        self.function_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                       wx.DefaultSize,
                                       wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.function_tcl.setDisplayLineNumbers(True)
        self.function_tcl.SetToolTipString(hint_function)

        self.func_horizon_sizer.Add(function_txt)
        self.func_horizon_sizer.Add(math_txt, 0, wx.LEFT, 250)
        self.func_horizon_sizer.Add(math_combo, 0, wx.LEFT, 10)

        self.function_sizer.Add(self.func_horizon_sizer, 0, wx.LEFT, 10)
        self.function_sizer.Add(self.function_tcl, 1, wx.EXPAND | wx.ALL, 10)
Exemplo n.º 2
0
    def _layout_function(self):
        """
        Do the layout for function related widgets
        """
        function_txt = wx.StaticText(self, -1, 'Function(x) : ')
        hint_function = "#Example:\n"
        hint_function += "if x <= 0:\n"
        hint_function += "    y = A + B\n"
        hint_function += "else:\n"
        hint_function += "    y = A + B * cos(2 * pi * x)\n"
        hint_function += "return y\n"
        math_txt = wx.StaticText(self, -1, '*Useful math functions: ')
        math_combo = self._fill_math_combo()

        newid = wx.NewId()
        self.function_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                       wx.DefaultSize,
                                       wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.function_tcl.setDisplayLineNumbers(True)
        self.function_tcl.SetToolTipString(hint_function)

        self.func_horizon_sizer.Add(function_txt)
        self.func_horizon_sizer.Add(math_txt, 0, wx.LEFT, 250)
        self.func_horizon_sizer.Add(math_combo, 0, wx.LEFT, 10)

        self.function_sizer.Add(self.func_horizon_sizer, 0, wx.LEFT, 10)
        self.function_sizer.Add(self.function_tcl, 1, wx.EXPAND | wx.ALL, 10)
Exemplo n.º 3
0
    def _layout_param(self):
        """
        Do the layout for parameter related widgets
        """
        param_txt = wx.StaticText(self, -1, 'Fit Parameters: ')

        param_tip = "#Set the parameters and their initial values.\n"
        param_tip += "#Example:\n"
        param_tip += "A = 1\nB = 1"
        #param_txt.SetToolTipString(param_tip)
        newid = wx.NewId()
        self.param_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                    wx.DefaultSize,
                                    wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.param_tcl.setDisplayLineNumbers(True)
        self.param_tcl.SetToolTipString(param_tip)

        self.param_sizer.AddMany([(param_txt, 0, wx.LEFT, 10),
                                  (self.param_tcl, 1, wx.EXPAND | wx.ALL, 10)])
Exemplo n.º 4
0
    def __init__( self, parent=None, title=u'简单Maven', pos=wx.DefaultPosition, \
            size=(800,600), style=wx.DEFAULT_FRAME_STYLE^wx.RESIZE_BORDER, name='mainFrame' ):
        wx.Frame.__init__( self, parent=parent, title=title, pos=pos, size=size, \
                style=style, name=name )

        self.SetBackgroundColour("gray")
        self.createStatusBar()
        self.createMenuBar()

        self.tree = wx.TreeCtrl(self,
                                id=wx.NewId(),
                                size=(300, -1),
                                style=wx.TR_HAS_BUTTONS | wx.TR_LINES_AT_ROOT)
        self.tree.SetBackgroundColour("light gray")

        self.html = wx.html.HtmlWindow(self)
        self.html.SetHTMLBackgroundColour("medium goldenrod")

        self.log = EditWindow(self)
        #self.log.SetReadOnly(True)
        self.log.setDisplayLineNumbers(True)
        handler = MyLogHandler("root", control=self.log)
        logging.getLogger().setLevel(logging.INFO)
        logging.getLogger().addHandler(handler)

        vbox = wx.BoxSizer(wx.VERTICAL)
        box = wx.BoxSizer(wx.HORIZONTAL)
        box.Add(self.tree, -1, wx.EXPAND | wx.RIGHT, 3)
        box.Add(self.html, 2, wx.EXPAND, 3)
        vbox.Add(box, 5, wx.EXPAND | wx.ALL, 3)
        vbox.Add(self.log, 1, wx.EXPAND | wx.RIGHT | wx.LEFT | wx.BOTTOM, 3)
        self.SetSizer(vbox)

        #创建SimpleMaven对象,加载TreeData.xml文件
        self.simpleMaven = SimpleMaven()
        wx.CallAfter(self.DataInit, controls=self.tree)

        self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnTreeRightClick,
                  self.tree)
        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeChanged, self.tree)
Exemplo n.º 5
0
    def _layout_param(self):
        """
        Do the layout for parameter related widgets
        """
        param_txt = wx.StaticText(self, -1, 'Fit Parameters NOT requiring' + \
                                  ' polydispersity (if any): ')

        param_tip = "#Set the parameters NOT requiring polydispersity " + \
        "and their initial values.\n"
        param_tip += "#Example:\n"
        param_tip += "A = 1\nB = 1"
        #param_txt.SetToolTipString(param_tip)
        newid = wx.NewId()
        self.param_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                    wx.DefaultSize,
                                    wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.param_tcl.setDisplayLineNumbers(True)
        self.param_tcl.SetToolTipString(param_tip)

        self.param_sizer.AddMany([(param_txt, 0, wx.LEFT, 10),
                                  (self.param_tcl, 1, wx.EXPAND | wx.ALL, 10)])

        # Parameters with polydispersity
        pd_param_txt = wx.StaticText(self, -1, 'Fit Parameters requiring ' + \
                                     'polydispersity (if any): ')

        pd_param_tip = "#Set the parameters requiring polydispersity and " + \
        "their initial values.\n"
        pd_param_tip += "#Example:\n"
        pd_param_tip += "C = 2\nD = 2"
        newid = wx.NewId()
        self.pd_param_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                    wx.DefaultSize,
                                    wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.pd_param_tcl.setDisplayLineNumbers(True)
        self.pd_param_tcl.SetToolTipString(pd_param_tip)

        self.param_sizer.AddMany([(pd_param_txt, 0, wx.LEFT, 10),
                                  (self.pd_param_tcl, 1, wx.EXPAND | wx.ALL, 10)])
Exemplo n.º 6
0
 def __init__(self,
              parent=None,
              id=-1,
              title='编辑工具',
              pos=wx.DefaultPosition,
              size=(800, 600),
              style=wx.DEFAULT_DIALOG_STYLE,
              name="edit"):
     wx.Dialog.__init__(self,
                        parent=parent,
                        id=id,
                        title=title,
                        pos=pos,
                        size=size,
                        style=style,
                        name=name)
     self.edit = edit = EditWindow(self)
     edit.setDisplayLineNumbers(True)
     with open("TreeData.xml") as fp:
         edit.SetText(fp.read())
Exemplo n.º 7
0
class EditorPanel(wx.ScrolledWindow):
    """
    Simple Plugin Model function editor
    """
    def __init__(self, parent, base, path, title, *args, **kwds):
        kwds['name'] = title
        #        kwds["size"] = (EDITOR_WIDTH, EDITOR_HEIGTH)
        kwds["style"] = wx.FULL_REPAINT_ON_RESIZE
        wx.ScrolledWindow.__init__(self, parent, *args, **kwds)
        self.SetScrollbars(1, 1, 1, 1)
        self.parent = parent
        self.base = base
        self.path = path
        self.font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
        self.font.SetPointSize(10)
        self.reader = None
        self.name = 'untitled'
        self.overwrite_name = False
        self.is_2d = False
        self.fname = None
        self.main_sizer = None
        self.name_sizer = None
        self.name_hsizer = None
        self.name_tcl = None
        self.overwrite_cb = None
        self.desc_sizer = None
        self.desc_tcl = None
        self.param_sizer = None
        self.param_tcl = None
        self.function_sizer = None
        self.func_horizon_sizer = None
        self.button_sizer = None
        self.param_strings = ''
        self.function_strings = ''
        self._notes = ""
        self._msg_box = None
        self.msg_sizer = None
        self.warning = ""
        #This does not seem to be used anywhere so commenting out for now
        #    -- PDB 2/26/17
        #self._description = "New Plugin Model"
        self.function_tcl = None
        self.math_combo = None
        self.bt_apply = None
        self.bt_close = None
        #self._default_save_location = os.getcwd()
        self._do_layout()

    def _define_structure(self):
        """
        define initial sizer
        """
        #w, h = self.parent.GetSize()
        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
        self.name_sizer = wx.BoxSizer(wx.VERTICAL)
        self.name_hsizer = wx.BoxSizer(wx.HORIZONTAL)
        self.desc_sizer = wx.BoxSizer(wx.VERTICAL)
        self.param_sizer = wx.BoxSizer(wx.VERTICAL)
        self.function_sizer = wx.BoxSizer(wx.VERTICAL)
        self.func_horizon_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.msg_sizer = wx.BoxSizer(wx.HORIZONTAL)

    def _layout_name(self):
        """
        Do the layout for file/function name related widgets
        """
        #title name [string]
        name_txt = wx.StaticText(self, -1, 'Function Name : ')
        self.overwrite_cb = wx.CheckBox(
            self, -1, "Overwrite existing plugin model of this name?",
            (10, 10))
        self.overwrite_cb.SetValue(False)
        self.overwrite_cb.SetToolTipString("Overwrite it if already exists?")
        wx.EVT_CHECKBOX(self, self.overwrite_cb.GetId(), self.on_over_cb)
        self.name_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1))
        self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name)
        self.name_tcl.SetValue('')
        self.name_tcl.SetFont(self.font)
        hint_name = "Unique Model Function Name."
        self.name_tcl.SetToolTipString(hint_name)
        self.name_hsizer.AddMany([(self.name_tcl, 0, wx.LEFT | wx.TOP, 0),
                                  (self.overwrite_cb, 0, wx.LEFT, 20)])
        self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.TOP, 10),
                                 (self.name_hsizer, 0,
                                  wx.LEFT | wx.TOP | wx.BOTTOM, 10)])

    def _layout_description(self):
        """
        Do the layout for description related widgets
        """
        #title name [string]
        desc_txt = wx.StaticText(self, -1, 'Description (optional) : ')
        self.desc_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1))
        self.desc_tcl.SetValue('')
        hint_desc = "Write a short description of the model function."
        self.desc_tcl.SetToolTipString(hint_desc)
        self.desc_sizer.AddMany([(desc_txt, 0, wx.LEFT | wx.TOP, 10),
                                 (self.desc_tcl, 0,
                                  wx.LEFT | wx.TOP | wx.BOTTOM, 10)])

    def _layout_param(self):
        """
        Do the layout for parameter related widgets
        """
        param_txt = wx.StaticText(self, -1, 'Fit Parameters NOT requiring' + \
                                  ' polydispersity (if any): ')

        param_tip = "#Set the parameters NOT requiring polydispersity " + \
        "and their initial values.\n"
        param_tip += "#Example:\n"
        param_tip += "A = 1\nB = 1"
        #param_txt.SetToolTipString(param_tip)
        newid = wx.NewId()
        self.param_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                    wx.DefaultSize,
                                    wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.param_tcl.setDisplayLineNumbers(True)
        self.param_tcl.SetToolTipString(param_tip)

        self.param_sizer.AddMany([(param_txt, 0, wx.LEFT, 10),
                                  (self.param_tcl, 1, wx.EXPAND | wx.ALL, 10)])

        # Parameters with polydispersity
        pd_param_txt = wx.StaticText(self, -1, 'Fit Parameters requiring ' + \
                                     'polydispersity (if any): ')

        pd_param_tip = "#Set the parameters requiring polydispersity and " + \
        "their initial values.\n"
        pd_param_tip += "#Example:\n"
        pd_param_tip += "C = 2\nD = 2"
        newid = wx.NewId()
        self.pd_param_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                       wx.DefaultSize,
                                       wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.pd_param_tcl.setDisplayLineNumbers(True)
        self.pd_param_tcl.SetToolTipString(pd_param_tip)

        self.param_sizer.AddMany([(pd_param_txt, 0, wx.LEFT, 10),
                                  (self.pd_param_tcl, 1, wx.EXPAND | wx.ALL,
                                   10)])

    def _layout_function(self):
        """
        Do the layout for function related widgets
        """
        function_txt = wx.StaticText(self, -1, 'Function(x) : ')
        hint_function = "#Example:\n"
        hint_function += "if x <= 0:\n"
        hint_function += "    y = A + B\n"
        hint_function += "else:\n"
        hint_function += "    y = A + B * cos(2 * pi * x)\n"
        hint_function += "return y\n"
        math_txt = wx.StaticText(self, -1, '*Useful math functions: ')
        math_combo = self._fill_math_combo()

        newid = wx.NewId()
        self.function_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                       wx.DefaultSize,
                                       wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.function_tcl.setDisplayLineNumbers(True)
        self.function_tcl.SetToolTipString(hint_function)

        self.func_horizon_sizer.Add(function_txt)
        self.func_horizon_sizer.Add(math_txt, 0, wx.LEFT, 250)
        self.func_horizon_sizer.Add(math_combo, 0, wx.LEFT, 10)

        self.function_sizer.Add(self.func_horizon_sizer, 0, wx.LEFT, 10)
        self.function_sizer.Add(self.function_tcl, 1, wx.EXPAND | wx.ALL, 10)

    def _layout_msg(self):
        """
        Layout msg
        """
        self._msg_box = wx.StaticText(self,
                                      -1,
                                      self._notes,
                                      size=(PANEL_WIDTH, -1))
        self.msg_sizer.Add(self._msg_box, 0, wx.LEFT, 10)

    def _layout_button(self):
        """
        Do the layout for the button widgets
        """
        self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH, -1))
        self.bt_apply.SetToolTipString("Save changes into the imported data.")
        self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)

        self.bt_help = wx.Button(self, -1, "HELP", size=(_BOX_WIDTH, -1))
        self.bt_help.SetToolTipString("Get Help For Model Editor")
        self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)

        self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH, -1))
        self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
        self.bt_close.SetToolTipString("Close this panel.")

        self.button_sizer.AddMany([(self.bt_apply, 0, 0),
                                   (self.bt_help, 0, wx.LEFT | wx.BOTTOM, 15),
                                   (self.bt_close, 0, wx.LEFT | wx.RIGHT, 15)])

    def _do_layout(self):
        """
        Draw the current panel
        """
        self._define_structure()
        self._layout_name()
        self._layout_description()
        self._layout_param()
        self._layout_function()
        self._layout_msg()
        self._layout_button()
        self.main_sizer.AddMany([
            (self.name_sizer, 0, wx.EXPAND | wx.ALL, 5),
            (wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5),
            (self.desc_sizer, 0, wx.EXPAND | wx.ALL, 5),
            (wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5),
            (self.param_sizer, 1, wx.EXPAND | wx.ALL, 5),
            (wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5),
            (self.function_sizer, 2, wx.EXPAND | wx.ALL, 5),
            (wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5),
            (self.msg_sizer, 0, wx.EXPAND | wx.ALL, 5),
            (self.button_sizer, 0, wx.ALIGN_RIGHT)
        ])
        self.SetSizer(self.main_sizer)
        self.SetAutoLayout(True)

    def _fill_math_combo(self):
        """
        Fill up the math combo box
        """
        self.math_combo = wx.ComboBox(self,
                                      -1,
                                      size=(100, -1),
                                      style=wx.CB_READONLY)
        for item in dir(math):
            if item.count("_") < 1:
                try:
                    exec "float(math.%s)" % item
                    self.math_combo.Append(str(item))
                except Exception:
                    self.math_combo.Append(str(item) + "()")
        self.math_combo.Bind(wx.EVT_COMBOBOX, self._on_math_select)
        self.math_combo.SetSelection(0)
        return self.math_combo

    def _on_math_select(self, event):
        """
        On math selection on ComboBox
        """
        event.Skip()
        label = self.math_combo.GetValue()
        self.function_tcl.SetFocus()
        # Put the text at the cursor position
        pos = self.function_tcl.GetCurrentPos()
        self.function_tcl.InsertText(pos, label)
        # Put the cursor at appropriate position
        length = len(label)
        print(length)
        if label[length - 1] == ')':
            length -= 1
        f_pos = pos + length
        self.function_tcl.GotoPos(f_pos)

    def get_notes(self):
        """
        return notes
        """
        return self._notes

    def on_change_name(self, event=None):
        """
        Change name
        """
        if event is not None:
            event.Skip()
        self.name_tcl.SetBackgroundColour('white')
        self.Refresh()

    def check_name(self):
        """
        Check name if exist already
        """
        self._notes = ''
        self.on_change_name(None)
        plugin_dir = self.path
        list_fnames = os.listdir(plugin_dir)
        # function/file name
        title = self.name_tcl.GetValue().lstrip().rstrip()
        self.name = title
        t_fname = title + '.py'
        if not self.overwrite_name:
            if t_fname in list_fnames:
                self.name_tcl.SetBackgroundColour('pink')
                return False
        self.fname = os.path.join(plugin_dir, t_fname)
        s_title = title
        if len(title) > 20:
            s_title = title[0:19] + '...'
        self._notes += "Model function name is set "
        self._notes += "to %s. \n" % str(s_title)
        return True

    def on_over_cb(self, event):
        """
        Set overwrite name flag on cb event
        """
        if event is not None:
            event.Skip()
        cb_value = event.GetEventObject()
        self.overwrite_name = cb_value.GetValue()

    def on_click_apply(self, event):
        """
        Changes are saved in data object imported to edit.

        checks firs for valid name, then if it already exists then checks
        that a function was entered and finally that if entered it contains at
        least a return statement.  If all passes writes file then tries to
        compile.  If compile fails or import module fails or run method fails
        tries to remove any .py and pyc files that may have been created and
        sets error message.

        :todo this code still could do with a careful going over to clean
        up and simplify. the non GUI methods such as this one should be removed
        to computational code of SasView. Most of those computational methods
        would be the same for both the simple editors.
        """
        #must post event here
        event.Skip()
        name = self.name_tcl.GetValue().lstrip().rstrip()
        info = 'Info'
        msg = ''
        result, check_err = '', ''
        # Sort out the errors if occur
        # First check for valid python name then if the name already exists
        if not name or not bool(re.match('^[A-Za-z0-9_]*$', name)):
            msg = '"%s" ' % name
            msg += "is not a valid model name. Name must not be empty and \n"
            msg += "may include only alpha numeric or underline characters \n"
            msg += "and no spaces"
        elif self.check_name():
            description = self.desc_tcl.GetValue()
            param_str = self.param_tcl.GetText()
            pd_param_str = self.pd_param_tcl.GetText()
            func_str = self.function_tcl.GetText()
            # No input for the model function
            if func_str.lstrip().rstrip():
                if func_str.count('return') > 0:
                    self.write_file(self.fname, name, description, param_str,
                                    pd_param_str, func_str)
                    try:
                        result, msg = check_model(self.fname), None
                    except Exception:
                        import traceback
                        result, msg = None, "error building model"
                        check_err = "\n" + traceback.format_exc(limit=2)
                else:
                    msg = "Error: The func(x) must 'return' a value at least.\n"
                    msg += "For example: \n\nreturn 2*x"
            else:
                msg = 'Error: Function is not defined.'
        else:
            msg = "Name exists already."

        #
        if self.base is not None and not msg:
            self.base.update_custom_combo()

        # Prepare the messagebox
        if msg:
            info = 'Error'
            color = 'red'
            self.overwrite_cb.SetValue(True)
            self.overwrite_name = True
        else:
            self._notes = result
            msg = "Successful! Please look for %s in Plugin Models." % name
            msg += "  " + self._notes
            info = 'Info'
            color = 'blue'
        self._msg_box.SetLabel(msg)
        self._msg_box.SetForegroundColour(color)
        # Send msg to the top window
        if self.base is not None:
            from sas.sasgui.guiframe.events import StatusEvent
            wx.PostEvent(self.base.parent,
                         StatusEvent(status=msg + check_err, info=info))
        self.warning = msg

    def write_file(self, fname, name, desc_str, param_str, pd_param_str,
                   func_str):
        """
        Write content in file

        :param fname: full file path
        :param desc_str: content of the description strings
        :param param_str: content of params; Strings
        :param pd_param_str: content of params requiring polydispersity; Strings
        :param func_str: content of func; Strings
        """
        out_f = open(fname, 'w')

        out_f.write(
            CUSTOM_TEMPLATE % {
                'name': name,
                'title': 'User model for ' + name,
                'description': desc_str,
                'date': datetime.datetime.now().strftime('%YYYY-%mm-%dd'),
            })

        # Write out parameters
        param_names = []  # to store parameter names
        pd_params = []
        out_f.write('parameters = [ \n')
        out_f.write(
            '#   ["name", "units", default, [lower, upper], "type", "description"],\n'
        )
        for pname, pvalue, desc in self.get_param_helper(param_str):
            param_names.append(pname)
            out_f.write("    ['%s', '', %s, [-inf, inf], '', '%s'],\n" %
                        (pname, pvalue, desc))
        for pname, pvalue, desc in self.get_param_helper(pd_param_str):
            param_names.append(pname)
            pd_params.append(pname)
            out_f.write("    ['%s', '', %s, [-inf, inf], 'volume', '%s'],\n" %
                        (pname, pvalue, desc))
        out_f.write('    ]\n')

        # Write out function definition
        out_f.write('def Iq(%s):\n' % ', '.join(['x'] + param_names))
        out_f.write('    """Absolute scattering"""\n')
        if "scipy." in func_str:
            out_f.write('    import scipy')
        if "numpy." in func_str:
            out_f.write('    import numpy')
        if "np." in func_str:
            out_f.write('    import numpy as np')
        for func_line in func_str.split('\n'):
            out_f.write('%s%s\n' % (spaces4, func_line))
        out_f.write('## uncomment the following if Iq works for vector x\n')
        out_f.write('#Iq.vectorized = True\n')

        # If polydisperse, create place holders for form_volume, ER and VR
        if pd_params:
            out_f.write('\n')
            out_f.write(CUSTOM_TEMPLATE_PD % {'args': ', '.join(pd_params)})

        # Create place holder for Iqxy
        out_f.write('\n')
        out_f.write('#def Iqxy(%s):\n' % ', '.join(["x", "y"] + param_names))
        out_f.write('#    """Absolute scattering of oriented particles."""\n')
        out_f.write('#    ...\n')
        out_f.write('#    return oriented_form(x, y, args)\n')
        out_f.write(
            '## uncomment the following if Iqxy works for vector x, y\n')
        out_f.write('#Iqxy.vectorized = True\n')

        out_f.close()

    def get_param_helper(self, param_str):
        """
        yield a sequence of name, value pairs for the parameters in param_str

        Parameters can be defined by one per line by name=value, or multiple
        on the same line by separating the pairs by semicolon or comma.  The
        value is optional and defaults to "1.0".
        """
        for line in param_str.replace(';', ',').split('\n'):
            for item in line.split(','):
                defn, desc = item.split('#', 1) if '#' in item else (item, '')
                name, value = defn.split('=', 1) if '=' in defn else (defn,
                                                                      '1.0')
                if name:
                    yield [v.strip() for v in (name, value, desc)]

    def set_function_helper(self, line):
        """
        Get string in line to define the local params

        :param line: one line of string got from the param_str
        """
        params_str = ''
        spaces = '        '  #8spaces
        items = line.split(";")
        for item in items:
            name = item.split("=")[0].lstrip().rstrip()
            params_str += spaces + "%s = self.params['%s']\n" % (name, name)
        return params_str

    def get_warning(self):
        """
        Get the warning msg
        """
        return self.warning

    def on_help(self, event):
        """
        Bring up the New Plugin Model Editor Documentation whenever
        the HELP button is clicked.

        Calls DocumentationWindow with the path of the location within the
        documentation tree (after /doc/ ....".  Note that when using old
        versions of Wx (before 2.9) and thus not the release version of
        installers, the help comes up at the top level of the file as
        webbrowser does not pass anything past the # to the browser when it is
        running "file:///...."

        :param evt: Triggers on clicking the help button
        """

        _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html"
        _PageAnchor = "#new-plugin-model"
        _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, _PageAnchor,
                                          "Plugin Model Editor Help")

    def on_close(self, event):
        """
        leave data as it is and close
        """
        self.parent.Show(False)  #Close()
        event.Skip()
 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
              size=wx.DefaultSize, style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
     EditWindow.__init__(self, parent, id=id, pos=pos, size=size, 
         style=style)
     self._selection = (-1, -1)
Exemplo n.º 9
0
class MainFrame(wx.Frame):
    #主框架类
    def __init__( self, parent=None, title=u'简单Maven', pos=wx.DefaultPosition, \
            size=(800,600), style=wx.DEFAULT_FRAME_STYLE^wx.RESIZE_BORDER, name='mainFrame' ):
        wx.Frame.__init__( self, parent=parent, title=title, pos=pos, size=size, \
                style=style, name=name )

        self.SetBackgroundColour("gray")
        self.createStatusBar()
        self.createMenuBar()

        self.tree = wx.TreeCtrl(self,
                                id=wx.NewId(),
                                size=(300, -1),
                                style=wx.TR_HAS_BUTTONS | wx.TR_LINES_AT_ROOT)
        self.tree.SetBackgroundColour("light gray")

        self.html = wx.html.HtmlWindow(self)
        self.html.SetHTMLBackgroundColour("medium goldenrod")

        self.log = EditWindow(self)
        #self.log.SetReadOnly(True)
        self.log.setDisplayLineNumbers(True)
        handler = MyLogHandler("root", control=self.log)
        logging.getLogger().setLevel(logging.INFO)
        logging.getLogger().addHandler(handler)

        vbox = wx.BoxSizer(wx.VERTICAL)
        box = wx.BoxSizer(wx.HORIZONTAL)
        box.Add(self.tree, -1, wx.EXPAND | wx.RIGHT, 3)
        box.Add(self.html, 2, wx.EXPAND, 3)
        vbox.Add(box, 5, wx.EXPAND | wx.ALL, 3)
        vbox.Add(self.log, 1, wx.EXPAND | wx.RIGHT | wx.LEFT | wx.BOTTOM, 3)
        self.SetSizer(vbox)

        #创建SimpleMaven对象,加载TreeData.xml文件
        self.simpleMaven = SimpleMaven()
        wx.CallAfter(self.DataInit, controls=self.tree)

        self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnTreeRightClick,
                  self.tree)
        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeChanged, self.tree)

    def createStatusBar(self):
        #创建状态栏
        statusBar = self.CreateStatusBar(3)
        statusBar.SetStatusWidths([-1, -2, -3])
        statusBar.SetStatusText(__version__, 0)
        statusBar.SetStatusText(__file__, 1)

    def createMenuBar(self):
        menuBar = wx.MenuBar()
        #工具菜单
        menuTool = wx.Menu()
        edit_tree_data = menuTool.Append(
            wx.MenuItem(menuTool,
                        id=wx.NewId(),
                        text="文件预览",
                        helpString="查看TreeData.xml文件"))
        self.Bind(wx.EVT_MENU, self.OnEditTreeData, edit_tree_data)
        menuBar.Append(menuTool, "&工具")

        self.SetMenuBar(menuBar)

    #事件处理
    def OnTreeChanged(self, event):
        if event.GetItem() == event.GetEventObject().GetRootItem():
            with open("README.md") as fp:
                self.html.SetPage(markdown.markdown(fp.read().decode("UTF-8")))
        else:
            self.html.SetPage(event.GetEventObject().GetItemData(
                event.GetItem()))
            logging.info(event.GetEventObject().GetItemData(event.GetItem()))

    def OnEditTreeData(self, event):
        parentSize = self.GetClientSize()
        edit = EditDialog(self,
                          size=(parentSize[0] * 0.8, parentSize[1] * 0.8),
                          title="文件预览")
        edit.SetReadOnly()
        edit.CenterOnParent()
        ret = edit.ShowModal()
        if ret == wx.ID_CANCEL:
            edit.Destroy()

    def DataInit(self, controls=None):
        if controls is not None:
            if isinstance(controls, wx.TreeCtrl):
                self.simpleMaven.parseTree(controls, xmlFile=TREE_DATA_XML)
        with open("README.md") as fp:
            txt = markdown.markdown(fp.read().decode("UTF-8"))
            self.html.SetPage(txt)

    def OnTreeRightClick(self, event):
        if not hasattr(self, "addNodeId"):
            self.addNodeId = wx.NewId()
            self.removeNodeId = wx.NewId()
            self.changeNodeId = wx.NewId()
            self.Bind(wx.EVT_MENU, self.OnAddNode, id=self.addNodeId)
            self.Bind(wx.EVT_MENU, self.OnRemoveNode, id=self.removeNodeId)
            self.Bind(wx.EVT_MENU, self.OnChangeNode, id=self.changeNodeId)
        menu = wx.Menu()
        menu.Append(wx.MenuItem(menu, id=self.addNodeId, text="添加子节点"))
        menu.Append(wx.MenuItem(menu, id=self.removeNodeId, text="删除子节点"))
        menu.Append(wx.MenuItem(menu, id=self.changeNodeId, text="修改字节点"))
        self.PopupMenu(menu, event.GetPoint())
        menu.Destroy()

    def OnAddNode(self, event):
        print self.tree.GetSelection()

    def OnRemoveNode(self, event):
        pass

    def OnChangeNode(self, event):
        pass
Exemplo n.º 10
0
class EditorPanel(wx.ScrolledWindow):
    """
    Simple Plugin Model function editor
    """
    def __init__(self, parent, base, path, title, *args, **kwds):
        kwds['name'] = title
#        kwds["size"] = (EDITOR_WIDTH, EDITOR_HEIGTH)
        kwds["style"] = wx.FULL_REPAINT_ON_RESIZE
        wx.ScrolledWindow.__init__(self, parent, *args, **kwds)
        self.SetScrollbars(1,1,1,1)
        self.parent = parent
        self.base = base
        self.path = path
        self.font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
        self.font.SetPointSize(10)
        self.reader = None
        self.name = 'untitled'
        self.overwrite_name = False
        self.is_2d = False
        self.fname = None
        self.main_sizer = None
        self.name_sizer = None
        self.name_hsizer = None
        self.name_tcl = None
        self.overwrite_cb = None
        self.desc_sizer = None
        self.desc_tcl = None
        self.param_sizer = None
        self.param_tcl = None
        self.function_sizer = None
        self.func_horizon_sizer = None
        self.button_sizer = None
        self.param_strings = ''
        self.function_strings = ''
        self._notes = ""
        self._msg_box = None
        self.msg_sizer = None
        self.warning = ""
        #This does not seem to be used anywhere so commenting out for now
        #    -- PDB 2/26/17
        #self._description = "New Plugin Model"
        self.function_tcl = None
        self.math_combo = None
        self.bt_apply = None
        self.bt_close = None
        #self._default_save_location = os.getcwd()
        self._do_layout()



    def _define_structure(self):
        """
        define initial sizer
        """
        #w, h = self.parent.GetSize()
        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
        self.name_sizer = wx.BoxSizer(wx.VERTICAL)
        self.name_hsizer = wx.BoxSizer(wx.HORIZONTAL)
        self.desc_sizer = wx.BoxSizer(wx.VERTICAL)
        self.param_sizer = wx.BoxSizer(wx.VERTICAL)
        self.function_sizer = wx.BoxSizer(wx.VERTICAL)
        self.func_horizon_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.msg_sizer = wx.BoxSizer(wx.HORIZONTAL)

    def _layout_name(self):
        """
        Do the layout for file/function name related widgets
        """
        #title name [string]
        name_txt = wx.StaticText(self, -1, 'Function Name : ')
        self.overwrite_cb = wx.CheckBox(self, -1, "Overwrite existing plugin model of this name?", (10, 10))
        self.overwrite_cb.SetValue(False)
        self.overwrite_cb.SetToolTipString("Overwrite it if already exists?")
        wx.EVT_CHECKBOX(self, self.overwrite_cb.GetId(), self.on_over_cb)
        self.name_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1))
        self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name)
        self.name_tcl.SetValue('')
        self.name_tcl.SetFont(self.font)
        hint_name = "Unique Model Function Name."
        self.name_tcl.SetToolTipString(hint_name)
        self.name_hsizer.AddMany([(self.name_tcl, 0, wx.LEFT | wx.TOP, 0),
                                  (self.overwrite_cb, 0, wx.LEFT, 20)])
        self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.TOP, 10),
                                 (self.name_hsizer, 0,
                                  wx.LEFT | wx.TOP | wx.BOTTOM, 10)])


    def _layout_description(self):
        """
        Do the layout for description related widgets
        """
        #title name [string]
        desc_txt = wx.StaticText(self, -1, 'Description (optional) : ')
        self.desc_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1))
        self.desc_tcl.SetValue('')
        hint_desc = "Write a short description of the model function."
        self.desc_tcl.SetToolTipString(hint_desc)
        self.desc_sizer.AddMany([(desc_txt, 0, wx.LEFT | wx.TOP, 10),
                                 (self.desc_tcl, 0,
                                  wx.LEFT | wx.TOP | wx.BOTTOM, 10)])
    def _layout_param(self):
        """
        Do the layout for parameter related widgets
        """
        param_txt = wx.StaticText(self, -1, 'Fit Parameters NOT requiring' + \
                                  ' polydispersity (if any): ')

        param_tip = "#Set the parameters NOT requiring polydispersity " + \
        "and their initial values.\n"
        param_tip += "#Example:\n"
        param_tip += "A = 1\nB = 1"
        #param_txt.SetToolTipString(param_tip)
        newid = wx.NewId()
        self.param_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                    wx.DefaultSize,
                                    wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.param_tcl.setDisplayLineNumbers(True)
        self.param_tcl.SetToolTipString(param_tip)

        self.param_sizer.AddMany([(param_txt, 0, wx.LEFT, 10),
                                  (self.param_tcl, 1, wx.EXPAND | wx.ALL, 10)])

        # Parameters with polydispersity
        pd_param_txt = wx.StaticText(self, -1, 'Fit Parameters requiring ' + \
                                     'polydispersity (if any): ')

        pd_param_tip = "#Set the parameters requiring polydispersity and " + \
        "their initial values.\n"
        pd_param_tip += "#Example:\n"
        pd_param_tip += "C = 2\nD = 2"
        newid = wx.NewId()
        self.pd_param_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                    wx.DefaultSize,
                                    wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.pd_param_tcl.setDisplayLineNumbers(True)
        self.pd_param_tcl.SetToolTipString(pd_param_tip)

        self.param_sizer.AddMany([(pd_param_txt, 0, wx.LEFT, 10),
                                  (self.pd_param_tcl, 1, wx.EXPAND | wx.ALL, 10)])

    def _layout_function(self):
        """
        Do the layout for function related widgets
        """
        function_txt = wx.StaticText(self, -1, 'Function(x) : ')
        hint_function = "#Example:\n"
        hint_function += "if x <= 0:\n"
        hint_function += "    y = A + B\n"
        hint_function += "else:\n"
        hint_function += "    y = A + B * cos(2 * pi * x)\n"
        hint_function += "return y\n"
        math_txt = wx.StaticText(self, -1, '*Useful math functions: ')
        math_combo = self._fill_math_combo()

        newid = wx.NewId()
        self.function_tcl = EditWindow(self, newid, wx.DefaultPosition,
                                       wx.DefaultSize,
                                       wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
        self.function_tcl.setDisplayLineNumbers(True)
        self.function_tcl.SetToolTipString(hint_function)

        self.func_horizon_sizer.Add(function_txt)
        self.func_horizon_sizer.Add(math_txt, 0, wx.LEFT, 250)
        self.func_horizon_sizer.Add(math_combo, 0, wx.LEFT, 10)

        self.function_sizer.Add(self.func_horizon_sizer, 0, wx.LEFT, 10)
        self.function_sizer.Add(self.function_tcl, 1, wx.EXPAND | wx.ALL, 10)

    def _layout_msg(self):
        """
        Layout msg
        """
        self._msg_box = wx.StaticText(self, -1, self._notes,
                                      size=(PANEL_WIDTH, -1))
        self.msg_sizer.Add(self._msg_box, 0, wx.LEFT, 10)

    def _layout_button(self):
        """
        Do the layout for the button widgets
        """
        self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH, -1))
        self.bt_apply.SetToolTipString("Save changes into the imported data.")
        self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)

        self.bt_help = wx.Button(self, -1, "HELP", size=(_BOX_WIDTH, -1))
        self.bt_help.SetToolTipString("Get Help For Model Editor")
        self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)

        self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH, -1))
        self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
        self.bt_close.SetToolTipString("Close this panel.")

        self.button_sizer.AddMany([(self.bt_apply, 0,0),
                                   (self.bt_help, 0, wx.LEFT | wx.BOTTOM,15),
                                   (self.bt_close, 0, wx.LEFT | wx.RIGHT, 15)])

    def _do_layout(self):
        """
        Draw the current panel
        """
        self._define_structure()
        self._layout_name()
        self._layout_description()
        self._layout_param()
        self._layout_function()
        self._layout_msg()
        self._layout_button()
        self.main_sizer.AddMany([(self.name_sizer, 0, wx.EXPAND | wx.ALL, 5),
                                 (wx.StaticLine(self), 0,
                                  wx.ALL | wx.EXPAND, 5),
                                 (self.desc_sizer, 0, wx.EXPAND | wx.ALL, 5),
                                 (wx.StaticLine(self), 0,
                                  wx.ALL | wx.EXPAND, 5),
                                 (self.param_sizer, 1, wx.EXPAND | wx.ALL, 5),
                                 (wx.StaticLine(self), 0,
                                  wx.ALL | wx.EXPAND, 5),
                                 (self.function_sizer, 2,
                                  wx.EXPAND | wx.ALL, 5),
                                 (wx.StaticLine(self), 0,
                                  wx.ALL | wx.EXPAND, 5),
                                 (self.msg_sizer, 0, wx.EXPAND | wx.ALL, 5),
                                 (self.button_sizer, 0, wx.ALIGN_RIGHT)])
        self.SetSizer(self.main_sizer)
        self.SetAutoLayout(True)

    def _fill_math_combo(self):
        """
        Fill up the math combo box
        """
        self.math_combo = wx.ComboBox(self, -1, size=(100, -1),
                                      style=wx.CB_READONLY)
        for item in dir(math):
            if item.count("_") < 1:
                try:
                    exec "float(math.%s)" % item
                    self.math_combo.Append(str(item))
                except:
                    self.math_combo.Append(str(item) + "()")
        self.math_combo.Bind(wx.EVT_COMBOBOX, self._on_math_select)
        self.math_combo.SetSelection(0)
        return self.math_combo

    def _on_math_select(self, event):
        """
        On math selection on ComboBox
        """
        event.Skip()
        label = self.math_combo.GetValue()
        self.function_tcl.SetFocus()
        # Put the text at the cursor position
        pos = self.function_tcl.GetCurrentPos()
        self.function_tcl.InsertText(pos, label)
        # Put the cursor at appropriate position
        length = len(label)
        print(length)
        if label[length-1] == ')':
            length -= 1
        f_pos = pos + length
        self.function_tcl.GotoPos(f_pos)

    def get_notes(self):
        """
        return notes
        """
        return self._notes

    def on_change_name(self, event=None):
        """
        Change name
        """
        if event is not None:
            event.Skip()
        self.name_tcl.SetBackgroundColour('white')
        self.Refresh()

    def check_name(self):
        """
        Check name if exist already
        """
        self._notes = ''
        self.on_change_name(None)
        plugin_dir = self.path
        list_fnames = os.listdir(plugin_dir)
        # function/file name
        title = self.name_tcl.GetValue().lstrip().rstrip()
        self.name = title
        t_fname = title + '.py'
        if not self.overwrite_name:
            if t_fname in list_fnames:
                self.name_tcl.SetBackgroundColour('pink')
                return False
        self.fname = os.path.join(plugin_dir, t_fname)
        s_title = title
        if len(title) > 20:
            s_title = title[0:19] + '...'
        self._notes += "Model function name is set "
        self._notes += "to %s. \n" % str(s_title)
        return True

    def on_over_cb(self, event):
        """
        Set overwrite name flag on cb event
        """
        if event is not None:
            event.Skip()
        cb_value = event.GetEventObject()
        self.overwrite_name = cb_value.GetValue()

    def on_click_apply(self, event):
        """
        Changes are saved in data object imported to edit.

        checks firs for valid name, then if it already exists then checks
        that a function was entered and finally that if entered it contains at
        least a return statement.  If all passes writes file then tries to
        compile.  If compile fails or import module fails or run method fails
        tries to remove any .py and pyc files that may have been created and
        sets error message.

        :todo this code still could do with a careful going over to clean
        up and simplify. the non GUI methods such as this one should be removed
        to computational code of SasView. Most of those computational methods
        would be the same for both the simple editors.
        """
        #must post event here
        event.Skip()
        name = self.name_tcl.GetValue().lstrip().rstrip()
        info = 'Info'
        msg = ''
        result, check_err = '', ''
        # Sort out the errors if occur
        # First check for valid python name then if the name already exists
        if not name or not bool(re.match('^[A-Za-z0-9_]*$', name)):
            msg = '"%s" '%name
            msg += "is not a valid model name. Name must not be empty and \n"
            msg += "may include only alpha numeric or underline characters \n"
            msg += "and no spaces"
        elif self.check_name():
            description = self.desc_tcl.GetValue()
            param_str = self.param_tcl.GetText()
            pd_param_str = self.pd_param_tcl.GetText()
            func_str = self.function_tcl.GetText()
            # No input for the model function
            if func_str.lstrip().rstrip():
                if func_str.count('return') > 0:
                    self.write_file(self.fname, name, description, param_str,
                                    pd_param_str, func_str)
                    try:
                        result, msg = check_model(self.fname), None
                    except Exception:
                        import traceback
                        result, msg = None, "error building model"
                        check_err = "\n"+traceback.format_exc(limit=2)
                else:
                    msg = "Error: The func(x) must 'return' a value at least.\n"
                    msg += "For example: \n\nreturn 2*x"
            else:
                msg = 'Error: Function is not defined.'
        else:
            msg = "Name exists already."

        # Prepare the messagebox
        if self.base is not None and not msg:
            self.base.update_custom_combo()
            # Passed exception in import test as it will fail for sasmodels.sasview_model class
            # Should add similar test for new style?
            Model = None
            try:
                exec "from %s import Model" % name
            except:
                logger.error(sys.exc_value)

        # Prepare the messagebox
        if msg:
            info = 'Error'
            color = 'red'
            self.overwrite_cb.SetValue(True)
            self.overwrite_name = True
        else:
            self._notes = result
            msg = "Successful! Please look for %s in Plugin Models."%name
            msg += "  " + self._notes
            info = 'Info'
            color = 'blue'
        self._msg_box.SetLabel(msg)
        self._msg_box.SetForegroundColour(color)
        # Send msg to the top window
        if self.base is not None:
            from sas.sasgui.guiframe.events import StatusEvent
            wx.PostEvent(self.base.parent,
                         StatusEvent(status=msg+check_err, info=info))
        self.warning = msg

    def write_file(self, fname, name, desc_str, param_str, pd_param_str, func_str):
        """
        Write content in file

        :param fname: full file path
        :param desc_str: content of the description strings
        :param param_str: content of params; Strings
        :param pd_param_str: content of params requiring polydispersity; Strings
        :param func_str: content of func; Strings
        """
        try:
            out_f = open(fname, 'w')
        except:
            raise
        # Prepare the content of the function
        lines = CUSTOM_TEMPLATE.split('\n')

        has_scipy = func_str.count("scipy.")
        if has_scipy:
            lines.insert(0, 'import scipy')

        # Think about 2D later
        #self.is_2d = func_str.count("#self.ndim = 2")
        #line_2d = ''
        #if self.is_2d:
        #    line_2d = CUSTOM_2D_TEMP.split('\n')

        # Also think about test later
        #line_test = TEST_TEMPLATE.split('\n')
        #local_params = ''
        #spaces = '        '#8spaces
        spaces4  = ' '*4
        spaces13 = ' '*13
        spaces16 = ' '*16
        param_names = []    # to store parameter names
        has_scipy = func_str.count("scipy.")
        if has_scipy:
            lines.insert(0, 'import scipy')

        # write function here
        for line in lines:
            # The location where to put the strings is
            # hard-coded in the template as shown below.
            out_f.write(line + '\n')
            if line.count('#name'):
                out_f.write('name = "%s" \n' % name)
            elif line.count('#title'):
                out_f.write('title = "User model for %s"\n' % name)
            elif line.count('#description'):
                out_f.write('description = "%s"\n' % desc_str)
            elif line.count('#parameters'):
                out_f.write('parameters = [ \n')
                for param_line in param_str.split('\n'):
                    p_line = param_line.lstrip().rstrip()
                    if p_line:
                        pname, pvalue, desc = self.get_param_helper(p_line)
                        param_names.append(pname)
                        out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], '', '%s'],\n" % (spaces16, pname, pvalue, desc))
                for param_line in pd_param_str.split('\n'):
                    p_line = param_line.lstrip().rstrip()
                    if p_line:
                        pname, pvalue, desc = self.get_param_helper(p_line)
                        param_names.append(pname)
                        out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], 'volume', '%s'],\n" % (spaces16, pname, pvalue, desc))
                out_f.write('%s]\n' % spaces13)

        # No form_volume or ER available in simple model editor
        out_f.write('def form_volume(*arg): \n')
        out_f.write('    return 1.0 \n')
        out_f.write('\n')
        out_f.write('def ER(*arg): \n')
        out_f.write('    return 1.0 \n')

        # function to compute
        out_f.write('\n')
        out_f.write('def Iq(x ')
        for name in param_names:
            out_f.write(', %s' % name)
        out_f.write('):\n')
        for func_line in func_str.split('\n'):
            out_f.write('%s%s\n' % (spaces4, func_line))

        Iqxy_string = 'return Iq(numpy.sqrt(x**2+y**2) '

        out_f.write('\n')
        out_f.write('def Iqxy(x, y ')
        for name in param_names:
            out_f.write(', %s' % name)
            Iqxy_string += ', ' + name
        out_f.write('):\n')
        Iqxy_string += ')'
        out_f.write('%s%s\n' % (spaces4, Iqxy_string))

        out_f.close()

    def get_param_helper(self, line):
        """
        Get string in line to define the params dictionary

        :param line: one line of string got from the param_str
        """
        items = line.split(";")
        for item in items:
            name = item.split("=")[0].strip()
            description = ""
            try:
                value = item.split("=")[1].strip()
                if value.count("#"):
                    # If line ends in a comment, remove it before parsing float
                    index = value.index("#")
                    description = value[(index + 1):].strip()
                    value = value[:value.index("#")].strip()
                float(value)
            except ValueError:
                value = 1.0 # default

        return name, value, description

    def set_function_helper(self, line):
        """
        Get string in line to define the local params

        :param line: one line of string got from the param_str
        """
        params_str = ''
        spaces = '        '#8spaces
        items = line.split(";")
        for item in items:
            name = item.split("=")[0].lstrip().rstrip()
            params_str += spaces + "%s = self.params['%s']\n" % (name, name)
        return params_str

    def get_warning(self):
        """
        Get the warning msg
        """
        return self.warning

    def on_help(self, event):
        """
        Bring up the New Plugin Model Editor Documentation whenever
        the HELP button is clicked.

        Calls DocumentationWindow with the path of the location within the
        documentation tree (after /doc/ ....".  Note that when using old
        versions of Wx (before 2.9) and thus not the release version of
        installers, the help comes up at the top level of the file as
        webbrowser does not pass anything past the # to the browser when it is
        running "file:///...."

    :param evt: Triggers on clicking the help button
    """

        _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html"
        _PageAnchor = "#new-plugin-model"
        _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, _PageAnchor,
                                          "Plugin Model Editor Help")

    def on_close(self, event):
        """
        leave data as it is and close
        """
        self.parent.Show(False)#Close()
        event.Skip()