"""
     CCP4CustomTaskManagerGui.py: CCP4 GUI Project
     Copyright (C) 2013 STFC

     This library is free software: you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public License
     version 3, modified in accordance with the provisions of the 
     license to address the requirements of UK law.
 
     You should have received a copy of the modified GNU Lesser General 
     Public License along with this library.  If not, copies may be 
     downloaded from http://www.ccp4.ac.uk/ccp4license.php
 
     This program 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.
"""

"""
     Liz Potterton July 2013 - create and manage custom tasks
"""

import os
from PyQt4 import QtGui,QtCore
import CCP4Data,CCP4Container,CCP4CustomisationGui,CCP4Widgets,CCP4CustomTaskManager
from CCP4ErrorHandling import *
from CCP4Modules import CUSTOMTASKMANAGER,WEBBROWSER,PROJECTSMANAGER

def openGui():
  if CCustomTaskManagerGui.insts is None:
    CCustomTaskManagerGui.insts = CCustomTaskManagerGui()
  CCustomTaskManagerGui.insts.show()
  CCustomTaskManagerGui.insts.raise_()


class CCustomTaskManagerGui(CCP4CustomisationGui.CCustomisationGui):

  insts = None


  def __init__(self,parent=None):
    CCP4CustomisationGui.CCustomisationGui.__init__(self,parent=parent,mode='customtask',title='Custom Task Manager')
    self.createWidget= None
    

  def manager(self):
    return CUSTOMTASKMANAGER()

  def handleNew(self):
    if self.createWidget is None:
      self.createWidget = CCreateCustomTaskDialog(self)
      self.connect(self.createWidget,QtCore.SIGNAL('customTaskCreated'),self.customListView.populate)
    else:
      self.createWidget.updateViewFromModel()
      
    self.createWidget.show()
    self.createWidget.raise_()


  def handleEdit(self,selected=None):
    if selected is None: selected = self.customListView.selectedItem()
    if selected is None: return
    editor = CCreateCustomTaskDialog(self,name=selected)
    editor.show()

class CCustomComFileView(CCP4Widgets.CComplexLineWidget):

  MODEL_CLASS =CCP4CustomTaskManager.CCustomComFile
  def __init__(self,parent=None,model=None,qualifiers={}):
    qualis = {}
    qualis.update(qualifiers)
    qualis['vboxLayout'] = True
    CCP4Widgets.CComplexLineWidget.__init__(self,parent=parent,qualifiers=qualis)
    self.layout().takeAt(0)
    self.iconButton.deleteLater()
    self.widgets['text'] = CCP4Widgets.CTextEdit(self)
    self.connect(self.widgets['text'],QtCore.SIGNAL('textChanged()'),self.updateText)
    self.widgets['name'] = CCP4Widgets.CLineEdit(self)
    self.connect(self.widgets['name'],QtCore.SIGNAL('textChanged(const QString &)'),self.updateName)
    self.layout().addWidget(QtGui.QLabel('Command file content',self))
    self.layout().addWidget(self.widgets['text'])
    self.layout().addWidget(QtGui.QLabel('Command file name',self))
    self.layout().addWidget(self.widgets['name'])
    self.setModel(model)

  def updateText(self):
    self.model.text.set(self.widgets['text'].toPlainText())

  def updateName(self,txt):
    self.model.name.set(str(txt))

  def updateModelFromView(self):
    CCP4Widgets.CComplexLineWidget.updateModelFromView(self)
    #print 'CCustomComFileView.updateModelFromView',repr(self.model),self.model
    
    
class CCustomComFileListView(CCP4Widgets.CListView):
  MODEL_CLASS =CCP4CustomTaskManager.CCustomComFileList
  def __init__(self,parent=None,model=None,qualifiers={}):
    qualis =  { 'mode' : 'table',
                'tableItems' : ['comFileName','comFileText'],
                'columnHeaders':['Name','Text'],
                'title' : 'Command file(s)'
               }   
    qualis.update(qualifiers)
    CCP4Widgets.CListView.__init__(self,parent,model=model,qualifiers=qualis)


    
class CCustomTaskParamView(CCP4Widgets.CComplexLineWidget):
  MODEL_CLASS =CCP4CustomTaskManager.CCustomTaskParam
  def __init__(self,parent=None,model=None,qualifiers={}):
    import functools
    qualis = {}
    qualis.update(qualifiers)
    qualis['vboxLayout'] = True
    CCP4Widgets.CComplexLineWidget.__init__(self,parent=parent,qualifiers=qualis)
    self.layout().takeAt(0)
    self.iconButton.deleteLater()
    
    self.widgets['name'] = CCP4Widgets.CStringView(self)
    self.widgets['dataType'] = CCP4Widgets.CStringView(self,qualifiers={ 'modelClass' : CCP4Data.CI2DataType })
    self.widgets['dataType'].widget.addItem('More..')
    self.widgets['dataType'].widget.setCurrentIndex(0)
    self.widgets['dataType'].widget.setEditable(True)
    self.connect(self.widgets['dataType'].widget,QtCore.SIGNAL('currentIndexChanged(int)'),self.handleDataTypeChanged)
    self.widgets['label'] =  CCP4Widgets.CStringView(self)
    self.widgets['obligatory'] = CCP4Widgets.CBooleanView(self)
    self.widgets['saveDataToDb'] = CCP4Widgets.CBooleanView(self)
    self.widgets['function'] = CCP4Widgets.CStringView(self,qualifiers= { 'modelClass' : CCP4CustomTaskManager.CCustomTaskFileFunction} )
    self.widgets['function'].widget.setCurrentIndex(0)
    #self.connect(self.widgets['function'].widget,QtCore.SIGNAL('currentIndexChanged(int)'),self.handleFunctionChange)
    self.mergeToWidget = QtGui.QComboBox( self )
    self.connect(self.mergeToWidget,QtCore.SIGNAL('currentIndexChanged(int)'),self.updateMergeToModel)
    self.widgets['splitColumns'] = CCP4Widgets.CStringView(self)
    self.widgets['requiredContentType'] = CMiniMtzRequiredContentWidget(parent=self)
    self.widgets['outputFilePath'] = CCP4Widgets.CStringView(self)
    self.widgets['outputFilePath'].setToolTip("'glob' style relative file path ")
    
    line = QtGui.QHBoxLayout()
    line.addWidget(self.widgets['name'] )
    line.addWidget(QtGui.QLabel('interface label',self))
    line.addWidget(self.widgets['label'])
    self.layout().addLayout(line)

    line = QtGui.QHBoxLayout()
    line.addWidget(QtGui.QLabel('Data type',self))
    line.addWidget(self.widgets['dataType'] )
    line.addStretch(1)
    line.addWidget(QtGui.QLabel('file function',self))
    line.addWidget(self.widgets['function'])
    line.addStretch(1)
    self.layout().addLayout(line)
    
    line = QtGui.QHBoxLayout()
    line.addWidget(self.widgets['obligatory'])
    line.addWidget(QtGui.QLabel('Parameter is obligatory',self))
    line.addStretch(1)
    line.addWidget(self.widgets['saveDataToDb'])
    line.addWidget(QtGui.QLabel('Record in database',self))
    line.addStretch(1)
    self.layout().addLayout(line)

    self.fileFrame  = QtGui.QFrame(self)
    self.fileFrame.setLayout(QtGui.QHBoxLayout())
    self.fileFrame.layout().setContentsMargins(0,0,0,0)
    self.fileFrame.layout().setSpacing(0)
    self.fileFrame.layout().addWidget(QtGui.QLabel("Input file name/ output file search path"))
    self.fileFrame.layout().addWidget(self.widgets['outputFilePath'])
    self.fileFrame.layout().setStretchFactor(self.widgets['outputFilePath'],5)
    self.layout().addWidget(self.fileFrame)
    
    self.mergeToFrame = QtGui.QFrame(self)
    self.mergeToFrame.setLayout(QtGui.QVBoxLayout())
    self.mergeToFrame.layout().setContentsMargins(0,0,0,0)
    self.mergeToFrame.layout().setSpacing(0)
    line = QtGui.QHBoxLayout()
    line.addWidget(QtGui.QLabel('Merge to or split from monster MTZ:'))
    line.addWidget(self.mergeToWidget)
    line.addStretch(1)
    self.mergeToFrame.layout().addLayout(line)
    self.columnLabelFrame = QtGui.QFrame(self)
    self.columnLabelFrame.setLayout(QtGui.QHBoxLayout())
    self.columnLabelFrame.layout().setContentsMargins(0,0,0,0)
    self.columnLabelFrame.layout().setSpacing(0)
    self.columnLabelFrame.layout().addWidget(QtGui.QLabel('Comma-separated list of column labels'))
    self.columnLabelFrame.layout().addWidget(self.widgets['splitColumns'])    
    self.mergeToFrame.layout().addWidget(self.columnLabelFrame)
    self.requiredContentFrame= QtGui.QHBoxLayout()
    self.requiredContentFrame.addWidget(self.widgets['requiredContentType'] )
    self.mergeToFrame.layout().addLayout(self.requiredContentFrame)
    self.layout().addWidget(self.mergeToFrame)
    self.mergeToFrame.hide()
    self.handleFunctionChange()

    self.setModel(model)


  def setModel(self,model=None):
    if model is not None:
      mergeTo = model.mergeTo.__str__()
    else:
      mergeTo = ''
    CCP4Widgets.CComplexLineWidget.setModel(self,model=model)
    self.handleDataTypeChanged(self.widgets['dataType'].widget.currentIndex())
    self.emit(QtCore.SIGNAL('showingMergeTo'))
    indx = self.mergeToWidget.findText(mergeTo)
    if indx<0: indx = 0
    self.mergeToWidget.setCurrentIndex(indx)
    if model is not None:
      self.connect(self.model.dataType,QtCore.SIGNAL('dataChanged'),self.setRequiredContentTypeMode)
    self.handleFunctionChange()

  def setRequiredContentTypeMode(self):
    #print 'CCustomTaskParamView.setRequiredContentTypeMode',self.model.dataType.__str__()
    self.widgets['requiredContentType'].setMode(self.model.dataType.__str__())

  def handleFunctionChange(self,indx=None):
    function = self.widgets['function'].widget.currentText().__str__()
    #print 'CCustomTaskParamView.handleFunctionChange',function,type(function)
    if function == 'input':
      self.widgets['requiredContentType'].show()
      self.columnLabelFrame.hide()
    elif function == 'output':
      self.widgets['requiredContentType'].hide()
      self.columnLabelFrame.show()
    else:
      self.widgets['requiredContentType'].hide()
      self.columnLabelFrame.hide()

      
  def handleDataTypeChanged(self,indx):
    dType = self.widgets['dataType'].widget.itemData(indx).toString().__str__()
    #print 'CCustomTaskParamView.handleDataTypeChanged',dType
    if dType.count('DataFile')>0:
      if not self.mergeToFrame.isVisible():
        self.emit(QtCore.SIGNAL('showingMergeTo'))
        self.mergeToFrame.show()
      self.handleFunctionChange()
      self.widgets['requiredContentType'].setMode( dType )
      self.fileFrame.show()
    else:
      if self.mergeToFrame.isVisible():
        self.mergeToFrame.hide()
      self.widgets['requiredContentType'].setMode(None)
      self.fileFrame.hide()
      

  def updateMergeToModel(self,indx=None):
    #print 'CCustomTaskParamView.updateMergeToModel dataType',self.model.dataType.__str__() , self.mergeToWidget.currentIndex()
    if self.model.dataType.__str__() in ['CObsDataFile', 'CPhsDataFile', 'CMapCoeffsDataFile','CFreeRDataFile']:
      text = self.mergeToWidget.itemText(self.mergeToWidget.currentIndex())
      if len(text)>0:
        self.model.mergeTo.set(text)
      else:
        self.model.mergeTo.unSet()
    else:
      self.model.mergeTo.unSet()


class CMiniMtzRequiredContentWidget(CCP4Widgets.CViewWidget):

  def __init__(self,parent=None,qualifiers={}):
    qualis = {}
    qualis.update(qualifiers)
    CCP4Widgets.CViewWidget.__init__(self,parent=parent,qualifiers=qualis)
    self.setLayout(QtGui.QStackedLayout())
    self.obsWidgets = []
    self.phsWidgets = []

    frame = QtGui.QFrame(self)
    frame.setLayout(QtGui.QHBoxLayout())
    frame.layout().setContentsMargins(0,0,0,0)
    frame.layout().setSpacing(0)
    frame.layout().addWidget(QtGui.QLabel(' ',self))
    self.layout().addWidget(frame)
    frame = QtGui.QFrame(self)
    frame.setLayout(QtGui.QHBoxLayout())
    frame.layout().setContentsMargins(0,0,0,0)
    frame.layout().setSpacing(0)
    frame.layout().addWidget(QtGui.QLabel('Observed data allowed content type:',self))
    for item in ['I+/-','F+/-','Imean','Fmean']:
      self.obsWidgets.append(QtGui.QCheckBox(item,self))
      frame.layout().addWidget(self.obsWidgets[-1])
    self.layout().addWidget(frame)
    frame = QtGui.QFrame(self)
    frame.setLayout(QtGui.QHBoxLayout())
    frame.layout().setContentsMargins(0,0,0,0)
    frame.layout().setSpacing(0)
    frame.layout().addWidget(QtGui.QLabel('Phase restraints allowed content type:',self))
    for item in ['Hendrickson-Lattmann coefficients','Phi+FOM']:
      self.phsWidgets.append(QtGui.QCheckBox(item,self))
      frame.layout().addWidget(self.phsWidgets[-1])
    self.layout().addWidget(frame)
    self.layout().setCurrentIndex(0)
    self.mode = None



  def setMode(self,mode):
    #print 'CMiniMtzRequiredContentWidget.setMode',mode,self.mode
    if mode == self.mode: return
    import copy
    self.mode = copy.deepcopy(mode)
    if self.mode == 'CObsDataFile':
      self.layout().setCurrentIndex(1)
    elif self.mode == 'CPhsDataFile':
      self.layout().setCurrentIndex(2)
    else:
      self.layout().setCurrentIndex(0)
      

  def getValue(self):
    v = []
    if self.mode == 'CObsDataFile':
      for w in self.obsWidgets: v.append(w.isChecked())
    elif self.mode == 'CPhsDataFile':
      for w in self.phsWidgets: v.append(w.isChecked())
    #print 'CMiniMtzRequiredContentWidget.getValue',v
    return v

  def setValue(self,value=[]):
    if value is None or len(value) == 0:
      #self.setMode(None)
      pass
    elif len(value) == 2:
      #self.setMode('CPhsDataFile')
      for ii in range(2):
        self.phsWidgets[ii].setChecked(bool(value[ii]))
    elif len(value) == 4:
      for ii in range(4):
        self.obsWidgets[ii].setChecked(bool(value[ii]))
      #self.setMode('CObsDataFile')
    

      
class CCustomTaskParamListView(CCP4Widgets.CListView):
  MODEL_CLASS =CCP4CustomTaskManager.CCustomTaskParamList
  def __init__(self,parent=None,model=None,qualifiers={}):
    qualis = {}
    qualis.update(qualifiers)
    qualis =  { 'mode' : 'table',
                'tableItems' : ['name','label','dataType','function','obligatory','saveDataToDb','mergeTo','outputFilePath','requiredContentType','splitColumns'],
                'columnHeaders':['Name','Label','Data type','File function','Oblig','Record','Merge to MTZ','File path','Representation','Output columns'],
                'title' : 'Parameters in command line or files'
               }   
    qualis.update(qualifiers)
    CCP4Widgets.CListView.__init__(self,parent,model=model,qualifiers=qualis)
    #print 'CCustomTaskParamListView.__init__ editor',self.editor
    self.connect(self.editor,QtCore.SIGNAL('showingMergeTo'),self.populateEditorMergeTo)
    self.listWidget.horizontalHeader().setResizeMode(QtGui.QHeaderView.Interactive)
    self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)



  def populateEditorMergeTo(self):
    #print 'CCustomTaskParamListView.populateEditorMergeTo'
    self.editor.mergeToWidget.clear()
    self.editor.mergeToWidget.addItem('')
    for obj in self.model:
      if obj != self.editor.model:
        if obj.dataType == 'CMtzDataFile':
          self.editor.mergeToWidget.addItem(obj.name.__str__())


class CCreateCustomTaskDialog(QtGui.QDialog):

  def __init__(self,parent=None,name=None):
    QtGui.QDialog.__init__(self,parent)

    self.setWindowTitle('Create a custom task')
    self.setLayout(QtGui.QVBoxLayout())
    self.layout().setContentsMargins(2,2,2,2)
    self.layout().setSpacing(2)
    
    self.widgets = {}
    self.model = CCP4CustomTaskManager.CCustomTaskDefinition(self,name=name)
    if name is not None:  
      self.model.loadDataFromXml(fileName=os.path.join(CUSTOMTASKMANAGER().getDirectory(name),'task.xml'),loadHeader=True,check=False)

    line = QtGui.QHBoxLayout()
    line.addWidget(QtGui.QLabel('Custom task name',self))
    self.widgets['name'] = CCP4Widgets.CStringView(parent=self,model=self.model.name)
    self.widgets['name'].setToolTip('Unique single-word identifier for task')
    line.addWidget(self.widgets['name'])
    line.addWidget(QtGui.QLabel('title',self))
    self.widgets['title'] = CCP4Widgets.CStringView(parent=self,model=self.model.title)
    self.widgets['title'].setToolTip('Task name that appears in the user interface')
    line.addWidget(self.widgets['title'])
    line.setStretchFactor(self.widgets['title'],5)
    line.addStretch(1)
    self.layout().addLayout(line)

    line = QtGui.QHBoxLayout()
    line.addWidget(QtGui.QLabel('Parameter names in command line/file begin with tag:',self))
    self.widgets['tagCharacter'] = CCP4Widgets.CStringView(parent=self,model=self.model.tagCharacter)
    self.widgets['tagCharacter'].setToolTip('Begin parameter names with this tag')
    self.widgets['tagCharacter'].setMaximumWidth(50)
    line.addWidget(self.widgets['tagCharacter'])
    line.addStretch(1)
    self.layout().addLayout(line)

    line =  QtGui.QHBoxLayout()
    line.addWidget(QtGui.QLabel('Command line',self))
    self.widgets['comLine'] = CCP4Widgets.CStringView(parent=self,model=self.model.comLine)
    self.widgets['comLine'].setToolTip("Command line with variables such as file names entered as '#HKLIN'")
    line.addWidget(self.widgets['comLine'])
    self.layout().addLayout(line)
    
    self.widgets['comFileList'] = CCustomComFileListView(parent=self,model=self.model.comFileList)
    self.widgets['comFileList'].setToolTip("Command file with variables such as file names entered as '#HKLIN'")
    self.layout().addWidget(self.widgets['comFileList'])

    line = QtGui.QHBoxLayout()
    line.addStretch(1)
    update = QtGui.QPushButton('Update parameters',self)
    self.connect(update,QtCore.SIGNAL('released()'),self.updateParametersList)
    line.addWidget(update)
    line.addStretch(1)
    self.layout().addLayout(line)

    self.widgets['paramsList'] = CCustomTaskParamListView(parent=self,model=self.model.paramList)
    self.widgets['paramsList'].setMinimumHeight(400)
    self.layout().addWidget(self.widgets['paramsList'])

    buttonBox = QtGui.QDialogButtonBox(self)
    but = buttonBox.addButton('Help',QtGui.QDialogButtonBox.HelpRole)
    but.setFocusPolicy(QtCore.Qt.NoFocus)
    self.connect(but,QtCore.SIGNAL('released()'),self.help)
    but = buttonBox.addButton('Cancel',QtGui.QDialogButtonBox.RejectRole)
    but.setFocusPolicy(QtCore.Qt.NoFocus)
    self.connect(but,QtCore.SIGNAL('released()'),self.cancel)
    but = buttonBox.addButton('Save custom task',QtGui.QDialogButtonBox.AcceptRole)
    but.setFocusPolicy(QtCore.Qt.NoFocus)
    self.connect(but,QtCore.SIGNAL('released()'),self.accept)
    self.layout().addWidget(buttonBox)

    self.updateViewFromModel()
    
    #print 'CCreateCustomTaskDialog.init',len(self.model.comFileList)

  
  def updateViewFromModel(self):
    for key in self.widgets.keys():
      self.widgets[key].updateViewFromModel()
    print 'CCreateCustomTaskDialog.updateViewFromModel pluginTitle',self.model.header.pluginTitle
    self.widgets['name'].setValue(self.model.header.pluginName)
    self.widgets['title'].setValue(self.model.header.pluginTitle)

  def updateModelFromView(self):
    for key in self.widgets.keys():
      self.widgets[key].updateModelFromView()
    print 'CCreateCustomTaskDialog.updateModelFromView title',self.widgets['title'].getValue()
    self.model.header.pluginName.set(self.widgets['name'].getValue())
    self.model.header.pluginTitle.set(self.widgets['title'].getValue())
  


  def help(self):
    WEBBROWSER().loadWebPage(helpFileName='customisation')

  def cancel(self):
    self.hide()

  def accept(self):
    if not self.model.name.isSet():
       QtGui.QMessageBox.warning(self,'Create Custom Task','Custom task name must be entered')
       return
    if self.model.name.validity(self.model.name.__str__()).maxSeverity() > SEVERITY_WARNING:
      QtGui.QMessageBox.warning(self,'Create Custom Task','Custom task name must be single word')
      return
    if not self.model.comLine.isSet():
       QtGui.QMessageBox.warning(self,'Create Custom Task','Custom command line must be entered')
       return
    tag = self.model.tagCharacter.__str__().strip()
    if len(tag)<0 or len(tag)>2:
      QtGui.QMessageBox.warning(self,'Create Custom Task','Tag character must be one or two characters')
      return

    paramNameList = self.paramNameList(tag)
    for param in paramNameList:
      obj,indx = self.model.paramList.getItemByName(param)
      if obj is None:
        QtGui.QMessageBox.warning(self,'Create Custom Task',"There are undefined parameters in the command line/file.\nPlease click 'Update parameters' and check the definitions in the parameter list")
        return

    mergedMtzs = CUSTOMTASKMANAGER().getMergedMtzs(self.model.paramList)
    #print 'CCreateCustomTaskDialog.accept mergedMtzs',mergedMtzs
    for key,value in mergedMtzs.items():
      if len(value)<=1:
         QtGui.QMessageBox.warning(self,'Create Custom Task',"The 'monster' MTZ: "+key+" is created from only one 'mini' MTZ: "+value[0]+'. ' + \
                                   "A 'monster' MTZ is expected to combine two or more 'mini' MTZs.")
         return

    defFile = CUSTOMTASKMANAGER().getCustomFile(name=self.model.name.__str__(),mustExist=True)
    if defFile is not None:
       msgBox = QtGui.QMessageBox()
       msgBox.setWindowTitle('Create custom task')
       msgBox.setText('There is already a custom task directory called '+self.model.name.__str__())
       b = msgBox.addButton(QtGui.QMessageBox.Cancel)
       b = msgBox.addButton('Overwrite',QtGui.QMessageBox.ApplyRole)
       import functools
       self.connect(b,QtCore.SIGNAL('released()'),functools.partial(self.createCustomTask,True))
       msgBox.exec_()
    else:        
      self.createCustomTask()
      self.hide()

  def createCustomTask(self,overwrite=False):
    self.hide()
    #try:
    err = CUSTOMTASKMANAGER().createCustomTask(name=self.model.name.__str__(),title=self.model.title.__str__(),container=self.model,overwrite=overwrite)
    '''
    except CException as err:
      pass
    except Exception as e:
       QtGui.QMessageBox.warning(self,'Create Custom Task',"Error saving custom task\n"+str(e))
       return
    ''' 
    if err.maxSeverity()>SEVERITY_WARNING:
      err.warningMessage('Create custom task','Error saving custom task',parent=self)
      return
    
    self.emit(QtCore.SIGNAL('customTaskCreated'),self.model.name.__str__())


  def updateParametersList(self):

    try:
      paramListCurrentRow = self.widgets['paramsList'].editItemIndex
      paramListCurrentRowName = self.model.paramList[paramListCurrentRow].name.__str__()
    except:
      paramListCurrentRowName = None
      
    self.updateModelFromView()
    tag = self.model.tagCharacter.__str__().strip()
    if len(tag)<0 or len(tag)>2:
      QtGui.MessageBox.warning(self,'Create Custom Task','Tag character must be one or two characters')
      return
    else:
      # Reset just in case the strip was necessary
      self.model.tagCharacter.set(tag)

    paramNameList = self.paramNameList(tag)

    '''
    for ii in range(len(self.model.paramList)-1,-1,-1):
      if not self.model.paramList[ii].name.__str__() in paramNameList:
        del self.model.paramList[ii]
    '''

    for param in paramNameList:
      obj,indx = self.model.paramList.getItemByName(param)
      if obj is None:
        self.model.paramList.append( { 'name' : param } )

    self.widgets['paramsList'].updateViewFromModel()
    if paramListCurrentRowName is not None:
      obj,indx = self.model.paramList.getItemByName(paramListCurrentRowName)
    else:
      indx = None
    if indx is None: indx = 0
    self.widgets['paramsList'].handleRowChange(row=indx,force=True)
    

  def paramNameList(self,tag='#'):
    paramNameList = CUSTOMTASKMANAGER().extractParams(tag,self.model.comLine.__str__())
    for ii in range(len(self.model.comFileList)):
      paramNameList.extend(CUSTOMTASKMANAGER().extractParams(tag,self.model.comFileList[ii].text.__str__()))
    return paramNameList


