1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 __id__ = "$Id: phaseconstraintspanel.py 2981 2009-04-02 02:13:58Z farrowch $"
20
21 import re
22 import wx
23 import wx.grid
24 from diffpy.pdfgui.control.constraint import Constraint
25 from diffpy.pdfgui.control.controlerrors import *
26 from diffpy.pdfgui.gui.pdfpanel import PDFPanel
27 from diffpy.pdfgui.gui.tooltips import phasepanel as toolTips
28 from diffpy.pdfgui.gui.wxExtensions.autowidthlabelsgrid import \
29 AutoWidthLabelsGrid
30 from diffpy.pdfgui.gui.wxExtensions.textctrlutils import textCtrlAsGridCell
31 from diffpy.pdfgui.gui.sgconstraindialog import SGConstrainDialog
32 from diffpy.pdfgui.gui import phasepanelutils
33
36 PDFPanel.__init__(self)
37
38 kwds["style"] = wx.TAB_TRAVERSAL
39 wx.Panel.__init__(self, *args, **kwds)
40 self.sizerLatticeParameters_staticbox = wx.StaticBox(self, -1, "")
41 self.sizerAdditionalParameters_staticbox = wx.StaticBox(self, -1, "")
42 self.sizerAtoms_staticbox = wx.StaticBox(self, -1, "")
43 self.sizerPanelName_staticbox = wx.StaticBox(self, -1, "")
44 self.labelPanelName = wx.StaticText(self, -1, "Phase Constraints")
45 self.labelA = wx.StaticText(self, -1, "a")
46 self.textCtrlA = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
47 self.labelB = wx.StaticText(self, -1, "b")
48 self.textCtrlB = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
49 self.labelC = wx.StaticText(self, -1, "c")
50 self.textCtrlC = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
51 self.labelAlpha = wx.StaticText(self, -1, "alpha")
52 self.textCtrlAlpha = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
53 self.labelBeta = wx.StaticText(self, -1, "beta")
54 self.textCtrlBeta = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
55 self.labelGamma = wx.StaticText(self, -1, "gamma")
56 self.textCtrlGamma = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
57 self.labelScaleFactor = wx.StaticText(self, -1, "Scale Factor")
58 self.textCtrlScaleFactor = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
59 self.labelDelta1 = wx.StaticText(self, -1, "delta1")
60 self.textCtrlDelta1 = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
61 self.labelDelta2 = wx.StaticText(self, -1, "delta2")
62 self.textCtrlDelta2 = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
63 self.labelSpdiameter = wx.StaticText(self, -1, "spdiameter")
64 self.textCtrlSpdiameter = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
65 self.labelSratio = wx.StaticText(self, -1, "sratio")
66 self.textCtrlSratio = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER)
67 self.labelRcut = wx.StaticText(self, -1, "rcut")
68 self.textCtrlRcut = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER|wx.TE_READONLY)
69 self.labelStepcut = wx.StaticText(self, -1, "stepcut")
70 self.textCtrlStepcut = wx.TextCtrl(self, -1, "", style=wx.TE_PROCESS_ENTER|wx.TE_READONLY)
71 self.labelIncludedPairs = wx.StaticText(self, -1, "Included Pairs")
72 self.textCtrlIncludedPairs = wx.TextCtrl(self, -1, "all-all", style=wx.TE_READONLY)
73 self.gridAtoms = AutoWidthLabelsGrid(self, -1, size=(1, 1))
74
75 self.__set_properties()
76 self.__do_layout()
77
78 self.Bind(wx.grid.EVT_GRID_CMD_CELL_RIGHT_CLICK, self.onCellRightClick, self.gridAtoms)
79 self.Bind(wx.grid.EVT_GRID_CMD_EDITOR_SHOWN, self.onEditorShown, self.gridAtoms)
80 self.Bind(wx.grid.EVT_GRID_CMD_LABEL_RIGHT_CLICK, self.onLabelRightClick, self.gridAtoms)
81 self.Bind(wx.grid.EVT_GRID_CMD_CELL_CHANGE, self.onCellChange, self.gridAtoms)
82
83 self.__customProperties()
84
86
87 self.labelPanelName.SetFont(wx.Font(18, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
88 self.labelA.SetToolTipString("lat(1)")
89 self.textCtrlA.SetToolTipString("lat(1)")
90 self.labelB.SetToolTipString("lat(2)")
91 self.textCtrlB.SetToolTipString("lat(2)")
92 self.labelC.SetToolTipString("lat(3)")
93 self.textCtrlC.SetToolTipString("lat(3)")
94 self.labelAlpha.SetToolTipString("lat(4)")
95 self.textCtrlAlpha.SetToolTipString("lat(4)")
96 self.labelBeta.SetToolTipString("lat(5)")
97 self.textCtrlBeta.SetToolTipString("lat(5)")
98 self.labelGamma.SetToolTipString("lat(6)")
99 self.textCtrlGamma.SetToolTipString("lat(6)")
100 self.labelScaleFactor.SetToolTipString("phase scale factor")
101 self.textCtrlScaleFactor.SetToolTipString("phase scale")
102 self.labelDelta1.SetToolTipString("linear atomic correlation factor")
103 self.textCtrlDelta1.SetToolTipString("linear atomic correlation factor")
104 self.labelDelta2.SetToolTipString("quadratic atomic correlation factor")
105 self.textCtrlDelta2.SetToolTipString("quadratic atomic correlation factor")
106 self.labelSpdiameter.SetToolTipString("spherical nanoparticle amplitude correction")
107 self.textCtrlSpdiameter.SetToolTipString("spherical nanoparticle amplitude correction")
108 self.labelSratio.SetToolTipString("low r peak sharpening")
109 self.textCtrlSratio.SetToolTipString("low r peak sharpening")
110 self.labelRcut.SetToolTipString("peak sharpening cutoff")
111 self.textCtrlRcut.SetToolTipString("peak sharpening cutoff")
112 self.labelStepcut.SetToolTipString("cutoff for profile step-function")
113 self.textCtrlStepcut.SetToolTipString("cutoff for profile step-function")
114 self.textCtrlIncludedPairs.SetMinSize((240, 25))
115 self.gridAtoms.CreateGrid(0, 11)
116 self.gridAtoms.EnableDragRowSize(0)
117 self.gridAtoms.SetColLabelValue(0, "elem")
118 self.gridAtoms.SetColLabelValue(1, "x")
119 self.gridAtoms.SetColLabelValue(2, "y")
120 self.gridAtoms.SetColLabelValue(3, "z")
121 self.gridAtoms.SetColLabelValue(4, "u11")
122 self.gridAtoms.SetColLabelValue(5, "u22")
123 self.gridAtoms.SetColLabelValue(6, "u33")
124 self.gridAtoms.SetColLabelValue(7, "u12")
125 self.gridAtoms.SetColLabelValue(8, "u13")
126 self.gridAtoms.SetColLabelValue(9, "u23")
127 self.gridAtoms.SetColLabelValue(10, "occ")
128
129 self.setToolTips(toolTips)
130
131
133
134 sizerMain = wx.BoxSizer(wx.VERTICAL)
135 sizerAtoms = wx.StaticBoxSizer(self.sizerAtoms_staticbox, wx.VERTICAL)
136 sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
137 sizerAdditionalParameters = wx.StaticBoxSizer(self.sizerAdditionalParameters_staticbox, wx.HORIZONTAL)
138 grid_sizer_4 = wx.FlexGridSizer(3, 6, 0, 0)
139 sizerLatticeParameters = wx.StaticBoxSizer(self.sizerLatticeParameters_staticbox, wx.HORIZONTAL)
140 grid_sizer_3 = wx.FlexGridSizer(2, 6, 0, 0)
141 sizerPanelName = wx.StaticBoxSizer(self.sizerPanelName_staticbox, wx.HORIZONTAL)
142 sizerPanelName.Add(self.labelPanelName, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
143 sizerMain.Add(sizerPanelName, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 5)
144 grid_sizer_3.Add(self.labelA, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
145 grid_sizer_3.Add(self.textCtrlA, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
146 grid_sizer_3.Add(self.labelB, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
147 grid_sizer_3.Add(self.textCtrlB, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
148 grid_sizer_3.Add(self.labelC, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
149 grid_sizer_3.Add(self.textCtrlC, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
150 grid_sizer_3.Add(self.labelAlpha, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
151 grid_sizer_3.Add(self.textCtrlAlpha, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
152 grid_sizer_3.Add(self.labelBeta, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
153 grid_sizer_3.Add(self.textCtrlBeta, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
154 grid_sizer_3.Add(self.labelGamma, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
155 grid_sizer_3.Add(self.textCtrlGamma, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
156 sizerLatticeParameters.Add(grid_sizer_3, 1, wx.EXPAND, 0)
157 sizerMain.Add(sizerLatticeParameters, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 5)
158 grid_sizer_4.Add(self.labelScaleFactor, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
159 grid_sizer_4.Add(self.textCtrlScaleFactor, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
160 grid_sizer_4.Add((20, 10), 0, 0, 0)
161 grid_sizer_4.Add((20, 10), 0, 0, 0)
162 grid_sizer_4.Add((20, 10), 0, 0, 0)
163 grid_sizer_4.Add((20, 10), 0, 0, 0)
164 grid_sizer_4.Add(self.labelDelta1, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
165 grid_sizer_4.Add(self.textCtrlDelta1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
166 grid_sizer_4.Add(self.labelDelta2, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
167 grid_sizer_4.Add(self.textCtrlDelta2, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
168 grid_sizer_4.Add(self.labelSpdiameter, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
169 grid_sizer_4.Add(self.textCtrlSpdiameter, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
170 grid_sizer_4.Add(self.labelSratio, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
171 grid_sizer_4.Add(self.textCtrlSratio, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
172 grid_sizer_4.Add(self.labelRcut, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
173 grid_sizer_4.Add(self.textCtrlRcut, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
174 grid_sizer_4.Add(self.labelStepcut, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
175 grid_sizer_4.Add(self.textCtrlStepcut, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0)
176 sizerAdditionalParameters.Add(grid_sizer_4, 1, wx.EXPAND, 0)
177 sizerMain.Add(sizerAdditionalParameters, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 5)
178 sizer_1.Add(self.labelIncludedPairs, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
179 sizer_1.Add(self.textCtrlIncludedPairs, 0, wx.ALL, 5)
180 sizerAtoms.Add(sizer_1, 0, wx.EXPAND, 0)
181 sizerAtoms.Add(self.gridAtoms, 1, wx.EXPAND, 0)
182 sizerMain.Add(sizerAtoms, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, 5)
183 self.SetSizer(sizerMain)
184 sizerMain.Fit(self)
185
186
187
188
189
191 """Custom properties for the panel."""
192 self.structure = None
193 self.constraints = {}
194 self.results = None
195 self._textctrls = ['textCtrlA', 'textCtrlB', 'textCtrlC',
196 'textCtrlAlpha', 'textCtrlBeta', 'textCtrlGamma',
197 'textCtrlScaleFactor', 'textCtrlDelta1', 'textCtrlDelta2',
198 'textCtrlSratio', 'textCtrlSpdiameter']
199 self._row = 0
200 self._col = 0
201 self._focusedText = None
202 self._selectedCells = []
203
204 for widget in self._textctrls:
205 self.__dict__[widget].Bind(wx.EVT_SET_FOCUS, self.onSetFocus)
206 self.__dict__[widget].Bind(wx.EVT_KILL_FOCUS, self.onKillFocus)
207 self.__dict__[widget].Bind(wx.EVT_KEY_DOWN, self.onTextCtrlKey)
208
209
210 self.lAtomConstraints = ['x','y','z',
211 'u11','u22','u33','u12','u13','u23','occ']
212
213 self.lConstraints = [
214 'lat(1)', 'lat(2)', 'lat(3)', 'lat(4)', 'lat(5)', 'lat(6)',
215 'pscale', 'delta1', 'delta2', 'sratio', 'spdiameter']
216 textCtrlIds = [getattr(self, n).GetId() for n in self._textctrls]
217 self._id2varname = dict(zip(textCtrlIds, self.lConstraints))
218
219
220 attr = wx.grid.GridCellAttr()
221 attr.SetReadOnly(True)
222 self.gridAtoms.SetColAttr(0, attr)
223 self.gridAtoms.SetColAttr(11, attr)
224
225
226 self.Bind(wx.EVT_KEY_DOWN, self.onKey)
227
228
229 self.labelRcut.Hide()
230 self.textCtrlRcut.Hide()
231 self.labelStepcut.Hide()
232 self.textCtrlStepcut.Hide()
233 return
234
235
236
237 onTextCtrlKey = textCtrlAsGridCell
238
240 """Cache the current structure and constraints for future comparison."""
241 pass
242
244 """Refresh wigets on the panel."""
245 if self.structure is None:
246 raise ValueError("structure is not defined.")
247
248 self.refreshTextCtrls()
249
250
251 natoms = len(self.structure)
252 nrows = self.gridAtoms.GetNumberRows()
253 self.gridAtoms.BeginBatch()
254
255 if natoms > nrows:
256 self.gridAtoms.InsertRows(numRows = natoms - nrows)
257 elif natoms < nrows:
258 self.gridAtoms.DeleteRows(numRows = nrows - natoms)
259
260
261 self.gridAtoms.ClearGrid()
262
263
264 for row, atom in zip(range(natoms), self.structure):
265 self.gridAtoms.SetCellValue(row, 0, atom.element)
266
267
268 bareAtomVarColumn = dict( zip(self.lAtomConstraints,
269 range(1, 1 + len(self.lAtomConstraints))) )
270 avpat = re.compile(r'(\w+)\((\d+)\)$')
271 for var, con in self.constraints.iteritems():
272 m = avpat.match(var)
273 if not m: continue
274 barevar = m.group(1)
275 if not barevar in bareAtomVarColumn: continue
276 column = bareAtomVarColumn[barevar]
277 row = int(m.group(2)) - 1
278 if not 0 <= row < natoms:
279 emsg = "Invalid variable index for %r" % var
280 raise ControlValueError(emsg)
281 self.gridAtoms.SetCellValue(row, column, con.formula)
282 barevar = re.sub(r'\(\d+\)$', '', var)
283 if not barevar in bareAtomVarColumn: continue
284
285 self.gridAtoms.AutosizeLabels()
286 self.gridAtoms.AutoSizeColumns()
287 self.gridAtoms.EndBatch()
288
289 self.gridAtoms.AdjustScrollbars()
290 self.gridAtoms.ForceRefresh()
291 return
292
294 """Refreshes the TextCtrls. """
295
296 for widget, var in zip(self._textctrls, self.lConstraints):
297 wobj = getattr(self, widget)
298 if var in self.constraints:
299 s = self.constraints[var].formula
300 else:
301 s = ""
302 wobj.SetValue(s)
303
304 pairs = self.structure.getSelectedPairs()
305 self.textCtrlIncludedPairs.SetValue(pairs)
306 return
307
308
309 - def applyTextCtrlChange(self, id, value):
310 """Update a structure according to a change in a TextCtrl.
311
312 id -- textctrl id
313 value -- new value
314 """
315 self.mainFrame.needsSave()
316 var = self._id2varname[id]
317 formula = value.strip()
318 if formula != "":
319 self.constraints[var] = Constraint(formula)
320 return self.constraints[var].formula
321 else:
322 self.constraints.pop(var, None)
323 return ""
324
326 """Update an atom according to a change in a cell.
327
328 i -- cell position
329 j -- cell position
330 value -- new value
331
332 returns the new value stored in the data object, or None if value is
333 somehow invalid.
334 """
335 self.mainFrame.needsSave()
336 key = self.lAtomConstraints[j-1] + '('+`i+1`+')'
337 formula = value.strip()
338 if formula != "":
339 self.constraints[key] = Constraint(formula)
340 return self.constraints[key].formula
341 else:
342 self.constraints.pop(key, None)
343 return ""
344 return
345
346
347
348
349
350
352 """Saves a TextCtrl value, to be compared in onKillFocuse later."""
353 self._focusedText = event.GetEventObject().GetValue()
354 return
355
357 """Check value of TextCtrl and update structure if necessary."""
358 if not self.mainFrame: return
359 textctrl = event.GetEventObject()
360 value = textctrl.GetValue()
361 if value != self._focusedText:
362 self.applyTextCtrlChange(textctrl.GetId(), value)
363 self.refreshTextCtrls()
364 self.mainFrame.needsSave()
365 self._focusedText = None
366 return
367
368
370 """Bring up right-click menu."""
371 if self.structure is not None:
372 dx = dy = 0
373 if event.GetRow() == -1:
374 dy = self.gridAtoms.GetGridCornerLabelWindow().GetSize().y
375 if event.GetCol() == -1:
376 dx = self.gridAtoms.GetGridCornerLabelWindow().GetSize().x
377
378
379 if len(self.structure) == 0:
380 self.popupMenu(self.gridAtoms, event.GetPosition().x-dx,
381 event.GetPosition().y-dy)
382 event.Skip()
383 return
384
386 """Bring up right-click menu."""
387 self._row = event.GetRow()
388 self._col = event.GetCol()
389
390
391
392 append = False
393 r = self._row
394 c = self._col
395 if self.gridAtoms.IsInSelection(r,c):
396 append = True
397 self.gridAtoms.SelectBlock(r,c,r,c,append)
398
399 self.popupMenu(self.gridAtoms, event.GetPosition().x, event.GetPosition().y)
400 event.Skip()
401 return
402
404 """Capture the focused text when the grid editor is shown."""
405 i = event.GetRow()
406 j = event.GetCol()
407 self._focusedText = self.gridAtoms.GetCellValue(i,j)
408 self._selectedCells = phasepanelutils.getSelectedCells(self)
409 return
410
412 """Update focused and selected text when a cell changes."""
413
414
415
416 i = event.GetRow()
417 j = event.GetCol()
418
419 value = self.gridAtoms.GetCellValue(i,j)
420 while (i,j) in self._selectedCells:
421 self._selectedCells.remove((i,j))
422
423 self._selectedCells.insert(0,(i,j))
424 self.fillCells(value)
425 self._focusedText = None
426 return
427
429 """Fill cells with a given value.
430
431 value -- string value to place into cells
432
433 This uses the member variable _selectedCells, a list of (i,j) tuples for
434 the selected cells.
435 """
436 for (i,j) in self._selectedCells:
437 if not self.gridAtoms.IsReadOnly(i,j):
438
439
440
441 oldvalue = self._focusedText
442 if oldvalue is None:
443 oldvalue = self.gridAtoms.GetCellValue(i,j)
444 self._focusedText = None
445 newvalue = self.applyCellChange(i,j, value)
446
447 if newvalue is None:
448
449
450 newvalue = oldvalue
451 self.gridAtoms.SetCellValue(i,j,str(newvalue))
452 break
453 else:
454 self.gridAtoms.SetCellValue(i,j,str(newvalue))
455
456 phasepanelutils.quickResizeColumns(self, self._selectedCells)
457 return
458
459
461 """Catch key events in the panel."""
462 key = event.GetKeyCode()
463
464
465 if event.ControlDown() and key == 65:
466 rows = self.gridAtoms.GetNumberRows()
467 cols = self.gridAtoms.GetNumberCols()
468 self.gridAtoms.SelectBlock(0,0,rows,cols)
469
470
471 elif key == 127:
472 self._selectedCells = phasepanelutils.getSelectedCells(self)
473 self.fillCells("")
474 self.mainFrame.needsSave()
475
476
477
478
479
480
481
482
483
484
485
486
487
488 else:
489 event.Skip()
490 return
491
492
493
494
496 """Creates the popup menu
497
498 window -- window, where to popup a menu
499 x -- x coordinate
500 y -- y coordinate
501 """
502
503 if not hasattr(self, "spaceGroupID"):
504 self.spaceGroupID = wx.NewId()
505 self.copyID = wx.NewId()
506 self.pasteID = wx.NewId()
507
508 self.Bind(wx.EVT_MENU, self.onPopupSpaceGroup, id=self.spaceGroupID)
509 self.Bind(wx.EVT_MENU, self.onPopupCopy, id=self.copyID)
510 self.Bind(wx.EVT_MENU, self.onPopupPaste, id=self.pasteID)
511
512
513 menu = wx.Menu()
514
515
516 menu.Append(self.spaceGroupID, "Symmetry constraints...")
517 menu.AppendSeparator()
518 menu.Append(self.copyID, "Copy")
519 menu.Append(self.pasteID, "Paste")
520
521
522 indices = phasepanelutils.getSelectedAtoms(self)
523 if not indices:
524 menu.Enable(self.spaceGroupID, False);
525
526
527 if not phasepanelutils.canCopySelectedCells(self):
528 menu.Enable(self.copyID, False)
529 if not phasepanelutils.canPasteIntoCells(self):
530 menu.Enable(self.pasteID, False)
531
532
533
534 window.PopupMenu(menu, wx.Point(x,y))
535 menu.Destroy()
536 return
537
559
564
569
570
571