#!/usr/bin/env python
##############################################################################
#
# PDFgui by DANSE Diffraction group
# Simon J. L. Billinge
# (c) 2006 trustees of the Michigan State University.
# All rights reserved.
#
# File coded by: Chris Farrow
#
# See AUTHORS.txt for a list of people who contributed.
# See LICENSE.txt for license information.
#
##############################################################################
"""Common methods used in the phase panels."""
import wx
from diffpy.utils.wx import gridutils
# List of row entries taken from the clipboard
clipcells = []
# String describing what atoms should be selected.
selected_atoms = ""
[docs]
def float2str(x):
"""Compact string representation of float."""
s = "%g" % x
if s.find(".") == -1 and s.find("e") == -1:
s = s + ".0"
return s
[docs]
def refreshTextCtrls(panel):
"""Refreshes the TextCtrls on the panel.
This is used by phaseconfigurepanel and phaseresultspanel.
This method updates the following TextCtrls with with contents of
the structure member variable of the panel. textCtrlA textCtrlB
textCtrlC textCtrlAlpha textCtrlBeta textCtrlGamma
textCtrlScaleFactor textCtrlDelta1 textCtrlDelta2 textCtrlSratio
textCtrlRcut textCtrlStepcut textCtrlSpdiameter
"""
if panel.structure is None:
# clear textcontrols
panel.textCtrlA.SetValue("")
panel.textCtrlB.SetValue("")
panel.textCtrlC.SetValue("")
panel.textCtrlAlpha.SetValue("")
panel.textCtrlBeta.SetValue("")
panel.textCtrlGamma.SetValue("")
panel.textCtrlScaleFactor.SetValue("")
panel.textCtrlDelta1.SetValue("")
panel.textCtrlDelta2.SetValue("")
panel.textCtrlSratio.SetValue("")
panel.textCtrlRcut.SetValue("")
panel.textCtrlStepcut.SetValue("")
panel.textCtrlSpdiameter.SetValue("")
else:
# update panel with values from panel.structure
# update textctrls
panel.textCtrlA.SetValue(float2str(panel.structure.lattice.a))
panel.textCtrlB.SetValue(float2str(panel.structure.lattice.b))
panel.textCtrlC.SetValue(float2str(panel.structure.lattice.c))
panel.textCtrlAlpha.SetValue(float2str(panel.structure.lattice.alpha))
panel.textCtrlBeta.SetValue(float2str(panel.structure.lattice.beta))
panel.textCtrlGamma.SetValue(float2str(panel.structure.lattice.gamma))
panel.textCtrlScaleFactor.SetValue(float2str(panel.structure.pdffit["scale"]))
panel.textCtrlDelta1.SetValue(float2str(panel.structure.pdffit["delta1"]))
panel.textCtrlDelta2.SetValue(float2str(panel.structure.pdffit["delta2"]))
panel.textCtrlSratio.SetValue(float2str(panel.structure.pdffit["sratio"]))
panel.textCtrlRcut.SetValue(float2str(panel.structure.pdffit["rcut"]))
panel.textCtrlStepcut.SetValue(float2str(panel.structure.pdffit["stepcut"]))
panel.textCtrlSpdiameter.SetValue(float2str(panel.structure.pdffit["spdiameter"]))
return
[docs]
def refreshGrid(panel):
"""Refreshes grid on the panel.
This is used by phaseconfigurepanel and phaseresultspanel.
This method fills the grid with the contents of the structure member
variable of the panel. It is expected that the grid is named
'gridAtoms'.
"""
if panel.structure is None:
# remove all rows from grid
panel.gridAtoms.BeginBatch()
if panel.gridAtoms.GetNumberRows() != 0:
panel.gridAtoms.DeleteRows(numRows=panel.gridAtoms.GetNumberRows())
panel.gridAtoms.EndBatch()
else:
# update the grid with atoms
panel.gridAtoms.BeginBatch()
# set column labels
panel.gridAtoms.SetColLabelValue(0, "elem")
panel.gridAtoms.SetColLabelValue(1, "x")
panel.gridAtoms.SetColLabelValue(2, "y")
panel.gridAtoms.SetColLabelValue(3, "z")
panel.gridAtoms.SetColLabelValue(4, "u11")
panel.gridAtoms.SetColLabelValue(5, "u22")
panel.gridAtoms.SetColLabelValue(6, "u33")
panel.gridAtoms.SetColLabelValue(7, "u12")
panel.gridAtoms.SetColLabelValue(8, "u13")
panel.gridAtoms.SetColLabelValue(9, "u23")
panel.gridAtoms.SetColLabelValue(10, "occ")
# make sure grid has correct number of rows and blank it
natoms = len(panel.structure)
nrows = panel.gridAtoms.GetNumberRows()
if natoms > nrows:
panel.gridAtoms.InsertRows(numRows=natoms - nrows)
elif natoms < nrows:
panel.gridAtoms.DeleteRows(numRows=nrows - natoms)
panel.gridAtoms.ClearGrid()
for i, atom in enumerate(panel.structure):
panel.gridAtoms.SetCellValue(i, 0, str(atom.element)) # element
panel.gridAtoms.SetCellValue(i, 1, float2str(atom.xyz[0])) # x
panel.gridAtoms.SetCellValue(i, 2, float2str(atom.xyz[1])) # y
panel.gridAtoms.SetCellValue(i, 3, float2str(atom.xyz[2])) # z
panel.gridAtoms.SetCellValue(i, 4, float2str(atom.U[0, 0])) # U(1,1)
panel.gridAtoms.SetCellValue(i, 5, float2str(atom.U[1, 1])) # U(2,2)
panel.gridAtoms.SetCellValue(i, 6, float2str(atom.U[2, 2])) # U(3,3)
panel.gridAtoms.SetCellValue(i, 7, float2str(atom.U[0, 1])) # U(1,2)
panel.gridAtoms.SetCellValue(i, 8, float2str(atom.U[0, 2])) # U(1,3)
panel.gridAtoms.SetCellValue(i, 9, float2str(atom.U[1, 2])) # U(2,3)
panel.gridAtoms.SetCellValue(i, 10, float2str(atom.occupancy)) # occupancy
panel.gridAtoms.AutosizeLabels()
panel.gridAtoms.AutoSizeColumns()
panel.gridAtoms.EndBatch()
panel.gridAtoms.AdjustScrollbars()
return
# Utility functions
[docs]
def showSelectAtomsDialog(panel):
"""Extend or limit selection to a string atom selection.
panel -- instance of PhaseConfigurePanel or PhaseConstraintsPanel
No return value.
"""
# do nothing for non-existent or empty structure
if not panel.structure:
return
msg = "\n".join(
[
'Specify index, symbol or "all", use "!" to subtract selection.',
'Examples: "Na", "1:4, 6, 9:10", "all, !Na".',
]
)
global selected_atoms
dlg = wx.TextEntryDialog(panel, msg, "Select Atoms", selected_atoms)
if dlg.ShowModal() == wx.ID_OK:
s1 = dlg.GetValue().strip()
rows = panel.structure.getSelectedIndices(s1)
selected_atoms = s1
if s1:
gridutils.limitSelectionToRows(panel.gridAtoms, rows)
dlg.Destroy()
return
[docs]
def canCopySelectedCells(panel):
"""Check to see if we can copy selected cells.
To be copyable, the cells must exist in a single block or there must
be a single cell selected. Note that a block that is selected by
individual cells is considered a collection of individual atoms, not
a block. This is default wxPython behavior.
"""
grid = panel.gridAtoms
topleft = grid.GetSelectionBlockTopLeft()
individuals = grid.GetSelectedCells()
numsel = len(topleft) + len(individuals)
return numsel == 1
[docs]
def canPasteIntoCells(panel):
"""Check if clipboard contents are formatted for grid insertion.
This also checks to see if the cell selection is appropriate for
pasting.
"""
grid = panel.gridAtoms
individuals = grid.GetSelectedCells()
topleft = grid.GetSelectionBlockTopLeft()
if len(individuals) + len(topleft) != 1:
return False
# Get the text
if not wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
return False
textdata = wx.TextDataObject()
if not wx.TheClipboard.IsOpened():
opened = wx.TheClipboard.Open()
if not opened:
return False
success = wx.TheClipboard.GetData(textdata)
wx.TheClipboard.Close()
if not success:
return False
copytext = textdata.GetText()
# Remove any trailing newline
copytext = copytext.rstrip("\n")
# Make sure it is of the appropriate format
try:
rowlist = copytext.split("\n")
# Strip any trailing tabs
rowlist = [r.rstrip("\t") for r in rowlist]
celllist = [r.split("\t") for r in rowlist]
except wx.PyDeadObjectError:
return False
if len(celllist) == 0:
return False
ncol = len(celllist[0])
for row in celllist:
if len(row) != ncol:
return False
if ncol == 0:
return False
global clipcells
clipcells = celllist
return True
[docs]
def copySelectedCells(panel):
"""Copy block of selected cells or individual cell into clipboard.
This stores the cells as a plain text grid so that it can be copied
to and from other applications. Columns are delimited by tabs '\t'.
Rows are delimited by newlines '\n'.
"""
grid = panel.gridAtoms
copytext = ""
# Get the cells
individuals = grid.GetSelectedCells()
topleft = grid.GetSelectionBlockTopLeft()
bottomright = grid.GetSelectionBlockBottomRight()
if len(individuals) == 1:
copytext = str(grid.GetCellValue(individuals[0]))
elif len(topleft) == 1:
# Format the block of cells
rtl = topleft[0][0]
ctl = topleft[0][1]
rbr = bottomright[0][0]
cbr = bottomright[0][1]
for row in range(rtl, rbr + 1):
for col in range(ctl, cbr + 1):
copytext += str(grid.GetCellValue(row, col))
copytext += "\t"
copytext += "\n"
# Place the copytext into the clipboard
if not wx.TheClipboard.IsOpened():
opened = wx.TheClipboard.Open()
if not opened:
raise IOError("Cannot open the clipboard.")
textdata = wx.TextDataObject(copytext)
wx.TheClipboard.SetData(textdata)
wx.TheClipboard.Close()
return
[docs]
def pasteIntoCells(panel):
"""Paste clipboard contents into cells.
canPasteIntoCells must be called before this method in order to
format clipboard text for pasting.
"""
# Double check the clipcells
if len(clipcells) == 0:
return
if len(clipcells[0]) == 0:
return
grid = panel.gridAtoms
individuals = grid.GetSelectedCells()
topleft = grid.GetSelectionBlockTopLeft()
if len(individuals) > 0:
tl = individuals[0]
elif len(topleft) > 0:
tl = topleft[0]
else:
return
rtl = tl[0]
ctl = tl[1]
nrows = grid.GetNumberRows()
ncols = grid.GetNumberCols()
rbr = min(nrows, rtl + len(clipcells)) - 1
cbr = min(ncols, ctl + len(clipcells[0])) - 1
selections = []
for row in range(rtl, rbr + 1):
for col in range(ctl, cbr + 1):
if not grid.IsReadOnly(row, col):
oldvalue = panel.gridAtoms.GetCellValue(row, col)
newvalue = panel.applyCellChange(row, col, clipcells[row - rtl][col - ctl])
if newvalue is None:
newvalue = oldvalue
panel.gridAtoms.SetCellValue(row, col, str(newvalue))
selections.append((row, col))
gridutils.quickResizeColumns(panel.gridAtoms, selections)
# Clear the grid and select the inserted entries
grid.ClearSelection()
# panel.refresh()
for row in range(rtl, rbr + 1):
for col in range(ctl, cbr + 1):
if not grid.IsReadOnly(row, col):
grid.SelectBlock(row, col, row, col, True)
return
# End of file