Changeset 1057


Ignore:
Timestamp:
Sep 17, 2013 4:22:51 PM (10 years ago)
Author:
toby
Message:

reorg UserCalibrants? into ImageCalibrants?; Add trim (whitespace) routine; fix InstName? bug in GetHistogramPhaseData?; rework ValidatedTxtCtrl? for CIF; ScrolledMultiEditor? now resets after Cancel; CIF export progress

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/GSASIIIO.py

    r1034 r1057  
    2727import cPickle
    2828import sys
     29import re
    2930import random as ran
    3031import GSASIIpath
     
    5354    else:
    5455        return 0
     56
     57
     58def trim(val):
     59    '''Simplify a string containing leading and trailing spaces
     60    as well as newlines, tabs, repeated spaces etc. into a shorter and
     61    more simple string, by replacing all ranges of whitespace
     62    characters with a single space.
     63
     64    :param str val: the string to be simplified
     65
     66    :returns: the (usually) shortened version of the string
     67    '''
     68    return re.sub('\s+', ' ', val).strip()
    5569
    5670def makeInstDict(names,data,codes):
  • trunk/GSASIIgrid.py

    r1056 r1057  
    181181      upper limit is unbounded
    182182
    183     :param wx.Size size: an optional size parameter that dictates the
    184       size for the TextCtrl. None (the default) indicates that the
    185       default size should be used.
    186 
    187183    :param function OKcontrol: specifies a function or method that will be
    188184      called when the input is validated. The called function is supplied
     
    209205      be called.
    210206
    211     :param type typeHint: the value of typeHint is used if the initial value
    212       for the dict/list element ``loc[key]`` is None. In this case typeHint
    213       must be int or float, which specifies the type for input to the TextCtrl.
    214       Defaults as None.
     207    :param type typeHint: the value of typeHint is overrides the initial value
     208      for the dict/list element ``loc[key]``, if set to
     209      int or float, which specifies the type for input to the TextCtrl.
     210      Defaults as None, which is ignored.
     211
     212    :param bool CIFinput: for str input, indicates that only printable
     213      ASCII characters may be entered into the TextCtrl. Forces output
     214      to be ASCII rather than Unicode. For float and int input, allows
     215      use of a single '?' or '.' character as valid input.
     216
     217    :param (other): other optional keyword parameters for the
     218      wx.TextCtrl widget such as Size or Style may be specified.
    215219
    216220    '''
    217221    def __init__(self,parent,loc,key,notBlank=True,min=None,max=None,
    218                  size=None,OKcontrol=None,OnLeave=None,typeHint=None):
     222                 OKcontrol=None,OnLeave=None,typeHint=None,
     223                 CIFinput=False, **kw):
    219224        # save passed values needed outside __init__
    220225        self.result = loc
     
    222227        self.OKcontrol=OKcontrol
    223228        self.OnLeave = OnLeave
     229        self.CIFinput = CIFinput
    224230        # initialization
    225231        self.invalid = False   # indicates if the control has invalid contents
    226232        self.evaluated = False # set to True when the validator recognizes an expression
    227233        val = loc[key]
    228         if isinstance(val,int) or (val is None and typeHint is int):
     234        if isinstance(val,int) or typeHint is int:
    229235            wx.TextCtrl.__init__(
    230236                self,parent,wx.ID_ANY,
    231                 validator=NumberValidator(int,result=loc,key=key,min=min,max=max,
    232                                           OKcontrol=OKcontrol)
    233                 )
     237                validator=NumberValidator(int,result=loc,key=key,
     238                                          min=min,max=max,
     239                                          OKcontrol=OKcontrol,
     240                                          CIFinput=CIFinput),
     241                **kw)
    234242            if val is not None:
    235243                self.SetValue(str(val))
    236             else:
     244                try:
     245                    int(val)
     246                except:
     247                    if CIFinput and (val == '?' or val == '.'):
     248                        pass
     249                    else:
     250                        self.invalid = True
     251                        self._IndicateValidity()
     252            else: # no default is invalid for a number
    237253                self.ShowStringValidity()
    238         elif isinstance(val,float) or (val is None and typeHint is float):
     254
     255        elif isinstance(val,float) or typeHint is float:
    239256            wx.TextCtrl.__init__(
    240257                self,parent,wx.ID_ANY,
    241                 validator=NumberValidator(float,result=loc,key=key,min=min,max=max,
    242                                           OKcontrol=OKcontrol)
    243                 )
     258                validator=NumberValidator(float,result=loc,key=key,
     259                                          min=min,max=max,
     260                                          OKcontrol=OKcontrol,
     261                                          CIFinput=CIFinput),
     262                **kw)
    244263            if val is not None:
    245264                self.SetValue(str(val))
     265                try:
     266                    float(val)
     267                except:
     268                    if CIFinput and (val == '?' or val == '.'):
     269                        pass
     270                    else:
     271                        self.invalid = True
     272                        self._IndicateValidity()
    246273            else:
    247274                self.ShowStringValidity()
    248275        elif isinstance(val,str) or isinstance(val,unicode):
    249             wx.TextCtrl.__init__(self,parent,wx.ID_ANY,val)
     276            if self.CIFinput:
     277                wx.TextCtrl.__init__(
     278                    self,parent,wx.ID_ANY,val,
     279                    validator=ASCIIValidator(result=loc,key=key),
     280                    **kw)
     281            else:
     282                wx.TextCtrl.__init__(self,parent,wx.ID_ANY,val,**kw)
    250283            if notBlank:
    251284                self.Bind(wx.EVT_CHAR,self._onStringKey)
     
    259292            raise Exception,("ValidatedTxtCtrl error: Unknown element ("+str(key)+
    260293                             ") type: "+str(type(val)))
    261         if size: self.SetSize(size)
     294#        if size: self.SetSize(size)
    262295        # When the mouse is moved away or the widget loses focus
    263296        # display the last saved value, if an expression
     
    272305            wx.CallAfter(self.ShowStringValidity,False) # was valid
    273306
     307    def _IndicateValidity(self):
     308        'Set the control colors to show invalid input'
     309        if self.invalid:
     310            self.SetForegroundColour("red")
     311            self.SetBackgroundColour("yellow")
     312            self.SetFocus()
     313            self.Refresh()
     314        else: # valid input
     315            self.SetBackgroundColour(
     316                wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
     317            self.SetForegroundColour("black")
     318            self.Refresh()
     319
    274320    def ShowStringValidity(self,previousInvalid=None):
    275321        '''Check if input is valid. Anytime the input is
     
    284330        val = self.GetValue().strip()
    285331        self.invalid = not val
    286         'Set the control colors to show invalid input'
     332        self._IndicateValidity()
    287333        if self.invalid:
    288             self.SetForegroundColour("red")
    289             self.SetBackgroundColour("yellow")
    290             self.SetFocus()
    291             self.Refresh()
    292334            if self.OKcontrol:
    293335                self.OKcontrol(False)
    294         else: # valid input
    295             self.SetBackgroundColour(
    296                 wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
    297             self.SetForegroundColour("black")
    298             self.Refresh()
    299             if self.OKcontrol and previousInvalid:
    300                 self.OKcontrol(True)
    301         self.result[self.key] = val # always store the result
     336        elif self.OKcontrol and previousInvalid:
     337            self.OKcontrol(True)
     338        # always store the result
     339        if self.CIFinput:
     340            self.result[self.key] = val.encode('ascii','replace')
     341        else:
     342            self.result[self.key] = val
    302343
    303344    def _onLoseFocus(self,event):
     
    348389      an OK button for a window.
    349390      Ignored if None (default)
     391
     392    :param bool CIFinput: allows use of a single '?' or '.' character
     393      as valid input.
     394     
    350395    '''
    351396    def __init__(self, typ, positiveonly=False, min=None, max=None,
    352                  result=None, key=None, OKcontrol=None):
     397                 result=None, key=None, OKcontrol=None, CIFinput=False):
    353398        'Create the validator'
    354399        wx.PyValidator.__init__(self)
     
    361406        self.key = key
    362407        self.OKcontrol = OKcontrol
     408        self.CIFinput = CIFinput
    363409        # set allowed keys by data type
     410        self.Bind(wx.EVT_CHAR, self.OnChar)
    364411        if self.typ == int and self.positiveonly:
    365412            self.validchars = '0123456789'
     
    372419        else:
    373420            self.validchars = None
    374         self.Bind(wx.EVT_CHAR, self.OnChar)
     421            return
     422        if self.CIFinput:
     423            self.validchars += '?.'
    375424    def Clone(self):
    376425        'Create a copy of the validator, a strange, but required component'
    377426        return NumberValidator(typ=self.typ,
    378                           positiveonly=self.positiveonly,
    379                           min=self.min, max=self.max,
    380                           result=self.result, key=self.key,
    381                           OKcontrol=self.OKcontrol)
     427                               positiveonly=self.positiveonly,
     428                               min=self.min, max=self.max,
     429                               result=self.result, key=self.key,
     430                               OKcontrol=self.OKcontrol,
     431                               CIFinput=self.CIFinput)
    382432        tc = self.GetWindow()
    383433        tc.invalid = False # make sure the validity flag is defined in parent
     
    400450          is associated with.
    401451        '''
    402         tc.invalid = False # assume invalid
     452        tc.invalid = False # assume valid
     453        if self.CIFinput:
     454            val = tc.GetValue().strip()
     455            if val == '?' or val == '.':
     456                self.result[self.key] = val
     457                return
    403458        try:
    404459            val = self.typ(tc.GetValue())
     
    497552
    498553################################################################################
     554class ASCIIValidator(wx.PyValidator):
     555    '''A validator to be used with a TextCtrl to prevent
     556    entering characters other than ASCII characters.
     557   
     558    The value is checked for validity after every keystroke
     559      If an invalid number is entered, the box is highlighted.
     560      If the number is valid, it is saved in result[key]
     561
     562    :param dict/list result: List or dict where value should be placed when valid
     563
     564    :param any key: key to use for result (int for list)
     565
     566    '''
     567    def __init__(self, result=None, key=None):
     568        'Create the validator'
     569        import string
     570        wx.PyValidator.__init__(self)
     571        # save passed parameters
     572        self.result = result
     573        self.key = key
     574        self.validchars = string.ascii_letters + string.digits + string.punctuation + string.whitespace
     575        self.Bind(wx.EVT_CHAR, self.OnChar)
     576    def Clone(self):
     577        'Create a copy of the validator, a strange, but required component'
     578        return ASCIIValidator(result=self.result, key=self.key)
     579        tc = self.GetWindow()
     580        tc.invalid = False # make sure the validity flag is defined in parent
     581    def TransferToWindow(self):
     582        'Needed by validator, strange, but required component'
     583        return True # Prevent wxDialog from complaining.
     584    def TransferFromWindow(self):
     585        'Needed by validator, strange, but required component'
     586        return True # Prevent wxDialog from complaining.
     587    def TestValid(self,tc):
     588        '''Check if the value is valid by casting the input string
     589        into ASCII.
     590
     591        Save it in the dict/list where the initial value was stored
     592
     593        :param wx.TextCtrl tc: A reference to the TextCtrl that the validator
     594          is associated with.
     595        '''
     596        self.result[self.key] = tc.GetValue().encode('ascii','replace')
     597
     598    def OnChar(self, event):
     599        '''Called each type a key is pressed
     600        ignores keys that are not allowed for int and float types
     601        '''
     602        key = event.GetKeyCode()
     603        tc = self.GetWindow()
     604        if key == wx.WXK_RETURN:
     605            self.TestValid(tc)
     606            return
     607        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255: # control characters get processed
     608            event.Skip()
     609            self.TestValid(tc)
     610            return
     611        elif chr(key) in self.validchars: # valid char pressed?
     612            event.Skip()
     613            self.TestValid(tc)
     614            return
     615        if not wx.Validator_IsSilent():
     616            wx.Bell()
     617        return  # Returning without calling event.Skip, which eats the keystroke
     618################################################################################
     619class EnumSelector(wx.ComboBox):
     620    '''A customized :class:`wxpython.ComboBox` that selects items from a list
     621    of choices, but sets a dict (list) entry to the corresponding
     622    entry from the input list of values.
     623
     624    :param wx.Panel parent: the parent to the :class:`~wxpython.ComboBox` (usually a
     625      frame or panel)
     626    :param dict dct: a dict (or list) to contain the value set
     627      for the :class:`~wxpython.ComboBox`.
     628    :param item: the dict key (or list index) where ``dct[item]`` will
     629      be set to the value selected in the :class:`~wxpython.ComboBox`. Also, dct[item]
     630      contains the starting value shown in the widget. If the value
     631      does not match an entry in :data:`values`, the first value
     632      in :data:`choices` is used as the default, but ``dct[item]`` is
     633      not changed.   
     634    :param list choices: a list of choices to be displayed to the
     635      user such as
     636      ::
     637     
     638      ["default","option 1","option 2",]
     639
     640      Note that these options will correspond to the entries in
     641      :data:`values` (if specified) item by item.
     642    :param list values: a list of values that correspond to
     643      the options in :data:`choices`, such as
     644      ::
     645     
     646      [0,1,2]
     647     
     648      The default for :data:`values` is to use the same list as
     649      specified for :data:`choices`.
     650    :param (other): additional keyword arguments accepted by
     651      :class:`~wxpython.ComboBox` can be specified.
     652    '''
     653    def __init__(self,parent,dct,item,choices,values=None,**kw):
     654        if values is None:
     655            values = choices
     656        if dct[item] in values:
     657            i = values.index(dct[item])
     658        else:
     659            i = 0
     660        startval = choices[i]
     661        wx.ComboBox.__init__(self,parent,wx.ID_ANY,startval,
     662                             choices = choices,
     663                             style=wx.CB_DROPDOWN|wx.CB_READONLY,
     664                             **kw)
     665        self.choices = choices
     666        self.values = values
     667        self.dct = dct
     668        self.item = item
     669        self.Bind(wx.EVT_COMBOBOX, self.onSelection)
     670    def onSelection(self,event):
     671        # respond to a selection by setting the enum value in the CIF dictionary
     672        if self.GetValue() in self.choices: # should always be true!
     673            self.dct[self.item] = self.values[self.choices.index(self.GetValue())]
     674        else:
     675            self.dct[self.item] = self.values[0] # unknown
     676
     677################################################################################   
    499678def CallScrolledMultiEditor(parent,dictlst,elemlst,prelbl=[],postlbl=[],
    500679                 title='Edit items',header='',size=(300,250)):
     
    503682
    504683    :returns: True if the OK button is pressed; False if the window is closed
    505       with the system menu or the Close button.
     684      with the system menu or the Cancel button.
    506685
    507686    '''
     
    586765            style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
    587766        mainSizer = wx.BoxSizer(wx.VERTICAL)
    588         # ad a header if supplied
     767        self.orig = []
     768        self.dictlst = dictlst
     769        self.elemlst = elemlst
     770        for d,i in zip(dictlst,elemlst):
     771            self.orig.append(d[i])
     772        # add a header if supplied
    589773        if header:
    590774            subSizer = wx.BoxSizer(wx.HORIZONTAL)
     
    622806        mainSizer.Add(panel,1, wx.ALL|wx.EXPAND,1)
    623807
    624         # Sizer for OK/Close buttons. N.B. using Close rather than Cancel because
    625         # Cancel would imply that the changes should be discarded. In fact
    626         # any valid changes are retained, unless one makes a copy of the
    627         # input dicts & lists and restores them.
     808        # Sizer for OK/Close buttons. N.B. on Close changes are discarded
     809        # by restoring the initial values
    628810        btnsizer = wx.BoxSizer(wx.HORIZONTAL)
    629811        btnsizer.Add(self.OKbtn)
    630         btn = wx.Button(self, wx.ID_CLOSE)
     812        btn = wx.Button(self, wx.ID_CLOSE,"Cancel")
    631813        btn.Bind(wx.EVT_BUTTON,self._onClose)
    632814        btnsizer.Add(btn)
     
    638820
    639821    def _onClose(self,event):
    640         'Close the window'
     822        'Restore original values & close the window'
     823        for d,i,v in zip(self.dictlst,self.elemlst,self.orig):
     824            d[i] = v
    641825        self.EndModal(wx.ID_CANCEL)
    642826       
     
    9951179    def __init__(self,parent,title,prompt,value='',size=(200,-1)):
    9961180        wx.Dialog.__init__(self,parent,wx.ID_ANY,title,
    997             pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
     1181                           pos=wx.DefaultPosition,
     1182                           style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
    9981183        self.value = value
    9991184        self.prompt = prompt
     
    13751560                                   'GSAS-II Updates',
    13761561                                   wx.OK|wx.CANCEL)
    1377             if dlg.ShowModal() != wx.ID_OK: return
     1562            if dlg.ShowModal() != wx.ID_OK:
     1563                dlg.Destroy()
     1564                return
     1565        dlg.Destroy()
    13781566        print 'start updates'
    13791567        dlg = wx.MessageDialog(self.frame,
  • trunk/GSASIIimgGUI.py

    r1049 r1057  
    4545    '''
    4646    import ImageCalibrants as calFile
    47     try:
    48         import UserCalibrants as userFile
    49         calFile.Calibrants.update(userFile.Calibrants)
    50     except:
    51         pass
    5247#patch
    5348    if 'GonioAngles' not in data:
  • trunk/GSASIIobj.py

    r1046 r1057  
    610610   
    611611    '''
     612    import re
    612613    IDdict = {}
    613614    IDdict['phases'] = {}
  • trunk/GSASIIstrIO.py

    r1053 r1057  
    17621762                hfx = ':%d:'%(hId)
    17631763                for item in inst:
     1764                    if type(inst) is not list: continue # skip over non-refined items (such as InstName)
    17641765                    hapDict[hfx+item] = inst[item][1]
    17651766                pfx = str(pId)+':'+str(hId)+':'
  • trunk/ImageCalibrants.py

    r1049 r1057  
    33----------------------------------------
    44
    5 GSASII powder calibrants as a dictionary of substances commonly used for powder
    6 calibrations for image data.
     5GSASII powder calibrants as a dictionary ``ImageCalibrants.Calibrants`` with substances
     6commonly used for powder calibrations for image data.
    77
    8 Create your own in file UserCalibrants.py following the format shown here;
    9 if you use the same names given here your entries will replace the corresponding
    10 ones given here.
    11 Each entry consists of:
    12  'name':(Bravais no,(a,b,c,alpha,beta,gamma),no. lines skipped,(dmin,pixLimit,cutOff)
    13 Useful Bravais nos.: F-cubic=0,I-cubic=1,P-cubic=2,R3/m(hex)=3, P6=4, P4mmm=6
     8Each entry in ``ImageCalibrants`` consists of::
     9
     10  'key':([Bravais num,],[(a,b,c,alpha,beta,gamma),],no. lines skipped,(dmin,pixLimit,cutOff))
     11
     12as an example::
     13
     14  'LaB6  SRM660a':([2,],[(4.1569162,4.1569162,4.1569162,90,90,90),],0,(1.0,10,10)),
     15
     16or where "Bravais num" and "(a,b,...)" are repeated in the case of mixtures::
     17
     18  'LaB6 & CeO2':([2,0], [(4.1569,4.1569,4.1569,90,90,90),(5.4117,5.4117,5.4117,90,90,90)], 0, (1.0,2,1)),
     19
     20To expand this list with locally needed additions, do not modify this file,
     21because you may lose these changes during a software update. Instead
     22duplicate the format of this file in a file named `UserCalibrants.py`
     23and there define the material(s) you want::
     24
     25  Calibrants={
     26    'LaB6 skip 2 lines':([2,],[(4.1569162,4.1569162,4.1569162,90,90,90),],2,(1.0,10,10)),
     27  }
     28
     29New key values will be added to the list of options.
     30If a key is duplicated, the information in  `UserCalibrants.py` will
     31override the information in this file.
     32
     33Note, some useful Bravais numbers are: F-cubic=0, I-cubic=1, P-cubic=2, R3/m (hex)=3, P6=4, P4mmm=6
    1434"""
    1535Calibrants={
     
    3151}
    3252   
     53# this should not be duplicated in the UserCalibrants.py file:
     54try:
     55    import UserCalibrants as userFile
     56    Calibrants.update(userFile.Calibrants)
     57except:
     58    pass
  • trunk/exports/G2cif.py

    r1045 r1057  
    2525#reload(G2IO)
    2626import GSASIIgrid as G2gd
     27reload(G2gd)
    2728import GSASIIstrIO as G2stIO
    2829#reload(G2stIO)
     
    3637#reload(G2pg)
    3738import GSASIIstrMain as G2stMn
    38 reload(G2stMn)
     39#reload(G2stMn)
    3940
    4041DEBUG = False    #True to skip printing of reflection/powder profile lists
     
    6667        '''
    6768   
     69        # ===== define functions for export method =======================================
    6870        def openCIF(filnam):
    6971            if DEBUG:
     
    115117            #WriteCIFitem('_refine_diff_density_max',rhomax)    #these need to be defined for each phase!
    116118            #WriteCIFitem('_refine_diff_density_min',rhomin)
    117             WriteCIFitem('_computing_structure_refinement','GSAS-II (Toby & Von Dreele, 2013)')
     119            WriteCIFitem('_computing_structure_refinement','GSAS-II (Toby & Von Dreele, J. Appl. Cryst. 46, 544-549, 2013)')
    118120            try:
    119121                vars = str(len(self.OverallParms['Covariance']['varyList']))
     
    854856                slam2 = self.sigDict.get('Lam2',-0.00009)
    855857                # always assume Ka1 & Ka2 if two wavelengths are present
     858                WriteCIFitem('_diffrn_radiation_type','K\\a~1,2~')
    856859                WriteCIFitem('loop_' +
    857860                             '\n\t_diffrn_radiation_wavelength' +
    858861                             '\n\t_diffrn_radiation_wavelength_wt' +
    859                              '\n\t_diffrn_radiation_type' +
    860862                             '\n\t_diffrn_radiation_wavelength_id')
    861863                WriteCIFitem('  ' + PutInCol(G2mth.ValEsd(lam1,slam1),15)+
    862864                             PutInCol('1.0',15) +
    863                              PutInCol('K\\a~1~',10) +
    864865                             PutInCol('1',5))
    865866                WriteCIFitem('  ' + PutInCol(G2mth.ValEsd(lam2,slam2),15)+
    866867                             PutInCol(G2mth.ValEsd(ratio,sratio),15)+
    867                              PutInCol('K\\a~2~',10) +
    868868                             PutInCol('2',5))               
    869869            else:
     
    903903                            )
    904904                    WriteCIFitem('loop_' +
    905                                  '\n\t_pd_proc_ls_R_F_factor' +
    906                                  '\n\t_pd_proc_ls_R_Fsqd_factor')
     905                                 '\n\t_gsas_proc_phase_R_F_factor' +
     906                                 '\n\t_gsas_proc_phase_R_Fsqd_factor' +
     907                                 '\n\t_gsas_proc_phase_id' +
     908                                 '\n\t_gsas_proc_phase_block_id')
    907909                    for phasenam in phasebyhistDict.get(histlbl):
    908910                        pfx = str(self.Phases[phasenam]['pId'])+':'+str(hId)+':'
     
    910912                            '  '+
    911913                            '  '+G2mth.ValEsd(histblk[pfx+'Rf']/100.,-.00009) +
    912                             '  '+G2mth.ValEsd(histblk[pfx+'Rf^2']/100.,-.00009)
     914                            '  '+G2mth.ValEsd(histblk[pfx+'Rf^2']/100.,-.00009)+
     915                            '  '+str(self.Phases[phasenam]['pId'])+
     916                            '  '+datablockidDict[phasenam]
    913917                            )
    914918            else:
     919                # single phase in this histogram
    915920                pfx = '0:'+str(hId)+':'
    916                 WriteCIFitem('_pd_proc_ls_R_F_factor      ','%.5f'%(histblk[pfx+'Rf']/100.))
    917                 WriteCIFitem('_pd_proc_ls_R_Fsqd_factor   ','%.5f'%(histblk[pfx+'Rf^2']/100.))
     921                WriteCIFitem('_refine_ls_R_F_factor      ','%.5f'%(histblk[pfx+'Rf']/100.))
     922                WriteCIFitem('_refine_ls_R_Fsqd_factor   ','%.5f'%(histblk[pfx+'Rf^2']/100.))
    918923               
    919924            WriteCIFitem('_pd_proc_ls_prof_R_factor   ','%.5f'%(histblk['R']/100.))
    920925            WriteCIFitem('_pd_proc_ls_prof_wR_factor  ','%.5f'%(histblk['wR']/100.))
    921             WriteCIFitem('_pd_proc_ls_prof_R_B_factor ','%.5f'%(histblk['Rb']/100.))
    922             WriteCIFitem('_pd_proc_ls_prof_wR_B_factor','%.5f'%(histblk['wRb']/100.))
     926            WriteCIFitem('_gsas_proc_ls_prof_R_B_factor ','%.5f'%(histblk['Rb']/100.))
     927            WriteCIFitem('_gsas_proc_ls_prof_wR_B_factor','%.5f'%(histblk['wRb']/100.))
    923928            WriteCIFitem('_pd_proc_ls_prof_wR_expected','%.5f'%(histblk['wRmin']/100.))
    924929
     
    11451150            WriteCIFitem('_reflns_R_F_factor_obs   ','%.4f'%(histblk[pfx+'Rf']/100.))
    11461151            WriteCIFitem('_reflns_R_Fsqd_factor_obs','%.4f'%(histblk[pfx+'Rf^2']/100.))
    1147 
    1148         #============================================================
     1152        def EditAuthor(event=None):
     1153            'Edit the CIF author name'
     1154            dlg = G2gd.SingleStringDialog(self.G2frame,
     1155                                          'Get CIF Author',
     1156                                          'Provide CIF Author name (Last, First)',
     1157                                          value=self.author)
     1158            if not dlg.Show():
     1159                dlg.Destroy()
     1160                return False  # cancel was pressed
     1161            self.author = dlg.GetValue()
     1162            dlg.Destroy()
     1163            try:
     1164                self.OverallParms['Controls']["Author"] = self.author # save for future
     1165            except KeyError:
     1166                pass
     1167            return True
     1168        def EditInstNames(event=None,msg=''):
     1169            'Provide a dialog for editing instrument names'
     1170            dictlist = []
     1171            keylist = []
     1172            lbllist = []
     1173            for hist in self.Histograms:
     1174                if hist.startswith("PWDR"):
     1175                    key2 = "Sample Parameters"
     1176                    d = self.Histograms[hist][key2]
     1177                elif hist.startswith("HKLF"):
     1178                    key2 = "Instrument Parameters"
     1179                    d = self.Histograms[hist][key2][0]
     1180                   
     1181                lbllist.append(hist)
     1182                dictlist.append(d)
     1183                keylist.append('InstrName')
     1184                instrname = d.get('InstrName')
     1185                if instrname is None:
     1186                    d['InstrName'] = ''
     1187            return G2gd.CallScrolledMultiEditor(
     1188                self.G2frame,dictlist,keylist,
     1189                prelbl=range(1,len(dictlist)+1),
     1190                postlbl=lbllist,
     1191                title='Instrument names',
     1192                header="Edit instrument names. Note that a non-blank\nname is required for all histograms"+msg)
     1193        def EditCIFDefaults(parent):
     1194            import wx.lib.scrolledpanel as wxscroll
     1195            cfrm = wx.Dialog(parent,style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
     1196            cfrm.SetTitle('child')
     1197            vbox = wx.BoxSizer(wx.VERTICAL)
     1198            cpnl = wxscroll.ScrolledPanel(cfrm,size=(300,300))
     1199            cbox = wx.BoxSizer(wx.VERTICAL)
     1200            but = wx.Button(cpnl, wx.ID_ANY,'Edit CIF Author')
     1201            but.Bind(wx.EVT_BUTTON,EditAuthor)
     1202            cbox.Add(but,0,wx.ALIGN_CENTER,3)
     1203            but = wx.Button(cpnl, wx.ID_ANY,'Edit Instrument Name(s)')
     1204            but.Bind(wx.EVT_BUTTON,EditInstNames)
     1205            cbox.Add(but,0,wx.ALIGN_CENTER,3)
     1206
     1207            cpnl.SetSizer(cbox)
     1208            cpnl.SetAutoLayout(1)
     1209            cpnl.SetupScrolling()
     1210            #cpnl.Bind(rw.EVT_RW_LAYOUT_NEEDED, self.OnLayoutNeeded)
     1211            cpnl.Layout()
     1212
     1213            vbox.Add(cpnl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 0)
     1214            btnsizer = wx.StdDialogButtonSizer()
     1215            btn = wx.Button(cfrm, wx.ID_OK, "Create CIF")
     1216            btn.SetDefault()
     1217            btnsizer.AddButton(btn)
     1218            btn = wx.Button(cfrm, wx.ID_CANCEL)
     1219            btnsizer.AddButton(btn)
     1220            btnsizer.Realize()
     1221            vbox.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)
     1222            cfrm.SetSizer(vbox)
     1223            vbox.Fit(cfrm)
     1224            if cfrm.ShowModal() == wx.ID_OK:
     1225                val = True
     1226            else:
     1227                val = False
     1228            cfrm.Destroy()
     1229            return val           
     1230
     1231        # ===== end of functions for export method =======================================
     1232        #=================================================================================
     1233
    11491234        # the export process starts here
    11501235        # load all of the tree into a set of dicts
     
    11711256                self.xtalDict[i] = hist
    11721257        # is there anything to export?
    1173         if len(self.Phases) + len(self.powderDict) + len(self.xtalDict) == 0:
    1174             self.G2frame.ErrorDialog(
    1175                 'Empty project',
    1176                 'No data or phases to include in CIF')
    1177             return
    1178         # is there a file name defined?
     1258        if len(self.Phases) == len(self.powderDict) == len(self.xtalDict) == 0:
     1259           self.G2frame.ErrorDialog(
     1260               'Empty project',
     1261               'Project does not contain interconnected data & phase(s)')
     1262           return
     1263        # get the project file name
    11791264        self.CIFname = os.path.splitext(
    11801265            os.path.split(self.G2frame.GSASprojectfile)[1]
    11811266            )[0]
    11821267        self.CIFname = self.CIFname.replace(' ','')
    1183         if not self.CIFname:
    1184             self.G2frame.ErrorDialog(
    1185                 'No GPX name',
    1186                 'Please save the project to provide a name')
    1187             return
     1268        if not self.CIFname: # none defined & needed, save as GPX to get one
     1269            self.G2frame.OnFileSaveas(None)
     1270            if not self.G2frame.GSASprojectfile: return
     1271            self.CIFname = os.path.splitext(
     1272                os.path.split(self.G2frame.GSASprojectfile)[1]
     1273                )[0]
     1274            self.CIFname = self.CIFname.replace(' ','')
    11881275        # test for quick CIF mode or no data
    11891276        self.quickmode = False
     
    12171304            pass
    12181305        while not (self.author or self.quickmode):
    1219             dlg = G2gd.SingleStringDialog(self.G2frame,'Get CIF Author','Provide CIF Author name (Last, First)')
    1220             if not dlg.Show(): return # cancel was pressed
    1221             self.author = dlg.GetValue()
    1222             dlg.Destroy()
    1223         try:
    1224             self.OverallParms['Controls']["Author"] = self.author # save for future
    1225         except KeyError:
    1226             pass
     1306            if not EditAuthor(): return
    12271307        self.shortauthorname = self.author.replace(',','').replace(' ','')[:20]
    12281308
    1229         # check the instrument name for every histogram
     1309        # check there is an instrument name for every histogram
    12301310        if not self.quickmode:
    1231             dictlist = []
    1232             keylist = []
    1233             lbllist = []
    12341311            invalid = 0
    12351312            key3 = 'InstrName'
     
    12401317                elif hist.startswith("HKLF"):
    12411318                    key2 = "Instrument Parameters"
    1242                     d = self.Histograms[hist][key2][0]
    1243                    
    1244                 lbllist.append(hist)
    1245                 dictlist.append(d)
    1246                 keylist.append(key3)
     1319                    d = self.Histograms[hist][key2][0]                   
    12471320                instrname = d.get(key3)
    12481321                if instrname is None:
     
    12581331                    "File/Copy option to duplicate the name"
    12591332                    )
    1260                 if not G2gd.CallScrolledMultiEditor(
    1261                     self.G2frame,dictlist,keylist,
    1262                     prelbl=range(1,len(dictlist)+1),
    1263                     postlbl=lbllist,
    1264                     title='Instrument names',
    1265                     header="Edit instrument names. Note that a non-blank\nname is required for all histograms"+msg,
    1266                     ): return
     1333                if not EditInstNames(msg=msg): return
     1334        # check for a distance-angle range search range for each phase
     1335        if not self.quickmode:
     1336            for phasenam in sorted(self.Phases.keys()):
     1337                i = self.Phases[phasenam]['pId']
     1338                phasedict = self.Phases[phasenam] # pointer to current phase info           
     1339                generalData = phasedict['General']
     1340                if 'DisAglCtls' not in generalData:
     1341                    dlg = G2gd.DisAglDialog(self.G2frame,{},generalData)
     1342                    if dlg.ShowModal() == wx.ID_OK:
     1343                        generalData['DisAglCtls'] = dlg.GetData()
     1344                    else:
     1345                        dlg.Destroy()
     1346                        return
     1347                    dlg.Destroy()
    12671348
    12681349        if oneblock and not self.quickmode:
    12691350            # select a dataset to use (there should only be one set in one block,
    1270             # but take whatever comes 1st
     1351            # but take whatever comes 1st)
    12711352            for hist in self.Histograms:
    12721353                histblk = self.Histograms[hist]
     
    12821363            fil = self.defSaveFile()
    12831364        if not fil: return
    1284         openCIF(fil)
     1365        if not self.quickmode: # give the user a chance to edit all defaults
     1366            if not EditCIFDefaults(self.G2frame): return
    12851367        #======================================================================
    12861368        # Start writing the CIF - single block
    12871369        #======================================================================
     1370        openCIF(fil)
    12881371        if oneblock:
    12891372            WriteCIFitem('data_'+self.CIFname)
Note: See TracChangeset for help on using the changeset viewer.