#@+leo-ver=4-thin
#@+node:tbrown.20091029123555.5319:@thin attrib_edit.py
#@<< docstring >>
#@+node:tbrown.20091009210724.10972:<< docstring >>
'''
attrib_edit.py - Edit attributes in v.u
=======================================
This plugin creates a frame for editing attributes similar to::
Name: Fred Blogs
Home: 555-555-5555
Work: 555-555-5556
``attrib_edit`` is also intended to provide attribute editing for
other plugins, see below.
The attributes can be stored in different ways, three modes are implemented
currently:
"v.u mode"
These attributes are stored in the "unknownAttributes" (uA) data for
each node, accessed via ``v.u``.
"Field:"
Attributes are lines starting (no whitespace) with "AttributeName:" in
the body text.
"@Child"
Attributes are the head strings of child nodes when the head string
starts with '@AttributeName' where the first letter (second character)
must be capitalized.
The plugin defines the following commands, available either in the
plugin's sub-menu in the Plugins menu, or as ``Alt-X attrib-edit-*``.
attrib-edit-modes
Select which attribute setting / getting modes to use. More than one mode
can be used at the same time.
You can also control which modes are active by listing them in
``@settings -> @data attrib_edit_active_modes``, e.g.::
Field:
@Child
# v.u mode
would cause only the "Field:" and "@Child" modes to be active be default.
attrib-edit-manage
Select which attributes, from allattributesseenso import
far in this outline, to include on the current node.
attrib-edit-scan
Scan the entire outline for attributes so ``attrib-edit-manage``
has the complete list.
attrib-edit-create
Create a new attribute on the current node. If "Field:" or "@Child" modes
are active, they simply remind you how to create an attribute in the log pane.
If the "v.u mode" mode is active, you're prompted for a path for the attribute,
e.g.::
"addressbook First"
to store the attribute in v.u['addressbook']['_edit']['First']
As a convenience, entering a path like::
"todo metadata created|creator|revised"
would create::
v.u.['todo']['metadata']['_edit']['created']
v.u.['todo']['metadata']['_edit']['creator']
v.u.['todo']['metadata']['_edit']['revised']
Technical details
+++++++++++++++++
See the source for complete documentation for use with other
plugins, here are some points of interest:
- in addition to ``v.u['addressbook']['_edit']['first']`` paths
like ``v.u['addressbook']['_edit']['_int']['age']`` may be used
to identify type, although currently there's no difference in
the edit widget.
- in future the plugin may allow other plugins to register
to provide attribute path information, instead of just
scanning for ['_edit'] entries in v.u.
- currently there's no sorting of the attributes in "v.u mode", which is
a problem for some applications. It's unclear where the
desired order would be stored, without even more repetition
in v.u. When other plugins can register to manipulate the
attribute list each plugin could address this, with unordered
presentation in the absence of the client plugin.
- There's code to have the editor appear in a tab instead
of its own area under the body editor, but (a) this is
always being buried by output in the log window, and
(b) there's a bug which leaves some (harmless) ghost
widgets in the background. Enable by @setting
``attrib_edit_placement`` to 'tab'.
'''
#@-node:tbrown.20091009210724.10972:<< docstring >>
#@nl
#@@language python
#@@tabwidth -4
#@<< imports >>
#@+node:tbrown.20091009210724.10973:<< imports >>
import leo.core.leoGlobals as g
import re
if g.app.gui.guiName() == "qt":
import leo.core.leoPlugins as leoPlugins
import os
from PyQt4 import QtCore,QtGui
Qt = QtCore.Qt
#@-node:tbrown.20091009210724.10973:<< imports >>
#@nl
__version__ = "0.1"
#@<< version history >>
#@+node:tbrown.20091009210724.10974:<< version history >>
#@@killcolor
#@+at
#@nonl
# Use and distribute under the same terms as leo itself.
#
# 0.1 TNB
# - initial version
#@-at
#@nonl
#@-node:tbrown.20091009210724.10974:<< version history >>
#@nl
#@+others
#@+node:tbrown.20091009210724.10975:init
def init():
if g.app.gui.guiName() != "qt":
print('attrib_edit.py plugin not loading because gui is not Qt')
return False
leoPlugins.registerHandler('after-create-leo-frame',onCreate)
g.plugin_signon(__name__)
return True
#@-node:tbrown.20091009210724.10975:init
#@+node:tbrown.20091009210724.10976:onCreate
def onCreate (tag,key):
c = key.get('c')
attrib_edit_Controller(c)
#@-node:tbrown.20091009210724.10976:onCreate
#@+node:tbrown.20091103080354.1400:class AttributeGetter
class AttributeGetter(object):
implementations = []
typeMap = {
'_int': int,
'_float': float,
'_bool': bool,
}
@classmethod
def register(cls, subclass):
cls.implementations.append(subclass)
def __init__(self, c):
self.c = c
def name(self):
return "ABSTRACT VIRTUAL BASE CLASS"
def getAttribs(self, v):
raise NotImplemented
def setAttrib(self, v, path, value):
raise NotImplemented
def delAttrib(self, v, path):
raise NotImplemented
def helpCreate(self):
"""either a string telling user how to add an attribute, or
True if the Getter needs to help the user create an attribute"""
return "ABSTRACT VIRTUAL BASE CLASS"
def longDescrip(self, path):
"""give the long description of the attribute on path 'path'.
ASSUMES: path determines name
E.g. attribute named 'count' might be described as 'address.people.count'
"""
raise NotImplemented
#@-node:tbrown.20091103080354.1400:class AttributeGetter
#@+node:tbrown.20091103080354.1402:class AttributeGetterUA
class AttributeGetterUA(AttributeGetter):
#@ @+others
#@+node:tbrown.20091103080354.6240:__init__
def __init__(self, c):
AttributeGetter.__init__(self, c)
#@-node:tbrown.20091103080354.6240:__init__
#@+node:tbrown.20091103080354.1409:recSearch
def recSearch(self, d, path, ans):
"""recursive search of tree of dicts for values whose
key path is like [*][*][*]['_edit'][*] or
[*][*][*]['_edit']['_int'][*]
Modifies list ans
"""
for k in d:
if isinstance(d[k], dict):
if k not in ('_edit', '_view'):
self.recSearch(d[k], path+[k], ans)
else:
# k == '_edit' or '_view'
for ek in d[k]:
if ek in self.typeMap:
# ek is '_int' or similar
type_ = self.typeMap[ek]
for ekt in d[k][ek]:
ans.append((self,
ekt, d[k][ek][ekt], tuple(path+['_edit',ek,ekt]),
type_, k != '_edit'))
else:
ans.append((self,
ek, d[k][ek], tuple(path+['_edit',ek]), str, k != '_edit'))
#@-node:tbrown.20091103080354.1409:recSearch
#@+node:tbrown.20091103080354.1410:getAttribs
def getAttribs(self, v):
"""Return a list of tuples describing editable uAs.
(class, name, value, path, type, readonly)
e.g.
(AttributeGetterUA, 'created', '2009-09-23', ('stickynotes','_edit','created'), str, False),
(AttributeGetterUA, 'cars', 2, ('inventory','_edit','_int','cars'), int, False)
Changes should be written back to
v.uA['stickynotes']['_edit']['created'] and
v.uA['inventory']['_edit']['_int']['cars'] respectively
"""
ans = []
d = v.u
self.recSearch(d, [], ans)
return ans
#@-node:tbrown.20091103080354.1410:getAttribs
#@+node:tbrown.20091103080354.1430:setAttrib
def setAttrib(self, v, path, value):
"""copy value into dict a on path,
e.g. a['one']['more']['level'] = value
"""
a = v.u
for i in path[:-1]:
a = a.setdefault(i, {})
a[path[-1]] = value
#@-node:tbrown.20091103080354.1430:setAttrib
#@+node:tbrown.20091103080354.1438:delAttrib
def delAttrib(self, v, path):
a = v.u
for i in path[:-1]:
try:
a = a[i]
except KeyError:
return
try:
del a[path[-1]]
except KeyError:
pass
#@-node:tbrown.20091103080354.1438:delAttrib
#@+node:tbrown.20091103080354.1411:name
def name(self):
return "v.u mode"
#@nonl
#@-node:tbrown.20091103080354.1411:name
#@+node:tbrown.20091103080354.1431:helpCreate
def helpCreate(self):
"""does the Getter need to help the user create an attribute?"""
return True
#@nonl
#@-node:tbrown.20091103080354.1431:helpCreate
#@+node:tbrown.20091103080354.1432:createAttrib
def createAttrib(self, v, gui_parent=None):
path,ok = QtGui.QInputDialog.getText(gui_parent, "Enter attribute path",
"Enter path to attribute (space separated words)")
ns = str(path).split() # not the QString
if not ok or not ns:
g.es("Cancelled")
return
#FIXME type_ = {True: '_view', False: '_edit'}[readonly]
type_ = '_edit'
if '|' in ns[-1]:
nslist = [ ns[:-1] + [i.strip()] for i in ns[-1].split('|') ]
else:
nslist = [ns]
for ns in nslist:
if type_ not in ns:
ns.insert(-1, type_)
self.setAttrib(v, ns, '')
#FIXME self.attrPaths.add(tuple(ns))
#@-node:tbrown.20091103080354.1432:createAttrib
#@+node:tbrown.20091103080354.1433:longDescrip
def longDescrip(self, path):
return '.'.join([j for j in path if j not in ('_edit','_view')])
#@nonl
#@-node:tbrown.20091103080354.1433:longDescrip
#@-others
AttributeGetter.register(AttributeGetterUA)
#@-node:tbrown.20091103080354.1402:class AttributeGetterUA
#@+node:tbrown.20091103080354.1420:class AttributeGetterAt
class AttributeGetterAt(AttributeGetter):
#@ @+others
#@+node:tbrown.20091103080354.6238:__init__
def __init__(self, c):
AttributeGetter.__init__(self, c)
#@-node:tbrown.20091103080354.6238:__init__
#@+node:tbrown.20091103080354.1422:getAttribs
def getAttribs(self, v):
"""Return a list of tuples describing editable uAs.
(class, name, value, path, type, readonly)
e.g.
(AttributeGetterUA, 'created', '2009-09-23', ('stickynotes','_edit','created'), str, False),
(AttributeGetterUA, 'cars', 2, ('inventory','_edit','_int','cars'), int, False)
Changes should be written back to
v.uA['stickynotes']['_edit']['created'] and
v.uA['inventory']['_edit']['_int']['cars'] respectively
"""
ans = []
for n in v.children:
if n.h and n.h[0] == '@' and ('A' <= n.h[1] <= 'Z'):
words = n.h[1:].split(None, 1)
if not words:
continue
if len(words) == 1:
words.append('')
ans.append( (self, words[0], words[1], words[0], str, False) )
return ans
#@-node:tbrown.20091103080354.1422:getAttribs
#@+node:tbrown.20091103080354.6237:setAttrib
def setAttrib(self, v, path, value):
for n in v.children:
if n.h[0] == '@' and ('A' <= n.h[1] <= 'Z'):
words = n.h[1:].split(None, 1)
if len(words) == 1:
words.append('')
if words[0] == path:
n.h = "@%s %s" % (path, value)
break
else:
p = self.c.vnode2position(v)
n = p.insertAsLastChild()
n.h = "@%s %s" % (path, value)
#@-node:tbrown.20091103080354.6237:setAttrib
#@+node:tbrown.20091103080354.6244:delAttrib
def delAttrib(self, v, path):
for n in v.children:
if n.h[0] == '@' and ('A' <= n.h[1] <= 'Z'):
words = n.h[1:].split(None, 1)
if not words:
continue
if words[0] == path:
p = self.c.vnode2position(n)
p.doDelete()
break
#@-node:tbrown.20091103080354.6244:delAttrib
#@+node:tbrown.20091103080354.1423:name
def name(self):
return "@Child"
#@nonl
#@-node:tbrown.20091103080354.1423:name
#@+node:tbrown.20091103080354.1443:helpCreate
def helpCreate(self):
return "Add a child named '@AttributeName'"
#@nonl
#@-node:tbrown.20091103080354.1443:helpCreate
#@+node:tbrown.20091103080354.1435:longName
def longDescrip(self, path):
return path
#@nonl
#@-node:tbrown.20091103080354.1435:longName
#@-others
AttributeGetter.register(AttributeGetterAt)
#@-node:tbrown.20091103080354.1420:class AttributeGetterAt
#@+node:tbrown.20091103080354.1427:class AttributeGetterColon
class AttributeGetterColon(AttributeGetter):
#@ @+others
#@+node:tbrown.20091103080354.6242:__init__
def __init__(self, c):
AttributeGetter.__init__(self, c)
#@-node:tbrown.20091103080354.6242:__init__
#@+node:tbrown.20091103080354.1428:getAttribs
def getAttribs(self, v):
ans = []
parts = v.b.split('\n',100)
for i in parts[:99]:
if not i or i[0].isspace():
continue
words = i.split(None, 1)
if words and len(words[0]) and words[0][-1] == ':':
if len(words) == 1:
words.append('')
ans.append( (self, words[0][:-1], words[1], words[0][:-1], str, False) )
return ans
#@-node:tbrown.20091103080354.1428:getAttribs
#@+node:tbrown.20091103080354.6246:setAttrib
def setAttrib(self, v, path, value):
parts = v.b.split('\n',100)
for n,i in enumerate(parts[:99]):
words = i.split(None, 1)
if words and len(words[0]) and words[0][-1] == ':' and words[0][:-1] == path:
parts[n] = "%s: %s" % (path, value)
v.b = '\n'.join(parts)
break
else:
v.b = "%s: %s\n%s" % (path, value, v.b)
#@-node:tbrown.20091103080354.6246:setAttrib
#@+node:tbrown.20091103080354.6248:delAttrib
def delAttrib(self, v, path):
parts = v.b.split('\n',100)
for n,i in enumerate(parts[:99]):
words = i.split(None, 1)
if words and len(words[0]) and words[0][-1] == ':' and words[0][:-1] == path:
del parts[n]
v.b = '\n'.join(parts)
break
#@-node:tbrown.20091103080354.6248:delAttrib
#@+node:tbrown.20091103080354.1429:name
def name(self):
return "Field:"
#@nonl
#@-node:tbrown.20091103080354.1429:name
#@+node:tbrown.20091103080354.1441:helpCreate
def helpCreate(self):
return "Add 'AttributeName:' to the text"
#@nonl
#@-node:tbrown.20091103080354.1441:helpCreate
#@+node:tbrown.20091103080354.1437:longName
def longDescrip(self, path):
return path
#@nonl
#@-node:tbrown.20091103080354.1437:longName
#@-others
AttributeGetter.register(AttributeGetterColon)
#@-node:tbrown.20091103080354.1427:class AttributeGetterColon
#@+node:tbrown.20091028131637.1353:class ListDialog
class ListDialog(QtGui.QDialog):
#@ @+others
#@+node:tbrown.20091028131637.1354:__init__
def __init__(self, parent, title, text, entries):
self.entries = entries
QtGui.QDialog.__init__(self, parent)
vbox = QtGui.QVBoxLayout()
sa = QtGui.QScrollArea()
salo = QtGui.QVBoxLayout()
frame = QtGui.QFrame()
frame.setLayout(salo)
self.buttons = []
for entry in entries:
hbox = QtGui.QHBoxLayout()
cb = QtGui.QCheckBox(entry[0])
self.buttons.append(cb)
if entry[1]:
cb.setCheckState(Qt.Checked)
hbox.addWidget(cb)
salo.addLayout(hbox)
sa.setWidget(frame)
vbox.addWidget(sa)
hbox = QtGui.QHBoxLayout()
ok = QtGui.QPushButton("Ok")
cancel = QtGui.QPushButton("Cancel")
QtCore.QObject.connect(ok, QtCore.SIGNAL('clicked(bool)'), self.writeBack)
QtCore.QObject.connect(cancel, QtCore.SIGNAL('clicked(bool)'), self.reject)
hbox.addWidget(ok)
hbox.addWidget(cancel)
vbox.addLayout(hbox)
self.setLayout(vbox)
#@-node:tbrown.20091028131637.1354:__init__
#@+node:tbrown.20091028131637.1359:writeBack
def writeBack(self, event=None):
for n,i in enumerate(self.buttons):
self.entries[n][1] = (i.checkState() == Qt.Checked)
self.accept()
#@-node:tbrown.20091028131637.1359:writeBack
#@-others
#@-node:tbrown.20091028131637.1353:class ListDialog
#@+node:tbrown.20091010211613.5257:class editWatcher
class editWatcher(object):
"""class to supply widget for editing attribute and handle
its textChanged signal"""
def __init__(self, c, v, class_, name, value, path, type_):
"""v - node whose attribute we edit
name - name of edited attribute
value - initial value of edited attribute
path - dictionary key path to attribute in v.u
type_ - attribute type
"""
self.c = c
self.v = v
self.class_ = class_
self.name = name
self.value = value
self.path = path
self.type_ = type_
self._widget = None
def widget(self):
"""return widget for editing this attribute"""
if not self._widget:
self._widget = QtGui.QLineEdit(str(self.value))
QtCore.QObject.connect(self._widget,
QtCore.SIGNAL("textChanged(QString)"), self.updateValue)
self._widget.focusOutEvent = self.lostFocus
# see lostFocus()
return self._widget
def updateValue(self, newValue):
"""copy value from widget to v.u"""
self.class_.setAttrib(self.v, self.path, self.type_(newValue))
self.v.setDirty()
def lostFocus(self, event):
"""Can activate this in in widget(), but it stops tabbing through
the attributes - unless we can check that none of our siblings
has focus..."""
sibs = self._widget.parent().findChildren(QtGui.QLineEdit)
for i in sibs:
if i.hasFocus():
break
else:
self.c.redraw()
#X def setValue(a, path, value):
#X """copy value into dict a on path,
#X e.g. a['one']['more']['level'] = value
#X """
#X for i in path[:-1]:
#X a = a.setdefault(i, {})
#X a[path[-1]] = value
#@-node:tbrown.20091010211613.5257:class editWatcher
#@+node:tbrown.20091009210724.10979:class attrib_edit_Controller
class attrib_edit_Controller:
'''A per-commander class that manages attribute editing.'''
#@ @+others
#@+node:tbrown.20091009210724.10981:__init__
def __init__ (self, c):
self.c = c
c.attribEditor = self
self.pname = "_attrib_edit_frame" # used to tag out panel
active = c.config.getData('attrib_edit_active_modes') or []
self.getsetters = []
for i in AttributeGetter.implementations:
s = i(c)
self.getsetters.append([s, (s.name() in active) ])
if not active:
self.getsetters[0][1] = True # turn on the first one
self.attrPaths = set() # set of tuples (getter-class, path)
self.handlers = [
('select3', self.updateEditor),
]
for i in self.handlers:
leoPlugins.registerHandler(i[0], i[1])
# 'body' or 'tab' mode
self.guiMode = c.config.getString('attrib_edit_placement') or 'body'
if self.guiMode == 'body':
self.holder = QtGui.QSplitter(QtCore.Qt.Vertical)
self.holder.setMinimumWidth(300)
os = c.frame.top.leo_body_frame.parent()
self.holder.addWidget(c.frame.top.leo_body_frame)
os.addWidget(self.holder)
self.parent = self.holder
elif self.guiMode == 'tab':
self.parent = QtGui.QFrame()
self.holder = QtGui.QHBoxLayout()
self.parent.setLayout(self.holder)
c.frame.log.createTab('Attribs', widget = self.parent)
#@-node:tbrown.20091009210724.10981:__init__
#@+node:tbrown.20091009210724.10983:__del__
def __del__(self):
for i in self.handlers:
leoPlugins.unregisterHandler(i[0], i[1])
#@-node:tbrown.20091009210724.10983:__del__
#@+node:tbrown.20091009210724.11210:initForm
def initForm(self):
"""set up self.form, the blank form layout before adding edit widgets"""
self.editors = []
w = self.holder
for i in w.findChildren(QtCore.QObject):
if i.objectName() == self.pname:
i.hide()
i.deleteLater()
pnl = QtGui.QFrame()
pnl.setObjectName(self.pname)
self.form = QtGui.QFormLayout()
self.form.setVerticalSpacing(0)
pnl.setLayout(self.form)
pnl.setAutoFillBackground(True)
w.addWidget(pnl)
#@-node:tbrown.20091009210724.11210:initForm
#@+node:tbrown.20091009210724.11047:updateEditor
def updateEditor(self,tag,k):
"""update edit panel when new node selected"""
if k['c'] != self.c: return # not our problem
self.updateEditorInt()
#@-node:tbrown.20091009210724.11047:updateEditor
#@+node:tbrown.20091028100922.1493:updateEditorInt
def updateEditorInt(self):
c = self.c
self.initForm()
for attr in self.getAttribs():
class_, name, value, path, type_, readonly = attr
if readonly:
self.form.addRow(QtGui.QLabel(name), QtGui.QLabel(str(value)))
else:
editor = editWatcher(c, c.currentPosition().v, class_, name, value, path, type_)
self.editors.append(editor)
self.form.addRow(QtGui.QLabel(name), editor.widget())
#@-node:tbrown.20091028100922.1493:updateEditorInt
#@+node:tbrown.20091103080354.1405:recSearch
def JUNKrecSearch(self, d, path, ans):
"""recursive search of tree of dicts for values whose
key path is like [*][*][*]['_edit'][*] or
[*][*][*]['_edit']['_int'][*]
Modifies list ans
"""
for k in d:
if isinstance(d[k], dict):
if k not in ('_edit', '_view'):
self.recSearch(d[k], path+[k], ans)
else:
# k == '_edit' or '_view'
for ek in d[k]:
if ek in self.typeMap:
# ek is '_int' or similar
type_ = self.typeMap[ek]
for ekt in d[k][ek]:
ans.append((ekt, d[k][ek][ekt], tuple(path+['_edit',ek,ekt]),
type_, k != '_edit'))
else:
ans.append((ek, d[k][ek], tuple(path+['_edit',ek]), str, k != '_edit'))
#@-node:tbrown.20091103080354.1405:recSearch
#@+node:tbrown.20091103080354.1406:getAttribs
def getAttribs(self, v = None):
"""Return a list of tuples describing editable uAs.
(class, name, value, path, type, readonly)
e.g.
(class, 'created', '2009-09-23', ('stickynotes','_edit','created'), str, False),
(class, 'cars', 2, ('inventory','_edit','_int','cars'), int, False)
Changes should be written back to
v.uA['stickynotes']['_edit']['created'] and
v.uA['inventory']['_edit']['_int']['cars'] respectively
"""
ans = []
if not v:
v = self.c.currentPosition().v
for getter, isOn in self.getsetters:
if not isOn:
continue
ans.extend(getter.getAttribs(v))
for ns in ans:
self.attrPaths.add( (ns[0], ns[1], ns[3]) ) # class, name, path
return ans
#@-node:tbrown.20091103080354.1406:getAttribs
#@+node:tbrown.20091029101116.1413:addAttrib
def addAttrib(self, attrib):
attrib[0].setAttrib(self.c.currentPosition().v, attrib[2], '')
#@-node:tbrown.20091029101116.1413:addAttrib
#@+node:tbrown.20091029101116.1414:delAttrib
def delAttrib(self, attrib):
attrib[0].delAttrib(self.c.currentPosition().v, attrib[2])
#@-node:tbrown.20091029101116.1414:delAttrib
#@+node:tbrown.20091029101116.1424:scanAttribs
def scanAttribs(self):
"""scan all of c for attrbutes"""
for v in self.c.all_unique_nodes():
self.getAttribs(v) # updates internal list of attribs
g.es("%d attributes found" % len(self.attrPaths))
#@nonl
#@-node:tbrown.20091029101116.1424:scanAttribs
#@+node:tbrown.20091011151836.14788:createAttrib
def createAttrib(self, event=None, readonly=False):
ans = []
for getter, isOn in self.getsetters:
if not isOn:
continue
if getter.helpCreate() is True:
ans.append(getter)
else:
g.es("For '%s' attributes:\n %s" % (getter.name(), getter.helpCreate()))
if len(ans) > 1:
g.es('ERROR: more than one attribute type (%s) active' %
', '.join([i.name() for i in ans]), color='red')
elif ans:
ans[0].createAttrib(self.c.currentPosition().v, gui_parent=self.parent)
self.updateEditorInt()
self.c.currentPosition().v.setDirty()
self.c.redraw()
#@-node:tbrown.20091011151836.14788:createAttrib
#@+node:tbrown.20091028131637.1358:manageAttrib
def manageAttrib(self):
attribs = [(i[0],i[1],i[3]) for i in self.getAttribs()]
dat = []
for attr in self.attrPaths:
txt = attr[0].longDescrip(attr[2])
active = attr in attribs
dat.append([txt, active, attr])
if not dat:
g.es('No attributes seen (yet)')
return
dat.sort(key=lambda x: x[0])
res = ListDialog(self.parent, "Enter attribute path",
"Enter path to attribute (space separated words)",
dat)
res.exec_()
if res.result() == QtGui.QDialog.Rejected:
return
# check for deletions
for i in dat:
if i[2] in attribs and not i[1]:
res = QtGui.QMessageBox(QtGui.QMessageBox.Question,
"Really delete attributes?","Really delete attributes?",
QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel, self.parent)
if res.exec_() == QtGui.QMessageBox.Cancel:
return
break
# apply changes
for i in dat:
if i[2] in attribs and not i[1]:
self.delAttrib(i[2])
elif i[2] not in attribs and i[1]:
self.addAttrib(i[2])
self.updateEditorInt()
self.c.redraw()
#@-node:tbrown.20091028131637.1358:manageAttrib
#@+node:tbrown.20091103080354.1415:manageModes
def manageModes(self):
modes = [ [i[0].name(), i[1]] for i in self.getsetters ]
res = ListDialog(self.parent, "Enter attribute path",
"Enter path to attribute (space separated words)",
modes)
res.exec_()
if res.result() == QtGui.QDialog.Rejected:
return
for n,i in enumerate(modes):
self.getsetters[n][1] = i[1]
self.updateEditorInt()
#@-node:tbrown.20091103080354.1415:manageModes
#@-others
#@-node:tbrown.20091009210724.10979:class attrib_edit_Controller
#@+node:tbrown.20091029101116.1415:cmd_Modes
def cmd_Modes(c):
c.attribEditor.manageModes()
#@-node:tbrown.20091029101116.1415:cmd_Modes
#@+node:tbrown.20091103080354.1413:cmd_Manage
def cmd_Manage(c):
c.attribEditor.manageAttrib()
#@-node:tbrown.20091103080354.1413:cmd_Manage
#@+node:tbrown.20091029101116.1419:cmd_Create
def cmd_Create(c):
c.attribEditor.createAttrib()
#@-node:tbrown.20091029101116.1419:cmd_Create
#@+node:tbrown.20091029101116.1421:cmd_CreateReadonly
def Xcmd_CreateReadonly(c):
c.attribEditor.createAttrib(readonly=True)
#@-node:tbrown.20091029101116.1421:cmd_CreateReadonly
#@+node:tbrown.20091029101116.1426:cmd_Scan
def cmd_Scan(c):
c.attribEditor.scanAttribs()
#@-node:tbrown.20091029101116.1426:cmd_Scan
#@-others
#@nonl
#@-node:tbrown.20091029123555.5319:@thin attrib_edit.py
#@-leo
|