# ----------------------------------------------------------------------------
# This file is part of qarbon (http://qarbon.rtfd.org/)
#
# Copyright (c) 2013 European Synchrotron Radiation Facility, Grenoble, France
#
# Distributed under the terms of the GNU Lesser General Public License,
# either version 3 of the License, or (at your option) any later version.
# See LICENSE.txt for more info.
# ----------------------------------------------------------------------------
"""A tree widget representing QObject hierarchy (for development purposes).
The most common use case of this widget is to debug applications which may have
"zombie" widgets lying around when some widget is removed, reparented in
a dynammic GUI.
Example::
from qarbon.external.qt import QtCore, QtGui
from qarbon.qt.gui.application import Application
from qarbon.qt.gui.treeqobject import TreeQObjectWidget
app = Application()
# mw will be the QObject to be "seen" in the Tree (along with all its
# childs, of course)
mw = QtGui.QMainWindow()
mw.setObjectName("main window")
w = QtGui.QWidget()
w.setObjectName("central widget")
mw.setCentralWidget(w)
l = QtGui.QVBoxLayout()
w.setLayout(l)
l1 = QtGui.QLabel("H1")
l1.setObjectName("label 1")
l.addWidget(l1)
l2 = QtGui.QLabel("H2")
l2.setObjectName("label 2")
l.addWidget(l2)
mw.show()
inspector = TreeQObjectWidget(qobject=w)
inspector.setAttribute(QtCore.Qt.WA_QuitOnClose, False)
inspector.show()
app.exec_()
"""
__all__ = ["QObjectRepresentation", "getQObjectTree", "getQObjectTreeStr",
"TreeQObjectInfoModel", "TreeQObjectWidget"]
import weakref
from qarbon import log
from qarbon.external.enum import Enum
from qarbon.external.qt import QtCore, QtGui
from qarbon.qt.gui.icon import Icon
from qarbon.qt.gui.application import Application
from qarbon.qt.gui.basetree import BaseTreeWidget
from qarbon.qt.gui.basemodel import BaseModel, BaseTreeItem
[docs]class QObjectRepresentation(Enum):
"possible displays of a QObject"
ClassName, ObjectName, FullName = range(3)
QR = QObjectRepresentation
__DEFAULT_FILTER_CLASSES = QtCore.QPropertyAnimation, QtGui.QPanGesture
def _filter(qobject):
# Filter
if isinstance(qobject, __DEFAULT_FILTER_CLASSES):
return
return qobject
def _buildQObjectsAsDict(qobject, container, ffilter=_filter):
container[qobject] = childs = {}
for child in qobject.children():
# Filter
if not ffilter(child) is None:
_buildQObjectsAsDict(child, childs, ffilter=ffilter)
def getQObjectTreeAsDict(qobject=None, ffilter=_filter):
if qobject is None:
app = Application()
qobjects = [app] + app.topLevelWidgets()
else:
qobjects = [qobject]
tree = {}
for qobject in qobjects:
if not ffilter(qobject) is None:
_buildQObjectsAsDict(qobject, tree, ffilter=ffilter)
return tree
def _buildQObjectsAsList(qobject, container, ffilter=_filter):
children = qobject.children()
node = qobject, []
container.append(node)
for child in children:
if not ffilter(child) is None:
_buildQObjectsAsList(child, node[1], ffilter=ffilter)
def getQObjectTreeAsList(qobject=None, ffilter=_filter):
if qobject is None:
app = Application()
qobjects = [app] + app.topLevelWidgets()
else:
qobjects = [qobject]
tree = []
for qobject in qobjects:
if not ffilter(qobject) is None:
_buildQObjectsAsList(qobject, tree, ffilter=ffilter)
return tree
getQObjectTree = getQObjectTreeAsList
def _getQObjectStr(qobject, representation):
if qobject is None:
return 'Null'
if representation == QObjectRepresentation.ClassName:
return qobject.__class__.__name__
try:
objectName = qobject.objectName()
except RuntimeError:
log.error("error accessing object %s", qobject)
log.debug("details: ", exc_info=1)
if representation == QObjectRepresentation.ClassName:
return qobject.__class__.__name__
else:
return "> ERROR! <"
if representation == QObjectRepresentation.ObjectName:
return objectName
elif representation == QObjectRepresentation.FullName:
className = qobject.metaObject().className()
return '{0}("{1}")'.format(className, objectName)
return str(qobject)
def _buildQObjectStr(node, str_tree,
representation=QObjectRepresentation.ClassName,
ffilter=_filter):
qobject, children = node
str_node = _getQObjectStr(qobject, representation)
str_children = []
if len(children):
str_tree.append((str_node, str_children))
for child in children:
if ffilter(child):
_buildQObjectStr(child, str_children,
representation=representation,
ffilter=ffilter)
else:
str_tree.append(str_node)
[docs]def getQObjectTreeStr(qobject=None,
representation=QObjectRepresentation.ClassName,
ffilter=_filter):
tree, str_tree = getQObjectTree(qobject=qobject, ffilter=ffilter), []
for e in tree:
_buildQObjectStr(e, str_tree, representation=representation,
ffilter=ffilter)
return str_tree
def _getWidgetLayout(widget):
if not isinstance(widget, QtGui.QWidget):
return
parent = widget.parent()
if parent is None or not isinstance(parent, QtGui.QWidget):
return
layout = parent.layout()
if layout.indexOf(widget) < 0:
return
return layout
def getQObjectIcon(qo):
if isinstance(qo, QtGui.QWidget):
name = "widget"
if isinstance(qo, QtGui.QLabel):
name = "label"
elif isinstance(qo, QtGui.QComboBox):
name = "combobox"
elif isinstance(qo, QtGui.QDoubleSpinBox):
name = "doublespinbox"
elif isinstance(qo, QtGui.QDateEdit):
name = "dateedit"
elif isinstance(qo, QtGui.QTimeEdit):
name = "timeedit"
elif isinstance(qo, QtGui.QDateTimeEdit):
name = "datetimeedit"
elif isinstance(qo, QtGui.QLineEdit):
name = "linedit"
elif isinstance(qo, QtGui.QPlainTextEdit):
name = "plaintextedit"
elif isinstance(qo, QtGui.QTextEdit):
name = "textedit"
elif isinstance(qo, QtGui.QTabWidget):
name = "tabwidget"
elif isinstance(qo, QtGui.QRadioButton):
name = "radiobutton"
elif isinstance(qo, QtGui.QPushButton):
name = "pushbutton"
elif isinstance(qo, QtGui.QToolButton):
name = "toolbutton"
elif isinstance(qo, QtGui.QCheckBox):
name = "checkbox"
elif isinstance(qo, QtGui.QToolBox):
name = "toolbox"
elif isinstance(qo, QtGui.QTreeView):
name = "tree"
elif isinstance(qo, QtGui.QTableView):
name = "table"
elif isinstance(qo, QtGui.QListView):
name = "listbox"
elif isinstance(qo, QtGui.QStackedWidget):
name = "widgetstack"
elif isinstance(qo, QtGui.QDockWidget):
name = "dockwidget"
elif isinstance(qo, QtGui.QDockWidget):
name = "dockwidget"
elif isinstance(qo, QtGui.QCalendarWidget):
name = "calendarwidget"
elif isinstance(qo, QtGui.QDialogButtonBox):
name = "dialogbuttonbox"
elif isinstance(qo, QtGui.QFrame):
name = "frame"
elif isinstance(qo, QtGui.QAbstractSpinBox):
name = "spinbox"
elif isinstance(qo, QtGui.QAbstractButton):
name = "pushbutton"
elif isinstance(qo, QtGui.QAbstractSlider):
name = "hslider"
return Icon(":/designer/" + name + ".png")
elif isinstance(qo, QtGui.QLayout):
name = "editform"
if isinstance(qo, QtGui.QVBoxLayout):
name = "editvlayout"
elif isinstance(qo, QtGui.QHBoxLayout):
name = "edithlayout"
elif isinstance(qo, QtGui.QGridLayout):
name = "editgrid"
elif isinstance(qo, QtGui.QFormLayout):
name = "editform"
elif isinstance(qo, QtCore.QCoreApplication):
return Icon("applications-development")
return Icon("emblem-system")
class TreeQObjecttInfoItem(BaseTreeItem):
def __init__(self, model, data, parent=None):
BaseTreeItem.__init__(self, model, data, parent=parent)
if data is not None:
self.qobject = weakref.ref(data)
dat = (_getQObjectStr(data, QR.ClassName),
_getQObjectStr(data, QR.ObjectName))
self.setData(0, dat)
self.__toolTip = _getQObjectStr(data, QR.FullName)
self.__icon = getQObjectIcon(data)
def toolTip(self, index):
return self.__toolTip
def icon(self, index):
if index.column() == 0:
return self.__icon
[docs]class TreeQObjectInfoModel(BaseModel):
ColumnNames = "Class", "Object name"
ColumnRoles = (QR.ClassName,), QR.ObjectName
def __init__(self, parent=None, data=None):
BaseModel.__init__(self, parent=parent, data=data)
[docs] def role(self, column, depth=0):
if column == 0:
return self.ColumnRoles[column][0]
return self.ColumnRoles[column]
[docs] def roleIcon(self, taurus_role):
return QtGui.QIcon()
[docs] def roleSize(self, taurus_role):
return QtCore.QSize(300, 70)
@staticmethod
def _build_qobject_item(model, parent, node):
qobject, children = node
item = TreeQObjecttInfoItem(model, qobject, parent)
parent.appendChild(item)
for child in children:
TreeQObjectInfoModel._build_qobject_item(model, item, child)
[docs] def setupModelData(self, qobject):
if qobject is None:
return
data = getQObjectTree(qobject=qobject)
rootItem = self._rootItem
for node in data:
TreeQObjectInfoModel._build_qobject_item(self, rootItem, node)
def buildGUI():
mw = QtGui.QMainWindow()
mw.setObjectName("main window")
w = QtGui.QWidget()
w.setObjectName("central widget")
mw.setCentralWidget(w)
l = QtGui.QVBoxLayout()
w.setLayout(l)
l1 = QtGui.QLabel("H1")
l1.setObjectName("label 1")
l.addWidget(l1)
l2 = QtGui.QLabel("H2")
l2.setObjectName("label 2")
l.addWidget(l2)
mw.show()
return mw
def main():
app = Application()
w = buildGUI()
w.show()
inspector = TreeQObjectWidget(qobject=w)
inspector.setAttribute(QtCore.Qt.WA_QuitOnClose, False)
inspector.show()
app.exec_()
if __name__ == "__main__":
main()